通过 JavaScript 分配时 CSS 转换不起作用

IT技术 javascript css css-transitions
2021-02-23 14:53:40

我在尝试通过 JavaScript 将 CSS3 转换应用于幻灯片放映时遇到了一些重大问题。

基本上,JavaScript 获取幻灯片中的所有幻灯片,并将 CSS 类应用于正确的元素以提供漂亮的动画效果,如果没有 CSS3 过渡支持,它将只应用没有过渡的样式。

现在,我的“小”问题。一切都按预期工作,所有幻灯片都获得了正确的样式,代码运行没有错误(到目前为止)。但是即使应用了正确的样式,指定的过渡也不起作用。此外,当我通过检查器自己应用样式和过渡时,它们会起作用。

由于我自己找不到合乎逻辑的解释,所以我认为这里有人可以回答,好吗?

我已经把代码现在的一个小例子放在一起:http : //g2f.nl/38rvma 或者使用 JSfiddle(无图像):http : //jsfiddle.net/5RgGV/1/

3个回答

为了transition工作,必须发生三件事。

  1. 元素必须明确定义属性,在这种情况下: opacity: 0;
  2. 元素必须定义过渡: transition: opacity 2s;
  3. 必须设置新属性: opacity: 1

如果您动态分配 1 和 2,就像您在示例中一样,则需要在 3 之前延迟,以便浏览器可以处理请求。它在您调试时起作用的原因是您通过逐步执行它来创建此延迟,从而为浏览器提供处理时间。延迟分配.target-fadein

window.setTimeout(function() {
  slides[targetIndex].className += " target-fadein";
}, 100); 

或者.target-fadein-begin直接放入您的 HTML 中,以便在加载时对其进行解析并准备好进行转换。

添加transition到元素不会触发动画,更改属性会触发动画。

// Works
document.getElementById('fade1').className += ' fade-in'

// Doesn't work
document.getElementById('fade2').className = 'fadeable'
document.getElementById('fade2').className += ' fade-in'

// Works
document.getElementById('fade3').className = 'fadeable'

window.setTimeout(function() {
  document.getElementById('fade3').className += ' fade-in'
}, 50)
.fadeable {
  opacity: 0;
}

.fade-in {
  opacity: 1;
  transition: opacity 2s;
}
<div id="fade1" class="fadeable">fade 1 - works</div>
<div id="fade2">fade 2 - doesn't work</div>
<div id="fade3">fade 3 - works</div>

有没有办法做到这一点,promise或者我们无法做到这一点,因为 className 分配不是异步对象?
2021-04-16 14:53:40
是的,似乎是唯一要做的事情。太糟糕了,没有关于何时应用样式的事件。我想我只需要等待 100 毫秒 :)
2021-05-05 14:53:40
谢谢 我真的很感谢你的帮助!我回家后会研究一下。
2021-05-16 14:53:40
我刚遇到这个问题,我花了几个小时才弄清楚在应用过渡属性后需要经过一些时间。有没有关于为什么会这样,因为通常样式是立即应用的?这是一个错误还是预期的行为?
2021-05-16 14:53:40
在我的例子中,我使用了0毫秒的延迟,setTimeout它仍然有效。
2021-05-16 14:53:40

欺骗布局引擎!

function finalizeAndCleanUp (event) {
    if (event.propertyName == 'opacity') {
        this.style.opacity = '0'
        this.removeEventListener('transitionend', finalizeAndCleanUp)
    }
}
element.style.transition = 'opacity 1s'
element.style.opacity = '0'
element.addEventListener('transitionend', finalizeAndCleanUp)
// next line's important but there's no need to store the value
element.offsetHeight
element.style.opacity = '1'

如前所述,transitions 通过从状态A插入到状态B 来工作如果您的脚本在同一函数中进行了更改,则布局引擎无法将状态A结束和状态B开始的位置分开除非你给它提示。

由于官方没有给出提示的方法,所以必须依赖一些函数的副作用。在这种情况下,.offsetHeightgetter 隐式地使布局引擎停止、评估和计算所有设置的属性,并返回一个值。通常,出于性能影响,应该避免这种情况,但在我们的情况下,这正是所需要的:状态整合。

为完整性添加了清理代码。

为了强调重要的行是一个未赋值的计算表达式,你可以写 void element.offsetHeight
2021-04-18 14:53:40
感谢您的提醒,@transistor09
2021-04-29 14:53:40
请注意transitionend:此事件不保证会触发。例如,如果选项卡不可见,浏览器可能会将其优化掉。不要依赖它或有后备!
2021-05-01 14:53:40

有人问为什么会延迟。该标准希望允许同时发生多个转换,称为样式更改事件(例如,元素在旋转到视图的同时淡入)。不幸的是,它没有定义一种明确的方式来对您希望同时发生的转换进行分组。相反,它让浏览器可以通过调用相距多远来任意选择同时发生哪些转换。大多数浏览器似乎使用它们的刷新率来定义这个时间。

如果您想要更多详细信息,这里是标准:http : //dev.w3.org/csswg/css-transitions/#starting