不懂就问,为什么 JS 要加入 setTimeout, css 的 transition 才能生效 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐关注
Meteor
JSLint - a Javascript code quality tool
jsFiddle
D3.js
WebStorm
推荐书目
Javascript 权威指南第 5 版
Closure: The Definitive Guide
McContax
V2EX    Javascript

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

  •  
  •   McContax 2019-12-28 11:32:09 +08:00 6200 次点击
    这是一个创建于 2190 天前的主题,其中的信息可能已经有所发展或是发生改变。

    当然我的标题有点极端化了,以前使用 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 名都没改

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

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

    如果你担心有的浏览器会煞有介事的把 setTimeout 0 优化掉,那你可以 setTimeout 1 或者 setTimeout 10
    muyunyun
        10
    muyunyun  
       2019-12-28 17:11:58 +08:00
    @zlgodpig display: none 到 block 不会触发动画是正解。动画可以分为两种形式的, 一种是 css 动画, 另一种是结合 Javascript 动画库完成的动画, Javascript 动画库本质做了事就是初始化了一些中间态 css 属性, 比如 width、height, 之前原来打算写一篇相关文章的, 一直没有时间。
    McContax
        11
    McContax  
    OP
       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
        12
    Tokin  
       2019-12-28 21:07:04 +08:00
    display:none;
    会忽略动画,直接就隐藏了。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     4328 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 34ms UTC 10:04 PVG 18:04 LAX 02:04 JFK 05:04
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86