javascript - Vue 组件回收导致 watch 意外起火

标签 javascript vue.js vuejs2

我正在为 vue 创建一个可重用的复选框组件,并且遇到了一个由 vue 回收未使用组件引起的有趣问题。

通过一个例子可以更好地看出这一点:

Vue.component("checkbox", {
  template: `
    <div>
      <slot></slot>:
      <input type="checkbox" v-model="checked" v-on:change="updateVModel"/>
      <span>changed!</span>  
    </div>
  `,
  props: {
    value: {
      type: Boolean,
      required: true
    }
  },
  data(){
    return {checked: this.value};
  },
  watch: {
    value(val){
      this.changeAnimation();
      this.checked = val;
    }
  },
  methods: {
    changeAnimation(){
      let $span = this.$el.querySelector("span");
      $span.classList.remove("animate");
      setTimeout(() => $span.classList.add("animate"), 50);
    },
    updateVModel(){
      this.changeAnimation();//this line is redundant since watch.value runs anyway
      this.$emit("input", this.checked);
    }
  }
});

new Vue({
  el: "#menu",
  data: {
    menu: 0,
    checked0: true,
    checked1: false
  }
});
    
span{
  transition: 1s;
  opacity: 0;
}
span.animate{
  animation: notice-me .3s ease-in-out 4 alternate
}


@keyframes notice-me{
  0%{
    opacity: 0;
  }
  100%{
    opacity: 1;
  }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.min.js"></script>
<div id="menu">
  <div v-if="menu == 0">
    <button v-on:click="menu = 1">Go to menu 1</button>
    <h3>Menu 0</h3>
    <checkbox v-model="checked0">checked0</checkbox>
    <checkbox v-model="checked0">checked0</checkbox>
  </div>
  <div v-else>
    <button v-on:click="menu = 0">Go to menu 0</button>
    <h3>Menu 1</h3>
    <checkbox v-model="checked1">checked1</checkbox>
    <checkbox v-model="checked1">checked1</checkbox>
  </div>
</div>

每当值发生变化时,无论是来自用户单击(使用 v-on:click )还是变量本身发生变化(使用 watch.value ),我都会这样制作我的组件,即“更改!”在复选框旁边闪烁几次。一切工作正常,但是当我们使用“更改为菜单”按钮更改菜单并且checked0和checked1是不同的值时,问题就出现了。 “changed”会闪烁,尽管它不应该闪烁。

这显然是由 vue 回收组件并将它们用于另一个变量引起的。由于变量的值与旧的不同,watch.value运行,在我们期望它不会发生时触发动画。

我做了一些研究,发现我可以给出所有不同的复选框 vue keys像这样:<checkbox v-model="checked1" key="thing1">checked1</checkbox> ,但我想优雅地解决这个问题并允许 vue 回收它想要的任何东西。应该有一种方法来检测值是否因实际发生变化或由于回收而发生变化。

所以我的问题是如何解决这个问题,或者如何以不同的方式编写代码来避免它?

最佳答案

一个key实际上应该与条件渲染(通过 v-for 或 v-if)单元相关联。它应该与该单元的任何独特之处绑定(bind)在一起。对于您的情况,您可以使用 menu:

  <div v-if="menu == 0" :key="menu">
    <button v-on:click="menu = 1">Go to menu 1</button>
    <h3>Menu 0</h3>
    <checkbox v-model="checked0">checked0</checkbox>
    <checkbox v-model="checked0">checked0</checkbox>
  </div>
  <div v-else :key="menu">
    <button v-on:click="menu = 0">Go to menu 0</button>
    <h3>Menu 1</h3>
    <checkbox v-model="checked1">checked1</checkbox>
    <checkbox v-model="checked1">checked1</checkbox>
  </div>

关于javascript - Vue 组件回收导致 watch 意外起火,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49163924/

相关文章:

javascript - iframe 内容高度。使用父页面滚动 iframe 内容

vue.js - Vuetify v-data-table - 如何使其填充可用高度?

vue.js - Vue 路由器警告消息 "passed with params but they will be ignored"

json - 在 Vue 中为 JSON 数据创建下拉过滤器

javascript - vue.js 未渲染组件

javascript - ReferenceError 状态未在 vuex 存储中定义

javascript - 使用 Javascript 在特定数组值之前添加所有数组值

javascript - vue-router 的 beforeEach 守卫偶尔会表现出奇怪的行为

javascript - 在 vue.js 中声明响应式(Reactive)数据属性?

javascript - 如何知道 onclick 发生的具体行?