不懂就问,为什么 JS 要加入 setTimeout, css 的 transition 才能生效

2019-12-28 11:32:09 +08:00
 McContax

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

<-- ! HTML -->
<div class="slideshow">
    <div class="carousel-inner">
        <div class="carousel-item active">
            <img src="http://8.8.8.8/webstorm/20191216headerimg01.jpg">
        </div>
        <div class="carousel-item">
            <img src="http://8.8.8.8/webstorm/20191210headerimg01.jpg">
        </div>
        <div class="carousel-item">
            <img src="http://8.8.8.8/webstorm/20191129headerimg01.jpg">
        </div>
    </div>
</div>

<-- ! 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 名都没改

5284 次点击
所在节点    JavaScript
12 条回复
randyo
2019-12-28 11:43:34 +08:00
不加的话就是执行完所有的 js 然后才渲染页面,这时候就是渲染的最终效果
momocraft
2019-12-28 12:08:56 +08:00
因爲不 setTimeout 時沒有 reflow 過一次?
pinews
2019-12-28 13:39:13 +08:00
被浏览器“优化”了吧,我也遇到过。不过,你的这个要求应该用动画而不是转换。
CAze
2019-12-28 14:00:15 +08:00
把要执行的 js 代码写到 window.onload 函数里
wanguorui123
2019-12-28 14:23:33 +08:00
setTimeout 目的是将当前函数放到事件队列的最末尾排队执行,页面渲染相对 setTimeout 中的方法会先被执行,这时候在添加 css 就会生效。不然页面没有渲染完成,直接添加 css 会失效的
zlgodpig
2019-12-28 15:01:06 +08:00
display none 直接到 block(或其他),是不会触发动画的
Austaras
2019-12-28 15:38:44 +08:00
加之前
主任务->渲染
加之后
主任务->渲染->定时器任务->渲染
顺带建议用 requestAnimationFrame
miniwade514
2019-12-28 16:13:19 +08:00
同步 JS 是阻塞渲染的,你看到的是所有同步代码执行完了的最终状态
isukkaw
2019-12-28 16:29:15 +08:00
帮忙把 #1 @randyo 没说完的话说完。
setTimeout 会把操作推迟到 Event Loop 的任务队列中,等待主调用栈清空后再执行。因此浏览器在解析到 setTimeou 时,会先跳过这一段 JS 开始渲染页面。

再扯远一点。使用 setTimeout 0 可以使耗时操作不再阻碍页面渲染、改善 FP/FCP。饿了么 H5 页面就把 Vue 扔进 setTimeout 0 里,让骨架屏的渲染不被 Vue 阻碍。

如果你担心有的浏览器会煞有介事的把 setTimeout 0 优化掉,那你可以 setTimeout 1 或者 setTimeout 10
muyunyun
2019-12-28 17:11:58 +08:00
@zlgodpig display: none 到 block 不会触发动画是正解。动画可以分为两种形式的, 一种是 css 动画, 另一种是结合 JavaScript 动画库完成的动画, JavaScript 动画库本质做了事就是初始化了一些中间态 css 属性, 比如 width、height, 之前原来打算写一篇相关文章的, 一直没有时间。
McContax
2019-12-28 20:10:45 +08:00
@zlgodpig
@muyunyun display 那里是没有要做动画的,我的思路是先将要移动的 carousel-item 移到轮播框的外边的右边 transform: translateX(100%);然后显示出来 display: block;,接下来移动的时候利用 transform translateX 改变位置做到动画效果,所以 display 那里本来就没做动画


@isukkaw 你说对了,我发现 settimeout 如果设置为 0 的话,我的安卓魅蓝 2 自带浏览器会忽略掉直接渲染结果出来

感谢上面回答的各位
Tokin
2019-12-28 21:07:04 +08:00
display:none;
会忽略动画,直接就隐藏了。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/633069

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX