2017-12-07 1 views
0

페이지 탐색을 위해 스크롤 처리기에서 Next.js 명령형 라우팅 API를 사용하려고합니다. 창에 연결하면 스크롤 위치 재설정과 같은 색 '플래시'가 있다는 작은 예외가 있습니다. 이전 페이지의 맨 위로 이동하면 새 경로의 맨 아래에서 계속 스크롤해야합니다. 색상 변환은 매끄럽게 이루어져야합니다. 브라우저의 밀리 초 (scrollTop가 0 인 경우) 때문에 가능하지 않습니다. 코드 :Next.js의 이상한 필수 onScroll 라우팅 동작 (서버에서만 렌더링)

export default class ScrollOMatic extends Component { 
 
    constructor(props) { 
 
    super(props) 
 
    this.state = { 
 
     prevRoute: '', 
 
     nextRoute: '', 
 
     isEndOfScroll: false 
 
    } 
 
    binder(this, ['handleScroll']) 
 
    } 
 
    componentWillMount() { 
 
    if (typeof window !== 'undefined') { 
 
     console.log(window) 
 
    } 
 
    } 
 
    componentDidMount() { 
 
    window.addEventListener('scroll', this.handleScroll) 
 
    const { 
 
     prevRoute, 
 
     nextRoute 
 
    } = this.props.routeData 
 
    this.setState({ 
 
     prevRoute, 
 
     nextRoute 
 
    }) 
 
    Router.prefetch('us') 
 
    Router.prefetch('work') 
 
    Router.prefetch('services') 
 
    Router.prefetch('converse') 
 
    } 
 
    componentWillUnmount() { 
 
    window.removeEventListener('scroll', this.handleScroll) 
 
    } 
 
    handleScroll(e) { 
 
    e.preventDefault() 
 
    let { 
 
     scrollTop, 
 
     scrollHeight 
 
    } = e.srcElement.scrollingElement 
 
    scrollHeight = scrollHeight/2 
 
    const scrollTiplier = scrollTop/scrollHeight 
 
    if (scrollTop === 0) { 
 
     Router.push(this.state.prevRoute) 
 
     window.scrollTo(0, scrollHeight - 1, { 
 
     duration: 0 
 
     }) 
 
    } 
 
    if (scrollTiplier === 1) { 
 
     Router.push(this.state.nextRoute) 
 
     window.scrollTo(0, 1, { 
 
     duration: 0 
 
     }) 
 
    } 
 
    } 
 
    render() { 
 
    return ( 
 
     <div className = 'scroll-o-matic' >{ this.props.children }</div> 
 
    ) 
 
    } 
 
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script> 
 
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

그래서, 내가 유망 보인다 반응 수평 스크롤에서 영감을 자신의 스크롤 동작과 컨테이너를 사용하고 있습니다. 그러나이 새로운 코드에서는 이상한 일이 발생합니다. 새 라우트는 클라이언트 측으로 잠시 렌더링되며 새 라우트가 서버에서 페! 될 때 페이지가 새로 고쳐집니다. enter image description here

// inspired by react-horizontal-scroll 
 
import { Motion, spring, presets } from 'react-motion' 
 
import raf from 'raf' 
 
import Router from 'next/router' 
 
import { fadeColor, binder } from '../../lib/_utils' 
 
import { setScrollState } from '../../lib/_navRules' 
 

 
export default class ScrollOMatic extends Component { 
 
    constructor (props) { 
 
    super(props) 
 
    this.state = { 
 
     prevRoute: '', 
 
     nextRoute: '', 
 
     animValues: 0 
 
    } 
 
    binder(this, ['handleWheel', 'resetMin', 'resetMax', 'navigator', 'canIscroll', 'getLayoutData']) 
 
    } 
 
