父子之间通信
props
子组件设置 props 来接收父组件传来的值/方法。
// mother组件
//将 name 和sayHi()传给 daughter
<my-daughter :name="name" :sayHi="sayHi"></my-daughter>
data() {
return {
name: 'cloud',
}
},
methods: {
sayHi() {
console.log('hi');
},
},
//daughter组件
<span> mother传来的name:{{ name }}</span>
<button @click="sayHi">mother传来的方法</button>
//接收mother传来的数据和方法并定义类型
props: {
name: {
type: String
},
sayHi: {
type: Function
}
},
emit
子组件通过emit传递方法的方式传递数据给父组件。
//mother组件
//接收daughter传来的方法
<my-daughter @changeAge="changeAge"></my-daughter>
<span>mother组件的年龄:{{ age }}</span>
data() {
return {
age: 18
}
},
methods: {
// 参数为daughter传来的
changeAge(age) {
this.age = age;
}
}
//daughter组件
//通过daughter自身定义的事件来触发传给mother的自定义事件
<button @click="emitAge">传给mother的修改年龄</button>
data() {
return {
age: 50,
}
},
methods: {
emitAge() {
// 传递一个自定义事件给mother组件,并携带要传递过去的参数
this.$emit('changeAge', this.age)
}
ref && refs
父组件可以通过在使用的子组件上添加ref属性,将子组件定义在$ref属性中,然后在父组件中可以通过this.$ref.给子组件定义的ref属性值 来访问子组件。
// mother
// 给daugher组件添加ref属性
<my-daughter ref="daughter"></my-daughter>
mounted() {
// 通过refs拿到daughter的数据
console.log(this.$refs.daughter.msg); // 我素女儿哦
// 通过refs拿到daughter的方法
this.$refs.daughter.sayBad(); // i think its so bad
}
// daughter
data() {
return {
msg: '我素女儿哦'
}
},
methods: {
sayBad() {
console.log('i think its so bad');
}
}
parent && children
子组件可以通过$parent来访问自己上一级的父组件,父组件使用$children获得的是子组件组成的数组。可以通过设置索引来访问不同的子组件。
注意:$children获得的数组是无序的。
PS: $root可以访问根组件。
//mother
data() {
return {
name: 'cloud',
}
},
mounted() {
//使用$chidlren拿到女儿的信息
console.log(this.$children[0].msg); //我素女儿哦
//使用$chidlren拿到女儿的方法
this.$children[0].sayGood(); // 妈妈你真棒
},
methods: {
sayMother() {
console.log('我素妈妈哦');
}
}
// daughter
data() {
return {
msg: '我素女儿哦'
}
},
mounted() {
//使用$parent拿到mother组件的数据
console.log(this.$parent.name); //cloud
//使用$parent拿到mother组件的方法
this.$parent.sayMother(); // 我素妈妈哦
},
methods: {
sayGood() {
console.log('妈妈你真棒');
}
}
祖孙间通信
需要祖孙间通信的时候,通常会先想到 vuex,但是当项目比较小用 vuex 就没有太大的必要。
依赖provide/注入inject
通常情况下,当我们需要从父组件向子组件传递数据时,会使用props。但当一个组件需要向一个很深层级的子组件传递数据的时候,如果仅使用 props 则必须将其沿着组件链逐级传递下去,这会非常麻烦,这一问题被称为“prop 逐级透传”。
provide 和 inject 可以帮助我们解决这一问题。一个父组件相对于其所有的后代组件,会作为依赖提供者。任何后代的组件树,无论层级有多深,都可以注入由父组件提供给整条链路的依赖。
provide是一个对象,用来给子/子孙传输数据、方法或者是整个组件
inject是一个数组,用来接收父/祖父传来的数据、方法或者是整个数组
这种方式,官方不推荐,因为这个方法真的是太不好管控了,比如说我在根组件 provide 了 this,孙孙重孙组件去使用了 this` 里面的一个变量,这时候很难去跟踪到这个变量的出处了,而且你也并不知道,项目中哪个组件有用到这个变量,有没有在其他组件中进行改变,所以这个api在项目中很少人使用,但是很多人拿来写组件用。
attrs && listeners
- 设置批量向下传属性
$attrs和$listeners。 - 包含了父级作用域中不作为
prop被识别 (且获取) 的特性绑定 ( class 和 style 除外)。 - 可以通过
v-bind="$attrs"传⼊内部组件。
兄弟间通信
EventBus事件总线
EventBus 又称为事件总线。在Vue中可以使用 EventBus 来作为沟通桥梁的概念,就像是所有组件共用相同的事件中心,可以向该中心注册发送事件或接收事件,所以组件都可以上下平行地通知其他组件,但也就是太方便所以若使用不慎,就会造成难以维护的“灾难”,因此才需要更完善的Vuex作为状态管理中心,将通知的概念上升到共享状态层次。
首先需要创建事件总线并将其导出,以便其它模块可以使用或者监听它。
我们可以通过两种方式来创建事件总线:
- event-bus.js
import Vue from 'vue'
const EventBus = new Vue();
export default EventBus
- main.js
//全局事件总线
new Vue({
render: h => h(App),
beforeCreate() {
Vue.prototype.$bus = this // 安装全局事件总线
}
}).$mount('#app')
使用EventBus.$emit发送消息
// friend组件
//点击触发事件
<button @click="sendMsg()">发送给daughter</button>
methods: {
sendMsg() {
// 发送消息
EventBus.$emit("friendMsg", "我是你的friend");
}
}
使用EventBus.$on监听接收消息
// daughter组件
mounted() {
//监听接收消息
EventBus.$on("friendMsg", msg => {
console.log(`daughter组件中:${msg}`); // daughter组件中:我是你的friend
})
},
注意
如果使用不善,EventBus会是一种灾难。
- vue是单页应用,如果你在某一个页面刷新了之后,与之相关的
EventBus会被移除,这样就导致业务走不下去。 - 如果业务有反复操作的页面,
EventBus在监听的时候就会触发很多次,也是一个非常大的隐患。这时候我们就需要好好处理EventBus在项目中的关系。通常在vue页面销毁时,需要同时移除EventBus事件监听。
//在监听的组件中销毁,这里是daughter
beforeDesroty() {
EventBus.$off('friendMsg');
}
PS
使用全局事件总线的话,调用this.$bus.$emit和this.$bus.$on来发送和监听消息,同时使用this.$bus.$off来移除事件监听。