父组件==>子组件 通信
父组件使用子组件时,利用v-bind:
标签属性进行传递数据,其中属性名为子组件在props中接收时的声明,属性值为父组件中定义的属性或者方法。
<!-- 父组件 -->
<MyHeader :addTodo="addTodo"/>
子组件中利用props进行接收父组件传递过来的数据,使用时直接读取或者调用。
//子组件
export default {
name:'MyHeader',
props:[
"addTodo"
]
};
数据保存在哪个组件
考虑数据存放位置:一个组件在用,放在自身;多个在用,放在共同的父组件(状态提升)
子组件==>父组件 通信
牢记:数据在哪里,操作数据的方法就在哪里
基础方法
原理:子组件需要操作父组件中的数据,不能直接修改props接收来的数据,通过父组件给子组件传递函数类型的props实现子组件向父组件传递数据。
<!-- 父组件 -->
<List :delTodo="delTodo"/>
//父组件
methods: {
delTodo(id){
this.todos = this.todos.filter(todo=>{
return todo.id!==id
})
}
}
//子组件
props:['delTodo'],
//调用父组件传过来的方法将参数传递,操作父组件中的数据
del(){this.delTodo(this.todo.id);}
缺点:当孙组件需要跟爷组件通信时,需要爷组件先将方法传递给父组件,再通过父组件将方法传递给子组件,操作繁琐,造成资源浪费。
组件自定义事件
父组件:
给子组件实例绑定自定义事件,两种写法
一种直接给自组件标签绑定,另一种通过给子组件实例ref属性,在mounted中获取组件实例,调用$on()绑定(更灵活)
//第一种,属性值addTodo为回调函数,存在父组件
<Header @addTodo="addTodo"/>
//或者第二种
<Header ref="header"/>
mounted(){
this.$refs.header.$on('addTodo', this.addTodo)
}
想让自定义事件只出现一次,可以使用once修饰符或者$once方法
子组件:
//触发组件实例上的自定义事件,todo为要传递的数据
this.$emit('addTodo', todo)
任意组件通信
可以弥补基础方法中孙组件需要跟爷组件通信时的缺点
利用全局事件总线实现
安装全局事件总线
main.js
里创建Vue实例时,在beforeCreate()
钩子中配置$bus
,$bus
就是当前应用的vm
new Vue({
el:'#app',
render:h => h(App),
beforeCreate(){
Vue.prototype.$bus = this //安装全局事件总线
}
})
使用事件总线
接收数据的组件中给this.$bus
绑定事件,提供数据的组件中调用this.$bus.$emit
//接收数据组件,回调可以配置到methods中,使用this.事件名调用
this.$bus.$on('事件名',()=>{})
//提供数据组件
this.$bus.$emit('事件名',参数)
注意:在组件销毁之前将当前组件上给$bus
绑定的事件解绑
beforeDestroy(){
this.$bus.$off('事件名') //注意一定要写事件名
}
利用第三方库实现
pubsub-js
详见消息订阅与发布(实现任意组件间通信)
组件通信总结
父组件==>子组件:使用props
子组件==>父组件:使用自定义事件
兄弟组件间(或者辈分较多,需要逐层传递方法的):使用全局事件总线