    componentDidMount() { 
 
    const { prevRoute, nextRoute } = this.props.routeData 
 
    this.setState({ 
 
     prevRoute, 
 
     nextRoute 
 
    }) 
 

 
    const prevRouteName = prevRoute === '/' ? 'index' : prevRoute.replace('/', '') 
 
    const nextRouteName = prevRoute === '/' ? 'index' : nextRoute.replace('/', '') 
 
    Router.prefetch(prevRouteName) 
 
    Router.prefetch(nextRouteName) 
 
    } 
 

 
    componentWillReceiveProps (nextProps) { 
 
    if (this.props.children !== nextProps.children) { this.resetMin() } 
 
    } 
 

 
    shouldComponentUpdate (nextProps, nextState) { 
 
    if (true && 
 
     this.calculate.timer !== void 0 && 
 
     this.props.children === nextProps.children && 
 
     this.state.animValues === nextState.animValues) { 
 
     return false 
 
    } 
 
    if (true && 
 
     this.props.children === nextProps.children && 
 
     this.canIscroll() === false) { 
 
     return false 
 
    } 
 
    return true 
 
    } 
 

 
    componentDidUpdate() { this.calculate() } 
 

 
    getLayoutData() { 
 
    const scrollOMatic = DOM.findDOMNode(this.scrollOMatic) 
 
    const scrollTray = DOM.findDOMNode(this.scrollTray) 
 
    const max = scrollOMatic.scrollHeight 
 
    const win = scrollOMatic.offsetHeight 
 
    const currentVal = this.state.animValues 
 
    const bounds = -(max - win) 
 
    const trayTop = scrollTray.offsetTop 
 
    const trayOffsetHeight = scrollTray.offsetHeight 
 
    const trayScrollHeight = scrollTray.scrollHeight 
 
    const scrollOMaticRect = scrollOMatic.getBoundingClientRect() 
 
    const scrollOMaticTop = scrollOMaticRect.top 
 
    const scrollOMaticHeight = scrollOMaticRect.height 
 
    const scrollOMaticOffsetHeight = scrollOMatic.offsetHeight 
 
    return { 
 
     currentVal, 
 
     bounds, 
 
     scrollTray, 
 
     trayTop, 
 
     trayOffsetHeight, 
 
     trayScrollHeight, 
 
     scrollOMatic, 
 
     scrollOMaticTop, 
 
     scrollOMaticHeight, 
 
     scrollOMaticOffsetHeight, 
 
     scrollOMaticRect 
 
    } 
 
    } 
 

 
    calculate() { 
 
    const layout = this.getLayoutData() 
 
    clearTimeout(this.calculate.timer) 
 
    this.calculate.timer = setTimeout(() => { 
 
     const max = layout.trayScrollHeight 
 
     const win = layout.scrollOMaticOffsetHeight 
 
     const currentVal = this.state.animValues 
 
     const bounds = -(max - win) 
 
     if (currentVal >= 1) { 
 
     this.resetMin() 
 
     } else if (currentVal <= bounds) { 
 
     const x = bounds + 1 
 
     this.resetMax(x) 
 
     } 
 
    }) 
 
    } 
 

 
    resetMin() { this.setState({ animValues: 0 }) } 
 
    resetMax (x) { this.setState({ animValues: x }) } 
 

 
    canIscroll() { 
 
    const layout = this.getLayoutData() 
 
    return layout.trayOffsetTop < layout.scrollOMaticTop || 
 
     layout.trayOffsetHeight > layout.scrollOMaticHeight 
 
    } 
 

 
    handleWheel (e) { 
 
    e.preventDefault() 
 
    const rawData = e.deltaY ? e.deltaY : e.deltaX 
 
    const mouseY = Math.floor(rawData) 
 
    const animationVal = this.state.animValues 
 
    const newAnimationVal = (animationVal + mouseY) 
 
    const newAnimationValNeg = (animationVal - mouseY) 
 

 
    if (!this.canIscroll()) return 
 

 
    const layout = this.getLayoutData() 
 
    const { currentVal, scrollOMaticHeight, trayScrollHeight } = layout 
 
    const isEndOfPage = -(currentVal - scrollOMaticHeight) + 1 === trayScrollHeight 
 

 
    this.navigator() 
 

 
    const scrolling =() => { 
 
     this.state.scrollInverted 
 
     ? this.setState({ animValues: newAnimationValNeg }) 
 
     : this.setState({ animValues: newAnimationVal }) 
 
    } 
 
    raf(scrolling) 
 
    } 
 
    
 
