涉及知识点:
window.scrollTo(x, y) requestAnimationFrame(()=>{}) //帧动画,优点:按浏览器的刷新频率渲染,更加流畅。特点:类似 setTimeout 只执行一次
啥也不说,直接上 react 版代码:
num 是需要到达的位置, 数字类型。调用:this.transitionScroll(100)
下面这段代码,亲只需要知道,每个索引对应的高度就可以了。
let timer = null; this.state = { onOff: true, //初始值为true,默认可以点击,在滚动的时候变成false,结束滚动再次为true active: 0 } headerBtnClick = (index) => { //点击改变索引 if(this.state.onOff) { this.setState({ active: index }, () => { this.scrollFn(index) }) } } scrollFn = (index) => { //每个索引对应的位置 //this.transitionScroll(...) 根据索引,判断需要滚动到的位置。 } componentDidMount() { window.addEventListener("scroll", () => { //监听是否为滚动状态,在滚动状态不可再次点击 clearTimeout(timer) //利用防抖技巧,在结束滚动250ms之后恢复可点击状态 timer = setTimeout(() => { this.setState({ onOff: true }) }, 250) this.setState({ onOff: false }) }) } componentWillUnmount() { if(timer) { clearTimeout(timer) } } //sensitivity: 容错率和灵敏度为 5 时正好 //容错率越小,滚动的位置越精确,太小可能会出现无限回调的错误(主要原因是数字相除再取整,值不再精确) transitionScroll = (num) => { //判断需要上滚,还是下滚 const n = window.pageYOffset; if(num < n) { this.ScrollDown(num) } if(num > n) { this.ScrollUp(num) } } ScrollDown = (num) => { //向下滚 const sensitivity = 5; window.requestAnimationFrame(() => { const n = window.pageYOffset; const Dvalue = Math.abs(num - n); if (num > n + sensitivity) {//容错率 window.scrollTo(0, n + parseInt(Dvalue / sensitivity))//灵敏度 this.ScrollDown(num) } }) } ScrollUp = (num) => { //向上滚 const sensitivity = 5; window.requestAnimationFrame(() => { const n = window.pageYOffset; const Dvalue = Math.abs(num - n); if (num < n - sensitivity) { window.scrollTo(0, n - parseInt(Dvalue / sensitivity)) this.ScrollDown(num) } }) }