技术解析

不懂就问,为什么 JS 要加入 setTimeout, css 的 transition 才能生效
0
2021-08-20 09:09:06
idczone

当然我的标题有点极端化了,以前使用 JS 修改一个 html 标签的样式,配合 css 的 transition 是可以看得到过渡的,然而最近的一个项目使用 transform 搭配 transition,标签的移动直接一步到位没有动画过渡效果,但是加入了 setTimeout 之后,transition 就能显现出来,下面是代码

<-- ! HTML -->
<-- ! CSS --> .carousel-inner { position: relative; width: 100%; overflow: hidden; } .carousel-item { position: relative; display: none; float: left; width: 100%; margin-right: -100%; -webkit-backface-visibility: hidden; backface-visibility: hidden; transition: transform .6s ease-in-out; } .carousel-item-next { transform: translateX(100%); } .carousel-item-next, .carousel-item.active { display: block; } .carousel-item.active.to-left, { transform: translateX(-100%); } <-- ! JavaScript --> var nextPic = document.getElementsByClassName('active')[0].nextElementSibling; var currentPic = document.getElementsByClassName('active')[0]; //将下一张图片的样式增加一个 carousel-item-next,使其 translateX(100%);display: block;并在轮播框外显示 nextPic.setAttribute('class', 'carousel-item carousel-item-next'); setTimeout(function () { /*给 active 状态的图片添加一个 to-left,使其 translateX(-100%), carousel-item 本身已经设置了针对 transform 的 transition, 所以这一步完成就会显示往左移*/ currentPic.setAttribute('class', 'carousel-item active to-left'); /*给下一张轮播图设置成 translateX(0),从原来的 translateX(100%)到 translateX(0),配合 transition 实现左移进入轮播框*/ nextPic.style.transform = 'translateX(0)'; },0) setTimeout(function () { //下面这三条将动画完成后的样式重置,确定新的 active 轮播图 currentPic.className = 'carousel-item'; nextPic.className = 'carousel-item active'; nextPic.style.transform = ''; },2000)

上面的代码是能够完成动画效果的,但是一开始写的时候我没有 setTimeout,没有 setTimeout 的情况下过渡效果没有了,直接显示过渡完之后的状态

所以 setTimeout 跟 transition 究竟是个什么关系,setTimeout 是时间结束之后执行代码,又不是指定每一行代码执行的时间间隔

还有,这个轮播思路是从 bootstrap 上面摸过来的,甚至连 class 名都没改


不加的话就是执行完所有的 js 然后才渲染页面,这时候就是渲染的最终效果

因爲不 setTimeout 時沒有 reflow 過一次?

被浏览器“优化”了吧,我也遇到过。不过,你的这个要求应该用动画而不是转换。

把要执行的 js 代码写到 window.onload 函数里

setTimeout 目的是将当前函数放到事件队列的最末尾排队执行,页面渲染相对 setTimeout 中的方法会先被执行,这时候在添加 css 就会生效。不然页面没有渲染完成,直接添加 css 会失效的

display none 直接到 block(或其他),是不会触发动画的

加之前
主任务->渲染
加之后
主任务->渲染->定时器任务->渲染
顺带建议用 requestAnimationFrame

同步 JS 是阻塞渲染的,你看到的是所有同步代码执行完了的最终状态

帮忙把 没说完的话说完。
setTimeout 会把操作推迟到 Event Loop 的任务队列中,等待主调用栈清空后再执行。因此浏览器在解析到 setTimeou 时,会先跳过这一段 JS 开始渲染页面。
再扯远一点。使用 setTimeout 0 可以使耗时操作不再阻碍页面渲染、改善 FP/FCP。饿了么 H5 页面就把 Vue 扔进 setTimeout 0 里,让骨架屏的渲染不被 Vue 阻碍。
如果你担心有的浏览器会煞有介事的把 setTimeout 0 优化掉,那你可以 setTimeout 1 或者 setTimeout 10

display: none 到 block 不会触发动画是正解。动画可以分为两种形式的, 一种是 css 动画, 另一种是结合 JavaScript 动画库完成的动画, JavaScript 动画库本质做了事就是初始化了一些中间态 css 属性, 比如 width、height, 之前原来打算写一篇相关文章的, 一直没有时间。


display 那里是没有要做动画的,我的思路是先将要移动的 carousel-item 移到轮播框的外边的右边 transform: translateX(100%);然后显示出来 display: block;,接下来移动的时候利用 transform translateX 改变位置做到动画效果,所以 display 那里本来就没做动画

你说对了,我发现 settimeout 如果设置为 0 的话,我的安卓魅蓝 2 自带浏览器会忽略掉直接渲染结果出来
感谢上面回答的各位

display:none;
会忽略动画,直接就隐藏了。

数据地带为您的网站提供全球顶级IDC资源
在线咨询
专属客服