    navigator() { 
 
    const layout = this.getLayoutData() 
 
    const { currentVal, scrollOMaticHeight, trayScrollHeight } = layout 
 
    const shouldBeNextRoute = -(currentVal - scrollOMaticHeight) + 1 >= trayScrollHeight 
 
    // const shouldBePrevRoute = this.state.animValues < 0 
 

 
    if (shouldBeNextRoute) { 
 
     Router.push(this.state.nextRoute) 
 
    } 
 
    // if (shouldBePrevRoute) { 
 
    // Router.push(this.state.prevRoute)  
 
    // } 
 
    } 
 

 
    render() { 
 
    const springConfig = presets.noWobble 
 
    return (
 
     <div style={{ position: 'relative', width: '100vw', height: '100vh' }} className='scroll-o-matic' onWheel={this.handleWheel} 
 
     ref={scrollOMatic => { this.scrollOMatic = scrollOMatic }}> 
 
     <Motion style={{ z: spring(this.state.animValues, springConfig) }}> 
 
      { ({ z }) => (
 
      <div className='scroll-tray' ref={(scrollTray) => { this.scrollTray = scrollTray }} 
 
       style={{ 
 
       height: '300vh', 
 
       width: '100vw', 
 
       // top: '-100vh', 
 
       transform: `translate3d(0,${z.toFixed(3)}px,0)`, 
 
       willChange: 'transform', 
 
       display: 'inline-flex', 
 
       position: 'absolute' 
 
       }}> 
 
       { this.props.children } 
 
      </div> 
 
     )} 
 
     </Motion> 
 
     <style jsx>{` 
 
      .scroll-o-matic { 
 
      background-color: ${this.state.currentColor}; 
 
      } 
 
     `}</style> 
 
     </div> 
 
    ) 
 
    } 
 
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script> 
 
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

서버 코드 : GIF 및 코드를 참조하십시오

const express = require('express') 
 
const next = require('next') 
 

 
const dev = process.env.NODE_ENV !== 'production' 
 
const app = next({ dev }) 
 
const port = process.env.PORT || 3000 
 
const handle = app.getRequestHandler() 
 

 
app.prepare() 
 
    .then(() => { 
 
    const server = express() 
 
    server.use('/static', express.static('static')) 
 

 
    server.get('/', (req, res) => { 
 
     return app.render(req, res, '/', req.query) 
 
    }) 
 
    server.get('/us', (req, res) => { 
 
     return app.render(req, res, '/us', req.query) 
 
    }) 
 
    server.get('/work', (req, res) => { 
 
     return app.render(req, res, '/work', req.query) 
 
    }) 
 
    server.get('/services', (req, res) => { 
 
     return app.render(req, res, '/services', req.query) 
 
    }) 
 
    server.get('/converse', (req, res) => { 
 
     return app.render(req, res, '/converse', req.query) 
 
    }) 
 

 
    server.get('*', (req, res) => { 
 
     return handle(req, res, '/', req.query) 
 
    }) 
 

 
    server.listen(port, (err) => { 
 
     if (err) throw err 
 
     console.log(`> Ready on http://localhost:${port}`) 
 
    }) 
 
    })

어쩌면 나는 다음의 '프리 페치'를 이해하지 못하는, 그러나 확실히 선집하는 것 같지 않습니다. 나는 주로 서버 측 페이지로드가 왜 일어나는지 혼란 스럽다. Express에서 와일드 카드 요청 처리기를 사용하더라도 페이지는 다시로드되지만 (자체로 리디렉션됩니까?) 생각하지는 않지만 서버 구성에는 문제가 없습니다.

나는 무엇이 없습니까, 인터넷의 신탁입니까?

답변

1

프리 페치 옵션은 이미 다운로드 된 것 페이지 변경을하고 싶은,하지만 당신이 프리 페치 기대한다면 아무것도, 이미 렌더링되지 그렇게 할 때, 백그라운드에서 페이지의 JS 코드를 다운로드한다 HTML 또는 수동으로 구현해야하는 데이터

0

동일한 문제가있을 수있는 사람은 누구나 다음과 같은 '스타일있는 JSX'렌더링 방법과 관련되어있는 문제를 그대로 둡니다.

클라이언트 측 페이지가로드되는 경우에도 스타일이 적용된 JSX를로드해야하는 시간이 0.5 초 정도 인 것 같습니다. 전체 앱의 배경색과 같은 극적인 것이 사용자의 <style jsx>{``}<style> 태그 안에 있지 않는 한 일반적으로 알지 못하는 부분입니다. 모든 스타일을 일반 old html 스타일 attr에 넣으면 'flash'가 해결됩니다.