Vue.js用于CSS动画重新触发的精确CSS类切换

时间:2019-11-22 09:51:19

标签: vue.js css-animations

我遇到了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.$nextTick的代码将在Vue完成执行已删除CSS类reconnectpulse的当前滴答后立即执行,因此下一个刻度reconnectpulse可以再次应用,然后DOM将触发动画。

但是由于某种原因,它只能运行一次。如果我将this.$nextTick替换为setTimeout,并且超时时间相对较长,那么在重新应用该元素之前,该元素已将其类reconnectpulse删除了足够长的时间,那么它将起作用。超时为20毫秒时,有时仅有时为0毫秒(因为reconnect_pulse的初始值为'')只有一次,而有时只有100毫秒。

非常奇怪的是,我当前正在重写Vue组件,而旧版本的setTimeout为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')
})

1 个答案:

答案 0 :(得分:0)

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

<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,我实际上更喜欢此解决方案,而不是尝试使用nextTicksetTimeout的解决方案。