当然我的标题有点极端化了,以前使用 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 名都没改
1
randyo 2019-12-28 11:43:34 +08:00 via Android 1
不加的话就是执行完所有的 js 然后才渲染页面,这时候就是渲染的最终效果
|
2
momocraft 2019-12-28 12:08:56 +08:00
因爲不 setTimeout 時沒有 reflow 過一次?
|
3
pinews 2019-12-28 13:39:13 +08:00
被浏览器“优化”了吧,我也遇到过。不过,你的这个要求应该用动画而不是转换。
|
4
CAze 2019-12-28 14:00:15 +08:00
把要执行的 js 代码写到 window.onload 函数里
|
5
wanguorui123 2019-12-28 14:23:33 +08:00
setTimeout 目的是将当前函数放到事件队列的最末尾排队执行,页面渲染相对 setTimeout 中的方法会先被执行,这时候在添加 css 就会生效。不然页面没有渲染完成,直接添加 css 会失效的
|
6
zlgodpig 2019-12-28 15:01:06 +08:00 via Android
display none 直接到 block(或其他),是不会触发动画的
|
7
Austaras 2019-12-28 15:38:44 +08:00
加之前
主任务->渲染 加之后 主任务->渲染->定时器任务->渲染 顺带建议用 requestAnimationFrame |
8
miniwade514 2019-12-28 16:13:19 +08:00 via iPhone
同步 JS 是阻塞渲染的,你看到的是所有同步代码执行完了的最终状态
|
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 |
10
muyunyun 2019-12-28 17:11:58 +08:00
@zlgodpig display: none 到 block 不会触发动画是正解。动画可以分为两种形式的, 一种是 css 动画, 另一种是结合 JavaScript 动画库完成的动画, JavaScript 动画库本质做了事就是初始化了一些中间态 css 属性, 比如 width、height, 之前原来打算写一篇相关文章的, 一直没有时间。
|
11
McContax OP |
12
Tokin 2019-12-28 21:07:04 +08:00
display:none;
会忽略动画,直接就隐藏了。 |