页面书签
简略讲就是你从以后页面进行滚动浏览,当“进来一趟”再回来的时候,要还原这个滚动地位,就如同一本书的书签一样。
那么就形容下对页面书签的冀望吧
- 当我跳转其余页面的时候,回来要还原。
- 还原不能间接就定位太突兀,应该是动画。
那么开始着手去实现冀望
如何实现“当我跳转其余页面的时候,回来要还原。”
顺推一下思路:
- “还原”是须要依附“数据”的。
- “ 数据 ” 是须要在页面之间跳转仍然能够“保留”的
- “保留”是须要脱离页面之外不受其“管制”的
- “管制”是须要谁来做呢🤔???
简略啊,那显著就交给数据仓库被😄。
如何实现“还原不能间接就定位太突兀,应该是动画。”
再顺推一下:
- “动画”是须要“细腻”的。
- “ 细腻 ” 是须要“连贯”的。
- “连贯”是须要对此执行“递归”的。
- “递归”是须要谁来做呢🤔???
通过摸索,Bom 对象的 requestAnimationFrame 就很适合。
requestAnimationFrame 官网介绍:
通知浏览器——你心愿执行一个动画,并且要求浏览器在下次重绘之前调用指定的回调函数更新动画。该办法须要传入一个回调函数作为参数,该回调函数会在浏览器下一次重绘之前执行
画面一秒 60fps,那么回调函数执行次数通常是每秒 60 次(除了卡掉帧了)那就足够“连贯”了,没次做一点扭转,间断做就能做到“细腻”了(这就跟游戏开发没啥区别了)。
这里必须要强调一下,查阅了几篇文章,有不少都说错了一个点(我感觉的)
比方这句:
你这么说就如同跟 setinterval
似的了,我感觉不对,逻辑矛盾了。
我的了解 :页面一秒 60fps,那么你执行了requestAnimationFrame
, 那么只是在 下一次 屏幕绘制的时候 执行一次 ,那么怎么连贯的呢,那是通过 递归执行 这个函数实现的,代码就是这么说的。不会骗人的。
上代码:
export function sineaseOut(t, b, c, d) {return c * ((t = t / d - 1) * t * t + 1) + b
}
export function scrollToView(scroller, value) {if (!scroller) {return}
const scroll = value
const scrollStart = 0
let start = null
const step = (timestamp) => {if (!start) {start = timestamp}
let stepScroll = sineaseOut(timestamp - start, 0, scroll, 500)
let total = scroller.scrollTop = scrollStart + stepScroll
if (total < scrollStart + scroll) {requestAnimationFrame(step)
}
}
requestAnimationFrame(step)
}
那么做个小结
- 状态数据交由数据管理器
Mobx
来负责,mobx
派global
仓库来做。 - 动画的细腻就通过一秒 60 次的绘制进行递归调用
requestAnimationFrame
来实现。
情理都懂,那么而后呢?
哎呀,的确啊。。。尽管两个都有方法解决了,但还有最最要害的问题,“用武之地”在哪啊???
“用武之地”可是很看“风水”的哦
地位要是没选好,那几乎让你的代码中处处充斥了 做作 ,就为了看起来难受那么一点,那就跟“ 打肿脸充胖子”差不多了。
最危险的陷阱往往很温顺
首先从需要上来看,很容易就联想到组件的卸载和挂载,因为真的很匹配,这就是 最大的引诱 ,因为它能实现,但这绝不是好的方法,至多不是最好的,因为你如果真这么做了,那所有的页面组件都要去写这个反复的逻辑,那太烦了,如果是给一个曾经写好了很多页面的我的项目加,你会解体的,这 不能承受。
要抓住乌云背地的幸福线
当我想来想去,几经挫折,差点“真香”的时候,终于让我想到了一个极佳的地位,那就是。
history.listen
那时那刻,我自信地嘴角微微上扬,稳了😄。
间接上代码,我置信 b 数自在大家心中,无需多言了。
let history = useHistory();
let location = useLocation();
const {global: { current, scrollData, changeParams},
} = store;
useEffect(() => {const { pathname, search} = location;
changeParams({current: decodeURIComponent(pathname + search)
})
if (!history._listenCount) {
history._listenCount++;
history.listen((locationState, type) => {
const {global: { current, scrollData, changeParams},
} = store;
let node = document.getElementsByClassName('ant-layout-content')[0]
if (!node) {return}
// node.scrollTop = 0;
// 最新页面的 Key,存上就行
let newkey = decodeURIComponent(locationState.pathname + locationState.search);
/* 找一下看看有没有记录值 */
let recordValue = scrollData[newkey]
if (typeof recordValue === 'number') {scrollToView(node, recordValue)
}
// 取值(过来的)存一下,old
let oldKey = current;
let scrollDataTemp = {...toJS(scrollData), [oldKey]: node.scrollTop }
if (type === "POP") {
//POP 状况下 node.scrollTop 曾经被设置成 0 了
changeParams({current: newkey,})
} else {
changeParams({
current: newkey,
scrollData: scrollDataTemp
})
}
})
}
}, [])
代码很清晰,就是页面走了,记录一下,页面回来,复原一下,解决的就是这么简略天然。
看下成果
结语
通过摸索 页面书签 性能的实现形式,可能更好的领会一个情理,实现的形式不止一种,分明本人想要什么,你也就晓得本人该保持什么,该怎么做,也就更有可能抓住乌云背地的幸福线。
集成了该性能的🌰