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: ...}
не работает.
Ответы
Ответ 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);
});
},