组件间的通讯是是实际开发中很是经常使用的一环,如何使用对项目总体设计、开发、规范都有很实际的的做用,我在项目开发中对此深有体会,总结下vue组件间通讯的几种方式,讨论下各自的使用场景php
文章对相关场景预览vue
文章相关技术预览 prop、emit、bus、vuex、路由URL、provide/inject、children/$parent、$attrs/inheritAttrsvuex
注:如下介绍与代码环境:vue2.0+、vue-cli2vue-cli
父子组件的通讯是开发是最经常使用的也是最重要的,大家必定知道父子通讯是用prop传递数据的,像这样:api
//父组件,传递数据
<editor :inputIndex="data" :inputName="王文健"></editor>
复制代码
//子组件,接受数据,定义传递数据的类型type与默认值default
props: {
inputIndex: {
type: Object,
default: function(){
return {}
}
},
inputName: {
type: String,
default: ''
},
复制代码
注意项:数组
父组件传递数据时相似在标签中写了一个属性,若是是传递的数据是data中的天然是要在传递属性前加v-bind:,若是传递的是一个已知的固定值呢bash
若是prop传到子组件中的数据是一个对象的话,要注意传递的是一个对象引用,虽然父子组件看似是分离的但最后都是在同一对象下session
在vue中子向父传递数据通常用**$emit**自定义事件,在父组件中监听这个事件并在回调中写相关逻辑dom
// 父组件监听子组件定义的事件
<editor :inputIndex="index" @editorEmit='editorEmit'></editor>
复制代码
// 子组件须要返回数据时执行,并能够传递数据
this.$emit('editorEmit', data)
复制代码
那么问题来了,我是否是真的有必要去向父组件返回这个数据,用自定义事件能够在当子组件想传递数据或向子组件传递的数据有变化须要从新传递时执行,那么另一种场景,父组件须要子组件的一个数据但子组件并不知道或者说没有能力在父组件想要的时候给父组件,那么这个时候就要用到组件的一个选项ref:ide
<editor ref="editor" @editorEmit='editorEmit'></editor>
vue中兄弟组件间的通讯是很不方便的,或者说不支持的,那么父子组件中都有什么通讯方式呢
// router index.js 动态路由
{
path:'/params/:Id',
component:Params,
name:Params
}
复制代码
// 跳转路由
<router-link :to="/params/12">跳转路由</router-link>
复制代码
在组件以外定义一个bus.js做为组件间通讯的桥梁,适用于比较小型不须要vuex又须要兄弟组件通讯的
bus.js中添加以下
import Vue from 'vue'
export default new Vue
复制代码
组件中调用bus.js经过自定义事件传递数据
import Bus from './bus.js'
export default {
methods: {
bus () {
Bus.$emit('msg', '我要传给兄弟组件们')
}
}
}
复制代码
兄弟组件中监听事件接受数据
import Bus from './bus.js'
export default {
mounted() {
Bus.$on('msg', (e) => {
console.log(e)
})
}
}
复制代码
注:以上两种使用场景并不高因此只是简略提一下,这两点都是好久之前写过,以上例子网上直接搜集而来若有错误,指正
规范:对于多人开发的大型应用规范的制定是相当重要的,对于全部人都会接触到的vuex对其修改数据调用数据都应有一个明确严格的使用规范
对于vuex的使用场景也有一些争论,有人认为正常组件之间就是要用父子组件传值的方式,即便子组件须要使vuex中的数据也应该由父组件获取再传到子组件中,但有的时候组件间嵌套很深,只容许父组件获取数据并非一个方便的方法,因此对于祖先元组件与子组件传值又有了新问题,vue官网也有一些方法解决,以下
provide/inject 除了正常的父子组件传值外,vue也提供了provide/inject
这对选项须要一块儿使用,以容许一个祖先组件向其全部子孙后代注入一个依赖,不论组件层次有多深,并在起上下游关系成立的时间里始终生效
官网实例
// 父级组件提供 'foo'
var Provider = {
provide: {
foo: 'bar'
},
// ...
}
// 子组件注入 'foo'
var Child = {
inject: ['foo'],
created () {
console.log(this.foo) // => "bar"
}
}
复制代码
提示:provide 和 inject 绑定并非可响应的。这是刻意为之的。然而,若是你传入了一个可监听的对象,那么其对象的属性仍是可响应的。 具体细节移步vue相关介绍cn.vuejs.org/v2/api/#pro…
provide/inject还未在项目中应用过,后面会作尝试
经小伙伴们提醒补充$attrs的使用
场景:祖先组件与子组件传值
包含了父做用域中不做为 prop 被识别 (且获取) 的特性绑定 (class 和 style 除外)。当一个组件没有声明任何 prop 时,这里会包含全部父做用域的绑定 (class 和 style 除外),而且能够经过 v-bind="$attrs" 传入内部组件——在建立高级别的组件时很是有用。
以上是官网对$attrs的解释,我刚看我也是一脸懵逼,回去试了一下其实并不难,并且比较适用组件深层嵌套场景下,祖先组件向子组件传值的问题
意思就是父组件传向子组件传的,子组件不prop接受的数据都会放在$attrs中,子组件直接用this.$attrs获取就能够了。如过从父->孙传,就在子组件中添加v-bind='$attrs',就把父组件传来的子组件没props接收的数据所有传到孙组件,具体看如下代码
使用:
祖先组件
// 祖先组件
// 在祖先组件中直接传入output和input
<template>
<div>
<child1 :output='output' :input="input"></child1>
</div>
</template>
<script>
import child1 from './child1.vue'
export default {
components: {
child1
},
data () {
return {
input: 'jijijijjijiji',
output: {
name: '王文健',
age: '18'
}
}
}
</script>
复制代码
子组件
<template>
<div
<h1>{{input}}</h1>
<child2 :child="child" v-bind='$attrs'></child2>
</div>
</template>
<script>
import child2 from './child2.vue'
export default {
components: {
child2
},
props: {
input: [String]
},
data () {
return {
child: 'child1child1child1child1s'
}
},
// 默认为true,若是传入的属性子组件没有prop接受,就会以字符串的形式出现为标签属性
// 设为false,在dom中就看不到这些属性,试一下就知道了
inheritAttrs: false,
created () {
// 在子组件中打印的$attrs就是父组件传入的值,刨去style,class,和子组件中已props的属性
console.log(this.$attrs) // 打印output
}
}
</script>
复制代码
孙组件
<template>
<div>
{{$attrs.output.name}}
</div>
</template>
<script>
export default {
created () {
// 打印output和child
console.log(this.$attrs)
}
}
</script>
复制代码
看起来仍是挺好用的,还没在具体项目中用过,相信不久会用到的,若是还有什么问题欢迎留言
$children/$parent
固然你能够直接用$children/$parent获取当前组件的子组件实例或父组件实例(若是有的话),也能对其作些操做,不过并不推荐这么作
你还能够放到localStorage,sessionStorage,cooikes之类的存在本地固然也能作到组件间的通讯
文章只是整理一下笔记,谈一谈遇到的问题和经验,并无严谨的措辞和详细的过程,若有错误望指正
原创文章转载引用请注明原文连接blog.wwenj.com/index.php/a…