vue组件通讯/传值
个人浅见:通讯的意思就是互相联系,我说的你能听到,并且有必要的话能做出回应,组件本身是个具有独立功能的整体,以下便是组件与组件之间的关系和通讯的方式。
一、通讯方式
目前按我了解到的共有以下几种
props
/$emit
$parent
/$children
/$refs
v-bind="$attrs"
&v-on="$listener"
(2.4+支持)1vuex
Vue.$bus
(中央事件总线)provide
/inject
(依赖如属性和方法 祖和后代)2Vue.observable
(创建一个store.js 进行监听,2.6+支持)3
二、组件间关系
-
兄弟组件(毫不相干)
-
父子组件(父子沟通的方式有很多)
-
跨层级组件(隔代的祖孙传值)
首先明确一点,就通讯方式而言,支持兄弟组件的必然支持跨层级组件,而支持跨层级组件的必然支持父子组件,故我们只说适合的。
三、应用场景及实例
父子组件
props
/$emit
(父子,emit可update:[propName]
)
prop接的不可修改,若要修改需要调用emit;
父组件
<template>
<div>
<child :lunch='foods' @changeFoods='changeFoods'></child>
</div>
</template>
<script>
import child from './child.vue';
export default {
data(){
return {
foods:'鱼香肉丝'
}
},
methods:{
changeFoods(newfoods){
// 得到孩子的反馈,把饭做出来,把午餐换掉
this.cook(newfoods);
},
cook(foods){
this.foods = foods;
}
}
}
</script>
子组件 child
<template>
<div>
<div>爸爸做的午饭:{{lunch}}</div>
<div @click='changeLunch'>{{lunch}}不好吃,换成红烧肉</div>
</div>
</template>
<script>
export default {
props:{
lunch: String
},
methods:{
changeLunch(){
// changeFoods 在使用当前组件时需要定义此接参方法。
this.$emit("changeFoods", '红烧肉');
// 正经话:如果当前的prop在改变值的时候不需要父组件执行任何其他操作,可以直接选用update更新,外面也不需要定义接事件也就是changeFoods
// this.$emit("update:lunch", '红烧肉');
}
}
}
</script>
$parent
/$refs
- 可在父组件通过
this.$refs[refName]
获取到子组件的值、方法,可直接调用。 - 可在子组件直接调用
this.$parent
获取到父组件实例。
v-bind="$attrs"
&v-on="$listener"
$attrs
包含了除prop定义之外的当前组件(父)的属性。
$listener
包含了当前组件的事件,传到子组件中。
一般可在UI库的二次封装或者定制时使用,减少代码
如封装element-ui的
<template>
<div>
<el-pagination
:background="background"
:current-page.sync="currentPage"
:page-size.sync="pageSize"
:layout="layout"
:page-sizes="pageSizes"
:total="total"
v-bind="$attrs"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
</div>
</template>
跨层级组件
props
、v-bind="$attrs"
层层传递 层级多了就不建议使用了,啰嗦。- provide & inject 优雅的方式4
祖先组件
data() {
return {
name2: "小明",
age2: 5
};
},
// 添加依赖数据,它里面定义的数据,子组件可以选择性注入并直接使用。
provide() {
return {
doveName: this.name2,
doveAge: this.age2,
// 将修改name2和age2的方法,设置为依赖数据
updateDove: this.updateDove,
};
},
methods: {
updateDove(dove) {
this.name2 = dove.name;
this.age2 = dove.age;
},
}
后代组件
// 从父级组件中注入依赖的数据
inject: ["doveName", "doveAge", "updateDove"],
methods: {
updateData() {
this.mydoveName = "小红";
this.mydoveAge = 8;
// 执行父级组件中的updateDove方法
this.updateDove({ name: this.mydoveName,age: this.mydoveAge, });
}
}
兄弟组件
- vuex4
- Vue.observable();3
- Vue.$bus中央事件总线4
- Vue.observable();3
定义一个store.js
import Vue from 'vue';
const defaultState = () => {
return Vue.observable({
name: '路飞'
});
};
const store = {
state: defaultState(),
getters: {
isData: (key) => store.state[key] && Object.keys(store.state[key]).length > 0
},
mutations: {
setName (data) {
store.state.name = data;
}
}
};
export default store;
使用
import store from '../store';
export default {
computed(){
name(){
// 获取
store.state.name;
}
},
methods:{
changeName(name){
// 修改,响应式的。
store.mutations.setName(name);
}
}
};
标注的在文章都有提到,就不再赘述了,都看到这里了,顺手点个赞呗~