我们在做项目的时候,应该会有这种情况:
“我写了一个组件,然后做成了 npm 包,然后给好几个项目一起用。”
Vue 组件
也是可以这么干的,所以在公司内部可能会将组件封装成 npm 模块
后分发给各个项目。
不过在 Vue 的项目中,有两个小地方可能需要精心处理下 (●’◡’●)
当公共组件使用 EventBus 时
EventBus
并不是什么独立的东西,而是 Vue 的事件系统
的一个最佳实践,算是一种使用方式:
/**
* EventBus.
* src/event-bus.js
*/
export default new Vue({})
/**
* 我的公用组件 my-component.
*/
import EventBus from 'src/event-bus'
export default {
...
methods: {
// 触发叫做 "SomeModule:SomeEvent" 的事件并传了值 "Yeah~" 过去~
triggerSomeEvent () {
EventBus.$emit('SomeModule:SomeEvent', 'Yeah~')
},
// 为我的组件注册两个事件~
registerEvents () {
EventBus.$on('MyComponent:Event-01', value => {
console.log('Event-01 in MyComponent: ', value)
}),
EventBus.$on('MyComponent:Event-02', value => {
console.log('Event-02 in MyComponent: ', value)
})
}
},
created () {
this.registerEvents()
}
}
当我们的公用模块在使用 EventBus 的时候,会有一个微小的问题,看这句话:
import EventBus from 'src/event-bus'
我怎么保证在使用我当前模块的不同的项目中的 EventBus 的路径都是 src/event-bus
呢?
所以,我们需要抽象一层,让模块并不关心
这个 EventBus 是从哪里引入的:
// 我们将 EventBus 做成插件,这样就可以在项目的任何组件内使用了.
// 起名叫 $events.
// 当检测到 $events 存在的时候就使用,不存在的时候使用其他方法.
/**
* 我们将 event-bus 封装为一个插件.
* plugin/event-bus.js
*/
export default {
install (Vue) {
const EventBus = new Vue({})
Vue.prototype.$events = EventBus
Vue.EventBus = EventBus
}
}
/**
* 所以我的公用组件 my-component 要变为:
*/
export default {
...
methods: {
// 触发叫做 "SomeModule:SomeEvent" 的事件并传了值 "Yeah~" 过去~
triggerSomeEvent () {
if (this.$events) {
this.$events.$emit('SomeModule:SomeEvent', 'Yeah~')
} else {
// 其他方式...
}
},
// 为我的组件注册两个事件~
registerEvents () {
if (this.$events) {
this.$events.$on('MyComponent:Event-01', value => {
console.log('Event-01 in MyComponent: ', value)
}),
this.$events.$on('MyComponent:Event-02', value => {
console.log('Event-02 in MyComponent: ', value)
})
} else {
// 其他方式...
}
}
},
created () {
this.registerEvents()
}
}
/**
* 项目入口.
* src/index.js
*/
import Vue from 'vue'
import EventBus from 'plugin/event-bus'
import MyComponent from 'my-component'
Vue.use(EventBus)
const Root = new Vue({
components: {
MyComponent
},
methods: {
doSomething () {
this.$events.$emit('MyComponent:Event-01', 'FA♂')
}
}
})
OK,这样我们的组件就可以在不同项目中适应 EventBus 了!
这里有一个组件 cklmercer/vue-events 就是解决这种问题而存在的.
当公共组件使用 Vuex 时
这个问题仅仅存在于 Vue 1.0
的项目中,Vue 2.0 + Vuex 2.0
已经解决这个问题:
/**
* 我的公用组件 my-component.
*/
import store from 'src/vuex/store'
import actions from 'src/vuex/actions'
import getters from 'src/vuex/getters'
export default {
...
store,
vuex: {
actions, getters
},
computed: {
userName () {
// "getUsername" 是 Vuex 中定义好的 getter.
return this.getUsername
}
},
methods: {
changeDataInVuexByUsingAction () {
// "setUserExperience" 是 Vuex 中定义好的 action.
this.setUserExperience(450)
}
}
}
那么还是同样的问题,
我怎么保证在使用我当前模块的不同的项目中的 Vuex 的路径都是 src/vuex
呢?
所以方法一样啦,抽象出来引用路径,让模块并不关心
是如何引入 Vuex 的:
// 我们将 Vuex 做成插件,这样就可以在项目的任何组件内使用了.
// 起名叫 $vuexer.
// 当检测到 $vuexer 存在的时候就使用 Vuex,不存在的时候就将数据写入组件自己内部的 state 中.
/**
* 我们将 event-bus 封装为一个插件.
* plugin/event-bus.js
*/
export default {
install (Vue, { store, actions, getters }) {
const vuexer = new Vue({
store, actions, getters
})
Vue.prototype.$vuexer = vuexer
Vue.vuexer = vuexer
}
}
/**
* 项目入口.
* src/index.js
*/
import Vue from 'vue'
import Vuexer from 'plugin/vuexer'
import store from 'src/vuex/store'
import actions from 'src/vuex/actions'
import getters from 'src/vuex/getters'
import MyComponent from 'my-component'
Vue.use(Vuexer, {
store, actions, getters
})
const Root = new Vue({
components: {
MyComponent
},
computed: {
userExperience () {
// "getExperience" 是在 Vuex 中定义好的 getter.
return this.$vuexer.getExperience
}
},
methods: {
changeUsernameInVuex () {
// "setUsername" 是在 Vuex 中定义好的 setter.
this.$vuexer.setUsername('John Smith')
}
}
})
/**
* 我的公用组件 my-component.
*/
export default {
data () {
return {
_userName: '神秘用户',
_userExperience: 65535
}
},
computed: {
userName () {
// 如果有 Vuexer, 如果木有 Vuexer...
return this.$vuexer
? this.$vuexer.getUsername
: this._userName
}
},
methods: {
// 如果有 vuexer, 如果木有 Vuexer...
changeDataInVuexByUsingAction () {
const userExperience = 450
if (this.$vuexer) {
this.$vuexer.setUserExperience(userExperience)
} else {
this._userExperience = userExperience
}
}
}
}
妥!⁄(⁄ ⁄•⁄ω⁄•⁄ ⁄)⁄
至于为什么 Vue 2.0 + Vuex 2.0
木有这个问题:
// 在 Vue 2.0 中使用 Vuex 要这么写:
// 创建一个组件.
const Components = {
template: `<div>{{ count }}</div>`,
computed: {
count () {
return this.$store.getters.doneTodosCount // 这是一个 getter.
}
}
}
注意 computed
中的 return this.$store.getters.doneTodosCount
,看看其中的 this.$store
,
是不是和 this.$vuexer
有点像? (°∀°)ノ
这里还有一个组件 lancercomet/vuexer 就是为 Vue 1.0
解决这个问题的!
完结撒花~
By LancerComet at 01:22, 2017.01.21.