在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: ...}
无效。
答案 0 :(得分:164)
你可以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>
答案 1 :(得分:38)
您尝试过吗?
watch: {
myProp: {
// the callback will be called immediately after the start of the observation
immediate: true,
handler (val, oldVal) {
// do your stuff
}
}
}
答案 2 :(得分:6)
您需要了解您所拥有的组件层次结构以及如何传递道具,当然您的情况很特殊,开发人员通常不会遇到这种情况。
父组件-myProp->子组件-myProp->孙子 组件
如果myProp在父组件中进行了更改,它也会也将在子组件中反映。
如果子组件中的myProp发生更改,它的也将反映在子组件中。
因此,如果myProp在父级组件中进行了更改,则它将在子级组件中反映。 (到目前为止一切顺利)。
因此,在层次结构中,您无需执行任何操作,道具本质上就是被动的。
现在谈论在层次结构中前进
如果myProp在grandChild组件中进行了更改,则它不会反映在子组件中。您必须在child中使用.sync修饰符,并从grandChild组件发出事件。
如果myProp在子组件中进行了更改,则它不会反映在父组件中。您必须在父级中使用.sync修饰符并从子级组件发出事件。
如果myChildp在grandChild组件中进行了更改,则不会反映(显然)。您必须使用.sync修饰符child并从孙子组件中发出事件,然后在子组件中观察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的尖叫警告
'避免直接更改道具,因为该值将被覆盖 每当父组件重新渲染时。”
正如我之前提到的,大多数开发人员都不会遇到此问题,因为这是一种反模式。这就是为什么您收到此警告。
但是为了解决您的问题(根据您的设计)。我相信您必须解决以上问题(老实说,hack)。我仍然建议您应该重新考虑您的设计,使其不易出现错误。
我希望它会有所帮助。
答案 3 :(得分: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>
实际上,在这种情况下处理复杂的集合时,你必须非常小心(传递几次)
答案 4 :(得分:5)
他
在我的情况下,我需要一个解决方案,随时更改任何道具,就需要再次解析我的数据。我已经厌倦了为所有道具做单独的观察者,所以我使用了这个:
watch: {
$props: {
handler() {
this.parseData();
},
deep: true,
immediate: true,
},
要脱离此示例的关键点是使用deep: true
,因此它不仅监视$ props,而且还嵌套嵌套的值,例如。 props.myProp
您可以在此处了解有关此扩展监视选项的更多信息:https://vuejs.org/v2/api/#vm-watch
答案 5 :(得分:2)
对于双向绑定,您必须使用.sync修饰符
<child :myprop.sync="text"></child>
,您必须使用子组件中的watch属性来侦听和更新所有更改
props: ['myprop'],
watch: {
myprop: function(newVal, oldVal) { // watch it
console.log('Prop changed: ', newVal, ' | was: ', oldVal)
}
}
答案 6 :(得分:2)
我使用的计算属性如下:
items:{
get(){
return this.resources;
},
set(v){
this.$emit("update:resources", v)
}
},
在这种情况下,资源是一个属性:
props: [ 'resources' ]
答案 7 :(得分:0)
您可以使用监视模式来检测更改:
在原子级别上执行所有操作。因此,首先要通过监视内部的内容来检查watch方法本身是否被调用。一旦确定要调用手表,请使用您的业务逻辑将其粉碎。
watch: {
myProp: function() {
console.log('Prop changed')
}
}
答案 8 :(得分:0)
如果需要在接收更改后创建逻辑,我会使用props
和变量computed
属性
export default {
name: 'getObjectDetail',
filters: {},
components: {},
props: {
objectDetail: {
type: Object,
required: true
}
},
computed: {
_objectDetail: {
let value = false
...
if (someValidation)
...
}
}
答案 9 :(得分:0)
对我来说,这是一种礼貌的解决方案,它可以更改一个具体的道具并由此创建逻辑
在接收更改后,我将使用props
和变量computed
属性创建逻辑
export default {
name: 'getObjectDetail',
filters: {},
components: {},
props: {
objectDetail: { // <--- we could access to this value with this.objectDetail
type: Object,
required: true
}
},
computed: {
_objectDetail: {
let value = false
// ...
// if || do || while -- whatever logic
// insert validation logic with this.objectDetail (prop value)
value = true
// ...
return value
}
}
因此,我们可以在html渲染上使用_objectDetail
<span>
{{ _objectDetail }}
</span>
或采用某种方法:
literallySomeMethod: function() {
if (this._objectDetail) {
....
}
}
答案 10 :(得分:0)
如果你的道具 myProp
有嵌套的项目,那些嵌套的不会是反应式的,所以你需要使用类似 lodash deepClone 的东西:
<child :myProp.sync="_.deepClone(myProp)"></child>
就是这样,不需要观察者或其他任何东西。
答案 11 :(得分:0)
道具和 v 模型处理。如何将值从父级传递给子级以及子级到父级。
Watch 不是必需的! 在 Vue 中改变 props 也是一种反模式,所以你永远不应该改变子组件或组件中的 props 值。使用 $emit 更改值,Vue 将始终按预期工作。
/* COMPONENT - CHILD */
Vue.component('props-change-component', {
props: ['value', 'atext', 'anumber'],
mounted() {
var _this = this
this.$emit("anumber", 6)
setTimeout(function () {
// Update the parent binded variable to 'atext'
_this.$emit("update:atext", "4s delay update from child!!")
}, 4000)
setTimeout(function () {
// Update the parent binded v-model value
_this.$emit("input", "6s delay update v-model value from child!!")
}, 6000)
},
template: '<div> \
v-model value: {{ value }} <br> \
atext: {{ atext }} <br> \
anumber: {{ anumber }} <br> \
</div>'
})
/* MAIN - PARENT */
const app = new Vue({
el: '#app',
data() {
return {
myvalue: 7,
mynumber: 99,
mytext: "My own text",
}
},
mounted() {
var _this = this
// Update our variable directly
setTimeout(function () {
_this.mytext = "2s delay update mytext from parent!!"
}, 2000)
},
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<props-change-component
v-model='myvalue'
:atext.sync='mytext'
:anumber.sync='mynumber'>
</props-change-component>
</div>
答案 12 :(得分:0)
对一些用例的有趣观察。
如果您通过 prop 从您的商店中查看数据项,并且您在同一个 store 突变中多次更改数据项,则不会被监视。
但是,如果您将数据项更改分成对同一突变的多个调用,则会对其进行监视。
此代码不会触发观察者:
// Somewhere in the code:
this.$store.commit('changeWatchedDataItem');
// In the 'changeWatchedDataItem' mutation:
state.dataItem = false;
state.dataItem = true;
这段代码将在每次突变时触发观察者:
// Somewhere in the code:
this.$store.commit('changeWatchedDataItem', true);
this.$store.commit('changeWatchedDataItem', false);
// In the 'changeWatchedDataItem' mutation:
changeWatchedDataItem(state, newValue)
state.dataItem = newValue;
答案 13 :(得分:-1)
如果myProp是一个对象,则通常不能更改它。因此,观看将永远不会被触发。之所以不能更改myProp的原因是,在大多数情况下,您只需设置myProp的某些键即可。 myProp本身仍然是其中之一。 尝试观看myProp的道具,例如“ myProp.a”,它应该可以工作。
答案 14 :(得分:-1)
监视功能应放在子组件中。不是父母。
答案 15 :(得分:-1)
@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);
});
},