Vue-听道具变化(对象),观看不触发

时间:2019-01-26 09:06:00

标签: javascript vue.js vuejs2 vue-component pass-by-reference

我对此有类似的问题: VueJs 2.0 - how to listen for `props` changes,但就我而言,我将对象从父级发送到子级,还传递了几次以使用JS中对象引用的好处。

有一个例子,但工作正常:

<div id="app">
  <child :myprop="myObj"></child>
  <button @click="text = 'Another text'">Change text</button>
</div>

<script>
new Vue({
  el: '#app',
  data: {
    myObj: {
       id: null
    }
  },
  components: {
    'child' : {
      template: `<div>
      <p>{{ myprop.id }}</p>
      <select v-model="myprop.id">
        <option value="1">1</option>
        <option value="2">2</option>
        <option value="3">3</option>
      </select>
      </div>`,
      props: ['myprop'],
      watch: { 
        'myprop.id': function(newVal, oldVal) { // watch it
          console.log('Prop changed: ', newVal, ' | was: ', oldVal)
        }
      }
    }
  }
});
</script>

https://jsfiddle.net/8hqwg6Ln/

在我的情况下,我将select上的v-model设置为“ parentObj.id”,然后为此添加了监视程序。目标是在更改id之后更改其他parentObj属性-用户选择id,此后,我在数组中搜索此id并设置parentObj.price,这是v模型与选择字段处于同一级别的其他组件(修改后的输入) 。

当我更改位置时,不会触发观察者。如果我使用自定义方法添加@change,它可以工作,但是会延迟(我在vue开发工具中看到了这一点,必须刷新才能获取当前数据),而且,它不适用于第二个输入组件-它看不到更改parentObj.price。

使用复杂的集合传递和修改具有许多不同组件的一个集合的最佳方法是什么? 我认为,我可以将属性的“副本”添加到本地级别(因此,使用ID和价格在子级上创建数据),添加观察者并使用this。$ set更新收到的道具。但是...这是一个不错的选择,也许这会更好?

6 个答案:

答案 0 :(得分:2)

很简单。您需要添加深色属性来监视对象。

+--------+------------------------------+
|lessonId|info                          |
+--------+------------------------------+
|1       |[[100A, jon], [200C, natalie]]|
|2       |[[100A, jon]]                 |
+--------+------------------------------+

您不需要使用类似的东西

props: ['myprop'],
  watch: { 
    myprop: {
        deep: true,
        handler: function(newVal, oldVal){
           console.log('Prop changed: ', newVal, ' | was: ', oldVal)
        }
      }
    }
  }

答案 1 :(得分:1)

您的代码中只有一个问题:

"text = 'Another text'"

不起作用,因为未声明文本。因此,您可能需要将其更改为

"myObj = { id: 'Another text' }"

我想这就是你想要的。然后是反应式的,选择时文本更改为1或2或3,单击时文本更改为“另一个文本”,并且观察者将触发并记录新旧值

答案 2 :(得分:1)

首先需要一个用于父组件的道具和一个用于选择v模型的本地数据:

<select v-model="localid">
        <option value="1">1</option>
        <option value="2">2</option>
        <option value="3">3</option>
      </select>

和您子组件的属性和数据是:

data() {
      return {
        localid:null
      }
    },
props: ['pid']

如果组件属性发生了变化,而他的父母想知道这一变化,则可以使用.sync修饰符。首先在组件中更新道具。观看您的localid数据,然后使用新数据更新pid道具:

watch:{
     localid:function(){
     this.$emit('update:pid', this.localid)
    }
}

现在,父级知道pid属性已更改,并且父级组件的数据将随属性的新数据而更改。您的父组件:

<div id="app">
  <child :pid="myObj.id"></child>
  <button @click="text = 'Another text'">Change text</button>
</div>

更多信息:https://vuejs.org/v2/guide/components-custom-events.html#sync-Modifier

答案 3 :(得分:0)

那样尝试

{
  ...
  props: ['myprop'],
  watch: { 
    'myprop.id': {
      handler(newVal, oldVal) {
        console.log('Prop changed: ', newVal, ' | was: ', oldVal)
      },
      deep: true
    }
  ...
}

答案 4 :(得分:0)

我测试了一些东西,发现了错误和解决方案。首先,我的自定义输入中存在一个错误-这是我的组件,该组件内部使用cleave-vue。 Cleave-vue具有v模型,我也在自定义组件上使用了v模型,这是错误的-我必须使用同步值绑定(例如::value.sync =“ parentCost”)。

第二件事:是的,我必须在本地创建值,然后将其传递给child,并添加观察者。在观察者中,我进行了其他操作,如parseInt / parseFloat等,并设置了父数据。现在一切正常。这是一些重复的数据,但是我认为这不是什么大问题-我创建“抽象” mixin,因为我有很多类似的自定义组件,并且每个组件都使用观察者/设置者模板。代码很干净。

答案 5 :(得分:0)

您应该只需使用“ $ emit”就可以将孩子的道具“ myprop”的值发送到父应用。

new Vue({
  el: '#app',
  data: {
    myObj: {
       id: null
    }
  },
  components: {
    'child' : {
      template: `<div>
      <p>{{ myprop.id }}</p>
      <select v-model="myprop.id" @change="$emit('update', myprop);">
        <option value="1">1</option>
        <option value="2">2</option>
        <option value="3">3</option>
      </select>
      </div>`,
      props: ['myprop'],
      watch: { 
        'myprop.id': function(newVal, oldVal) { // watch it
          console.log('Prop changed: ', newVal, ' | was: ', oldVal)
        }
      }
    }
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
  <child :myprop="myObj"></child>
  reading from child: {{myObj.id}}
</div>