Vue.js:父组件向子组件props动态传递对象的三种方法
1、背景
Vue的核心是组件模块与数据驱动。正是因为这两点,我们才能开发出各式各样的灵活的小组件。通过这些组件的相互配合就能够搭建出一个完整的界面,这里面就涉及到一个配合顺序——父组件与子组件。这两个名称的区别也仅仅是前者包含了后者,两者在开发时是独立的,但是,我们在开发过程中通常会有父子组件间的数据传递,尤其是父组件把数据交给子组件,然后让子组件渲染这种操作。
Vue为我们提供这种传递的简便方法,即子组件通过props暴露出数据接口,父组件通过绑定的方式将数据传递到子组件中。如下操作:
//子组件:child.vue
<template>
<label >{{attrs}}</label>
</template>
<script>
export default {
name: 'child',
props: {
attrs: {
type: Object,
default () {
return {}
}
}
},
//从父组件传递进来的props会在mout阶段赋值,之后便不会再触发该阶段
//beforeCreate(开始创建实例)、created(数据和方法已经初始化,但dom还没有挂载到页面上)、
//beforeMount(挂载之间,准备挂载)、mounted(dom跟数据都成功挂载)、
//beforeUpdate(数据更新,页面还没有同步)、updated(数据更新,页面已经同步)、
//beforeDestroy(实例销毁前)、destroyed(实例销毁后)
mounted () {
})
}
</script>
//父组件:father.vue
<template>
<child :attrs='fatherAttrs'>
</template>
<script>
export default {
name: 'child',
data(): return{
fatherAttrs: {aAttr: 'A', bAttr: 'B'}
}
}
</script>
这种方法为我们父子组件传递简化了很多,由上面我们知道父组件向子组件传递的值只会在mount阶段挂载到页面一次,之后便不再执行这个阶段。那么就存在一个问题,如果我们把fatherAttrs对象修改后,子组件的attrs对象能够接收到改变,但没有办法同步更新到页面上,即上面这种方法无法使得父组件能动态地向子组件传递数据。
那怎么办?以下提供两种解决方法
2、解决方法
2.1、data与watch辅助【推荐】
Vue内置的监听器watch是一个监听数据发生变化的处理函数,监听范围包括data函数中的数据和props函数中的数据。而我们知道data函数中的数据是与页面紧密绑定的,那么我们就可以通过监听props中的数据,如果其修改了出发watch函数,再将新值赋予data中的对象,则能实现动态更新props的对象。这是一种从子组件的角度实现的做法,具体做法如下。
//子组件:child.vue
<template>
<!-- 注意:这里修改为data中的对象 -->
<label >{{dataAttrs}}</label>
</template>
<script>
export default {
name: 'child',
data():{
return{
dataAttrs: null //新增一个对象来动态更新
}
}
props: {
attrs: {
type: Object,
default () {
return {}
}
}
},
mounted () {
this.dataAttrs= this.attrs; //用props中的对象对data中的对象赋初始值
},
watch: { // 监听到数据然后赋值
attrs{
// 监听数据发生变化的处理函数
handler(newV) {
this.dataAttrs = JSON.parse(JSON.stringify(newV));//将监听到修改的值赋予到dataAttrs中
},
// 是否开启深度监听,由于我们上面props中是一个Object对象,所以需要开启深度监听功能
deep: true
}
}
</script>
2.2、重建实例【适合没有实现动态更新的第三方库】
上面第一种方法能很好地处理动态更新props的情景,但它的前提是这个子组件我们是能够修改的,也就是说,这个子组件是我们自己写的,能够随意修改里面的内容。那要是我们用的是第三方的库呢?而且这个库里面也没有实现上面那种动态更新的方法,这怎么办?这就得从父组件的角度来解决了。
在上面背景的child.vue中的注释,我们知道props无法动态更新是因为组件的生命周期在mount阶段只执行一次的原因。我们一定要实现动态监听,那就需要想方设法让mount再执行一次了,这种方法就是重建子组件的实例,销毁更新前的实例,为子组件创建一个新的生命周期。
在父组件中要让子组件重新创建,最简单的指令是v-if,当为false时,该组件在dom中被移除,当为true时,该组件重新加入到dom,此时,子组件会重新创建【注意:v-if与v-show虽然都是控制组件显示与否,但v-show只是修改了display属性,使得没有前端显示而已,其实例还是存在的。所以,一般而言,v-if与v-show相比,其消耗的时间更多】。具体做法如下:
//父组件:father.vue
<template>
<child :attrs='fatherAttrs' v-if="show">
</template>
<script>
export default {
name: 'child',
data(): return{
fatherAttrs: {aAttr: 'A', bAttr: 'B'},
show: true
},
methods: {
changeAttrs(){ //触发该函数,动态更新子组件
this.fatherAttrs = {aAttr: 'C', bAttr: 'D'};
this.show= false;
this.$nextTick(() => {
this.show= true;
});
}
}
}
</script>
2.3、Vuex辅助【不推荐】
原本不想把这个添加到这里面的,因为仅仅父子组件传递数据就需要用到Vuex的话,那真的是有些杀鸡用牛刀了。但是就顺手记录一下吧。具体做法相对上面比较复杂一点,建议参考以下文章:vue中使用vuex(超详细)。
更多推荐
所有评论(0)