目录

  • 前言
  • 常用方式
    • 1. 通过父组件on监听子组件emit事件实现修改prop
    • 2. 通过父组件sync修饰符 + 子组件emit事件实现修改prop
  • 取巧方式
    • 3.通过data实现修改prop
    • 4.通过计算属性computed实现修改prop

前言

实际工作项目开发中,很经常会有父组件先传递值给子组件,再由子组件渲染展示的场景,下面我总结一下目前工作中遇到和用过的一些方式,也算是给大家一个实现方式和思路参考,如有理解不对or有其他方法欢迎在评论区留言指导~

常用方式

推荐,遵循prop单向传递的规则,基本数据类型和引用数据类型均可。

1. 通过父组件on监听子组件emit事件实现修改prop

原理:

  • 给子组件中的input标签绑定value属性赋值prop中的值,因为是用value而不是v-model,所以修改input值的时候并不会影响到prop。
  • 然后给input绑定input事件,每次输入内容都会触发input事件,在事件里通过this.$emit(‘父要监听的事件名’, 修改后的值)去将值向上传递。
  • 父组件中通过on监听子组件刚刚触发的emit事件,将事件传递过来的值更新到父组件的data中。
  • 父组件data中的值更新后,因为有通过prop传递给子组件,所以子组件也会同步更新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中的objupdateObj (key, newVal) {this.obj[key] = newVal},// 监听子组件触发的事件并更新data中的msgupdateMsg (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: {// 通知父组件更新objupdateObj ($event, key) {// 接收输入的值,和obj中对应需要更新值的属性,然后回传给父组件// 父组件就可以知道子组件需要更新obj中哪个属性的值this.$emit('update-obj', key, $event.target.value)},// 通知父组件更新msgupdateMsg (newVal) {this.$emit('update-msg', newVal)}}
}
</script>

2. 通过父组件sync修饰符 + 子组件emit事件实现修改prop

原理:

  • 给子组件中的input标签绑定value属性赋值prop中的值,因为是用value而不是v-model,所以修改input值的时候并不会影响到prop。
  • 然后给input绑定input事件,每次输入内容都会触发input事件,在事件里通过this.$emit(‘父要监听的事件名’, 修改后的值)去将值向上传递。
  • 父组件调用子组件传递prop时,在prop后加上.sync即可将事件传递过来的值更新到父组件的data中,因为sync其实就相当于执行了@监听子触发的事件名 = "父data中的属性名 = emit传递的值(即$event)"这一段代码。
  • 父组件data中的值更新后,因为有通过prop传递给子组件,所以子组件也会同步更新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: {// 通知父组件更新objupdateObj ($event, key) {// 接收输入的值,和childObj中对应需要更新值的属性// 然后更新childOBj后,回传给父组件// 父组件直接把拿到的childObj更新到data的obj即可this.childObj[key] = $event.target.valuethis.$emit('update:obj', this.childObj)},// 通知父组件更新msgupdateMsg (newVal) {this.$emit('update:msg', newVal)}}
}
</script>

取巧方式

主要针对引用数据类型,绕过了vue对于prop的检测机制,具体看项目规范是否允许这样写。

3.通过data实现修改prop

前提:只有引用数据类型可以实现

原理:

  • 将父组件传入的prop直接赋值给子组件的data,此时prop和data两边的变量指向的都是同一个内存地址,所以修改data等于修改prop。
  • vue2开始不允许直接修改prop,但此时我们表面修改的是data不是prop,因此vue不会抛出错误,相当于绕过了vue对于不允许修改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

前提:只有引用数据类型可以实现

