本文已参与「新人创作礼」活动,一起开启掘金创作之路。
组件通信主要有以下几种方式: props
,$emit和$on
,vuex
,$attrs和$listeners
,provide和inject
,$parent,$children与 ref
,evenbus
以及 $root
按使用场景可以划分为以下三类:
1. 父子组件通信
props
$emit和$on
$parent和$children
ref
$attrs和$listeners
2. 兄弟组件通信
$parent
$root
eventBus
vuex
3. 跨层级通信
eventBus
provide和inject
vuex
- 父组件向子组件传值:使用prop向子组件传值;
- 子组件实时监听父组件传来的值的变化:使用watch去监听父组件传来的值;
- 父组件可以通过this.$refs.name.去访问子组件的值或方法;
- 子组件可以通过this.$parent.去访问父组件的值或方法;
父组件向子组件传值
这是父子间组件通信的常见方式,一般用于父组件向子组件传递数据,并且是响应式的。一般情况下子组件不会去直接改变从父组件同过 prop
传过来的数据,如果想改变的话,一般会在子组件 data
中定义一个变量来进行接收:
1. 引入子组件
import child '@/components/child'
2. components 中加入子组件
components:{child},
3. 定义数据
dataList:[{id:'1',name:'2'}]
1. 使用props 定义数据类型
props:{
dataList:{
type:Array,
require:true,
}
},
2. watch中进行监听
watch(){
dataList(data){
... // 根据实际业务需求
}
},
子组件向父组件传值 ($emit()可以传多个值)
$emit和$on这 种通信方式主要是解决子组件向父组件传递数据的问题。不适合数据隔代传递(跨组件)。
1. 定义一个事件触发执行 (子组件中)
<button @click="a"></button>
2. 执行方法
this.$emit("show","我是子组件的数据")
3. 父组件接收数据 (直接写在created 中,但这样只是初始化才会加载,跟设计不符合 如下)
this.$on("show",data=>{
console.log(data);
})
<template>
<div style="height:100%">
<transition name="ams-drawer-transform" >
<report-collect-main @show="show" v-show="currentView=='main'" />
</transition>
<report-collect-add @show="show" v-show="currentView=='add'"/> <!-- 手工录入 -->
<report-collect-setvolume @show="show" v-show="currentView=='setvolume'" /> <!-- 组卷 -->
<report-collect-handover @show="show" v-show="currentView=='handover'" /> <!-- 交接 -->
<report-collect-transferlist @show="show" v-show="currentView=='transferlist'" /> <!-- 交接清单 -->
</div>
</template>
这样写法在主页页面加载时候就会初始化所有,这种方式不适合,只能抛弃了
第二种方式
1. this.$emit("show","我是子组件的数据") //子组件
然后在父组件中声明一个show方法
2. 在父组件methods 创建一个方法用来接收子组件传过的数据
methods: {
show(val){
console.log("我是子组件数据");
},
}
子组件向父子件传,父组件向子组件传
1. 父组件中引入所有子组件
2. 引入之后加入 components
3. 子组件使用 this.$emit()进行传值
4. 父组件中接收数据
<proof-collect-handover @show="show" v-show="currentView=='handover'" /> //父组件中引入的子组件 show为定义的方法
5. methods 中创建show 方法
methods: {
show(val){
console.log("我是子组件数据");
},
}
6. 动态定义一个方法 加入 :handoverList="handoverList"
<proof-collect-handover @show="show" v-show="currentView=='handover'" />
<proof-collect-handover @show="show" :handoverList="handoverList" v-show="currentView=='handover'" />
7. 去子组件中声明接收该集合
props:{
handoverList:{
type:Array, //声明为是Array类型的
require:true, // 必须传
}
},
8. 监听数据变化
watch: {
handoverList(val){
this.tableData = val;
}
}
$parent(获取当前组件的父组件实例)和$children(获取当前组件的子组件实例)
- 适用情况父子之间
1. $parent -父组件把方法传入子组件中, 子组件里直接调用这个方法
this.$parent.data //可以是方法,可以是数据
2. $child - 当前实例的直接子组件。需要注意 `$children` 并不保证顺序,也不是响应式的.
$children为当前组件的直接子组件,是一个无序的数组
this.$children[0].data = "pass children set value";
ref
1. 定义ref
<div> <!-- 定义ref -->
<p ref="refs">ref测试</p>
<button @click="show">使用ref</button> </div>
2. 引入子组件
import ....
3. 操作
this.$refs.refs.data
4.注意
eg:子组件里el-table不是唯一组件,this.$refs.refs.$children[0]找到table组件
bus
1. bus.js文件内容
import Vue from 'vue'
// export default new Vue()
const Bus = new Vue()
export default Bus
2. 局部引用一般是兄弟之间,如果操作频繁不推荐,可以直接使用vuex
import vueEvent from '@/api/.../.../vueEvent.js'
3. 全局引用 在main.js里面直接引用
import Bus from '../src/bus' //这是我的路径,正确引用你们的路径
Vue.prototype.$bus = Bus
4.赋值(局部)
vueEvent.$emit('data',this.parentData);
5.取值(局部)
mounted(){ // 钩子函数
let that = this; // 先关闭,然后再接收
vueEvent.$off("data")
vueEvent.$on('data',function(array){
console.log(array)
});
},
6. 赋值(局部)
this.$bus.$emit("busEvent", this.message);
7. 取值(局部)
//用局部引用的时候 this.$bus改成Bus,跟上面引用的名字一样
this.$bus.$on("data", (data) => {
console.log(data)
});
},
vuex
1. store 文件夹下,根据不同模块进行区分 eg:./user/user.js
const user = {
state: {
token: getToken(),
name: '',
},
mutations: {
SET_TOKEN: (state, token) => {
state.token = token
},
SET_NAME: (state, name) => {
state.name = name
},
},
赋值 $this.commit('SET_TOKEN', res.data.token)
2. 取值
3.1 $this.$store.state.name
使用`mapState`辅助函数简写代码
3.2 computed: {
...mapState({
name: state => state.user.name,
}),
}