从这个博客皮肤迈入前端性能优化一小步

软件发布|下载排行|最新软件

当前位置:首页IT学院IT技术

从这个博客皮肤迈入前端性能优化一小步

DIV狂魔   2020-03-18 我要评论
# 前置 正如你所见,我现在用的这个博客皮肤,在没优化之前帧率会降到个位数. 现在与之相比,是不是好很多呀? 下面将从滚动 scroll 优化这一方面展开,主要说一下思路. ![](https://img2020.cnblogs.com/blog/1501373/202003/1501373-20200318101718711-885124719.png) 只在极少情况下会降到 30fps,一般稳定在 55-60fpx. # 头部导航条 头部导航条会监听滚动条上下滚动的方向随之展开或隐藏.当隐藏时,文章目录会上移一小段距离并固定;反之,会回到原来的位置.这里的头部导航条使用了 css3 `transform` 属性, 有时会调动 GPU 来加速, 所以导航条优化主要在于对监听滚动条事件的处理. **不好的做法** 头部导航条和文章目录各监听一个事件,分别写在一个 func 中. 这样会增加一个事件消耗,且代码会有冗余. **优化** 仔细分析, 文章目录是随头部导航条的变化而变化的.完全可以做一次事件监听完成这两件事,例如下面这样: ```js $(window).scroll(function() { if (condition) { // 显示导航条 // 目录下移 } else { // 隐藏导航条 // 目录上移 } }) ``` 因为代码量比较大, 当时写的时候就没考虑合并, 主要是先把功能做出来. 有了经验,以后再遇到类似的情况,就会考虑他们之间的联系了, 这里的重点就是找到这两者之间的联系. 但是这样就完了吗 ? 有些经验的, 可能想到防抖(debounce), 但仔细想想防抖真的够好吗? 如果加上防抖, 只会降低在一段时间内事件触发的频率.这样能减少很大的性能开销,一般遇到监听 scroll 或者 resize 等事件首先都会这样想吧. 仔细观察,就可以发现: 如果一直向上或向下滚动,导航条和文章目录都会保持一个状态, 只有逆向滚动时,它们才会一起发生一次状态改变. 这里有更好的做法: ```js function scrollFunc() { let scrollDirection if (!scrollAction) { scrollAction = window.pageYOffset } let diff = scrollAction - window.pageYOffset if (diff < 0) { scrollDirection = "down" } else if (diff > 0) { scrollDirection = "up" } scrollAction = window.pageYOffset return scrollDirection } let scrollAction, originalDir $(window).scroll(function() { let direction = scrollFunc() if (direction && originalDir != direction) { if (direction == "down") { // 显示导航条 // 目录下移 } else { // 隐藏导航条 // 目录上移 } originalDir = direction } }) ``` 上面这段代码,很容易明白.概括一下: 相当于增加一个做**更少计算**的中间层,只有符合条件时才会触发真正需要执行的操作. 甚至想让给这个所谓的**中间层**加上防抖也是可以的.这样和原来的对比更加明显了. # 文章目录活跃标题样式 监听滚动条滚动,如果这个文章标题超出了顶部, 即认为当前标题下的内容活跃(你正在浏览这部分),就会给当前目录中的标题添加活跃样式. 很显然,这里涉及遍历操作,所以计算量较大.这里可以使用防抖来优化,但是我使用了节流.使用节流能保证你较快速滚动页面时,依然能触发指定频次的 func,以显示目录活跃状态. 这样看起来就更平滑.使用防抖则不能,会等你停止滑动瞬间移动给最后一个活跃的标题添加样式,这样有明显的顿感.当然使用防抖也是可以的.很显然,这里使用节流仍然会增加部分开销. 另外,有更好的方法实现文章目录,比如使用 canvas 来绘制.我写的代码有些糟,可以另做一番优化. 另外补充一个小知识, 如何判断文章标题是否超出了顶部呢 ? 我是这样实现的: ```js getClientRect(element) { const {top, bottom, left, right, height, width} = element.getBoundingClientRect() return { top, bottom, left, right, height: height || bottom - top, width: width || right - left } } ``` 如果你对 `Element.getBoundingClientRect()` 没有了解, 如果有兴趣, 我在这里放了一个[链接-MDN](https:/https://img.qb5200.com/download-x/developer.mozilla.org/zh-CNhttps://img.qb5200.com/download-x/docs/Web/API/Element/getBoundingClientRect), 你可以跳转以学习它. # 百分比的指示器 例如右下角带百分比的指示器,通过监听滚动条位置转化成百分比,同时改变元素高度, 以控制动画的高度. 这里就犯了大忌了, 不断改变元素高度, 会导致不断重绘. 这部分使用 `requestAnimationFrame` 来优化, 虽然帧数提升明显, 这样仍然是极不好的做法, 不要在监听滚动的事件中修改样式! 找了很久没找到能够不改变高度就能实现这个效果的方式, 就给这个皮肤添加了一个可以选择简易指示器的选项. ```js back2top: { enable: true, type: "complex", // 可选 'simple' 不使用动画效果 right: "" }, ``` 这个指示器的配置为什么叫 `back2top` ? 这是因为如果你将鼠标放上去,它会显示一个箭头,点击可以回到顶部,它其实是一个返回顶部的按钮. 如果你对 `window.requestAnimationFrame` 没有了解, 如果有兴趣, 我在这里放了一个[链接-MDN](https:/https://img.qb5200.com/download-x/developer.mozilla.org/zh-CNhttps://img.qb5200.com/download-x/docs/Web/API/Window/requestAnimationFrame), 你可以跳转以学习它. # 最后 另外, 没优化之前在firefox上就很流畅 <( ̄▽ ̄)/ 博客还有其他地方的滚动监听, 思路重复就不一一列举了. 其实完全可以删去很多滚动监听事件, 这样也好, 能够稍微锻炼一下自己, 稍微增加这方面经验. 文章有错误不足,敬请指出,谢谢!

Copyright 2022 版权所有 软件发布 访问手机版

声明:所有软件和文章来自软件开发商或者作者 如有异议 请与本站联系 联系我们