Подтвердить что ты не робот

VueJs 2.0 - как слушать изменения `реквизита`

В VueJs 2.0 docs Я не могу найти никаких крючков, которые будут прослушивать изменения props.

Есть ли у VueJs такие крючки, как onPropsUpdated() или подобные?

Обновление

Как предположил @wostex, я попытался watch мою собственность, но ничего не изменилось. Затем я понял, что у меня есть специальный случай:

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

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

Я передаю myProp, что родительский компонент получает компонент child. Тогда watch: {myProp: ...} не работает.

4b9b3361

Ответ 1

Вы можете 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>

Ответ 2

Вы пробовали это?

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

Ответ 3

Он,

в моем случае мне нужно было решение, при котором в любое время менялся бы любой реквизит, мне нужно было снова анализировать мои данные. Я устал делать отдельный наблюдатель для всех моих реквизитов, поэтому я использовал это:

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

Ключевым моментом, который следует исключить из этого примера, является использование deep: true, чтобы он не только просматривал $ props, но и вложенные значения, например, например props.myProp

Вы можете узнать больше об этих расширенных опциях часов здесь: https://vuejs.org/v2/api/#vm-watch

Ответ 4

Вы должны понимать, иерархию компонентов, которую вы имеете, и то, как вы передаете реквизит, определенно, ваш случай особенный и обычно не встречается разработчиками.

Родительский компонент -myProp-> Дочерний компонент -myProp-> Внучатый компонент

Если myProp изменяется в родительском компоненте, это будет отражено и в дочернем компоненте.

И если myProp изменяется в дочернем компоненте, это будет отражено и в компоненте внука.

Поэтому, если myProp изменяется в родительском компоненте, он будет отражен в компоненте внука. (Все идет нормально).

Поэтому вниз по иерархии вам не нужно ничего делать, реквизит будет неотъемлемо реактивным.

Теперь говорим о повышении в иерархии

Если myProp изменяется в компоненте grandChild, он не будет отражен в дочернем компоненте. Вы должны использовать модификатор .sync в дочернем элементе и генерировать событие из компонента grandChild.

Если myProp изменяется в дочернем компоненте, он не будет отражен в родительском компоненте. Вы должны использовать модификатор .sync в родительском и событие emit из дочернего компонента.

Если myProp изменяется в компоненте grandChild, он не будет отражен в родительском компоненте (очевидно). Вы должны использовать дочерний модификатор .sync и событие emit из компонента grandchild, затем наблюдать за подпоркой в дочернем компоненте и генерировать событие при изменении, которое прослушивается родительским компонентом с использованием модификатора .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>

Но после этого вы не заметите кричащих предупреждений о том, что

"Избегайте прямого изменения свойства, так как значение будет перезаписываться при повторном рендеринге родительского компонента".

Опять же, как я упоминал ранее, большинство разработчиков не сталкиваются с этой проблемой, потому что это анти паттерн. Вот почему вы получаете это предупреждение.

Но для того, чтобы решить вашу проблему (в соответствии с вашим дизайном). Я считаю, что вы должны сделать вышеупомянутую работу (взломать, если честно). Я все еще рекомендую вам пересмотреть свой дизайн и сделать его менее подверженным ошибкам.

Я надеюсь, что это помогает.

Ответ 5

Не уверен, что вы его разрешили (и если я правильно понял), но вот моя идея:

Если родитель получает 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>

на самом деле вы должны быть очень осторожны при работе над сложными коллекциями в таких ситуациях (несколько раз пропуская)

Ответ 6

для двухстороннего связывания вы должны использовать модификатор .sync

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

подробнее...

и вы должны использовать свойство watch в дочернем компоненте, чтобы прослушивать и обновлять любые изменения

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

Ответ 7

Я работаю с вычисляемым свойством, таким как:

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

Ресурсы в этом случае являются свойством:

props: [ 'resources' ]

Ответ 8

Вы можете использовать режим просмотра, чтобы обнаружить изменения:

Делай все на атомном уровне. Поэтому сначала проверьте, вызывается ли сам метод watch или нет, утешая что-то внутри. Как только установлено, что часы вызывают, разбейте их своей бизнес-логикой.

watch: { 
  myProp: function() {
   console.log('Prop changed')
  }
}

Ответ 9

если myProp - объект, он не может быть изменен в обычном режиме. таким образом, часы никогда не сработают. причина, по которой myProp не изменяется, заключается в том, что в большинстве случаев вы просто устанавливаете некоторые ключи myProp. Сам myProp все еще один. попробуйте посмотреть реквизиты myProp, например "myProp.a", он должен работать.

Ответ 10

Функция watch должна размещаться в дочернем компоненте. Не родитель.

Ответ 11

У @JoeSchr хороший ответ. Вот еще один способ сделать это, если вы не хотите, чтобы 'Deep: True'.

 mounted() {
    this.yourMethod();
    // re-render any time a prop changes
    Object.keys(this.$options.props).forEach(key => {
      this.$watch(key, this.yourMethod);
    });
  },