普通 DOM fadeOut 然后立即 fadeIn

Plain DOM fadeOut then fadeIn immediately

我想使用原生 DOM 实现 fadeIn 和 fadeOut,而不使用 JQuery。

如果我们快速点击按钮两次,意味着它会在淡入还在进行时开始淡出,文字会闪烁。

这是 jsfiddle 中的代码:https://jsfiddle.net/keegoo/vyuqdxLs/

关于如何解决这个问题的任何想法?

document.getElementById('button').addEventListener('click', () => switch_state())
const text = document.getElementById('text')
const btn = document.getElementById('button')
let state = true

function switch_state() {
  if (state == true) {
    fadeOut(text, 3000)
    btn.innerHTML = 'show'
    state = false
  } else {
    fadeIn(text, 3000)
    state = true
    btn.innerHTML = 'hide'
  }
}

function fadeOut(elem, ms) {
  elem.style.opacity = 1
  if (ms) {
    let opacity = 1
    const timer = setInterval(() => {
      opacity -= 50 / ms
      if (opacity <= 0) {
        clearInterval(timer)
        opacity = 0
      }
      elem.style.opacity = opacity
    }, 50)
  } else {
    elem.style.opacity = 0
  }
}

function fadeIn(elem, ms) {
  elem.style.opacity = 0;

  if (ms) {
    let opacity = 0;
    const timer = setInterval(function() {
      opacity += 50 / ms;
      if (opacity >= 1) {
        clearInterval(timer);
        opacity = 1;
      }
      elem.style.opacity = opacity;
    }, 50);
  } else {
    elem.style.opacity = 1;
  }
}
<button id='button'>hide</button>
<text id='text'>some text</text>

你可以用 setProperty 这样做。

document.getElementById('button').addEventListener('click', () => switch_state())
const text = document.getElementById('text')
const btn = document.getElementById('button')
let state = true

function switch_state() {
  if (state == true) {
    fadeOut(text, 800)
    btn.innerHTML = 'show'
    state = false
  } else {
    fadeIn(text, 800)
    state = true
    btn.innerHTML = 'hide'
  }
}

function fadeOut(elem, ms) {
  elem.style.setProperty("opacity",0);
  elem.style.setProperty("transition", "opacity " + ms + "ms");
}

function fadeIn(elem, ms) {
  elem.style.setProperty("opacity",1);
  elem.style.setProperty("transition", "opacity " + ms + "ms");
}
<button id='button'>hide</button>
<text id='text'>some text</text>

您可以使用 CSS 自定义属性:

document.getElementById("button").addEventListener("click", switch_state)
const text = document.getElementById('text')
const btn = document.getElementById('button')
let state = true
let root = document.documentElement;

function switch_state() {
  if (state == true) {
    fadeOut(text, 3000)
    btn.innerHTML = 'show'
    state = false
  } else {
    fadeIn(text, 3000)
    state = true
    btn.innerHTML = 'hide'
  }
}

// Native fadeOut
function fadeOut(elem, ms) {
  root.style.setProperty('--opacity', 0);
  root.style.setProperty('--transition', "1s");
}

// Native fadeIn
function fadeIn(elem, ms) {
  root.style.setProperty('--opacity', 1);
  root.style.setProperty('--transition', "1s");
}
:root {
  --transition: 1s;
  --opacity: 1;
}

#text {
  opacity: var(--opacity);
  transition: all var(--transition);
}
<button id='button'>hide</button>
<text id='text'>some text</text>

嗯,您最好在单独的 css 文件中定义 hidden class 样式,并使用该 class 设置过渡时间。这对于客户端的性能以及稳定性和调试都会更好。

css应该是这样的:

#text {
  transition: ease-in-out 1s;
  opacity: 1;
}

#text.hidden {
  opacity: 0;
}

那么,你应该只切换更改 Js 中的 class。我在下面的示例代码中所做的是尝试仔细检查文本和按钮的初始状态。所以,我认为文本上有一个初始的 hidden class,这是错误的,所以首先我们需要将其设置正确。这就是 DOMContentLoaded 事件存在的原因。

然后设置初始状态后,我们不知道文本元素上是否有classes,所以如果它没有任何classes ,当我们测试aginst text.classList时,它可能会给出未定义变量的错误,即使它满足条件并且不包含hidden class。这就是为什么在 if 语句中我们应该测试 classList 是否存在,然后我们需要测试我们想要的任何东西。

else 中,出于同样的原因,我将 text.classlist.add() 包装在 try/catch 中;如果我立即使用 text.classList.add() 它可能会在根本没有 class 列表时失败。在这种情况下,我们意识到如果我们覆盖了元素的 class 属性,我们将不会丢失任何先前设置的 classes,它们不存在,所以我们抓住了错误并将 class 直接分配给 属性.

这是它的样子:

document.getElementById('button').addEventListener('click', (e) => {
    switch_state()
})
const text = document.getElementById('text')
const btn = document.getElementById('button')

// First when we initialize the page, it should set the status of the text and button. Better for debugging.
document.addEventListener('DOMContentLoaded', () => {
  if (text.classList && text.classList.value.includes('hidden')) {
    text.classList.toggle('hidden')
    btn.innerHTML = 'Hide'
  }
})

// Then we run our manipulation.
function switch_state() {
  if (text.classList && text.classList.value.includes('hidden')) { // If there's a classList AND it contains 'hidden'
    text.classList.remove('hidden')
    btn.innerHTML = 'Hide'
  } else { // Reaching here makes us unsure if the reason is because there is no classList, or it's because the 'hidden' class is not in the classList
    try { // So first we assume there's a classList
      text.classList.add('hidden')
      btn.innerHTML = 'Show'
    } catch (error) { // Or we fail to the last probability of having no classList at all
      text.class = 'hidden'
      btn.innerHTML = 'Show'
    }
  }
}

希望我已经解释清楚了。