Vue:在触发过渡之前更新过渡名称不会呈现新过渡

问题描述

我看到了一些我不了解的Vue转换行为。通过显示示例将更容易解释:

给出以下组件:

<transition :name="transitionName">
    <div v-if="showMe">hey</div>
</transition>
<button @click="transitionName='slide-left'; showMe = false">Left</button>

以下是正确的:

  • 为过渡名称.slide-left.slide-right提供了css类,它们的名称所暗示的作用。
  • transitionName的初始状态为slide-right
  • showMe的初始状态为true

我希望单击该按钮时div向左滑动 。但是,它向右滑动

此处提供完整的可复制内容

var demo = new Vue({
  el: '#demo',data: {
    showMe: true,transitionName: 'slide-right'
  }
});
#demo {
  display: flex;
  justify-content: center;
  flex-direction: column;
  width: 20%;
  margin: 100px auto;
  text-align: center;
}

.buttons {
  display: flex;
  justify-content: space-between;
}

.slide-right-enter-active,.slide-left-enter-active,.slide-right-leave-active,.slide-left-leave-active {
  transition: all 1s ease-in-out;
}

.slide-left-enter,.slide-left-leave-to {
  transform: translateX(-100%);
}

.slide-right-enter,.slide-right-leave-to {
  transform: translateX(100%);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="demo">
  <transition :name="transitionName">
    <div v-if="showMe">hey</div>
  </transition>
  <div class="buttons">
    <button @click="transitionName='slide-left'; showMe = false">left</button>
    <button @click="transitionName='slide-right'; showMe = !showMe">right</button>
  </div>
</div>

它同时包含“向左”和“向右”按钮,但是无论您单击哪个组件,组件都将向右滑动。

我可以通过将按钮的回调更改为此:

this.transitionName = 'slide-left';
Vue.nextTick(() => {
    this.showMe = false;
});

但是我想知道为什么这里nextTick是必要的,以及总体上是否有更好的方法解决问题。

解决方法

这是因为Vue的更新周期。它将所有更新排入队列并同时“刷新”它们,以便可以评估页面的哪些部分需要更改,并且仅修补这些更改。当您使用Vue.nextTick时,实际上是在告诉Vue等到下一个更新周期,然后再设置this.showMe = false

docs比我解释得更好:

... Vue异步执行DOM更新。每当观察到数据更改时,它将打开队列并缓冲在同一事件循环中发生的所有数据更改。如果多次触发同一观察者,则它将仅被推入队列一次。这种缓冲的重复数据删除对于避免不必要的计算和DOM操作非常重要。然后,在下一个事件循环“ tick”中,Vue刷新队列并执行实际的(已重复数据删除)工作...

...例如,设置vm.someData = 'new value'时,组件不会立即重新渲染。刷新队列后,它将在下一个“滴答”中更新。大多数时候,我们不需要关心这一点,但是当您想要执行依赖于更新后DOM状态的操作时,这可能会很棘手...为了等到Vue.js完成更新DOM之后更改数据后,可以在更改数据后立即使用Vue.nextTick(callback)。 DOM更新后将调用回调。