原理:

  • 在子组件中直接通过计算属性computed监听父组件传入的prop,此时计算属性computed和prop两边的变量指向的都是同一个内存地址,所以修改计算属性computed等于修改prop。
  • vue2开始不允许直接修改prop,但此时我们表面修改的是计算属性computed不是prop,因此vue不会抛出错误,相当于绕过了vue对于不允许修改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的几种实现方式相关推荐

  1. Vue 子组件修改父组件值的解决方法

    分析 vue中父组件向子组件传值时,其父子prop之间形成单向下行绑定,反过来则不行,这样可以防止子组件意外改变父组件的值,怕子组件污染父组件,造成不可控: 此外,每次父组件的数据发生更新时,子组件的 ...

  2. 重构ElementUI解决DatePicker日期选择组件修改父组件placement参数问题[Vue.js项目实践: 新冠自检系统]

    新冠疫情自我检测系统网页设计开发文档 Sylvan Ding 的第一个基于 Vue.js 的项目. 本项目所提供的信息,只供参考之用,不保证信息的准确性.有效性.及时性和完整性,更多内容请查看国家卫健 ...

  3. vue-自定义事件之—— 子组件修改父组件的值

    如何利用自定义的事件,在子组件中修改父组件里边的值? 关键点记住:三个事件名字 步骤如下: 这里,相对本案例,父组件定义为Second-module,对应的子组件是Three-module 第一步:你 ...

  4. vue子组件修改父组件的值

    1. $emit('event', val) 最常用的一种方法,父组件通过v-on绑定一个事件,在事件中修改自己的值,子组件通过$emit触发该事件 在子组件MobileMessage中: 这种方法有 ...

  5. vue子组件修改父组件上的属性

    子组件中再定义一个参数,使用 $emit(update: prop, "newPropVulue") => $emit(update: 属性名, "新的属性值&qu ...

  6. vue3子组件修改父组件值,vue3 子组件修改属性

    如何在TypeScript中应用像Jquery之类的第三方JavaScript框架 要在TypeScript引用第三方JavaScript库和框架,首先要了解TypeScript的类型定义文件. Ty ...

  7. VUE子组件如何改变父组件传来的值,以及VUE子组件如何修改父组件的值,以及父组件修改子组件的值

    一)子组件修改父组件传来的值: 父组件传递给我一个名为deptName数据,但是现在我要在子组件中修改它的值并且实时更新页面,直接this.deptName是不能直接修改他的值的,所以我采用了使用一个 ...

  8. vue 子页面调用父页面的参数_Flutter子组件调用父组件方法修改父组件参数

    子组件调用父级组件方法的主要实现是父组件给子组件传入一个方法,然后在子组件中调用父级方法来修改父级的参数.看一下效果图 父级组件实现 在父级组件中写一个_editParentText的方法来修改组件中 ...

  9. 【Vue开发实战课后题】子组件为何不可以修改父组件传递的props?

    在 Vue 中,子组件为何不可以修改父组件传递的 Prop,如果修改了,Vue 是如何监控到属性的修改并给出警告的. 一.为何不可以修改伏组件传递的Prop? 因为Vue是单向数据流,为了保证数据的单 ...

最新文章

  1. Redis安装与调试
  2. 【结果很简单,过程很艰辛】记阿里云Ons消息队列服务.NET接口填坑过程
  3. java运用网络编程技术代码_Java 网络编程
  4. nginx location 正则表达式匹配多个地址_就是要让你搞懂Nginx,这篇就够了!
  5. 关于Anaconda的环境和包管理
  6. Mina、Netty、Twisted一起学(五):整合protobuf
  7. const类型成员函数与mutable
  8. 小熊派:用OpenHarmory3.0点亮LED
  9. C++_类和对象_C++继承_继承的方式_公共继承_保护继承_私有继承---C++语言工作笔记062
  10. java 8 api 下载_JDK8 API文档(下载)
  11. 【Css】Css实现DIV半透明效果(示例)
  12. C64x+ CPU中断 .
  13. 45本程序员圣经级别书籍,包邮送到家
  14. 物联网模块跨阵M1控制LED
  15. 全屏css,CSS之全屏背景图
  16. css中鼠标手,css各种鼠标手型集合
  17. OpenCV | 直线拟合fitline函数(Python)
  18. javascript 代码中的“use strict“;是什么意思
  19. arm_neon.h引用
  20. html5标签不区分大小写对错,html5 不区分大小写、标记结束符及属性是否加引号?...

热门文章

  1. win10 linux uef系统,超详细!Win10(UEFI启动模式)安装Ubuntu18.04双系统
  2. uiautomatorviewer无法启动
  3. 开源项目之Android 向下刷新列表
  4. 参数validator/valid校验用法(通俗)
  5. SQL server Date函数之CONVERT()函数
  6. scrapy爬取51job职位信息(针对2020.851job新的反爬虫机制)
  7. 数据库: mongodb导入json数据
  8. 上传文件到OOS服务器
  9. 使用Scanner收集你的身高体重,并用三目运算符判断BMI的范围
  10. 使用xpath解析爬取链家