首页 文章

VueJs 2.0 - 如何监听`props`的变化

提问于
浏览
81

VueJs 2.0 docs中,我找不到任何可以监听 props 更改的钩子 .

VueJs有像 onPropsUpdated() 这样的钩子吗?

Update

正如@wostex建议的那样,我试图 watch 我的 property ,但没有任何改变 . 然后我意识到我有一个特例:

<template>
    <child :my-prop="myProp"></child>
</template>

<script>
   export default {
      props: ['myProp']
   }
</script>

我传递 myProp ,父组件收到 child 组件 . 然后 watch: {myProp: ...} 无效 .

9 回答

  • 0

    您可以 watch 道具在道具更改时执行一些代码:

    new Vue({
      el: '#app',
      data: {
        text: 'Hello'
      },
      components: {
        'child' : {
          template: `<p>{{ myprop }}</p>`,
          props: ['myprop'],
          watch: { 
          	myprop: function(newVal, oldVal) { // watch it
              console.log('Prop changed: ', newVal, ' | was: ', oldVal)
            }
          }
        }
      }
    });
    
    <script src="https://unpkg.com/vue/dist/vue.js"></script>
    
    <div id="app">
      <child :myprop="text"></child>
      <button @click="text = 'Another text'">Change text</button>
    </div>
    
  • 4

    你试过这个吗?

    watch: {
      myProp: {
        // the callback will be called immediately after the start of the observation
        immediate: true, 
        handler (val, oldVal) {
          // do your stuff
        }
      }
    }
    

    https://vuejs.org/v2/api/#watch

  • 0

    不确定你是否已经解决了(如果我理解正确的话),但这是我的想法:

    如果父接收到myProp,并且您希望它传递给子节点并在子节点中观看它,则父节点必须具有myProp的副本(不是引用) .

    试试这个:

    new Vue({
      el: '#app',
      data: {
        text: 'Hello'
      },
      components: {
        'parent': {
          props: ['myProp'],
          computed: {
            myInnerProp() { return myProp.clone(); } //eg. myProp.slice() for array
          }
        },
        'child': {
          props: ['myProp'],
          watch: {
            myProp(val, oldval) { now val will differ from oldval }
          }
        }
      }
    }
    

    并在HTML中:

    <child :my-prop="myInnerProp"></child>
    

    实际上你在这种情况下处理复杂的集合时要非常小心(传递几次)

  • 1

    你需要了解,你正在拥有的组件层次结构以及你如何传递道具,绝对是你的情况特殊,开发人员通常不会遇到 .

    父组件-myProp->子组件-myProp->孙组件

    如果在父组件中更改了myProp,它也会在子组件中更改 will be reflected .

    并且如果myProp在子组件中被更改,那么它也在孙子组件中 will be reflected .

    因此,如果myProp在父组件中更改,那么它在孙组件中是 will be reflected . (到现在为止还挺好) .

    因此,在层次结构中,您不必做任何道具将具有固有的反应性 .

    现在谈论在层次结构中上升

    如果在grandChild组件中更改myProp,则在子组件中更改 won't be reflected . 您必须在child中使用.sync修饰符并从grandChild组件中使用emit事件 .

    如果在子组件中更改了myProp,则在父组件中更改 won't be reflected . 您必须在父级中使用.sync修饰符并从子组件中使用emit事件 .

    如果在grandChild组件中更改myProp,则在父组件中显然为 won't be reflected (显然) . 您必须使用.sync修饰符子项并从孙组件中发出事件,然后在子组件中观察prop,并使用.sync修饰符发出父组件正在侦听的更改事件 .

    让我们看一些代码以避免混淆

    Parent.vue

    <template>
        <div>
        <child :myProp.sync="myProp"></child>
        <input v-model="myProp"/>
        <p>{{myProp}}</p>
    </div>
    </template>
    
    <script>
    
        import child from './Child.vue'
    
        export default{
            data(){
                return{
                    myProp:"hello"
                }
            },
            components:{
                child
            }
        }
    </script>
    
    <style scoped>
    </style>
    

    Child.vue

    <template>
    <div>   <grand-child :myProp.sync="myProp"></grand-child>
        <p>{{myProp}}</p>
    </div>
    
    </template>
    
    <script>
        import grandChild from './Grandchild.vue'
    
        export default{
            components:{
                grandChild
            },
            props:['myProp'],
            watch:{
                'myProp'(){
                    this.$emit('update:myProp',this.myProp)
    
                }
            }
        }
    </script>
    
    <style>
    
    </style>
    

    Grandchild.vue

    <template>
        <div><p>{{myProp}}</p>
        <input v-model="myProp" @input="changed"/>
        </div>
    </template>
    
    <script>
        export default{
            props:['myProp'],
            methods:{
                changed(event){
                    this.$emit('update:myProp',this.myProp)
                }
            }
        }
    </script>
    
    <style>
    
    </style>
    

    但在此之后你不会注意到vue说的尖叫警告

    '避免直接改变道具,因为只要父组件重新渲染,该值就会被覆盖 .

    正如我之前提到的,大多数开发人员都没有遇到过这个问题,因为它是一种反模式 . 这就是你得到这个警告的原因 .

    但是为了解决你的问题(根据你的设计) . 我相信你必须做上述工作(说实话) . 我仍然建议您重新考虑您的设计,使其不易出错 .

    我希望它有所帮助 .

  • 2

    他,

    在我的情况下,我需要一个解决方案,任何时候任何道具将改变,我需要再次解析我的数据 . 我厌倦了为我的所有道具制作分离的观察者,所以我使用了这个:

    watch: {
        $props: {
          handler() {
            this.parseData();
          },
          deep: true,
          immediate: true,
        },
    

    取消这个例子的关键是使用 deep: true 所以它不仅可以观看$ props,还可以看到嵌套值,例如: props.myProp

    您可以在此处详细了解此扩展 Watch 选项:https://vuejs.org/v2/api/#vm-watch

  • 10

    对于双向绑定,您必须使用.sync修饰符

    <child :myprop.sync="text"></child>
    

    more details...

    并且您必须在子组件中使用watch属性来侦听和更新任何更改

    props: ['myprop'],
      watch: { 
        myprop: function(newVal, oldVal) { // watch it
          console.log('Prop changed: ', newVal, ' | was: ', oldVal)
        }
      }
    
  • 1

    如果myProp是一个对象,它通常不会被更改 . 所以,永远不会触发 Watch . 为什么不改变myProp的原因是你在大多数情况下只设置了myProp的一些键 . myProp本身仍然是那个 . 尝试观看myProp的道具,比如“myProp.a”,它应该可以工作 .

  • 0

    watch函数应放在Child组件中 . 不是父母 .

  • 98

    我使用计算属性,如:

    items:{
            get(){
                return this.resources;
            },
            set(v){
                this.$emit("update:resources", v)
            }
        },
    

    在这种情况下,资源是一个属性:

    props: [ 'resources' ]
    

相关问题