[Vue] 父组件明明按照正确的绑定方式更新了传递给子组件的prop属性 子组件却没有及时更新。解决方案:key值 nextTick watch监听。
prop介绍prop是单向数据流,父组件传递给子组件的数据发生改变,而子组件的页面中引用了该prop,那么按理说子组件会重新渲染,将最新的prop渲染到页面上。能正常更新的案例在父组件中启动定时器,每隔1s对状态数据parentNum进行加一操作。父组件中引用子组件时将parentNum作为属性传入。下面的例子实现的效果是子组件每隔一秒都会更新。从0开始每隔一秒加1并更新在页面上。<!--父
·
prop介绍
prop是单向数据流,父组件传递给子组件的数据发生改变,而子组件的页面中引用了该prop,那么按理说子组件会重新渲染,将最新的prop渲染到页面上。
能正常更新的案例
在父组件中启动定时器,每隔1s对状态数据parentNum进行加一操作。父组件中引用子组件时将parentNum作为属性传入。
下面的例子实现的效果是子组件每隔一秒都会更新。从0开始每隔一秒加1并更新在页面上。
<!--父组件-->
<template>
<div class="parentContainer">
我是父组件
<child ref="mychild" :num="parentNum"></child>
</div>
</template>
<script>
import Child from './Child.vue'
export default {
data () {
return {
parentNum: 0
}
},
components: {
Child
},
mounted () {
this.changeData()
},
methods: {
changeData () {
const _this = this
setInterval(function () {
_this.parentNum = _this.parentNum + 1
}, 1000)
}
}
}
</script>
<style scoped>
.parentContainer {
width: 500px;
height: 500px;
background-color: gray;
}
</style>
<!--子组件-->
<template>
<div class="childContainer">
我是子组件
<div class="inner" ref="inner">{{num}}</div> <!--在模板中使用num-->
</div>
</template>
<script>
export default {
props: {
num: Number
},
}
</script>
<style scoped>
.childContainer {
width: 200px;
height: 200px;
background-color: green;
font-size: 30px;
margin: auto;
}
.inner {
color: red;
}
</style>
不能更新的按钮
如果我们在子组件的模板中没有使用到prop变量,而只是在子组件的方法中使用了prop变量,那么根据vue的绑定原理来说是不会触发重绘的。所以子组件中即使获取到更改后的prop但是组件不会进行重新渲染。
参考下面的例子:下面的例子是子组件中永远显示0。通过调试工具我们发现,子组件的num一直在进行自加操作,但是没有更新页面。
<!--父组件-->
<template>
<div class="parentContainer">
我是父组件
<child ref="mychild" :num="parentNum"></child>
</div>
</template>
<script>
import Child from './Child.vue'
export default {
data () {
return {
parentNum: 0
}
},
components: {
Child
},
mounted () {
this.changeData()
},
methods: {
changeData () {
const _this = this
setInterval(function () {
_this.parentNum = _this.parentNum + 1
}, 1000)
}
}
}
</script>
<style scoped>
.parentContainer {
width: 500px;
height: 500px;
background-color: gray;
}
</style>
<!--子组件-->
<template>
<div class="childContainer">
我是子组件
<div class="inner" ref="inner"></div>
</div>
</template>
<script>
export default {
props: {
num: Number
},
mounted () {
this.init()
},
methods: {
init () {
this.$refs.inner.innerHTML = this.num // 在此处使用了prop 在模板中没有使用prop
// 通过上面的语句去更新页面
}
}
}
</script>
<style scoped>
.childContainer {
width: 200px;
height: 200px;
background-color: green;
font-size: 30px;
margin: auto;
}
.inner {
color: red;
}
</style>
解决方案
通过分析上面的代码,我们发现页面不更新的根本原因是因为子组件的init方法没有被调用。所以有以下三种解决方案。
第一种方案是在子组件中监听prop的变化然后去调用方法
// 子组件
export default {
props: {
num: Number
},
mounted () {
this.init()
},
watch: {
num (val) { // 关键
this.init() // 调用init
}
},
methods: {
init () {
this.$refs.inner.innerHTML = this.num
}
}
}
第二种方案是通过nextTick结合ref在父组件中调用子组件的方法。nextTick的作用是在在下次 DOM 更新循环结束之后执行延迟回调。
// 父组件
export default {
data () {
return {
parentNum: 0
}
},
components: {
Child
},
mounted () {
this.changeData()
},
methods: {
changeData () {
const _this = this
setInterval(function () {
console.log(1)
_this.parentNum = _this.parentNum + 1
_this.$nextTick(() => {
_this.$refs.mychild.init() // 调用
})
}, 1000)
}
}
}
第三种方案是在使用子组件时添加key属性
<!--父组件-->
<template>
<div class="parentContainer">
我是父组件
<child :num="parentNum" ref="mychild" :key="new Date().getTime()"></child>
</div>
</template>
参考
更多推荐
已为社区贡献1条内容
所有评论(0)