目录
父向子传值
子向父传值
兄弟传值
后代传值
非兄弟传值
在解决组件通讯方面,比较好用的就是vuex,但是在小型的项目中使用vuex就会有点大材小用的感觉,而且会增加文件体积。以下的都是不用vuex的传值解决方法,本文着重点是 后代的传值 和 非兄弟的传值,一些基本的操作就粗略带过。。。
好的,进入正题
现在假设 App.vue 下有两个子组件
brother.vue 和 sister.vue
brother.vue 中有 brotherChild.vue
父子传值一般在子组件上绑定自定义的属性,然后子组件在实例中通过props接收该属性
app.vue:
brother.vue:
export default {
name:'brother',
props:['name'],
data () {
return {
};
}
}
这种情况一般使用emit反向传值,通过注册自定义事件,在事件函数中接收值
brother.vue:
click
export default {
name:'brother',
data () {
return {
};
},
aaa(){
//注册自定义事件,并传递参数
this.$emit('custom-event','你好,我是子组件传过来的值')
}
}
app.vue:
//在对应的子组件上,绑定自定义事件
export default {
name:'app',
data () {
return {
};
},
bbb(params){
//自定义事件的回调函数中 会接受一个参数 来自于注册事件时传递的参数
console.log(params) //输出结果:你好,我是子组件传过来的值
}
}
解决的方案基于上面的两种方法来实现的,操作的步骤:
1.brother.vue 自定义事件 传值
2.app.vue 绑定自定义事件 回调函数接收值
3.再将该值通过属性绑定传递到sister.vue中
总结一下:子传给父,父再传给子
这种方法的话有个不太美观的问题就是,需要在app.vue中创建一个变量来存放第二步接收到的值
咳咳,敲黑板,重点来了。这里要介绍的是 provide(提供) 和 inject (注入)两个属性,说实话这两个属性有点vuex的味道,在一些特殊情况下是非常滴好用的。这两个属性我只做大概的介绍,详细的大家可以百度,里面讲的很详细。
provide:相当于分享自己实例中的一些东西出去
inject :用来接受provide分享出去的东西
假设一个场景:
brotherChild.vue 想要拿到 app.vue 的一些属性,用之前的方法的话,
需要绑定属性到brother.vue上,
brother.vue 接收属性再绑定到 brotherChild.vue上,
这时候brotherChild.vue又要通过props拿到。
可能层级比较少的时候不会觉得很麻烦,但如果是很多级的后代,需要重复的绑定接收,这简直就是折磨。。
此时 provide 和 inject 就起到的关键的作用,有了这个东西简直就像看到天使
app.vue:
export default {
name:'app',
provide(){
return {
//将当前的app.vue的实例分享出去
'app':this
}
},
data () {
return {
};
},
}
app.vue 的N个后代组件:
export default {
name:'appChild',
inject:['app'],
data () {
return {
};
},
methods:{
fn(){
// 获取到app.vue的整个实例 想要什么拿就完事了
// 比如app上有个属性name, this.app.name 就能拿到
console.log(this.app)
}
}
}
看完是不是超简单,这个属性好用的地方就在于,父组件 provide 出去的东西,只要下面的后代组件 inject 一下就能拿到,无视距离(哭了,来自于爸爸无私的爱)
又假设一个场景:
brotherChild.vue 想拿 sister.vue 的一些属性(provide 和 inject 只能解决父组件和后代组件的问题,在这里已经无效了)
额。。想了想,这貌似有点棘手
不慌,办法总是有的,
这种情况我们可以使用 vue 实例中的 emit(触发自定义事件)和 on(监听自定义事件)
首先我们需要一个中间人(app.vue),app.vue 将自己的实例 provide 出去
sister.vue:
export default {
name:'sister',
inject:['app'],
data () {
return {
val:'我是sister的值'
};
},
methods:{
emit(){
//注册自定义事件
this.app.$emit('custom-event',this.val)
}
}
}
brotherChild.vue:
export default {
name:'brotherChild',
inject:['app'],
data () {
return {
};
},
//在实例创建后监听自定义事件
created(){
this.app.$on('custom-event',function(msg){
console.log(msg)//输出结果 我是来自sister的值
})
}
}
想了想,这个方法也可以适用于上面的所有场景,用app.vue作为中间人,子组件在父组件上注册自定义事件,又通过父组件来监听事件拿到值。
如果不想用app.vue作为中间人的话,也可以在,main.js中新建一个vue实例,export出去
export const eventBus = new Vue()
import {eventBus} from 'main.js'
export default {
name:'sister',
data () {
return {
val:'我是sister的值'
};
},
methods:{
emit(){
//注册自定义事件
eventBus.$emit('custom-event',this.val)
}
}
}
import {eventBus} from 'main.js'
export default {
name:'brotherChild',
data () {
return {
};
},
//在实例创建后监听自定义事件
created(){
eventBus.$on('custom-event',function(msg){
console.log(msg)//输出结果 我是来自sister的值
})
}
}
但是这种方法用多了也会出现一个问题,就是数据的流向不明确,比如谁定义了这个事件,谁又监听了这个事件,都没有一个明确的标识,维护起来也比较困难。其实也能够通过对事件命名来缓解这个问题,不过始终还是不优雅。
emmmmm...貌似还是vuex好用点,哈哈哈哈。
这些方法也见仁见智吧,具体情况具体分析,选用合适的方法才是最佳方案!