在vue的学习中,vue组件间的通讯是不得不了解的,在实际开发中,也是很是经常使用的,因此这里我总结了Vue组件的通讯的6种方式,但愿能帮助小伙伴们更好更快的去理解Vue组件间的通讯前端
由上边的图能够看出如下几个关系:vue
由上边几个关系对下边场景预览:vuex
下面来为你们详细讲解实现这些关系的几种通讯方式跨域
props/$emit $parent / $children与 ref $emit/$on vuex $attrs/$listeners provide/inject
几种组件通讯方法更好地选用markdown
当咱们的项目比较大时,能够选择更好的状态管理解决方案vuex。 节制地使用$parent和$children,它们的主要目的是做为访问组件的应急方法, 更推荐用props和events实现父子组件通讯 若是仅仅是传递数据,就用$attrs/$listeners好点 如何不只传递数据,还作中间处理,就用vuex好些
下面经过一个例子来看父组件是如何向子组件传递数据的:
这个例子是子组件son.vue 经过 props 获取 父组件father.vue 中的数据:
sonList: ['小白', '小红', '小蓝','小绿']app
<template> <div class="father"> <com-son :sons="sonList"></com-son> </div> </template> <script> import comSon from './son' export default { name: 'HelloWorld', components: { comSon }, data() { return { sonList: ['小白', '小红', '小蓝','小绿'] } } } </script>
<template> <div> <span v-for="(item, index) in sons" :key="index">{{item}}</span> </div> </template> <script> export default { props: ['sons'] } </script>
注意:异步
props 只能够从上一级组件传递到下一级组件,也就是父子组件,即这就是单向数据流ide
props是只读,不能够被修改,全部被修改都会失效和被警告函数
下面经过一个例子来看子组件是如何向父组件传递值:这个例子是子组件son.vue经过$emit向父组件值的传递学习
<template> <div class="father"> <com-son :sons="sonList" @onEmitIndex="onEmitIndex"></com-son> <p>{{currentIndex}}</p> </div> </template> <script> import comSon from './son' export default { name: 'HelloWorld', components: { comSon }, data() { return { currentIndex: -1, sonList: ['小白', '小红', '小蓝','小绿'] } }, methods:{ onEmitIndex(idx){ this.currentIndex = idx } } } </script>
<template> <div> <span v-for="(item, index) in sons" :key="index" @click="emitIndex(index)">{{item}}</span> </div> </template> <script> export default { props: ['sons'], methods: { emitIndex(index){ this.$emit('onEmitIndex',index) } } } </script>
在这里我要说一下:
节制地使用$parent和$children,它们的主要目的是做为访问组件的应急方法, 更推荐用props和events实现父子组件通讯
下面咱们来经过一个实例说明$parent和$children的用法:
<template> <div class="father"> <com-son></com-son> <button @click="name">点击改变子组件的值</button> </div> </template> <script> import comSon from './son' export default { name: 'HelloWorld', components: { comSon }, data() { return { msg: 'hello,早上好!' } }, methods:{ name(){ this.$children[0].message = "hello" } } } </script>
<template> <div class="com_a"> <span>{{message}}</span> <p>获取父组件的值:{{parentVal}}</p> </div> </template> <script> export default { data(){ return { message:'Good wether' } }, computed:{ parentVal(){ return this.$parent.msg; } } } </script>
下边再说ref访问组件的例子:
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); comA.sayHello(); } } </script>
注意:
这两种方法的弊端,没法在跨域兄弟间通讯
这个方法可用于父子、隔代、兄弟组件通讯
这种方式是经过一个相似App.vue的实例做为一个模块的事件中心,用它来触发事件和监听事件,从而实现任何组件间的通讯,包括父子、隔代、兄弟组件
当项目比较大的时候,能够选择更好的状态管理解决方案vuex
下边咱们来经过一个实例说明emit/on的用法:
在这里先说一下:
有两个组件A、B,在B组件中接收到A组件传过来的数据
首先开辟个新的Vue根实例
而后咱们在A组件中经过$emit方式去定义一个自定义事件方法
而后经过$on去接收A组件自定义的事件传过来的值
import Vue from 'vue' export default new Vue()
把组件A经过$emit传到那个Vue空白实例里面
<template> <div> <span>A组件->{{msg}}</span> <input type="button" value="把a组件数据传给b" @click ="send"> </div> </template> <script> import vmson from "util/emptyVue" export default { data(){ return { msg:{ a:'666', b:'999' } } }, methods:{ send:function(){ vmson.$emit("aevent",this.msg) } } } </script>
组件B经过$on去监听vmson实例中的自定义方法aevent
<template> <div> <span>{{msg}}</span> </div> </template> <script> import vmson from "util/emptyVue" export default { data(){ return { msg:"" } }, mounted(){ vmson.$on("aevent",(val)=>{//监听aevent事件 console.log(val);//打印出来结果 this.msg = val; }) } } </script>
这个父组件就是把A、B两个组件放在父组件中注册渲染
<template> <div> <childa></childa> <childb></childb> </div> </template> <script> import childa from './childa.vue'; import childb from './childb.vue'; export default { components:{ childa, childb }, data(){ return { msg:"" } }, methods:{ } } </script>
Vuex是一个专为Vue.js应用程序开发的状态管理模式,它解决了组件之间同一状态的共享问题,它采用集中式存储管理应用的全部组件的状态,因此组件就能够和stort通信了,其实Vuex就是用来管理组件之间通讯的一个组件
假如不使用vuex
用了Vuex以后
state
state中存放页面共享的状态字段
getters
至关于当前模块state的计算属性
mutations
若是想更新state中的字段,提交mutations中定义的事件的惟一的方式 (key为事件名,value是一个函数),可是中国事件函数必须是同步执行的
actions
能够定义异步函数,并在回调中提交mutation,就至关于异步更新了state中的字段
modules
相似于命名空间,用于项目中将各个模块的状态分开定义和操做,便于维护
<template> <div id="app"> <ChildA/> <ChildB/> </div> </template> <script> import ChildA from 'components/ChildA' import ChildB from 'components/ChildB' export default { name: 'App', components: {ChildA, ChildB} } </script>
<template> <div id="childA"> <h1>我是A组件</h1> <button @click="transform">点我让B组件接收到数据</button> <p>{BMessage}}</p> </div> </template> <script> export default { data() { return { AMessage: 'Hello,B组件,我是A组件' } }, computed: { BMessage() { return this.$store.state.BMsg } }, methods: { transform() { this.$store.commit('receiveAMsg', { AMsg: this.AMessage }) } } } </script>
<template> <div id="childB"> <h1>我是B组件</h1> <button @click="transform">点我看A组件接收的数据</button> <p>{{AMessage}}</p> </div> </template> <script> export default { data() { return { BMessage: 'Hello,A组件,我是B组件' } }, computed: { AMessage() { return this.$store.state.AMsg } }, methods: { transform() { this.$store.commit('receiveBMsg', { BMsg: this.BMessage }) } } } </script>
import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) const state = { // 初始化A和B组件的数据,等待获取 AMsg: '', BMsg: '' } const mutations = { receiveAMsg(state, payload) { state.AMsg = payload.AMsg }, receiveBMsg(state, payload) { state.BMsg = payload.BMsg } } export default new Vuex.Store({ state, mutations })
用在父组件传递数据给子组件或者孙组件
若是仅仅是传递数据,就用$attrs/$listeners好点 如何不只传递数据,还作中间处理,就用vuex好些
$attrs:
$attrs继承全部的父组件属性(除了prop传递的属性、class和style)
当一个组件没有声明任何 prop 时,这里会包含全部父做用域的绑定 ( class 和 style 除外 ),而且能够经过 v-bind="$attrs" 传入内部组件。一般配合 inheritAttrs 选项一块儿使用。
$listeners:
它是一个对象,包含了父做用域中的v-on事件监听器,能够配合v-on="$listeners"将全部的事件监听器指向这个组件的某个特定的子元素
下面咱们来经过一个实例看$attrs/$listeners的用法:
例:假设有三个组件:A组件包含B组件,B组件包含C组件
<template> <div id="app"> <child1 :p-child1="child1" :p-child2="child2" v-on:test1="onTest1" v-on:test2="onTest2" //此处监听了两个事件,能够在B组件或者C组件中直接触发 > </child1> </div> </template> <script> import Child1 from './Child1.vue'; export default { data() { return {}; }, components: { Child1 }, methods: { onTest1() { console.log('test1 running...'); }, onTest2() { console.log('test2 running'); } } }; </script>
<template> <div class="child-1"> <p>in child1:</p> <p>props: {{pChild1}}</p> <p>$attrs: {{$attrs}}</p> <hr> <child2 v-bind="$attrs" v-on="$listeners"></child2> //v-on绑定了$listeners,因此C组件能直接触发test //v-bind绑定了$attrs,因此C组件能够获取A组件传递下来的props的值 </div> </template> <script> import Child2 from './Child2.vue'; export default { props: ['pChild1'], data() { return {}; }, inheritAttrs: false, components: { Child2 }, mounted() { this.$emit('test1'); } }; </script>
<template> <div class="child-2"> <p>in child2:</p> <p>props: {{pChild2}}</p> <p>$attrs: {{$attrs}}</p> <hr> </div> </template> <script> export default { props: ['pChild2'], data() { return {}; }, inheritAttrs: false, mounted() { this.$emit('test2'); } }; </script>
祖先组件中经过provider来提供变量,而后在孙组件中经过inject来注入变量
procide/inject API主要解决了跨域组件间的通信问题,不过它的使用场景,主要是子组件获取上级组件的状态,跨级组件间创建了一种主动提供与依赖注入的关系
下边经过一个例子来讲明provide/inject的用法:
<template> <div> <son prop="data"></son> </div> </template> <script> export default { provide: { name: 'Tom' } }
这里的孙子组件指的是:父组件、子组件、孙子组件
<template> <div> {{name}} </div> </template> <script> export default { name: 'grandson', inject: [name] } </script>
这里能够经过inject直接访问其两个层次以上的数据,
用法与props彻底相同
vue组件间的通信大体能够分为三类
props/emit、parent/children、 attrs/$listeners、provide/inject API、ref
父向子传递数据经过props 子向父传递是经过$emit、event 子实例访问父实例经过$parent 父实例访问子实例经过$children $attrs用父组件传递数据给子组件或孙组件 (包含了父做用域中不做为 prop 被识别 (且获取) 的特性绑定 (class 和 style 除外)) listeners用父组件传递数据给子组件或孙组件 包含了父做用域中的 (不含 .native 修饰器的) v-on 事件监听器 祖先组件经过provider提供变量给子孙组件 子孙组件经过inject注入变量给祖先组件 ref用来访问组件实例
Vuex
vuex用来做为兄弟之间和跨级之间的通讯
Vuex、attrs/listeners、provide/inject API
vuex用来做为兄弟之间和跨级之间的通讯 $attrs用父组件传递数据给子组件或孙组件 (包含了父做用域中不做为 prop 被识别 (且获取) 的特性绑定 (class 和 style 除外)) listeners用父组件传递数据给子组件或孙组件 包含了父做用域中的 (不含 .native 修饰器的) v-on 事件监听器 祖先组件经过provider提供变量给子孙组件 子孙组件经过inject注入变量给祖先组件
若是本文对你有帮助得话,给本文点个赞❤️❤️❤️
欢迎你们加入,一块儿学习前端,共同进步!