组件通信
组件可大可小,小到把一个按钮封装成组件,大到一个页面就是一个组件。多数情况,我们的页面是由很多个组件组成,不可避免的要用到组件间的通讯。
一、 父组件向子组件传值
1. prop 属性传值
speaktoson
传到子组件里面作为变量 props :["speaktoson"]
实现原理: 父组件里面的自定义属性 <div id="app">
<!-- 静态prop -->
<my-local-com speaktoson="我是你爸爸"></my-local-com>
<!-- 动态prop -->
<my-local-com :speaktoson="fatherData"></my-local-com>
</div>
var myLocalCom = {
template: `
<div>
<p>爸爸说:{{speaktoson}}</p>
</div>
`,
props: ["speaktoson"]
};
new Vue({
el: "#app",
data: {
fatherData: "这条数据来自父组件的data"
},
components: {
//必须注册
myLocalCom
}
});
目前为止,我们已经能够在三个地方声明 vue 变量(数据)了,分别为 data,computed,props;
2. props 的数据结构
(1) 数组的写法
props: ["speaktoson"];
(2) 对象的写法
Vue.component("example", {
props: {
// 基础类型检测 (`null` 指允许任何类型)
propA: Number,
// 可能是多种类型
propB: [String, Number],
// 必传且是字符串
propC: {
type: String,
required: true
},
// 数值且有默认值
propD: {
type: Number,
default: 100
},
// 数组/对象的默认值应当由一个工厂函数返回
propE: {
type: Object,
default: function() {
return { message: "hello" };
}
},
// 自定义验证函数
propF: {
validator: function(value) {
return value > 10;
}
}
}
});
!> 注意: prop 会在组件实例创建之前进行校验,所以在 default
或 validator 函数里,诸如 data
、computed
或 methods
等实例属性还无法使用。
二、 子组件向父组件传值
实现原理: 父组件监听自定义事件,子组件通过 $emit
触发自定义事件,父组件此时在事件对象里面拿到消息。 注意:vue 里面的 $on
和 $emit
和原生 js 的 addEventListener
和 dispatchEvent
实现机制并不相同。
子组件中
var myLocalCom = {
template: `
<div>
<p @click="sonSay">点击向爸爸组件发送消息</p>
</div>
`,
data() {
return {
sonWords: "今晚吃鸡!"
};
},
methods: {
sonSay() {
this.$emit("speaktobaba", this.sonWords);
}
}
};
父组件中
<div id="app">
<my-local-com @speaktobaba="receivedSon"></my-local-com>
</div>
var app = new Vue({
el: "#app",
methods: {
receivedSon(e) {
console.log(e); //获取到了子组件的信息
}
}
});
.sync
修饰符
.sync
修饰符,它会被扩展为一个自动更新父组件属性的v-on
监听器。
<comp :foo.sync="bar"></comp>
当子组件需要更新 foo 的值时,它需要显式地触发一个更新事件:
this.$emit("update:foo", newValue);
三、 非父子通信
有时候,非父子关系的两个组件之间也需要通信。在简单的场景下,可以使用一个空的 Vue 实例作为事件总线。但其实上父子间也可以利用这种方式实现通讯。
独立的 js 代码中
注意:这时已经有了两个 vue 实例
var busHub = new Vue(); //声明一个中央集线器
组件 A:
var myLocalCom = {
template: `
<div>
<p @click="broSay">点击向兄弟传递消息</p>
</div>`,
data() {
return {
msg: "兄弟,妈妈喊我们回家吃饭"
};
},
methods: {
broSay() {
busHub.$emit("speakToBro", this.msg);
}
}
};
组件 B:
var myGlobal = Vue.component("my-global-com", {
template: "#my_template2",
created() {
//在created里面打开监听
busHub.$on("speakToBro", function(e) {
console.log(e); //获取兄弟组件传递过来的消息
});
}
});
这里的原理是利用的另一个 vue 的实例作为事件的监听
$on
和触发$emit
,为了保证能够监听到组件 A 传过来的事件,组件 B 中在created
钩子中注册了监听事件。