【问题标题】:Vue component recycling causing watch to fire unexpectedlyVue组件回收导致手表意外触发
【发布时间】:2018-03-08 01:25:22
【问题描述】:

我正在为 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 是不同的值时,就会出现问题。 “已更改”会闪烁,即使它不应该闪烁。

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

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

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

【问题讨论】:

    标签: javascript vue.js vuejs2


    【解决方案1】:

    key 确实应该与条件渲染(由v-forv-if)单元相关联。它应该绑定到该单元的任何独特之处。在您的情况下,您可以使用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>
    

    【讨论】:

    • 谢谢罗伊。正如我所说(在第 4 段中)我知道我可以使用 vue 键,但是我想知道是否有比给所有组件随机 id 更优雅的方法来解决这个问题。
    • 那里有重复结构的事实表明您应该使用数组。我认为这是更优雅的方法,但您仍然需要使用keys。这只是对它们的更传统的使用。
    • 我有一个复杂的多页 Web 应用程序,其中包含数百个复选框。在那个规模上,我认为这不是一个优雅的解决方案。您是否知道我这样做的另一种方法或让这些组件生成自己的随机密钥?
    • 哦哦哦。这是你可以做的事情。这是一个非常优雅的解决方案。谢谢。
    猜你喜欢
    • 1970-01-01
    • 2017-08-01
    • 1970-01-01
    • 2019-07-04
    • 2013-01-17
    • 2015-07-21
    • 2018-02-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多