首页 > 解决方案 > Vue.js 精确的 CSS 类切换以重新触发 CSS 动画

问题描述

我遇到了 Vue.js 的问题,nextTick()似乎没有按预期工作。

我有以下 HTML 代码

<q-icon
  color='grey-7'
  :name="connectionStateIcon"
  class="icon-reconnect"
  :class='[$storage.state.websocket.state, reconnect_pulse]'></q-icon>

其中connectionStateIcon是一个计算属性,它选择当前连接状态的图标,$storage.state.websocket.state保存当前连接状态(打开、关闭...)的文本表示,用于选择一个 CSS 定义(即.q-icon.icon-reconnect.open)应用某个基础图标的颜色,reconnect_pulse是一个data用于触发动画的变量。

每当触发新的重新连接尝试时,应该运行动画,并且reconnect_pulse应该从类转换'''reconnectpulse'以触发动画。

data: function () {
  return {
    reconnect_pulse: '',
  }
},
created() {
  this.$eventbus.$on('connection-state', (state) => {
    if (state == 'reconnecting') {
      this.reconnect_pulse = ''; // remove the class `reconnectpulse`
      this.$nextTick(() => { this.reconnect_pulse = 'reconnectpulse'; }); // add the class `reconnectpulse` to trigger the animation
      //setTimeout(() => { this.reconnect_pulse = 'reconnectpulse'; }, 100) // this works, and more reliably, the bigger the timeout is.
    }
  })
},

CSS如下:

@keyframes reconnectpulse {
  from { color:#ffa000; } to { }    /* from orange to whichever base color the icon has */
}

.q-icon.reconnectpulse {
  animation: reconnectpulse 2.0s ease-in; /* the above animation's properties */
}

.q-icon.icon-reconnect { }  /* "grey-7" is default base color */

.q-icon.icon-reconnect.open {
  color: yellowgreen; /* when the connection is established, select green as the base color */
}

我的问题是,我假设this.$nextTickVue 完成执行删除 CSS 类的当前滴答后,将立即执行 's 代码reconnectpulse,以便在下一个滴答reconnectpulse中可以再次应用,然后触发 DOM动画。

但由于某种原因,这只适用于一次。如果我用相对较大的超时替换this.$nextTicksetTimeout,以便元素reconnectpulse在重新应用之前将类删除足够长的时间,那么它就可以工作。超时时间为 20 毫秒,它有时工作,有时不工作,只有一次 0 毫秒(因为初始值为reconnect_pulseis ''),每次 100 毫秒。

很奇怪的是,我目前正在重写Vue组件,而旧版本的asetTimeout为0ms,而且每次都能正常工作。我不知道究竟有哪些区别,因为旧代码有些混乱,但本质上,关于动画的代码是相同的。

我希望this.$nextTick能够以setTimeout非常精确的方式进行替换,但它不起作用,而且我不擅长手动调整setTimeout' 延迟,因为这可能因设备而异。

this.$nextTick在这种情况下有什么问题?在不使用的情况下,我还能做些什么来存档所需的效果setTimeout


直接访问元素时也是如此:

_.forEach(document.querySelectorAll('.icon-reconnect'), (icon) => {
  icon.classList.remove('reconnectpulse')
})
setTimeout(() => {
  _.forEach(document.querySelectorAll('.icon-reconnect'), (icon) => {
    icon.classList.add('reconnectpulse')
  })
}, 100)

然后我期待以下工作(但它没有):

_.forEach(document.querySelectorAll('.icon-reconnect'), (icon) => {
  icon.classList.remove('reconnectpulse')
  icon.classList.add('reconnectpulse')
})

标签: vue.jscss-animations

解决方案


一种解决方案是在重新应用之前不清除该类,而是将其替换为另一个具有相同动画属性的类。

<q-icon
  color='grey-7'
  :name="connectionStateIcon"
  class="icon-reconnect"
  :class='[$storage.state.websocket.state, reconnect_pulse]'></q-icon>
data: function () {
  return {
    reconnect_pulse: '',
  }
},
created() {
  this.$eventbus.$on('connection-state', (state) => {
    if (state == 'reconnecting') {
      if (this.reconnect_pulse != 'reconnect-pulse-tick') {
        this.reconnect_pulse = 'reconnect-pulse-tick'
      }
      else {
        this.reconnect_pulse = 'reconnect-pulse-tock'
      }
    }
  })
},
@keyframes reconnect-pulse-tick {
  from { color:#ffa000; } to { }
}
.q-icon.reconnect-pulse-tick {
  animation: reconnect-pulse-tick 2.0s ease-in;
}

@keyframes reconnect-pulse-tock {
  from { color:#ffa000; } to { }
}
.q-icon.reconnect-pulse-tock {
  animation: reconnect-pulse-tock 2.0s ease-in;
}

.q-icon.icon-reconnect { }  /* "grey-7" is default base color */

.q-icon.icon-reconnect.open {
  color: yellowgreen; /* when the connection is established, select green as the base color */
}

在这种情况下,重要的是动画关键帧也有不同的名称,如上面的 css 代码所示。

TBH,我实际上更喜欢这个解决方案,而不是尝试使用nextTickor的解决方案setTimeout


推荐阅读