@zhouyy
2018-05-28T06:11:25.000000Z
字数 3944
阅读 546
vue
来源:https://segmentfault.com/a/1190000008184629
我们在做项目的时候,应该会有这种情况:
"我写了一个组件,然后做成了 npm 包,然后给好几个项目一起用。"
Vue 组件也是可以这么干的,所以在公司内部可能会将组件封装成 npm 模块后分发给各个项目。
不过在 Vue 的项目中,有两个小地方可能需要精心处理下 (●’◡’●)
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 = EventBusVue.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 = vuexerVue.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 = 450if (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 解决这个问题的!