【问题标题】:CSS transitions do not work when assigned trough JavaScript通过 JavaScript 分配 CSS 转换时不起作用
【发布时间】:2012-01-02 21:04:24
【问题描述】:

尝试通过 JavaScript 将 CSS3 转换应用于幻灯片时,我头疼不已。

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

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

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

我已经整理了一个小例子来说明现在的代码:http://g2f.nl/38rvma 或者使用 JSfiddle(无图片):http://jsfiddle.net/5RgGV/1/

【问题讨论】:

    标签: javascript css css-transitions


    【解决方案1】:

    要使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>

    【讨论】:

    • 非常感谢您的帮助!我回家后会调查此事。
    • 是的,似乎是唯一要做的事情。太糟糕了,没有关于何时应用样式的事件。我想我只需要等待 100 毫秒 :)
    • 我刚刚遇到了这个问题,我花了几个小时才发现在应用过渡属性后需要一段时间。有什么知道为什么会这样,因为通常样式会立即应用?这是错误还是预期行为?
    • 在我的情况下,我在 setTimeout 中使用了 0 毫秒的延迟,它仍然有效。
    • 有没有办法用promise 来做,或者我们不能因为 className 分配不是异步对象而做?
    【解决方案2】:

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

    如果您想了解更多详情,请参考以下标准: http://dev.w3.org/csswg/css-transitions/#starting

    【讨论】:

      【解决方案3】:

      欺骗布局引擎!

      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 开始的位置。除非你给它一个提示。

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

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

      【讨论】:

      • 为了强调重要的行是一个未赋值的计算表达式,你可以写void element.offsetHeight
      • 关于transitionend 的注意事项:不保证会触发此事件。例如,如果选项卡不可见,浏览器可能会将其优化掉。不要依赖它或有后备!
      • 感谢您的提醒,@transistor09
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-11-24
      • 1970-01-01
      • 2021-11-24
      • 2022-11-23
      • 1970-01-01
      • 2016-11-13
      相关资源
      最近更新 更多