将元素添加到 DOM 时过渡无法正常工作

Transition not working correctly when element is added to the DOM

当我在 JavaScript 中触发一个函数时,我正试图淡入吐司消息。

我想要创建元素的函数,将其添加到 dom,然后使用 css 过渡将其淡入,然后使用相同的过渡将其淡出,然后将其从dom.

除非我将其包装在超时中,否则淡出将不起作用。

编辑::瑞卡德
我添加了一个按钮来显示吐司。

function flashToast(msg, duration) {
  duration = duration || 3000;

  // create the toast element
  const toastElement = document.createElement("p");
  toastElement.innerHTML = msg;

  toastElement.classList.add("toast");

  // add it to the dom

  document.body.appendChild(toastElement);

  // fade in won't work unless I wrap it in a timeout
  setTimeout(function() {
    toastElement.style.opacity = "1";
  }, 1);

  // remove it after the duration is over
  setTimeout(function() {
    toastElement.style.opacity = "0";
  }, duration - 500);

  // start fading it out 500ms before removing it
  setTimeout(function() {

    document.body.removeChild(toastElement);
  }, duration);
}
.toast {
  display: inline-block;
  font-size: 1.2rem;
  padding: 0.8em 1em;
  border-radius: 5rem;
  color: #eaeaea;
  background: #606060;
  background: rgba(96, 96, 96, 0.7);
  position: absolute;
  bottom: 2%;
  left: 50%;
  transform: translate(-50%, -50%);
  /* opacity is 0 when first enjected */
  opacity: 0;
  transition: opacity 500ms ease;
}
<button onclick="flashToast('Toast!')">Show toast</button>

您必须使用 setTimeout 是因为 javascript 如何与事件循环一起工作。这是一个非常好的视频,解释了您需要了解的关于 javascript 的基本知识。 (嘿,我从事 Web 开发已有五年,但使用 javascript 已有 20 年,今年夏天才知道这个。)

Jake Archibald: In The Loop

如果您不想使用超时,可以改用动画。缺点是很难控制具体时间。如果您从不透明度 0 开始,然后将不透明度 1 设置为 15%,那么对于更长的 toast 持续时间,将会创建更慢的淡入效果。

function flashToast(msg, duration) {
  duration = duration || 3000;

  const toastElement = document.createElement("p");
  toastElement.innerHTML = msg;

  toastElement.classList.add("toast");
  
  // Added 
  toastElement.style.setProperty("--duration", duration + "ms");

  document.body.appendChild(toastElement);

  setTimeout(function() {
    document.body.removeChild(toastElement);
  }, duration);
}
.toast {
  display: inline-block;
  font-size: 1.2rem;
  padding: 0.8em 1em;
  border-radius: 5rem;
  color: #eaeaea;
  background: #606060;
  background: rgba(96, 96, 96, 0.7);
  position: absolute;
  bottom: 2%;
  left: 50%;
  transform: translate(-50%, -50%);
  
  /* NEW */
  animation: fade var(--duration) linear;
}

@keyframes fade {
  0%   {opacity: 0;}
  15%  {opacity: 1;}
  85%  {opacity: 1;}
  100% {opacity: 0;}
}
<button onclick="flashToast('Toast!')">Show toast</button>

看完 Rickard Elimää 推荐的视频后。我发现 requestAnimationFrame 解决了这个问题。这是最后的 JavaScript:

function flashToast(msg, duration) {
  duration = duration || 3000;
 
  // create the toast element
  const toastElement = document.createElement("p");
  toastElement.innerHTML = msg;

  toastElement.classList.add("toast");

  // add it to the dom
  document.body.appendChild(toastElement);

  requestAnimationFrame(function() {
    toastElement.style.opacity = "1";
  });

  // remove it after the duration is over
  setTimeout(function() {
    toastElement.style.opacity = "0";
  }, duration - 500);

  // start fading it out 500ms before removing it
  setTimeout(function() {
    document.body.removeChild(toastElement);
  }, duration);
}