发得快项目在优化时,有个优化是在切换菜单时,让菜单有一个过渡动画,但是在切换到订单时,过渡动画有一个明显的卡顿,要做的就是解决这个卡顿。
代码如下:(代码为demo,公司代码不可泄露)
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Documenttitle>
<style>
#menu {
width: 100px;
height: 100px;
background: #000;
transition: all 2s;
color: #fff;
}
#menu.selected {
background: #f00;
}
style>
head>
<body>
<div id="menu">点击触发过渡动画div>
<script>
let menu = document.getElementById("menu");
menu.onclick = function () {
// 计时器模拟异步http请求订单
setTimeout(() => {
kill();
}, 500);
// 切换选中状态
if (menu.classList.value.includes("selected")) {
menu.classList.remove("selected");
} else {
menu.classList.add("selected");
}
};
// while循环卡住js两秒,模拟订单渲染阻塞
function kill() {
var start = +new Date();
while (+new Date() - start < 2000) {
}
}
script>
body>
html>
首先分析卡顿原因,订单界面数据量较大,渲染这个页面需要较长的时间,js执行进程去渲染订单表格时间过长,打断了过度动画的计算,所以出现了卡顿的情况。
浏览器分为几个进程
渲染进程又分为几个线程
关于这个案例,我们需要用到GPU进程,GUI线程与js执行线程
js执行线程主要负责执行js代码,计算HTML 元素的 CSS 样式,绘制位图
GUI线程负责将js绘制好的位图递交给GPU进程,然后GPU进程渲染页面
拿到定单数据以后,将定单数据赋值给表格的data,angular框架的diff算法计算出改变的虚拟dom节点,并开始绘制,但是50条数据过于庞大,绘制时间过久,造成了卡顿
知道了问题是如何发生的,那么就可以思考解决方式,我目前找到了两种方式可以解决这个问题
分散渲染时间
浏览器渲染50条数据时间太久,那么我们就不要一次渲染那么多,只渲染当前能看到的就可以,其他的以后再说,那么渲染的少了,卡顿时间自然也就少了
这种方法没有降低总的渲染时间,只是将一大块时间分散开了,那么在每段时间的间隔中,就可以继续执行过渡动画的渲染
这种思路对应的解决方法是ng-zorro的虚拟滚动,类似懒加载
ng-zorro虚拟滚动示例
使用特定的css
在上网查资料的时候,发现了一个很有意思的demo
demo链接
同样是js阻塞,凭什么transform可以继续动,定位就卡住了呢?
带着这个问题,去查阅资料
发现浏览器对一些css样式有优化处理
深入浏览器理解CSS animations 和 transitions的性能问题
↑这个文章的图片丢失了
图片可以参考这个文章的图片↓
CSS3 动画卡顿解决方案
所以是浏览器对transform,opacity,filter属性有优化
猜测: 浏览器会优化这几个样式是因为,甭管这几个样式怎么变化,都不会影响到其他的dom元素,所以这部分的位图只需要计算一遍就完事了,没有必要重复递交
那么根据这个思路我们改进代码
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Documenttitle>
<style>
#menu {
width: 100px;
height: 100px;
background: #000;
color: #f00;
transition: all 2s linear;
opacity: 0.2;
}
#menu.selected {
opacity: 1;
}
style>
head>
<body>
<div id="menu">点击开始过渡动画div>
<script>
let menu = document.getElementById("menu");
menu.onclick = function () {
setTimeout(() => {
kill();
}, 500);
if (menu.classList.value.includes("selected")) {
menu.classList.remove("selected");
} else {
menu.classList.add("selected");
}
};
function kill() {
var start = +new Date();
while (+new Date() - start < 2000) {
}
}
script>
body>
html>
这样,通过opacity属性,我们也解决了这个卡顿问题
但是这两个方法都有缺点
懒加载方法如果加载的部分需要的时间也比较久的话(比如遇到垃圾电脑),那也会造成卡顿
而更改css属性的方法,由于只有这么几个属性有优化效果,所以并不是所有的动画效果都可以做到的,而且这个方法只解决了卡顿,订单表格加载慢的问题依然存在
所以以后遇到这种过渡动画卡顿的情况,最好把两个方法结合起来
查资料三天,写博客两小时,点个赞噻?