目录
整理vue
中9种常规的通信方案
- 通过 props 传递
- 通过 $emit 触发自定义事件
- 子组件调用父组件函数传参方式
- 使用 ref
- $EventBus
- 消息订阅与发布
- $parent 或$root
- attrs 与 listeners
- Provide 与 Inject
- Vuex
props传递数据-父传子(推荐)
- 适用场景:父组件传递数据给子组件
- 子组件设置
props
属性,定义接收父组件传递过来的参数 - 父组件在使用子组件标签中通过字面量来传递值
- 注意:传递参数可以是字符串、数字、对象、数组等类型的变量,也可以是函数
-
使用v-model时要切记:v-model绑定的值不能是props传过来的值(绑定基本数据类型修改会报错),因为props是不可以修改的!(如需修改请复制一份)
-
props传过来的若是对象类型的值,修改对象中的属性时Vue不会报错,但不推荐这样做。
Father.vue
组件
<Children :name="jack" :age=18 />
Children.vue
简单接收写法(常用)
props:["name","age"]
数据类型限制写法
props:{
name:String, // 接收的类型为字符串
age:Number, // 接收的类型为数值
}
数据类型限制+默认值指定+必要性限制
props:{
age:{
type:Number, // 接收的类型为数值
defaule:18, // 默认值为18
require:true // age属性必须传递
}
}
子组件使用传参(传参数据已存储在props中,直接使用即可,props中参数在不需要修改的前提下,无需在data中再次声明)
<h1>{{name}}</h1>
<h1>{{age}}</h1>
备注:props是只读的,Vue底层会监测你对props的修改,如果进行了修改,就会发出警告,若业务需求确实需要修改,那么请复制props的内容到data中一份,然后去修改data中的数据。
复制举例: <h1>{{MyName}}</h1> <h1>{{MyAge}}</h1> props:["name","age"], data() { return { MyName:this.name, MyAge:this.age, } },
$emit 触发自定义事件-子传父(推荐)
- 适用场景:子组件传递数据给父组件
- 子组件通过
$emit触发
自定义事件,$emit
第二个参数为传递的数值 - 父组件绑定监听器获取到子组件传递过来的参数
Chilfen.vue
this.$emit('add', good)
Father.vue
<Children @add="cartAdd($event)" />
子组件调用父组件函数传参方式-子传父
适用场景:子组件传递数据给父组件
流程原理:将父组件中的函数通过props传递给子组件,让子组件调用并传参,父组件函数被调用,并接收到参数。
Father.vue
<Children :receive="receive" />
methods:{
receive(x){
console.log("我是父组件,收到参数:",x);
}
}
Chilfen.vue
props:["receive"],
methods:{
add(){
console("调用父组件内的函数");
this.receive("参数1...");
}
}
ref-子传父(推荐)
ref 写在标签上时:this.$refs.名字 获取的是标签对应的dom元素---vue获取dom元素方法
ref 写在组件上时:这时候获取到的是 子组件(传参)的引用
标签上使用
<div ref="hello">ref绑定标签</div>
console.log(this.$refs.hello); // <div data-v-9ea40744>ref绑定标签</div>
组件中使用
注意:$refs赋值子组件变量后,子组件mounted()钩子函数内取不到ref赋予的值,mounted()内只能拿到自己组件内部data初始化的默认值,所以想在页面挂载前后做操作的话,可以直接在父组件内调用子组件方法或传参即可,没必要执着于使用子组件的mounted()钩子函数。
- 父组件在使用子组件的时候设置
ref
- 父组件通过设置子组件
ref
来获取数据(父拿子值)响应式的值(动态更新) - 不只可以获取数据,还可以使用子组件中的方法
- 不仅可以获取数据,还可以通过this.$refs.设置子组件值(可读写)
父组件
<Children ref="hello" /> //hello代表子组件实例(对象形式)
this.$refs.hello.num // 获取子组件实例,通过子组件实例我们就能拿到对应的数据
this.$refs.hello.addNum(num) // 通过子组件实例我们也可以使用子组件的方法
this.$refs.hello.num = 父组件内数据 // 获取子组件实例,通过子组件实例我们也可以设置子组件数据
子组件
data() {
return {
num:"ref传参"
};
},
methods: {
addNum(numBer){
this.numBer++;
console.log("同样可调用子组件事件");
},
},
$EventBus全局事件总线-任意组件传参(推荐)
- 使用场景:任意组件传值
- 创建一个中央事件总线
EventBus
- 传参组件通过
$emit
触发自定义事件,$emit
第二个参数为传递的数值 - 收参组件通过
$on
监听自定义事件 - 在使用$on的收参组件中使用$off移除自定义事件监听器
第一步:在main文件中添加如下代码
new Vue({
router,
store,
render: h => h(App),
beforeCreate(){
Vue.prototype.$bus = this // 安装全局事件总线
}
}).$mount('#app')
第二步:需要发起传参的组件使用this.$bus.$emit
注意:使用全局事件总线时,事件名称不可重复,需与其他开发人员协商一致
// 发起全局事件总线传参
sendStudentName(){
this.$bus.$emit('hello',this.name)
},
第三步:接收事件总线传参
在mounted函数中开启事件监听
方式一
mounted(){
this.$bus.$on('hello',(data)=>{
console.log('收参组件接收到了数据',data);
})
},
方式二
mounted(){
this.$bus.$on('hello',this.busValue)
},
methods: {
busValue(data){
console.log('收参组件接收到了数据',data);
}
},
第四步:在使用$on的组件中解绑对应的监听事件
beforeDestroy() {
this.$bus.$off('hello');
},
$off使用演示
unbind(){
this.$off("add"); // 解绑单个事件
this.$off(["add","addTwo"]); // 解绑多个事件
this.$off(); // 解绑所有事件
}
EventBus(方式二)
消息订阅与发布
注意:消息订阅发布与全局事件总线传参类似,更推荐使用全局事件总线传参;
第一步:安装pubsub插件(其他同类型插件也可)
npm i pubsub-js
第二步:分别在需要发布和订阅消息的组件中引入使用pubsub插件
import pubsub from 'pubsub-js'
第三步: 在订阅消息的组件中mounted内使用pubsub插件,并在销毁前移除订阅
methods:{
pubIdFun(msgName,data){
console.log('有人发布了hello消息,hello消息的回调执行了','发布事件名:',msgName,'参数:',data);
}
},
mounted(){
注意:pubsub.subscribe中回调函数this是undefined,所以回调函数需使用箭头函数或methods中的函数
清除订阅发布时用到的id变量 = pubsub.subscribe('订阅发布的事件名','订阅发布的回调函数');
this.pubId = pubsub.subscribe('hello',this.pubIdFun);
},
beforeDestroy() {
pubsub.unsubscribe(this.pubId);
},
第三步: 在发布消息的组件中使用pubsub插件发布消息
methods:{
sendStudentName(){
pubsub.publish('订阅发布的事件名',参数);
pubsub.publish('hello',this.dataObj);
}
},
$parent 或$ root
- 通过共同祖辈
$parent
或者$root
搭建通信桥连
兄弟组件
this.$parent.on('add',this.add)
另一个兄弟组件
this.$parent.emit('add')
$attrs 与$ listeners
- 适用场景:祖先传递数据给子孙
- 设置批量向下传属性
$attrs
和$listeners
- 包含了父级作用域中不作为
prop
被识别 (且获取) 的特性绑定 ( class 和 style 除外)。 - 可以通过
v-bind="$attrs"
传⼊内部组件
// child:并未在props中声明foo
<p>{{$attrs.foo}}</p>
// parent
<HelloWorld foo="foo"/>
// 给Grandson隔代传值,communication/index.vue
<Child2 msg="lalala" @some-event="onSomeEvent"></Child2>
// Child2做展开
<Grandson v-bind="$attrs" v-on="$listeners"></Grandson>
// Grandson使⽤
<div @click="$emit('some-event', 'msg from grandson')">
{{msg}}
</div>
provide 与 inject
- 在祖先组件定义
provide
属性,返回传递的值 - 在后代组件通过
inject
接收组件传递过来的值
祖先组件
provide(){
return {
foo:'foo'
}
}
后代组件
inject:['foo'] // 获取到祖先组件传递过来的值
vuex
-
适用场景: 复杂关系的组件数据传递
-
Vuex
作用相当于一个用来存储共享变量的容器 -
state
用来存放共享变量的地方 -
getter
,可以增加一个getter
派生状态,(相当于store
中的计算属性),用来获得共享变量的值 -
mutations
用来存放修改state
的方法。 -
actions
也是用来存放修改state的方法,不过action
是在mutations
的基础上进行。常用来做一些异步操作
路由传参
参考文章:http://t.csdnimg.cn/E5YG2
小结
- 父子关系的组件数据传递选择
props
与$emit
进行传递,也可选择ref
- 兄弟关系的组件(或任意组件)数据传递可选择
$bus
,其次可以选择$parent
进行传递 - 祖先与后代组件数据传递可选择
attrs
与listeners
或者Provide
与Inject
- 复杂关系的组件数据传递可以通过
vuex
存放共享的变量