Vue组件间通信
参考:
Vue组件间通信的6种方式
几种场景预览
- 父子 组件 之间的数据传递
- 兄弟 组件 之间的数据传递
- 祖先 组件 与 子组件之间的数据传递
- props / $emit
- $parent / $children and ref
- $emit / $on
- vuex
- $attrs / $listeners
- provide / inject
几种组件通信方法更好的地选用
- 当项目比较大的时候,使用vuex
- 节制的使用$parent 和 $children,他们的目的是作为访问组件的应急方法,更加推荐使用props和events实现父子组件通信
- 如果只是传递数据,使用 a t t r s / attrs/ attrs/listeners好点
- 如果不仅传递数据,还做中间处理,用vuex好点
方法一:props/$emit
- 父组件A 向 子组件B 传递数据 通过props方法
- 子组件B 向 父组件A 发送数据 通过emit
父 —> 子
sonList: [‘white’,‘red’,‘blue’,‘green’]
父组件
<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: ['white','red','blue','green']
}
}
}
</script>
子组件 son.vue
<template>
<div>
<span v-for="(item, index) in sons" :key="index">{{item}}</span>
</div>
</template>
<script>
export default {
props: ['sons']
}
</script>
注意:
- 子组件中从上一级组件传递到下一级组件,也就是父子组件,这就是单向数据流
- props是只读,不可以被修改,所有的修改都会失效和被警告
子组件向父组件传递数据
父组件father.vue
<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>
子组件son.vue
<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>
为何使用vuex
不使用vuex的话
- 父子组件依赖同一个state
- 兄弟组件依赖同一个state
用了vuex
Vuex各个模块
state
state中存放页面共享的状态字段
getters
相当于当前模块state的计算属性
mutations
如果想更新state中的字段,提交mutations中定义的事件的唯一的方式(key为事件名,value是一个函数),但是change事件函数必须是同步执行的
actions
可以定义异步函数,并在回调函数中提交mutation,就相当于异步更新了state中的字段
modules
类似于命名空间(namespace),用于项目中各个模块的状态分开定义和操作,便于维护
$attrs / $listeners
用在父组件传递数据给子组件或者孙组件
如果仅仅是传递数据,就用$attrs / $listeners好点
如何不仅传递数据,还做中间处理,就用vuex好点
$attrs:
- $attrs继承所有的父组件属性(除了props传递的属性,class和style)
- 当一个组件没有声明任何prop时,这里会包含所有父作用域
$listeners
- 一个对象,包含了父作用域中的v-on事件监听器,可以配合v-on="$listeners"将所有的事件监听指向特定的子元素
provide / inject API
祖先组件中通过provider来提供变量,然后在孙组件中通过inject来注入变量
provide / inject API 主要解决了跨域组件的通讯问题,不过他的使用场景主要是子组件或去商机组件的状态,跨级组件间建立了一种主动提供与依赖注入的关系
- 父组件
<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, attrs/listeners, provide/inject API
vuex作为兄弟之间和跨级之间的通讯
$attrs用父组件传递数据给子组件或者孙组件
(包含了父作用域中不作为prop被识别的特性绑定(class和style除外))
listeners用父组件传递数据给子组件或孙组件
包含了父作用域中的(不含.native修饰器)v-on事件监听器
祖先组件通过provider提供变量给子孙组件
子孙组件通过inject注入变量给祖先组件
- 父组件向子组件传递数据,使用props属性;子组件向父组件中传递数据,在子组件中使用$emit派发事件,父组件中使用v-on监听事件;
- 缺点:组件嵌套层次多的话,传递数据比较麻烦。
- 祖先组件通过依赖注入(inject / provide)的方式,向其所有子孙后代传递数据;
- 缺点:无法监听数据修改的来源,不支持响应式。
- 通过属性$root / $parent / $children / ref, 访问根组件,父级组件,子组件中的数据
- 缺点:不支持响应式,vue2已经放弃
- 通过 VueJs 的状态管理模式 Vuex,实现多个组件进行数据共享,推荐使用这种方式进行项目中各组件间的数据传递。
当然,除了数据以外我们还可以在组件之间传递方法
方法
- 父组件调用子组件:ref
- 子组件调用父组件:emit
数据
- 父传子:props
- 子传父:emit