Vue组件通信方式全面详解
vue组件通信方式全面详解
众所周知,Vue主要思想就是组件化开发。因为,在实际的项目开发中,肯定会以组件的开发模式进行。形如页面和页面之间需要通信一样,Vue 组件和组件之间肯定也需要互通有无、共享状态。接下来,我们就悉数给大家展示所有 Vue 组件之间的通信方式。
组件关系
- App组件和A组件、A组件和B组件、B组件和C组件形成父子关系
- B组件和D组件形成兄弟关系
- App组件和C组件、App和B组件形成了隔代关系(其中的层级可能是多级,既隔多代)
组件通信
这么多的组件关系,那么组件和组件之间又有哪些通信的方式呢?各种方式的区别又是什么?适用场景又是什么呢?
props和$emit
这种方式是我们日常开发中应用最多的一种方式。
props以单向数据流的形式可以很好的完成父子组件的通信
所谓单向数据流:就是数据只能通过 props 由父组件流向子组件,而子组件并不能通过修改 props 传过来的数据修改父组件的相应状态。至于为什么这样做,Vue 官网做出了解释:
**所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定:父级 prop 的更新会向下流动到子组件中,但是反过来则不行。这样会防止从子组件意外改变父级组件的状态,从而导致你的应用的数据流向难以理解。
额外的,每次父级组件发生更新时,子组件中所有的 prop 都将会刷新为最新的值。这意味着你不应该在一个子组件内部改变 prop。如果你这样做了,Vue 会在浏览器的控制台中发出警告。
正因为这个特性,于是就有了对应的 $emit
。$emit
用来触发当前实例上的事件。对此,我们可以在父组件自定义一个处理接受变化状态的逻辑,然后在子组件中如若相关的状态改变时,就触发父组件的逻辑处理事件。
let Child = {
template: `<div>
<input type="text" v-model='msg'/>
<button @click='handleClick'>传递</button>
</div>`,
props: ['msg'],
methods: {
handleClick() {
this.$emit('getChildData', '子组件数据')
}
},
}
let Parent = {
data() {
return {
msg: '小马哥',
val:''
}
},
methods: {
getChildData(val) {
this.val = val;
}
},
template: `
<div>
<p>我是一个父组件</p>
<p>我是{{val}}</p>
<Child :msg='msg' @getChildData='getChildData'></Child>
</div>
`,
components: {
Child
}
}
let vm = new Vue({
el: '#app',
template: `
<div>
<Parent></Parent>
</div>
`,
components: {
Parent
}
})
- 父传子:父组件传递msg数据给子组件,通过v-bind绑定msg,子组件中直接可以用props接收绑定的数据
- 子传父:子组件触发相应的事件,通过$emit触发事件传递数据,父组件中绑定对应的事件,通过$on监听对应的事件 接收子组件传递的数据
EventBus-中央事件总线
如果想实现兄弟组件之间进行通信,在项目规模不大的情况下,完全可以使用中央事件总线EventBus
的方式。如果你的项目规模是大中型的,那我们会使用vuex状态管理
EventBus
通过新建一个Vue
事件bus
对象,通过bus.$emit
触发事件,bus.$on监听触发的事件。
Vue.component('A', {
template: `
<div>
<p>我是A组件</p>
<button @click='handleClick'>A传递到B</button>
</div>
`,
data() {
return {
msg: 'hello 小马哥'
}
},
methods: {
handleClick() {
this.$bus.$emit('globalEvent',this.msg);
}
},
})
Vue.component('B', {
template: `
<div>
<p>我是B组件</p>
<h3>{{aValue}}</h3>
</div>
`,
data() {
return {
aValue: ''
}
},
created () {
this.$bus.$on('globalEvent',(val)=>{
this.aValue = val;
})
},
})
// 定义中央事件总线
let bus = new Vue();
// 将中央事件总线赋值给Vue.prototype中,这样所有组件都能访问到了
Vue.prototype.$bus = bus;
let vm = new Vue({
el: '#app',
template: `
<div>
<A></A>
<B></B>
</div>
`,
})
$attrs和$listeners
通过 props
进行组件通信的方式只适合直接的父子组件,如果父组件A下面有子组件B,组件B下面有组件C,这时如果组件A直接想传递数据给组件C那就行不通了! 只能是组件A通过 props 将数据传给组件B,然后组件B获取到组件A 传递过来的数据后再通过 props 将数据传给组件C。当然这种方式是非常复杂的,无关组件中的逻辑业务一种增多了,代码维护也没变得困难,再加上如果嵌套的层级越多逻辑也复杂,无关代码越多!
针对这样一个问题,Vue 2.4提供了$attrs
和$listeners
来实现能够直接让组件A传递消息给组件C
Vue.component('A', {
template: `
<div>
<p>我是A组件</p>
<B :msg='msg' @getCData='getCData'></B>
</div>
`,
methods: {
getCData(val) {
alert(val)
}
},
data() {
return {
msg: 'hello 小马哥'
}
},
})
Vue.component('B', {
template: `
<div>
<p>我是B组件</p>
<!-- C组件中能直接触发 getCData 的原因在于:B组件调用 C组件时,使用 v-on 绑定了 $listeners 属性 -->
<!-- 通过v-bind 绑定 $attrs 属性,C组件可以直接获取到 A组件中传递下来的 props(除了 B组件中 props声明的) -->
<C v-bind='$attrs' v-on='$listeners'></C>
</div>
`,
// props: ['msg'],
data() {
return {
}
}
})
Vue.component('C', {
template: `
<div>
<p>我是C组件</p>
<p>{{$attrs.msg}}</p>
<button @click='handleClick'>传递数据</button>
</div>
`,
methods: {
handleClick() {
this.$emit('getCData', 'C组件的数据')
}
},
data() {
return {
}
}
})
let vm = new Vue({
el: '#app',
template: `
<div>
<A></A>
</div>
`,
})
$attrs
:包含了父作用域中不被 prop 所识别 (且获取) 的特性绑定 (class
和style
除外)。当一个组件没有声明任何 prop 时,这里会包含所有父作用域的绑定属性 (class和style
除外),并且可以通过v-bind="$attrs"
传入内部组件。$listeners
:包含了父作用域中的 (不含.native
修饰器的)v-on
事件监听器。它可以通过v-on="$listeners"
传入内部组件。
provide和inject
在父组件中通过 provider
来提供属性,然后在子组件中通过 inject 来注入变量。不论子组件有多深,只要调用了 inject
那么就可以注入在 provider 中提供的数据,而不是局限于只能从当前父组件的 prop 属性来获取数据,只要在父组件的生命周期内,子组件都可以调用。这和 React 中的 Context API
有没有很相似!
Vue.component('A', {
template: `
<div>
<p>我是A组件</p>
<B></B>
</div>
`,
provide:{
a:"祖先A的数据"
},
data() {
return {
msg: 'hello 小马哥'
}
},
})
Vue.component('B', {
template: `
<div>
<p>我是B组件</p>
<C></C>
</div>
`,
data() {
return {
}
}
})
Vue.component('C', {
template: `
<div>
<p>我是C组件</p>
<h3>{{a}}</h3>
</div>
`,
inject:['a'],
data() {
return {
}
}
})
let vm = new Vue({
el: '#app',
template: `
<div>
<A></A>
</div>
`,
})
- 在
parent
组件中,通过provide
属性,以对象的形式向子孙组件暴露了一些属性 - 在
child
组件中,通过inject
属性注入了parent
组件提供的数据,实际这些通过inject
注入的属性是挂载到 Vue 实例上的,所以在组件内部可以通过 this 来访问
⚠️ 注意:官网文档提及 provide 和 inject 主要为高阶插件/组件库提供用例,并不推荐直接用于应用程序代码中。
$parent和$children
这里要说的这种方式就比较直观了,直接操作父子组件的实例。$parent
就是父组件的实例对象,而 $children
就是当前实例的直接子组件实例了,不过这个属性值是数组类型的,且并不保证顺序,也不是响应式的。
Vue.component('Parent', {
template: `
<div>
<p>我是父组件</p>
{{msg}}
<hr/>
<Child></Child>
</div>
`,
mounted () {
//读取子组件数据,注意$children并不保证顺序,也不是响应式的
console.log(this.$children[0].a)
},
data() {
return {
msg: 'hello 小马哥'
}
},
})
Vue.component('Child', {
template: `
<div>
<p>我是孩子组件</p>
<input type="text" @input='changeValue'/>
<h2>{{myMsg}}</h2>
</div>
`,
methods: {
changeValue() {
this.$parent.msg = '子组件中的数据'
}
},
data() {
return {
myMsg:this.$parent.msg,
a:"小马哥"
}
}
})
let vm = new Vue({
el: '#app',
template: `
<div>
<Parent></Parent>
</div>
`,
})
Vuex状态管理
Vuex 是状态管理工具,实现了项目状态的集中式管理。工具的实现借鉴了 Flux、Redux、和 The Elm Architecture 的模式和概念。当然与其他模式不同的是,Vuex 是专门为 Vue.js 设计的状态管理库,以利用 Vue.js 的细粒度数据响应机制来进行高效的状态更新。详细的关于 Vuex 的介绍,你既可以去查看官网文档,也可以查看本专栏关于 Vuex 一系列的介绍。
Vue组件通信方式全面详解的更多相关文章
- vue组件生命周期详解
Vue所有的生命周期钩子自动绑定在this上下文到实例中,因此你可以访问数据,对属性和方法进行运算.这意味着你不能使用箭头函数来定义一个生命周期方法.这是因为箭头函数绑定了父上下文,因此this与你期 ...
- vue组件is属性详解
查看官网对is属性的讲解,请移步:vue.js 本文参考资料 在vue.js组件教程的一开始提及到了is特性 下面是官网对is属性使用的说明: 组件功能是vue项目的一大特色.组件可以扩展html元素 ...
- vue组件间传值详解
1.父传子----传值要点: <1> 在组件注册的时候必须要使用 return 去返回 data对象;
- vc中调用Com组件的方法详解
vc中调用Com组件的方法详解 转载自:网络,来源未知,如有知晓者请告知我.需求:1.创建myCom.dll,该COM只有一个组件,两个接口: IGetRes--方法Hello(), IGet ...
- 整理4种Vue组件通信方式
整理4种Vue组件通信方式 重点是梳理了前两个,父子组件通信和eventBus通信,我觉得Vue文档里的说明还是有一些简易,我自己第一遍是没看明白. 父子组件的通信 非父子组件的eventBus通信 ...
- iOS 组件化流程详解(git创建流程)
[链接]组件化流程详解(一)https://www.jianshu.com/p/2deca619ff7e
- Vue.js 数据绑定语法详解
Vue.js 数据绑定语法详解 一.总结 一句话总结:Vue.js 的模板是基于 DOM 实现的.这意味着所有的 Vue.js 模板都是可解析的有效的 HTML,且通过一些特殊的特性做了增强.Vue ...
- React—组件生命周期详解
React—组件生命周期详解 转自 明明的博客 http://blog.csdn.net/slandove/article/details/50748473 (非原创) 版权声明:转载请注明出处,欢 ...
- Vue基础语法-数据绑定、事件处理和扩展组件等知识详解(案例分析,简单易懂,附源码)
前言: 本篇文章主要讲解了Vue实例对象的创建.常用内置指令的使用.自定义组件的创建.生命周期(钩子函数)等.以及个人的心得体会,汇集成本篇文章,作为自己对Vue基础知识入门级的总结与笔记. 其中介绍 ...
随机推荐
- JavaScript之三 - 语法
1.block 一般就是{}包括起来的代码块,注意的是,js没有块作用域,但是有函数作用域,全局作用域. 2.var 1 var a = b = 1; 如: 123456 function () { ...
- OO第四单元总结暨学期总结
一.第四单元作业架构设计 我们第四单元围绕UML图展开,在第四单元开始之前,本来以为我们的工作是学习如何使用UML工具,开始后才意识到我们要做的是解析UML类图.顺序图和状态图.当然,让我们解析的只是 ...
- C++走向远洋——41(深复制体验,3,)
*/ * Copyright (c) 2016,烟台大学计算机与控制工程学院 * All rights reserved. * 文件名:text.cpp * 作者:常轩 * 微信公众号:Worldhe ...
- 30s源码刨析系列之函数篇
前言 由浅入深.逐个击破 30SecondsOfCode 中函数系列所有源码片段,带你领略源码之美. 本系列是对名库 30SecondsOfCode 的深入刨析. 本篇是其中的函数篇,可以在极短的时间 ...
- tp5.1 请求时间格式化
当前时间:{$Request.time|date='Y-m-d H:i:s'} 注意database.php的配置!记录一下!
- 【5min+】保持程序健康的秘诀!AspNetCore的HealthCheck
系列介绍 [五分钟的dotnet]是一个利用您的碎片化时间来学习和丰富.net知识的博文系列.它所包含了.net体系中可能会涉及到的方方面面,比如C#的小细节,AspnetCore,微服务中的.net ...
- Web环境从Apache转Nginx后页面报404错误
问题原因: Apache支持伪静态规则在项目的入口目录有个.htaccess文件,Apache默认识别此文件内容, 但是Nginx不识别.htaccess文件,导致伪静态规则失效,从而无法解析url地 ...
- 算法入门——二分查找,旅行商问题,大O表示法
一. 算法入门 博主在市面上发现了很多,很多有关书算法的书籍,但是真正能够让初学者易懂的算法书籍,只是一点点,以下我讲以 Aditya Bhargava写的一本关于算法的入门书籍,为参考,这本书非常的 ...
- 用 Java 实现人脸识别功能(附源码)
整理了一些Java方面的架构.面试资料(微服务.集群.分布式.中间件等),有需要的小伙伴可以关注公众号[程序员内点事],无套路自行领取 更多优选 一口气说出 9种 分布式ID生成方式,面试官有点懵了 ...
- Vue 项目分环境打包
我们开发项目的时候,用vue-cli 2.x版本新建的项目,只有dev, pro两种开发环境, 有时需要个test环境来给测试使用,所以找了很多方法,总结了个最简单的方法来给大家使用 packa ...