从父组件重置一个 Vue 计数器组件

Reset a Vue counter component from the parent component

我有一个从 1 计数到 10 的 Vue 计数器。它是作为一个组件实现的。我需要从主应用程序重置计数器。最好的方法是什么?从我的示例中可以看出,watch 方法无法完成工作:

Vue.component('my-counter', {
  template: "#counter-vue",
  data: function() {
    return {
      age_now: null
    }
  },
  props: {
    age: Number
  },
  mounted: function() {
    this.age_now = this.age;
    TweenLite.to(this, 10, { age_now: this.$root.age_end, roundProps: "age_now", ease:Linear.easeNone });
  },
  watch: {
    age(val) {
      this.age_now = val;
    }
  }
});

var app = new Vue({
  el: '.container',
  data: {
    age: 1,
    age_end: 10
  },
  methods: {
    reset() {
      this.age = 1;
    } 
  }
});
<script src="http://cdnjs.cloudflare.com/ajax/libs/gsap/1.19.0/TweenMax.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.17/dist/vue.js"></script>

<script type="text/x-template" id="counter-vue">
 <div>
  <p>Age: {{age_now}}</p>
 </div>
</script>
   
<div class="container">
   <h1>Vue Component Reset</h1>
  <my-counter :age="age"></my-counter>
  <button @click.prevent="reset">Reset</button>
    <p>What's the best way to implement the reset of the component to restart the count up from 1 to 10?</p>
</div>

另见 CodePen:https://codepen.io/MSCAU/pen/OagMJy

首先,my-counter 组件中 age 的观察者永远不会触发,因为您永远不会更改 age 属性的值。如果它初始化为 1 并在点击处理程序中设置为 1,它不会触发观察者,因为值没有改变。

但其次,在这种情况下,将 reset 方法移动到 my-counter 组件,然后通过 ref,像这样:

<my-counter ref="counter" :age="age"></my-counter>
<button @click.prevent="$refs.counter.reset">Reset</button>

如果您希望计数器再次递增,您似乎还需要再次调用 TweenLite.to 方法。因此,最好将该逻辑拉入它自己的方法(例如 count),您可以从 mounted 挂钩和 reset 方法调用该方法。

此外,我注意到 TweenLite.to 方法似乎也在覆盖 age 道具的绑定,直到计数器完成递增。如果您想在 TweenLite.to 方法完成之前重置计数器,您需要存储对返回的补间对象的引用,然后在计数器开始之前调用其 kill 方法。

最后,我发现您在传递给 TweenLite.to 的对象中引用了 this.$root.age_end。除了在极少数情况下,这被认为是不好的做法,因为现在组件不必要地依赖于始终具有 age_end 属性 的根 Vue 实例,并且它模糊了数据流。由于该值似乎是静态的,您应该将其设置为组件的数据 属性。或者至少将其作为父项的道具传递。

这是一个包含我建议的更改的工作示例:

Vue.component('my-counter', {
  template: "#counter-vue",
  data: function() {
    return {
      age_now: null,
      age_end: 10,
      tween: null,
    }
  },
  props: {
    age: Number
  },
  mounted: function() {
    this.age_now = this.age;
    this.count();
  },
  methods: {
    count() {
      if (this.tween) {
        this.tween.kill();
      }
    
      this.tween = TweenLite.to(this, 10, { 
        age_now: this.age_end, 
        roundProps: "age_now", 
        ease: Linear.easeNone 
      });
    },
    reset() {
      this.age_now = 1;
      this.count();
    }
  }
});

var app = new Vue({
  el: '.container',
  data: {
    age: 1,
  }
});
<script src="http://cdnjs.cloudflare.com/ajax/libs/gsap/1.19.0/TweenMax.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.17/dist/vue.js"></script>

<script type="text/x-template" id="counter-vue">
  <div>
    <p>Age: {{age_now}}</p>
  </div>
</script>
   
<div class="container">
  <h1>Vue Component Reset</h1>
  <my-counter ref="counter" :age="age"></my-counter>
  <button @click.prevent="$refs.counter.reset">Reset</button>
</div>