【问题标题】:Fade In without jQuery (fadeIn) - CSS transition opacity and displayFade In without jQuery (fadeIn) - CSS 过渡不透明度和显示
【发布时间】:2019-12-02 01:33:15
【问题描述】:

我正在尝试实现与 jQuery 的 fadeIn() 函数相同的效果,其中显示一个元素,然后它的不透明度从 0 变为 1。我需要以编程方式(不使用 jQuery)来实现,我需要能够淡出 (display:none) 然后淡入的元素。

理想的解决方案将使用 CSS 过渡来利用硬件加速 - 我可以通过收听 transitionend 事件使元素成功淡出。然而,淡入淡出被证明是一个挑战,因为以下代码没有按预期工作:

fader.style.transition = 'opacity 1s';

const fadeIn = () => {
  fader.style.display = 'block';
  fader.style.opacity = 1;
};

fadeIn() 被调用时,元素只是简单地重新插入,而不是平滑地动画。我有一个codePen that I've been tinkering with 来说明问题。

我的理论是过渡无法在不在 DOM 中的元素上执行,因为我可以通过设置 height:0 而不是 display:none 来使动画工作。也许在我设置 fader.style.display = 'block'; 和 DOM 实际更新之间存在延迟,在此期间我无法转换?

关于这个想法:我似乎也可以通过使用setTimeout(() => {fader.style.opacity = 1}, 20} 延迟不透明度更改来使动画正常工作。然而,这似乎会产生一种竞争条件,因为随着超时持续时间越来越接近 0,动画的效果会越来越不可靠。

请注意,我不想像this question 的解决方案那样切换visibility 属性,因为这不会有效地从DOM 中删除元素。

将高度/宽度更改为 0 是一个更可行的选择,但由于元素的高度和宽度未知,因此需要在淡出之前捕获这些值的额外步骤,以便可以在以下情况下重新应用它们淡入。例如,如果应用程序的不同部分尝试更改这些值(例如媒体查询,并且用户在隐藏元素时旋转他们的设备),这似乎很脆弱

【问题讨论】:

  • 由于您的元素被隐藏然后显示,因此不透明度不会受到影响。在将元素设置为显示后立即使用动画或添加 requestAnimationFrame 将不透明度从 0 更改为 1:块。
  • @MisterJojo 谢谢! fadeOut 的函数实际上与我的函数相同......该 fadeIn 函数,但是通过使用 setInterval 动画来绕过理想的解决方案。似乎必须有一种方法来做到这一点,并利用更流畅的硬件加速 css 动画。
  • 非常感谢@Kyle!我不得不深入研究 rAF,但这成功了!

标签: javascript html css transition


【解决方案1】:

以下代码应该有效地替换 jQuery 的 fadeOut()fadeIn() 函数(非常感谢 @Kyle 提供的线索!)。

const fadeIn = (el, ms, callback) => {
  ms = ms || 400;
  const finishFadeIn = () => {
    el.removeEventListener('transitionend', finishFadeIn);
    callback && callback();
  };
  el.style.transition = 'opacity 0s';
  el.style.display = '';
  el.style.opacity = 0;
  requestAnimationFrame(() => {
    requestAnimationFrame(() => {
      el.addEventListener('transitionend', finishFadeIn);
      el.style.transition = `opacity ${ms/1000}s`;
      el.style.opacity = 1
    });
  });
};

const fadeOut = (el, ms, callback) => {
  ms = ms || 400;
  const finishFadeOut = () => {
    el.style.display = 'none';
    el.removeEventListener('transitionend', finishFadeOut);
    callback && callback();
  };
  el.style.transition = 'opacity 0s';
  el.style.opacity = 1;
  requestAnimationFrame(() => {
    requestAnimationFrame(() => {
      el.style.transition = `opacity ${ms/1000}s`;
      el.addEventListener('transitionend', finishFadeOut);
      el.style.opacity = 0;
    });
  });
};

在深入研究 rAF (requestAnimationFrame) 并观看此 video on the event loop 后,这一点变得非常清楚。就在21:00 附近,我突然想到为什么 rAF 需要嵌套在另一个 rAF 中。

这里是working example on Codepen

如果您发现任何未解决的边缘情况,请发表评论:)

【讨论】:

    猜你喜欢
    • 2021-01-08
    • 2021-07-26
    • 2014-05-25
    • 2020-05-29
    • 2017-06-27
    • 1970-01-01
    • 2019-01-03
    • 2018-08-01
    • 1970-01-01
    相关资源
    最近更新 更多