最初了解到eventBus和vuex并不清楚其原理只知道无脑用,甚至有些时候用的时候还不是很清楚,最近比较好奇这二者的区别,特以此文梳理vue
// event-bus.js
import Vue from 'vue'
export const EventBus = new Vue()
复制代码
建立一个全局事件总线vuex
// main.js
Vue.prototype.$EventBus = new Vue()
复制代码
export default new Vue({
data() {
return {
searchShow: true,
showBtn: true
}
},
methods: {
searchShowChange(value) {
if (typeof value === 'boolean') {
this.searchShow = false
} else {
this.searchShow = !this.searchShow
}
this.$emit('searchShowChange')
}
}
})
复制代码
$on
/$emit
/$off
$off移除监听者
beforeDestroy() {
//组件销毁前须要解绑事件。不然会出现重复触发事件的问题
this.bus.$off(this.$route.path);
}
复制代码
当咱们的应用遇到多个组件共享状态时,单向数据流的简洁性很容易被破坏: 1.多个视图依赖于同一状态。 2.来自不一样视图的行为须要变动同一状态。设计模式
对于问题一,传参的方法对于多层嵌套的组件将会很是繁琐,而且对于兄弟组件间的状态传递无能为力。对于问题二,咱们常常会采用父子组件直接引用或者经过事件来变动和同步状态的多份拷贝。以上的这些模式很是脆弱,一般会致使没法维护的代码。数组
是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的全部组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。缓存
缺点:须要频繁地导入,而且在测试组件时须要模拟状态bash
computed: {
count () {
return store.state.count
}
}
复制代码
子组件能经过 this.$store 访问到app
const app = new Vue({
el: '#app',
// 把 store 对象提供给 “store” 选项,这能够把 store 的实例注入全部的子组件
store,
components: { Counter },
template: `
<div class="app">
<counter></counter>
</div>
`
})
const Counter = {
template: `<div>{{ count }}</div>`,
computed: {
count () {
return this.$store.state.count
}
}
}
复制代码
// 在单独构建的版本中辅助函数为 Vuex.mapState
import { mapState } from 'vuex'
export default {
// ...
computed: mapState({
// 箭头函数可以使代码更简练
count: state => state.count,
// 传字符串参数 'count' 等同于 `state => state.count`
countAlias: 'count',
// 为了可以使用 `this` 获取局部状态,必须使用常规函数
countPlusLocalState (state) {
return state.count + this.localCount
}
})
}
复制代码
computed: mapState([
// 映射 this.count 为 store.state.count
'count'
])
复制代码
computed: {
localComputed () { /* ... */ },
// 使用对象展开运算符将此对象混入到外部对象中
...mapState({
// ...
})
}
复制代码
store.getters.doneTodos
复制代码
getters: {
// ...
doneTodosCount: (state, getters) => {
return getters.doneTodos.length
}
}
复制代码
注意,getter 在经过方法访问时,每次都会去进行调用,而不会缓存结果。异步
getters: {
// ...
getTodoById: (state) => (id) => {
return state.todos.find(todo => todo.id === id)
}
}
store.getters.getTodoById(2) // -> { id: 2, text: '...', done: false }
复制代码
mapGetters 辅助函数仅仅是将 store 中的 getter 映射到局部计算属性async
import { mapGetters } from 'vuex'
export default {
// ...
computed: {
// 使用对象展开运算符将 getter 混入 computed 对象中
...mapGetters([
'doneTodosCount',
'anotherGetter',
// ...
])
}
}
//若是你想将一个 getter 属性另取一个名字,使用对象形式
...mapGetters({
// 把 `this.doneCount` 映射为 `this.$store.getters.doneTodosCount`
doneCount: 'doneTodosCount'
})
复制代码
在大多数状况下,载荷应该是一个对象,这样能够包含多个字段而且记录的 mutation 会更易读函数
mutations: {
increment (state, payload) {
state.count += payload.amount
}
}
store.commit('increment', {
amount: 10
})
//对象风格的提交方式
store.commit({
type: 'increment',
amount: 10
})
复制代码
在组件中提交 Mutation
mapMutations
辅助函数将组件中的 methods 映射为 store.commit 调用import { mapMutations } from 'vuex'
export default {
// ...
methods: {
...mapMutations([
'increment', // 将 `this.increment()` 映射为 `this.$store.commit('increment')`
// `mapMutations` 也支持载荷:
'incrementBy' // 将 `this.incrementBy(amount)` 映射为 `this.$store.commit('incrementBy', amount)`
]),
...mapMutations({
add: 'increment' // 将 `this.add()` 映射为 `this.$store.commit('increment')`
})
}
}
复制代码
注意事项
Vue.set(obj, 'newProp', 123)
, 或者以新对象替换老对象。
例如,利用对象展开运算符咱们能够这样写:
state.obj = { ...state.obj, newProp: 123 }
使用常量替代 Mutation 事件类型
1.常量更容易避免程序出现错误。若是把一个值赋给程序中的一个常量,而该常量已经有一个值,编译器就回报告错误。 2.在其多人协做的时候,方便统一管理,并且在其状态管理当中调用方法时一眼就是看出是其mutation里面的方法,有问题直接快速找到。
// mutation-types.js
export const SOME_MUTATION = 'SOME_MUTATION'
// store.js
import Vuex from 'vuex'
import { SOME_MUTATION } from './mutation-types'
const store = new Vuex.Store({
state: { ... },
mutations: {
// 咱们可使用 ES2015 风格的计算属性命名功能来使用一个常量做为函数名
[SOME_MUTATION] (state) {
// mutate state
}
}
})
复制代码
actions: {
increment ({ commit }) {
commit('increment')
}
}
复制代码
store.dispatch('increment')
// 以载荷形式分发
store.dispatch('incrementAsync', {
amount: 10
})
// 以对象形式分发
store.dispatch({
type: 'incrementAsync',
amount: 10
})
复制代码
actions: {
checkout ({ commit, state }, products) {
// 把当前购物车的物品备份起来
const savedCartItems = [...state.cart.added]
// 发出结帐请求,而后乐观地清空购物车
commit(types.CHECKOUT_REQUEST)
// 购物 API 接受一个成功回调和一个失败回调
shop.buyProducts(
products,
// 成功操做
() => commit(types.CHECKOUT_SUCCESS),
// 失败操做
() => commit(types.CHECKOUT_FAILURE, savedCartItems)
)
}
}
复制代码
methods: {
...mapActions([
'increment', // 将 `this.increment()` 映射为 this.$store.dispatch('increment')
// mapActions 也支持载荷:
'incrementBy' // 将 `this.incrementBy(amount)` 映射为 this.$store.dispatch('incrementBy', amount)
]),
...mapActions({
add: 'increment' // 将 `this.add()` 映射为 this.$store.dispatch('increment')
})
}
复制代码
//利用 async / await,咱们能够以下组合 action
// 假设 getData() 和 getOtherData() 返回的是 Promise
actions: {
async actionA ({ commit }) {
commit('gotData', await getData())
},
async actionB ({ dispatch, commit }) {
await dispatch('actionA') // 等待 actionA 完成
commit('gotOtherData', await getOtherData())
}
}
复制代码