在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
前言实际工作项目开发中,很经常会有父组件先传递值给子组件,再由子组件渲染展示的场景,下面我总结一下目前工作中遇到和用过的一些方式,也算是给大家一个实现方式和思路参考,如有理解不对or有其他方法欢迎在评论区留言指导~ 常用方式推荐,遵循prop单向传递的规则,基本数据类型和引用数据类型均可。 1. 通过父组件on监听子组件emit事件实现修改prop原理:
父组件代码如下: <template> <div style="background-color: skyblue;"> <h3>通过父组件on监听子组件emit事件实现修改prop</h3> <div>父obj:{{ obj }}</div> <div>父msg:{{ msg }}</div> <!-- 父组件调用子组件时通过on监听子组件触发的emit事件,以接收值并更新用 --> <emitChild :obj="obj" :msg="msg" @update-obj="updateObj" @update-msg="updateMsg" /> </div> </template> <script> import emitChild from './components/emitChild' export default { name: 'emitUpdate', components: { emitChild }, data () { return { obj: { name: 'zhangsan', age: 18 }, msg: 'hello' } }, methods: { // 监听子组件触发的事件并更新data中的obj updateObj (key, newVal) { this.obj[key] = newVal }, // 监听子组件触发的事件并更新data中的msg updateMsg (newVal) { this.msg = newVal } } } </script> 子组件代码如下: <template> <div style="background-color: pink;"> <div> <span>修改name:</span> <!-- 这里绑定值用value,因为input在这主要用作展示prop数据,实际修改不在子组件,子组件只是作为修改触发源 --> <!-- 绑定input事件,作为触发源的入口 --> <input type="text" :value="obj.name" @input="updateObj($event, 'name')"> </div> <div> <span>修改age:</span> <input type="text" :value="obj.age" @input="updateObj($event, 'age')"> </div> <div> <span>修改msg:</span> <input type="text" :value="msg" @input="updateMsg($event.target.value)"> </div> </div> </template> <script> export default { name: 'emitUpdateChild', props: { obj: { type: Object, default: () => {} }, msg: { type: String, default: '' } }, methods: { // 通知父组件更新obj updateObj ($event, key) { // 接收输入的值,和obj中对应需要更新值的属性,然后回传给父组件 // 父组件就可以知道子组件需要更新obj中哪个属性的值 this.$emit('update-obj', key, $event.target.value) }, // 通知父组件更新msg updateMsg (newVal) { this.$emit('update-msg', newVal) } } } </script> 2. 通过父组件sync修饰符 + 子组件emit事件实现修改prop原理:
父组件代码如下: <template> <div style="background-color: skyblue;"> <h3>通过父组件sync修饰符 + 子组件emit事件实现修改prop</h3> <div>父obj:{{ obj }}</div> <div>父msg:{{ msg }}</div> <!-- 父组件调用子组件传递prop时,在prop后加上.sync即可 --> <syncChild :obj.sync="obj" :msg.sync="msg" /> <!-- sync其实就相当于执行了 @监听子触发的事件名 = "父data中的属性名 = emit传递的值(即$event)" 这一段代码 --> <!-- 效果相当于下面的代码,所以父组件methods中不需要再定义修改data数据的方法 --> <!-- <syncChild :obj="obj" :msg="msg" @update-obj="obj = $event" @update-msg="msg = $event" /> --> </div> </template> <script> import syncChild from './components/syncChild' export default { name: 'syncUpdate', components: { syncChild }, data () { return { obj: { name: 'zhangsan', age: 18 }, msg: 'hello' } } } </script> 子组件代码如下: <template> <div style="background-color: pink;"> <div> <span>修改name:</span> <!-- 这里绑定值用value,因为input在这主要用作展示prop数据,实际修改不在子组件,子组件只是作为修改触发源 --> <!-- 绑定input事件,作为触发源的入口 --> <input type="text" :value="childObj.name" @input="updateObj($event, 'name')"> </div> <div> <span>修改age:</span> <input type="text" :value="childObj.age" @input="updateObj($event, 'age')"> </div> <div> <span>修改msg:</span> <input type="text" :value="msg" @input="updateMsg($event.target.value)"> </div> </div> </template> <script> // 这里引入lodash工具库的cloneDeep深拷贝方法 // 官方文档地址 https://www.lodashjs.com/ import { cloneDeep } from 'lodash' export default { name: 'emitUpdateChild', props: { obj: { type: Object, default: () => {} }, msg: { type: String, default: '' } }, data () { return { // 这里通过深拷贝将prop的obj复制了一份,主要为了: // 1.区分2个对象(引用类型)用的不是同一个内存地址 // 2.保留对象中所有的值,方便子组件渲染/修改/回传用 childObj: cloneDeep(this.obj) } }, methods: { // 通知父组件更新obj updateObj ($event, key) { // 接收输入的值,和childObj中对应需要更新值的属性 // 然后更新childOBj后,回传给父组件 // 父组件直接把拿到的childObj更新到data的obj即可 this.childObj[key] = $event.target.value this.$emit('update:obj', this.childObj) }, // 通知父组件更新msg updateMsg (newVal) { this.$emit('update:msg', newVal) } } } </script> 取巧方式主要针对引用数据类型,绕过了vue对于prop的检测机制,具体看项目规范是否允许这样写。 3.通过data实现修改prop前提:只有引用数据类型可以实现 原理:
父组件代码如下: <template> <div style="background-color: skyblue;"> <h3>通过赋值到data实现修改prop</h3> <div>父obj:{{ obj }}</div> <div>父msg:{{ msg }}</div> <dataChild :obj="obj" :msg.sync="msg" /> </div> </template> <script> import dataChild from './components/dataChild' export default { name: 'dataUpdate', components: { dataChild }, data () { return { obj: { name: 'zhangsan', age: 18 }, msg: 'hello' } } } </script> 子组件代码如下: <template> <div style="background-color: pink;"> <div> <span>修改name:</span> <!-- 这里因为我们直接把prop赋值给data了,所以可以直接用v-model双向绑定修改数据 --> <input type="text" v-model="dataObj.name"> </div> <div> <span>修改age:</span> <input type="text" v-model="dataObj.age"> </div> <div> <span>修改msg:</span> <!-- 这里提供另一种修改基本数据类型的思路,可以通过watch侦听器实现 --> <input type="text" v-model="dataMsg"> </div> </div> </template> <script> export default { name: 'dataChild', props: { obj: { type: Object, default: () => {} }, msg: { type: String, default: '' } }, data () { return { // 引用数据类型直接赋值时是浅拷贝,只会复制内存地址,修改其中一个会影响另一个 dataObj: this.obj, // 基本数据类型直接赋值时是复制值,修改其中一个不会影响另一个 dataMsg: this.msg } }, watch: { // 这里侦听data中复制过来的dataMsg,当修改时执行emit通知父组件进行更新 dataMsg (newVal) { this.$emit('update:msg', newVal) } } } </script> 4.通过计算属性computed实现修改prop前提:只有引用数据类型可以实现 原理:
父组件代码如下: <template> <div style="background-color: skyblue;"> <h3>通过计算属性监听实现修改prop</h3> <div>父obj:{{ obj }}</div> <div>父msg:{{ msg }}</div> <computedChild :obj="obj" :msg.sync="msg" /> </div> </template> <script> import computedChild from './components/computedChild' export default { name: 'computedUpdate', components: { computedChild }, data () { return { obj: { name: 'zhangsan', age: 18 }, msg: 'hello' } } } </script> 子组件代码如下: <template> <div style="background-color: pink;"> <div> <span>修改name:</span> <!-- 这里因为我们直接通过计算属性computed监听prop了,所以可以直接用v-model双向绑定修改数据 --> <input type="text" v-model="computedObj.name"> </div> <div> <span>修改age:</span> <input type="text" v-model="computedObj.age"> </div> <div> <span>修改msg:</span> <!-- 这里提供另一种修改基本数据类型的思路,可以通过计算属性computed的setter实现 --> <input type="text" v-model="computedMsg"> </div> </div> </template> <script> export default { name: 'computedChild', props: { obj: { type: Object, default: () => {} }, msg: { type: String, default: '' } }, computed: { computedObj () { // 这里直接return引用数据类型obj,此时computedObj相当于obj // 所以是浅拷贝,只会复制内存地址,修改其中一个会影响另一个 return this.obj }, computedMsg: { get () { // 这里prop每次更新时,都会触发计算属性的getter方法获取最新的值 // 直接return基本数据类型时是复制值,修改其中一个不会影响另一个 return this.msg }, set (newVal) { // 这里利用计算属性的setter方法,监听到值修改时触发emit通知父组件更新值 this.$emit('update:msg', newVal) } } } } </script> 到此这篇关于vue通过子组件修改父组件prop的几种实现方式的文章就介绍到这了,更多相关vue子组件修改父组件prop内容请搜索极客世界以前的文章或继续浏览下面的相关文章希望大家以后多多支持极客世界! |
请发表评论