本节内容
vue中的消息订阅与发布组件 pubsub
– 回顾下父子两个组件之间的交互方式
- 方式1 数据直接传递
– 父组件定义data方法中定义数据 将数据名称绑定到标签中
– 子组件通过props接收 然后通过for循环遍历数据或直接取值操作
方式1 代码思路
父组件
// 标签中绑定属性
<Menu222 :menus="menus" :webSide="webSide" />
// 定义数据
data(){
return {
webSide:{// logo图片连接
url:'http://www/sun.com/',
title:'Java官方网站'
},
menus:[
{id:1,name:'科技2'},
{id:2,name:'体育2'},
{id:3,name:'财经2'},
{id:4,name:'医疗2'},
{id:5,name:'政治2'},
{id:6,name:'教育2'}
]
}
}
子组件
// 直接取值或通过遍历取值
<a :href="webSide.url" :title="webSide.title" target="_blank">
<img src="../assets/logo.jpg" alt="SUN JAVA" >
</a>
<ul>
<!-- 这里必须要加上key 以免后期出现数据混乱 -->
<li v-for="(menu,index) in menus" :key="menu.id">
<a :href="'http://localhost/ment/'+menu.id">{{menu.name}}</a>
</li>
</ul>
// 接收父组件的属性
props:['menus','webSide']
- 方式2 调用父组件中的方法
– 首先父组件中定义方法并绑定到标签中
– 然后子组件通过props接收
– 子组件接收到父组件的方法后 在methods中通过this.父组件中的方法名来调用父组件中的方法
方式2 代码思路
// 父组件
// 绑定方法到标签中 addMenus
<Menu222 :menus="menus" :webSide="webSide" :addMenus="addMenus"/>
// 定义方法
methods:{
addMenus(menu){// 接收子组件调用时传递过来的值
this.menus.push(menu);// 在menus数组的最后位置添加元素
}
}
// 子组件
// 页面传值操作
// input中双向绑定数据content
<input type="text" v-model="content" key="Math.random()"><br>
<button @click="add">添加</button>
// 接收父组件传递的属性
props:['menus','webSide','addMenus'],
data(){ // 接收当前页面输入的值
return {
content:''
}
},
methods:{
add(){
const content = this.content.trim();
if(!content){
alert("菜单名称不能为空");
return;
}
let menuu = {id:Math.random(),name:content};
this.addMenus(menuu);
}
}
方式3 自定义事件
– 3.1 父组件通过注册事件方式将方法传递到子组件
– 3.1 子组件无法使用props接收了 因为父组件是注册事件 不是绑定属性
– 3.1 子组件可以使用this.$emit来调用
3.1 代码思路
父组件
// 注册@addMenus事件
<Menu222 :menus="menus" :webSide="webSide" @addMenus="addMenus"/>
// 创建接收子组件的值并添加到当前组件的数据集合中的方法
methods:{
addMenus(menu){
this.menus.push(menu);// 在menus数组的最后位置添加元素
}
}
--------------------------------------------------
子组件
<input type="text" v-model="content" key="Math.random()"><br>
<button @click="add">添加</button>
// 子组件方法中接收页面的值并拼装成对象然后通过this.父组件中注册的方法名传递参数给父组件
methods:{
add(){
const content = this.content.trim();
if(!content){
alert("菜单名称不能为空");
return;
}
let menuu = {id:Math.random(),name:content};
this.$emit('addMenus2',menuu); // 参数1 调用的是父组件中@addMenus2 参数2是需要传递值到父组件的属性
}
}
– 3.2 父组件中 使用mounted函数注册事件
– 3.2 mounted函数是vue生命周期中的页面加载完毕执行的函数,且只会执行一次
– 3.2 父组件中通过mounted函数注册时需要先获取所有引用标签
– 3.2 父组件中标签使用ref添加引用
– 3.2 父组件中mounted勾子函数中通过this.
r
e
f
s
获取引用标签
−
−
3.2
子组件还是通过
t
h
i
s
.
refs获取引用标签 -- 3.2 子组件还是通过this.
refs获取引用标签−−3.2子组件还是通过this.emit调用父组件中的事件
3.2 代码思路
父组件
// ref指定引用
<Menu222 :menus="menus" :webSide="webSide" ref="mm2"/>
//当页面加载完毕后获取指定的引用标签并注册事件
mounted () {
// 生命周期中页面初始化后执行的勾子函数,且只执行一次
// $refs可以获取到左右带有引用的标签 前提是标签中添加了ref
// 获取到mm2的标签引用 添加注册事件 即 $on
// $on 参数1 注册事件的名字,参数2是具体要注册的事件
this.$refs.mm2.$on('addMenus2',this.addMenus);// 这句话的意思是给标签引用为mm2的标签注册addMenus2的addMenus事件 相当于@addMenu321='addMenus'
}
// 子组件
// 页面传值 双向绑定到content属性
<input type="text" v-model="content" key="Math.random()"><br>
<button @click="add">添加</button>
props:['menus','webSide'], // 无法接收 'addMenus'
data(){ // 接收当前页面输入的值
return {
content:''
}
},
methods:{
add(){
const content = this.content.trim();
if(!content){
alert("名称不能为空");
return;
}
let menuu = {id:Math.random(),name:content};
this.$emit('addMenus2',menuu); // 参数1 调用的是父组件中@addMenus2 参数2是需要传递值到父组件的属性
}
}
– 前边三节主要是父 子两个组件之间的交互,在日常开发中多级之间传递数据,方法是比较多的 本节主要探索多级之间的交互
开始今天的正文 消息订阅与发布组件
工欲善其事必先利其器 订阅与发布组件是在pubsub中的 因此需要安装组件先
– 安装指令: npm install --save pubsub-js
- 安装完成后 在父组件中定义mounted函数 在页面加载完成后执行订阅组件
父组件中修改
<template>
<!-- 不需要在添加引用或添加事件又或者添加绑定方法 传递至到子组件中的还是需要绑定的-->
<Menu :addMenu="addMenu" :webSide="webSIde"/>
</template>
<script>
import PubSub from 'pubsub-js'
</script>
mounted:{
// 订阅组件 相当于绑定监听事件
// subscribe参数1 订阅组件的名称 即 需要监听的名称
// subscribe参数2 回调函数 这里使用箭头函数(箭头函数表示的是vm实例 相当于全局的)
// subscribe参数2中如果使用function方式作为回调函数 则只能表示PubSub当前本身(局部的)
// subscribe参数2中msg 就是接收的子组件中发布的对应的父组件中订阅的名称
// subscribe参数2中data才是子组件中封装的返回数据
PubSub.subscribe('add2',(msg,data)=>{
this.addMenu(data);
});
}
子组件中发布
methods:{
let menuu = {id:Math.random(),name:content};
// 发布组件 相当于this.$emit('组件名称',组件的值)
PubSub.publish('add2',menuu);
}
完整代码
APP.vue
<template>
<div>
<Menu222 :menus="menus" :webSide="webSide" />
</div>
</template>
<script>
import Menu from './components/Menu.vue'
import PubSub from 'pubsub-js'
export default {
name: 'App',
components:{
Menu222:Menu // 映射Menu标签 如果属性名与属性值不同 则属性名:属性值 如果相同可以省略:属性值
},
data(){
return {
webSide:{// logo图片连接
url:'http://www.sun.com/',
title:'Java官方网站'
},
menus:[
{id:1,name:'科技2'},
{id:2,name:'体育2'},
{id:3,name:'财经2'},
{id:4,name:'医疗2'},
{id:5,name:'政治2'},
{id:6,name:'教育2'}
]
}
},
methods:{
addMenus(menu){
this.menus.push(menu);// 在menus数组的最后位置添加元素
}
},
mounted () {
/*
订阅消息,相当于绑定监听事件 PubSub.subscribe
subscribe 订阅 - 父组件订阅消息
publish 发布 - 子组件发布消息
*/
PubSub.subscribe('add2',(msg,data)=> {
this.addMenus(data);
});
}
}
</script>
<style scoped>
</style>
Menu.vue
<template>
<div>
<a :href="webSide.url" :title="webSide.title" target="_blank">
<img src="../assets/logo.jpg" alt="SUN JAVA" >
</a>
<ul>
<!-- 这里必须要加上key 以免后期出现数据混乱 -->
<li v-for="(menu,index) in menus" :key="menu.id">
<a :href="'http://localhost/ment/'+menu.id">{{menu.name}}</a>
</li>
</ul>
<br>
<!-- input框输入的值双向绑定到data方法中对应的属性上 -->
<input type="text" v-model="content" key="Math.random()"><br>
<button @click="add">添加</button>
</div>
</template>
<script>
import PubSub from 'pubsub-js'
export default {
name: 'Menu',
// peops 声明接收属性,这个属性就会成为组件对象的属性 接收父组件的属性
props:['menus','webSide'], // ,'addMenus'
data(){ // 接收当前页面输入的值
return {
content:''
}
},
methods:{
add(){
const content = this.content.trim();
if(!content){
alert("菜单名称不能为空");
return;
}
let menuu = {id:Math.random(),name:content};
// this.$emit('addMenus2',menuu); // 参数1 调用的是父组件中@addMenus2 参数2是需要传递值到父组件的属性
// this.addMenus(menuu);
// 发布组件 参数1对应订阅组件中的名称,参数2需要传递的值
PubSub.publish('add2',menuu);
}
}
}
</script>
<style scoped>
ul li{
float: left;
padding-left: 5px;
list-style-type: none;
}
img{
width: 300px;
}
</style>