临时阻止transition

如何用transition做出一个无缝的幻灯片

Posted by AllocatorXy on February 18, 2017

动机

看到淘宝的slider是用transition做的,就自己试着用transition做一个同样效果的幻灯片播放器,但发现了一个问题:无论最后如何设置复位图片,都会触发transition,不能达到视觉上的无缝衔接。

突然想到,那每次让它复位时transition为0,复位完毕再加上transition属性不就好了:

const oDiv = document.querySelector('div');
oDiv.style.transition = '0';            // 设置transition为0
oDiv.style.transform = 'translateX(0)'; // 复位图片
oDiv.style.transition = '.3s';          // 复位后设置transition

结果神奇的事情发生了:还是会触发transition!!


搞事

我们在用js改变css样式时,是这样的过程:
赋值 => 消息进入队列 => 轮到css赋值消息 => Recalculate Style => Layout => Paint
js在改变css样式时,它做的事情其实只是赋值而已,而在这个栗子中,我们的赋值消息是在同一个消息处理中的,那么在轮到Recalculate Style时,这两条赋值是被一起计算的。

那么我们为了解决这个问题,可以有两种思路:

  • 将这两个设置transition的语句,分别扔到两个消息中;
  • 或者当复位图片的语句赋值完毕之后,让它立马进行Recalculate Style;

方法1:加入新消息

// 用两个消息解决:
const oDiv = document.querySelector('div');
oDiv.style.transition = '0';            // 设置transition为0
oDiv.style.transform = 'translateX(0)'; // 复位图片

setTimeout(function() {                 // 在新的消息中设置transition
    oDiv.style.transition = '.3s';
}, 0);

虽然这个定时器时间为0,但因为js是单线程的,在处理完当前消息之前是不会处理下一条消息的,所以这个定时器一定会在上面的语句实际执行完后才执行。


方法2:立即计算样式

// 用getComputedStyle方法让浏览器立即处理复位的赋值消息:
const oDiv = document.querySelector('div');
oDiv.style.transition = '0';             // 设置transition为0
oDiv.style.transform = 'translateX(0)';  // 复位图片
getComputedStyle(oDiv, false).transform; // 强制计算样式

oDiv.style.transition = '.3s';           // 将transition调回去

demo: