组件通信
组件间的数据共享
组件的关系:父子关系和非父子关系
三种通信方式:
1.父子通信:父组件的数据要传递给子组件
2.子父通信:子组件的数据要传递给父组件
3.非父子组件通信:非父子之间的数据传递
父向子传递数据
1.在父组件中通过v-bind
传递数据
格式:<子组件 :自定义接收名称="要传递的数据"></子组件>
2.在子组件中通过props
属性来接收数据
props:['自定义接收名称']
3.在子组件中就可以通过 自定义数据名称来使用 数据了
HTML :
<div id="app">
<father></father>
</div>
<!-- 父组件的模板内容 -->
<template id="father">
<div>
<p>父组件数据为:{{msg}}</p>
<!-- message不是固定的,而是我们自定义的属性 -->
<son :message="msg"></son>
</div>
</template>
<!-- 子组件的模板内容 -->
<template id="son">
<div>
<p>子组件获取父组件的数据:{{message}}</p>
</div>
</template>
JS :
Vue.compinent("father",{
//找到id为father的template标签
template:'#father',
data(){
return{
msg:"I am is your father"
}
},
//局部自定义的方式,去定义子组件
components:{
//定义子组件
son:{
template:'#son',
//props中的元素必须与上面自定义的属性名一致,Prop是你可以在组件上注册的一些自定义attribute 属性
props:['message']
}
}
})
new Vue({
el:"#app",
})
props验证
props还可以对传入的参数进行验证,比如: 验证传入的是不是布尔值,是不是数组等
验证格式:
props:{
数据1:{
type:类型,
default:默认值
},
数据2:{
type:类型,
default:默认值
}
}
<div id="app">
<navbar :title="title"></navbar>
</div>
<template id="navbar">
<div>
<button v-if="leftbutton">返回</button>
<span>{{title}}</span>
<button>搜索</button>
</div>
</template>
Vue.component('navbar',{
template:"#navbar",
props:{
title:{
type:String,
default:"标题"
},
leftbutton:{
type:Boolean,
default:false
}
}
})
new Vue({
el:"#app",
data:{
title:"电影",
leftbutton:false
}
})
运行效果展示:返回按钮并未被创建
单向数据流
所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定:父级 prop 的更新会向下流动到子组件中,但是反过来则不行。这样会防止从子组件意外变更父级组件的状态,从而导致你的应用的数据流向难以理解。
看案例:
<div id="app">
<father></father>
</div>
<!-- 父组件的内容 -->
<template id="father">
<div>
<input type="text" v-model="msg">
<p>父组件的数据为:{{msg}}</p>
<hr>
<son :message="msg"></son>
</div>
</template>
<!-- 子组件的模板内容 -->
<template id="son">
<div>
<p>子组件获取父组件的数据:{{message}}</p>
<input type="text" v-model="msg">
<p>子组件获取父组件的数据为:{{msg}}</p>
</div>
</template>
//定义一个全局的父组件
Vue.component('father',{
//找到id为father的template标签
template:"#father",
data(){
return{
msg:"I am is your father"
}
},
components:{
//定义子组件
son:{
template:"#son",
props:['message'],
data(){
return{
//初始化msg变量,它的值为父组件传递过来的数据
msg:this.message
}
},
watch:{
message(value){
this.msg = value
}
}
}
}
})
new Vue({
el:"#app",
data:{}
})
运行效果展示:
在子组件的输入框中输入新的值,其下也会相应的更新,而父组件则不会更新,在父组件输入新的值,子组件也会进行相应的更新
【注意】不要在子组件中直接修改父组件传入的数据
子向父传递数据
本质上是让子组件调用父组件的方法,通过方法传参的方式传递数据
1.在父组件使用子组件的时候,给子组件绑定一个自定义的事件名称,值为 自己的方法
<子组件 @自定义事件名 = "事件处理函数" />
2.在子组件自定义一个方法,在方法中 通过 this.$emit("自定义事件名",params)
来触发传递过来的方法,并通过参数的方式传递数据
<div id="app">
<father></father>
</div>
<!-- 父组件的模板内容 -->
<template id="father">
<div>
<p>儿子发消息来了:{{msg}}</p>
<hr>
<son @change="getMsg"></son>
</div>
</template>
<!-- 子组件的模板内容 -->
<template id="son">
<div>
<button @click="sendMsg">给父组件发消息</button>
</div>
</template>
//定义一个全局的父组件
Vue.component('father',{
template:"#father",
data(){
return{
msg:'',
}
},
methods:{
getMsg(value){
this.msg = value
}
},
//局部组件定义的方式,去定义子组件
components:{
//定义子组件
son:{
template:"#son",
data(){
return{
msg:"没钱吃饭了"
}
},
methods:{
sendMsg(){
this.$emit('charge',this.msg)
}
}
}
}
})
new Vue({
el:"#app",
data:{}
})
点击发送消息运行效果展示:
非父子通信
非父子组件要实现通信,有两个解决方案:
1.bus 中央事件总线
2.vuex 状态管理
bus中央事件总线:使用一个空的Vue实例作为中央事件总线,通俗理解:中介
步骤:
1.创建一个空的Vue实例
let bus = new Vue();
2.在组件的mouted钩子函数中,通过bus.$on来监听一个自定义类型的事件函数,
methods(){
bus.$on("自定义事件名",(传递的数据)=>{
//...
})
}
3.在另外一个组件的方法中,通过bus.$emit来触发这个自定义类型的事件函数
bus.$emit("自定义事件名",传递的数据)
一、$emit
1、this $emit('自定义时间名',要传递的数据)
2、触发当前实例上的时间,要传递的数据会传递给监听器
二、$on
1、VM.$on("事件名",callback)---------callback回调$emit要传送的数据
2、监听当前实例上自定义时间
实例:
<div id="#app">
</div>
<!-- 租客组件模板内容 -->
<template id="tenant">
<div>
<h3>租客</h3>
<p>租客信息:{{msg}}</p>
<p>接收到的房东信息:{{renterMsg}}</p>
<!-- 点击按钮,将租客信息发送给房东 -->
<button @click="rentIn">我要租房</button>
</div>
</template>
<!-- 房东组件模板内容 -->
<template id="renter">
<div>
<h3>房东</h3>
<p>房东信息:{{msg}}</p>
<p>接收到的租客信息:{{tenantMsg}}</p>
<!-- 点击按钮,将房东信息发送给租客 -->
<button @click="rentOut">我要租房</button>
</div>
</template>
let bus = new Vue();
new Vue({
el:"#app",
data:{
},
components:{
//租客组件
tenant:{
template:"#tenant",
data(){
return{
msg:"无不良嗜好,单身",
reterMsg:""
}
},
methods:{
rentIn(){
bus.$emit("renter-event",this.msg)
}
},
//创建阶段的第4个钩子函数
mounted(){
//监听自定义事件
bus.$on("tenant-event",value => {
this.renterMsg = value;
})
}
},
//房东组件
renter: {
template: "#renter",
data() {
return {
msg: "押一付三,押金不退",
tenantMsg: ""
}
},
methods: {
rentOut() {
bus.$emit("tenant-event", this.msg)
}
},
//创建阶段的第4个钩子函数
mounted() {
//监听自定义事件
bus.$on("renter-event", value => {
this.tenantMsg = value;
})
}
}
}
})
运行效果展示:
点击我要租房按钮,房东将会接收到租客的信息,点击我要招租,租客将会接收到房东的信息