我們在做專案的時候,應該會有這種情況:
“我寫了一個元件,然後做成了 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.