페이지 탐색을 위해 스크롤 처리기에서 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>
그래서, 내가 유망 보인다 반응 수평 스크롤에서 영감을 자신의 스크롤 동작과 컨테이너를 사용하고 있습니다. 그러나이 새로운 코드에서는 이상한 일이 발생합니다. 새 라우트는 클라이언트 측으로 잠시 렌더링되며 새 라우트가 서버에서 페! 될 때 페이지가 새로 고쳐집니다.
// 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에서 와일드 카드 요청 처리기를 사용하더라도 페이지는 다시로드되지만 (자체로 리디렉션됩니까?) 생각하지는 않지만 서버 구성에는 문제가 없습니다.
나는 무엇이 없습니까, 인터넷의 신탁입니까?