vue中组件之间传值的六种方式(完整版)
前言
组件是 vue.js 最强大的功能之一,而组件实例的作用域是相互独立的,这就意味着不同组件之间的数据无法相互引用。一般来说,组件可以有以下几种关系:
如上图所示,A 和 B、B 和 C、B 和 D 都是父子关系,C 和 D 是兄弟关系,A 和 C 是隔代关系(可能隔多代)。
针对不同的使用场景,如何选择行之有效的通信方式?这是我们所要探讨的主题。本文总结了 vue 组件间通信的几种方式,如 props
、$emit/$on
、vuex、$parent / $children
、$attrs/$listeners
和 provide/inject
,以通俗易懂的实例讲述这其中的差别及使用场景,希望对小伙伴有些许帮助。
本文的代码请猛戳 github博客,纸上得来终觉浅,大家动手多敲敲代码!
方法一、props/$emit
父组件 A 通过 props
的方式向子组件 B 传递,B to A 通过在 B 组件中 $emit
, A 组件中 v-on
的方式实现。
1.父组件向子组件传值
接下来我们通过一个例子,说明父组件如何向子组件传递值:在子组件 Users.vue 中如何获取父组件 App.vue 中的数据 users:["Henry","Bucky","Emily"]
//App.vue父组件<template><div id="app"><users v-bind:users="users"></users>//前者自定义名称便于子组件调用,后者要传递数据名</div></template><script>import Users from "./components/Users"export default {name: 'App',data(){return{users:["Henry","Bucky","Emily"]}},components:{"users":Users}}
//users子组件<template><div class="hello"><ul><li v-for="user in users">{{user}}</li>//遍历传递过来的值,然后呈现到页面</ul></div></template><script>export default {name: 'HelloWorld',props:{users:{ //这个就是父组件中子标签自定义名字type:Array,required:true}}}</script>
总结:父组件通过 props
向下传递数据给子组件。注:组件中的数据共有三种形式:data
、props
、computed
2.子组件向父组件传值(通过事件形式)
// 子组件<template><header><h1 @click="changeTitle">{{title}}</h1>//绑定一个点击事件</header></template><script>export default {name: 'app-header',data() {return {title:"Vue.js Demo"}},methods:{changeTitle() {this.$emit("titleChanged","子向父组件传值");//自定义事件 传递值“子向父组件传值”}}}</script>
// 父组件<template><div id="app">//与子组件titleChanged自定义事件保持一致<app-header v-on:titleChanged="updateTitle" ></app-header>// updateTitle($event)接受传递过来的文字<h2>{{title}}</h2></div></template><script>import Header from "./components/Header"export default {name: 'App',data(){return{title:"传递的是一个值"}},methods:{updateTitle(e){ //声明这个函数this.title = e;}},components:{"app-header":Header,}}</script>
总结:子组件通过 events
给父组件发送消息,实际上就是子组件把自己的数据发送到父组件。
方法二、$emit/$on
1. 具体实现方式:
var Event=new Vue();Event.$emit(事件名,数据);Event.$on(事件名,data => {});
2. 举个例子
假设兄弟组件有三个,分别是 A、B、C 组件,C 组件如何获取 A 或者 B 组件的数据。
<div id="itany"><my-a></my-a><my-b></my-b><my-c></my-c></div><template id="a"><div><h3>A组件:{{name}}</h3><button @click="send">将数据发送给C组件</button></div></template><template id="b"><div><h3>B组件:{{age}}</h3><button @click="send">将数组发送给C组件</button></div></template><template id="c"><div><h3>C组件:{{name}},{{age}}</h3></div></template><script>var Event = new Vue();//定义一个空的Vue实例var A = {template: '#a',data() {return {name: 'tom'}},methods: {send() {Event.$emit('data-a', this.name);}}}var B = {template: '#b',data() {return {age: 20}},methods: {send() {Event.$emit('data-b', this.age);}}}var C = {template: '#c',data() {return {name: '',age: ""}},mounted() {//在模板编译完成后执行Event.$on('data-a',name => {this.name = name;//箭头函数内部不会产生新的this,这边如果不用=>,this指代Event})Event.$on('data-b',age => {this.age = age;})}}var vm = new Vue({el: '#itany',components: {'my-a': A,'my-b': B,'my-c': C}}); </script>
$on
监听了自定义事件 data-a 和 data-b,因为有时不确定何时会触发事件,一般会在 mounted 或 created 钩子中来监听。
方法三、vuex
1.简要介绍 Vuex 原理
2.简要介绍各模块在流程中的功能:
- Vue Components:Vue组件。HTML页面上,负责接收用户操作等交互行为,执行
dispatch
方法触发对应action
进行回应。 - dispatch:操作行为触发方法,是唯一能执行
action
的方法。 - actions:操作行为处理模块,由组件中的
$store.dispatch('action 名称', data1)
来触发。然后由commit()
来触发mutation
的调用 , 间接更新state
。负责处理 Vue Components 接收到的所有交互行为。包含同步/异步操作,支持多个同名方法,按照注册的顺序依次触发。向后台 API 请求的操作就在这个模块中进行,包括触发其他action
以及提交mutation
的操作。该模块提供了Promise
的封装,以支持action
的链式触发。 - commit:状态改变提交操作方法。对
mutation
进行提交,是唯一能执行mutation
的方法。 - mutations:状态改变操作方法,由
actions
中的commit('mutation 名称')
来触发。是 Vuex 修改state
的唯一推荐方法。该方法只能进行同步操作,且方法名只能全局唯一。操作之中会有一些 hook 暴露出来,以进行state
的监控等。 - state:页面状态管理容器对象。集中存储 Vue components 中
data
对象的零散数据,全局唯一,以进行统一的状态管理。页面显示所需的数据从该对象中进行读取,利用 Vue 的细粒度数据响应机制来进行高效的状态更新。 - getters:
state
对象读取方法。图中没有单独列出该模块,应该被包含在了 render 中,Vue Components 通过该方法读取全局state
对象。
3.Vuex 与 localStorage
let defaultCity = "上海"try { // 用户关闭了本地存储功能,此时在外层加个try...catchif (!defaultCity){defaultCity = JSON.parse(window.localStorage.getItem('defaultCity'))}}catch(e){}export default new Vuex.Store({state: {city: defaultCity},mutations: {changeCity(state, city) {state.city = citytry {window.localStorage.setItem('defaultCity', JSON.stringify(state.city));// 数据改变的时候把数据拷贝一份保存到localStorage里面} catch (e) {}}}})
这里需要注意的是:由于 vuex 里,我们保存的状态,都是数组,而 localStorage 只支持字符串,所以需要用 JSON 转换:
JSON.stringify(state.subscribeList); // array -> stringJSON.parse(window.localStorage.getItem("subscribeList")); // string -> array
方法四、$attrs/$listeners
1.简介
$attrs
:包含了父作用域中不被prop
所识别 (且获取) 的特性绑定 (class 和 style 除外)。当一个组件没有声明任何prop
时,这里会包含所有父作用域的绑定 (class 和 style 除外),并且可以通过v-bind="$attrs"
传入内部组件。通常配合 interitAttrs 选项一起使用。
有关 interitAttrs 详情可见 博客园鲁小风lyf 的文章 vue组件的inheritAttrs属性$listeners
:包含了父作用域中的 (不含.native
修饰器的)v-on
事件监听器。它可以通过v-on="$listeners"
传入内部组件。
// index.vue<template><div><h2>浪里行舟</h2><child-com1:foo="foo":boo="boo":coo="coo":doo="doo"title="前端工匠"></child-com1></div></template><script>const childCom1 = () => import("./childCom1.vue");export default {components: { childCom1 },data() {return {foo: "Javascript",boo: "Html",coo: "CSS",doo: "Vue"};}};</script>
// childCom1.vue<template class="border"><div><p>foo: {{ foo }}</p><p>childCom1的$attrs: {{ $attrs }}</p><child-com2 v-bind="$attrs"></child-com2></div></template><script>const childCom2 = () => import("./childCom2.vue");export default {components: {childCom2},inheritAttrs: false, // 可以关闭自动挂载到组件根元素上的没有在 props 声明的属性props: {foo: String // foo 作为 props 属性绑定},created() {console.log(this.$attrs); // { "boo": "Html", "coo": "CSS", "doo": "Vue", "title": "前端工匠" }}};</script>
// childCom2.vue<template><div class="border"><p>boo: {{ boo }}</p><p>childCom2: {{ $attrs }}</p><child-com3 v-bind="$attrs"></child-com3></div></template><script>const childCom3 = () => import("./childCom3.vue");export default {components: {childCom3},inheritAttrs: false,props: {boo: String},created() {console.log(this.$attrs); // {"coo": "CSS", "doo": "Vue", "title": "前端工匠" }}};</script>
// childCom3.vue<template><div class="border"><p>childCom3: {{ $attrs }}</p></div></template><script>export default {props: {coo: String,title: String}};</script>
如上图所示 $attrs
表示没有继承数据的对象,格式为 {属性名:属性值}。Vue2.4 提供了 $attrs
, $listeners
来传递数据与事件,跨级组件之间的通讯变得更简单。
简单来说:$attrs
与 $listeners
是两个对象,$attrs
里存放的是父组件中绑定的非 Props
属性,$listeners
里存放的是父组件中绑定的非原生事件。
方法五、provide/inject
1.简介
2.举个例子
假设有两个组件: A.vue 和 B.vue,B 是 A 的子组件
// A.vueexport default {provide: {name: '浪里行舟'}}// B.vueexport default {inject: ['name'],mounted () {console.log(this.name); // 浪里行舟}}
3.provide
与 inject
怎么实现数据响应式
provide
祖先组件的实例,然后在子孙组件中注入依赖,这样就可以在子孙组件中直接修改祖先组件的实例的属性,不过这种方法有个缺点就是这个实例上挂载很多没有必要的东西比如props
,methods
等- 使用 2.6 最新 API Vue.observable 优化响应式
provide
(推荐)
我们来看个例子:孙组件 D、E 和 F 获取 A 组件传递过来的 color 值,并能实现数据响应式变化,即 A 组件的 color 变化后,组件 D、E、F 会跟着变(核心代码如下:)
// A 组件 <div><h1>A 组件</h1><button @click="() => changeColor()">改变color</button><ChildrenB /><ChildrenC /></div>......data() {return {color: "blue"};},// provide() {// return {// theme: {// color: this.color //这种方式绑定的数据并不是可响应的// } // 即A组件的color变化后,组件D、E、F不会跟着变// };// },provide() {return {theme: this//方法一:提供祖先组件的实例};},methods: {changeColor(color) {if (color) {this.color = color;} else {this.color = this.color === "blue" ? "red" : "blue";}}}// 方法二:使用2.6最新API Vue.observable 优化响应式 provide// provide() {// this.theme = Vue.observable({// color: "blue"// });// return {// theme: this.theme// };// },// methods: {// changeColor(color) {// if (color) {// this.theme.color = color;// } else {// this.theme.color = this.theme.color === "blue" ? "red" : "blue";// }// }// }
// F 组件 <template functional><div class="border2"><h3 :style="{ color: this.theme.color }">F 组件</h3></div></template><script>export default {inject: ["theme"]// inject: {// theme: {// from: theme,// //函数式组件取值不一样// default: () => ({})// }// }};</script>
虽说 provide
和 inject
主要为高阶插件/组件库提供用例,但如果你能在业务中熟练运用,可以达到事半功倍的效果!
有关 inject
参数为对象的用法可见 provide / inject
方法六、$parent
/$children
与 ref
转载自 segmentfault 浪里行舟 的文章 vue组件间通信六种方式(完整版)
ref
:如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子组件上,引用就指向组件实例$parent
/$children
:访问父 / 子实例
需要注意的是:这两种都是直接得到组件实例,使用后可以直接调用组件的方法或访问数据。我们先来看个用ref
来访问组件的例子:// component-a 子组件export default {data () {return {title: 'Vue.js'}},methods: {sayHello () {window.alert('Hello');}}}
// 父组件<template><component-a ref="comA"></component-a></template><script>export default {mounted () {const comA = this.$refs.comA;console.log(comA.title); // Vue.jscomA.sayHello(); // 弹窗}}</script>
不过,这两种方法的弊端是,无法在跨级或兄弟间通信。
// parent.vue<component-a></component-a><component-b></component-b><component-b></component-b>
我们想在 component-a 中,访问到引用它的页面中(这里就是 parent.vue)的两个 component-b 组件,那这种情况下,就得配置额外的插件或工具了,比如 Vuex 和 Bus 的解决方案。
总结
父子通信:
父向子传递数据是通过props
,子向父是通过events($emit)
;通过父链 / 子链也可以通信($parent/$children)
;ref
也可以访问组件实例;provide
/inject
API;$attrs/$listeners
兄弟通信:
Bus;Vuex跨级通信:
Bus;Vuex;provide
/inject
API、$attrs
/$listeners
vue中组件之间传值的六种方式(完整版)相关推荐
- vue父子组件之间传值的方法
vue父子组件之间传值的方法 一.基本父子传值 父传子 方式: props 效果: 把父组件的fatherName属性传入子组件,在子组件中使用 父组件代码: <template>< ...
- Vue中组件之间8中通信方式
vue是数据驱动视图更新的框架, 所以对于vue来说组件间的数据通信非常重要,那么组件之间如何进行数据通信的呢? 首先我们需要知道在vue中组件之间存在什么样的关系, 才更容易理解他们的通信方式, 就 ...
- vue中组件之间调用方法——子组件调用父组件的方法 父组件调用子组件的方法
vue中组件之间调用方法--子组件调用父组件的方法 & 父组件调用子组件的方法 1.vue中子组件调用父组件的方法 1.1.第一种方法是直接在子组件中通过this.$parent.event来 ...
- Vue - 全局组件之间传值(中间件传值)
Vue项目中全局组件之间传值(中间件传值) 一. 使用方法 二. 传值实例 一. 使用方法 创建一个中间件文件,文件名自定义 这里创建的文件为 send.js send.js 中配置 import V ...
- Vue 兄弟组件之间传值 Bus方法
1.在vue项目中新建一个js文件(文件名:bus.js) import Vue from 'vue'export default new Vue(); 2.在需要传值的页面引用并开始传参 <s ...
- vue 2 组件之间传值
对vue2版本的组件之间传值的一个简单整合: 父组件 => 子组件: props 和 refs - props: { msg: String } //parent <hello-world ...
- vue变量传值_Vue各类组件之间传值的实现方式
1.父组件向子组件传值 首先在父组件定义好数据,接着将子组件导入到父组件中.父组件只要在调用子组件的地方使用v-bind指令定义一个属性,并传值在该属性中即可,此时父组件的使命完成,请看下面关键代码: ...
- VUE中组件之间的通信方式
目录 一.父子组件之间的通信方式 1.props+$emit() 3.$parent+$children 4.provide+inject 5.$attrs+$listeners 6.ref+$ref ...
- vue跨组件之间传值Provide/Inject
官网传送门:inject Vue2.2.0+ # 背景 关于Vue组件的通讯方式相信大家能倒背如流 父子组件:通过prop,$emit,[$root,$parent,$children] 非父子 ...
最新文章
- SAP HUM 如何看哪些HU还在923包装区尚未上架?
- Python List中的append和extend
- IOS贝塞尔曲线圆形进度条和加载动画
- 硅谷渐患“大城市”病,世界创新中心或将外移...
- 【select模块】select IO多路复用和select实现FTP
- java 挥发注解_Java的挥发性修饰符
- php 添加音乐,PHP网站插入音乐
- linux phpstudy
- 文件与流 -- fopen/fclose
- 解决java.lang.OutOfMemoryError: unable to create new native thread问题
- 【JavaScript 封装库】BETA 2.0 测试版发布!
- 国二java好过还是office好过,计算机二级考哪一个科目比较容易过,Ms office 较为简单实用...
- BT5R3安装及汉化
- 空降的技术管理者应该如何开展工作?
- Allegro中Change铜皮至其他层
- 笔记本自动打开计算机,笔记本电脑自动开机是什么原因
- Win7开自带的虚拟WIFI
- 在PS中如何旋转箭头
- AODV=DSR+DSDV
- RS485自收发实现方案,典型应用电路及问题经验总结
热门文章
- python 超参数_完整介绍用于Python中自动超参数调剂的贝叶斯优化
- 聊聊springboot项目数据库密码如何加密
- day02_java基础加强(jdk新特性 javaa设计模式 反射)
- PS学习笔记-----吸管工具
- RFID标签技术变成仓储物流物流关键技术
- NVIDIA Jetson AGX Xavier设置风扇转速、工作模式及性能监控
- linux下的压缩和解压命令
- Think技术社区与UXweek社区的联谊活动~单身男女看过来,好福利!!
- 凤凰金融:“区块链+”如何改变金融服务?
- GB28181入门笔记