我们都知道Vue是一款渐进式的js框架,在开发大型应用的时候,Vue官方推荐你使用组件化进行开发,即每一个页面都是一个组件,一个组件内包含了一个或多个组件,下面举一个简单的例子描述一下Vue中的组件。
如上一个简单的搜索Github用户的单页面应用可以分为搜索组件和列表组件,当然如果你非要较真的的话一个列表组件是由一个又一个的itme组成的我也不反对,不过为了方便编写测试代码,我将其分为搜索组件和列表组件,很明显search这个动作是在搜索组件中发起的,搜索组件如何把请求到的数据交给列表组件呢,这就要谈一谈Vue中常见的三种组件通信方式啦。
全局事件总线
Vue 原型对象上包含事件处理的方法:
- $on(eventName, listener): 绑定自定义事件监听
- $emit(eventName, data): 分发自定义事件
- $off(eventName): 解绑自定义事件监听
- $once(eventName, listener): 绑定事件监听, 但只能处理一次
又因为所有组件实例对象的原型对象的原型对象就是 Vue 的原型对象
- 所有组件对象都能看到 Vue 原型对象上的属性和方法
- Vue.prototype.bus = new Vue(), 所有的组件对象都能看到bus 这个属性 对象
so这个$bus就是全局事件总线,我们可以使用他的绑定自定义事件和分发自定义事件来进行组件间的通信,步骤也是非常的easy哇,只需要简简单单的三步即可完成组件的通信
1.在main.js中绑定全局事件总线
import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = true
new Vue({
render: h => h(App),
beforeCreate () { // 尽量早的执行挂载全局事件总线对象的操作
Vue.prototype.$bus = this
}
}).$mount('#app')
2.列表组件$on绑定自定义事件
export default {
name: "List",
data() {
return {
info: {
userList: [],
isFirst: true,
isLoading: false,
errMsg: ''
},
};
},
mounted() {
this.$bus.$on("getUserList", (info) => { // 绑定自定义事件
console.log("@@", "收到回调", info);
this.info = {...this.info,...info};
});
},
props: {},
};
3.搜索组件$emit分发自定义事件
axios.get("https://api.github.com/search/users?q=" + this.keyword).then(
(response) => {
console.log("@@", "请求成功啦"),
this.userList = response.data.items,
this.$bus.$emit("getUserList", { // 发送自定义事件
userList: this.userList,
isFirst: false,
isLoading: false
});
},
(error) => {
console.error("@@", "请求失败啦");
this.$bus.$emit("getUserList", {
userList: [],
isFirst: false,
isLoading: false,
errMsg: error.message
});
}
);
消息的发布订阅
消息的发布订阅使用过消息中间件的同学想必对此不会陌生吧,搜索组件是消息的生产者,列表组件是消息的的消费者,生产者和消费者都有了,那谁是消息中间件哇,e’m’m~消息中间件自然就是Vue支持的各种各样的消息订阅的第三方库啦,我这一个前端菜鸡也不推荐你哪个库好用,因为我只会用PubSubJs,使用方法也是very的easy哇。
1.安装注册pubsubjs
import pubsub from 'pubsub-js'; // 哪里用到就在那里导入
2.列表组件订阅消息
mounted() {
pubsub.subscribe("getUserList",(msgName,info) => { // 订阅消息
console.log("@@", "收到回调", msgName,info);
this.info = {...this.info,...info};
})
}
3.搜索组件发布消息
searchUsers() {
axios.get("https://api.github.com/search/users?q=" + this.keyword).then(
(response) => {
console.log("@@", "请求成功啦"),
this.userList = response.data.items,
pubsub.publish("getUserList",{ // 发布消息
userList: this.userList,
isFirst: false,
isLoading: false,
errMsg: ''
})
}
}
);
}
4.最后别忘了在Vue生命周期中的beforeDestroy()上取消消息的订阅哦
beforeDestroy(){
PubSub.unsubscribe(subscribeId) //pubsub.subscribe的返回值就是subscribeId
}
Vuex共享状态
写着写着我发现把Vuex放在这里不太合适,因为Vuex官方给出的定义是Vuex是用来给大型单页面应用共享状态的,而不是负责组件通信的,但是既然都写了,还是把它放到这里吧。
### 每一个 Vuex 应用的核心就是 store(仓库)。“store”基本上就是一个容器,它包含着你的应用中大部分的状态 (state)
如下是官方给Vuex的定义,简单的来说无非就是Vuex有一个store他保存着Vue全局的共享状态,因为这是Vuex的官方插件,使用Vue.use(Vuex)之后Vue实例对象就有了$store这个属性,你就可以让着他对共享状态为所欲为了,在我们的搜索案例里,我们就把列表里面的用户信息当作是一个共享状态就好了啦
1.快速安装Vuex
如果你用的是Vue2.x的脚手架注意安装Vuex3.x才可以哦。
npm install vuex
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store ({
state: {
userInfo: []
},
mutations: {
setUserInfo (state,userInfo) {
state.userInfo = userInfo;
}
}
})
2.搜索组件commit改变共享状态
axios.get("https://api.github.com/search/users?q=" + this.keyword).then(
response => {
console.log("@@", "请求成功啦"),
this.userList = response.data.items,
this.$store.commit('setUserInfo',{ // commit
userList: this.userList,
isFirst: false,
isLoading: false,
errMsg: ''
})
},
3.列表组件展示共享状态$store.state
<div class="card" v-for="user in $store.state.userInfo.userList" :key="user.id"> // here
<a :href="user.html_url" target="_blank">
<img :src="user.avatar_url" style="width: 100px" />
</a>
<p class="card-text">{{ user.login }}</p>
</div>