每个熟悉Vue的人都知道Vue应用程序只有一个入口点
main.js
文件。 除了创建Vue实例外,还存在所有全局依赖项(指令,组件,插件)的导入和一种依赖项注入。 项目越大,依赖项就越多,此外,每个依赖项都有自己的配置。 结果,我们得到了一个包含所有配置的巨大文件。
本文将讨论如何组织全局依赖性以避免这种情况。

为什么要自己写?
许多人可能会认为-如果有
Nuxt ,这为什么有必要为您解决? 在我的项目中,我也使用了它,但是在简单的项目中,这可能是多余的。 此外,还没有人取消那些遗留在您身上的遗留代码的项目,就像您的头上积雪一样。 并在那里连接框架-实际上是从头开始。
策划者
这种组织的组织者是Nuxt。 我在Vue的一个大型项目中使用了它。
Nuxt有一个很棒的功能-插件。 每个插件都是一个导出函数的文件。 配置被传递给函数,在创建实例以及整个
商店时,也将传递给Vue构造函数。
此外,每个插件都提供了一个非常有用的功能–
inject
。 它对Vue的根实例和
store
对象进行依赖注入。 这意味着在每个组件,每个存储功能中,指定的依赖项将通过
this
。
这可以派上用场吗?
除了
main.js
明显“失重”这一事实
main.js
,您还将有机会在应用程序中的任何位置使用依赖项,而无需不必要的导入。
依赖注入的主要示例是
vue-router 。 它并不经常使用-获取当前路由的参数,进行重定向,但这是全局依赖项。 如果它可以在任何组件中派上用场,那么为什么不将其全局化呢? 另外,由于这个原因,它的状态也将被全局存储并在整个应用程序中改变。
另一个例子是
vue-wait 。 该插件的开发人员走得更远,不仅将
$wait
属性添加到Vue实例,还添加到vuex存储。 给定插件的细节,这被证明是非常有用的。 例如,商店具有在多个组件上调用的动作。 在每种情况下,您都需要在某些元素上显示加载程序。 不必在每次操作调用之前和之后调用
$wait.start('action')
和
$wait.end('action')
,只需在操作本身中一次调用这些方法即可。 而且这比
dispatch('wait/start', 'action' {root: true})
更具可读性,也较省时。 就存储而言,这是语法糖。
从文字到代码
项目的基本结构
让我们看看项目现在的样子:
src
- store
- App.vue
- main.js
main.js
看起来像这样:
import Vue from 'vue'; import App from './App.vue'; import store from './store'; new Vue({ render: h => h(App), store }).$mount('#app');
我们联系第一个依赖
现在,我们想将
axios连接到我们的项目并为其创建某种配置。 我遵循了Nuxt的术语,并在
src
创建了一个
plugins
目录。 目录内有
index.js
和
axios.js
。
src
- plugins
-- index.js
-- axios.js
- store
- App.vue
- main.js
如上所述,每个插件都必须导出一个函数。 同时,在函数内部,我们要访问存储,然后要访问
inject
函数。
axios.js
import axios from 'axios'; export default function (app) {
index.js
:
import Vue from 'vue'; import axios from './axios'; export default function (app) { let inject = () => {};
如您所见,
index.js
文件还导出了该函数。 这样做是为了能够在其中传递
app
对象。 现在让我们
main.js
修改
main.js
并调用此函数。
main.js
:
import Vue from 'vue'; import App from './App.vue'; import store from './store'; import initPlugins from './plugins';
结果
在这一阶段,我们已经实现了将插件配置从
main.js
中删除的单独文件中。
顺便说一句,将
app
对象传递给我们所有插件的好处是,我们现在可以在每个插件内部访问商店。 您可以通过调用
commit
,
dispatch
以及访问
store.state
和
store.getters
来自由使用它。
如果您喜欢ES6风格,则可以执行以下操作:
axios.js
import axios from 'axios'; export default function ({store: {dispatch, commit, state, getters}}) { ... }
第二阶段-依赖注入
我们已经创建了第一个插件,现在我们的项目如下所示:
src
- plugins
-- index.js
-- axios.js
- store
- App.vue
- main.js
由于在大多数确实需要的库中,已经使用
Vue.use
实现了依赖注入,因此我们将创建自己的简单插件。
例如,尝试重复
vue-wait
操作。 这是一个相当繁重的库,因此如果要在一对按钮上显示加载程序,最好放弃它。 但是,我无法抗拒它的便利性,并在其项目中重复了其基本功能,包括商店中的语法糖。
等待插件
在
plugins
目录中创建另一个文件
wait.js
我已经有一个vuex模块,我也称它为
wait
。 他执行三个简单步骤:
-start-将名为
action
的对象的state属性设置为
true
-end-从状态中删除名为
action
的对象的属性
-
is
-从状态获取名为
action
的对象的属性
在这个插件中,我们将使用它。
wait.js
export default function ({store: {dispatch, getters}}, inject) { const wait = { start: action => dispatch('wait/start', action), end: action => dispatch('wait/end', action), is: action => getters['wait/waiting'](action) }; inject('wait', wait); }
并连接我们的插件:
index.js
:
import Vue from 'vue'; import axios from './axios'; import wait from './wait'; export default function (app) { let inject = () => {}; Injection axios(app, inject); wait(app, inject); }
进样功能
现在我们实现
inject
功能。
Vue.prototype的魔力
现在关于魔术。
Vue文档说编写
Vue.prototype.$appName = ' ';
就足够了
Vue.prototype.$appName = ' ';
和
$appName
将在
this
可用。
但是,事实证明事实并非如此。 由于谷歌搜索,没有答案为什么这样的设计不起作用。 因此,我决定与已经实现此功能的插件作者联系。
全局混合
在我们的示例中,我查看了
vue-wait
插件代码。 他们提供了这样的实现(为清晰起见,清除了源代码):
Vue.mixin({ beforeCreate() { const { wait, store } = this.$options; let instance = null; instance.init(Vue, store);
建议使用全局混合来代替原型。 效果可能基本相同,除了一些细微差别。 但是,鉴于注入是在此处的商店中完成的,因此看起来并不太正确,并且根本与文档不符。
但是,如果原型呢?
用于
inject
函数
inject
的原型解决方案背后的思想是从Nuxt借来的。 它看起来比全局mixin正确得多,所以我选择了它。
Vue.use(() => {
结果
完成这些操作后,我们将有机会访问
this.$wait
从任何组件以及商店中的任何方法
this.$wait
。
发生什么事了
项目结构:
src
- plugins
-- index.js
-- axios.js
-- wait.js
- store
- App.vue
- main.js
index.js
:
import Vue from 'vue'; import axios from './axios'; import wait from './wait'; export default function (app) { let inject = (name, plugin) => { let key = `$${name}`; app[key] = plugin; app.store[key] = plugin; Vue.use(() => { if (Vue.prototype.hasOwnProperty(key)) { return; } Object.defineProperty(Vue.prototype, key, { get () { return this.$root.$options[key]; } }); }); }; axios(app, inject); wait(app, inject); }
wait.js
export default function ({store: {dispatch, getters}}, inject) { const wait = { start: action => dispatch('wait/start', action), end: action => dispatch('wait/end', action), is: action => getters['wait/waiting'](action) }; inject('wait', wait); }
axios.js
import axios from 'axios'; export default function (app) { axios.defaults.baseURL = process.env.API_BASE_URL; axios.defaults.headers.common['Accept'] = 'application/json'; axios.defaults.headers.post['Content-Type'] = 'application/json'; }
main.js
:
import Vue from 'vue'; import App from './App.vue'; import store from './store'; import initPlugins from './plugins'; const app = { render: h => h(App), store }; initPlugins(app); new Vue(app).$mount('#app');
结论
通过这些操作,我们在
main.js
文件中收到了一个导入和一个函数调用。 现在,可以立即清楚地在哪里找到每个插件和每个全局依赖项的配置。
添加新插件时,您只需要创建一个导出函数的文件,然后将其导入
index.js
并调用此函数即可。
在我的实践中,这种结构被证明非常方便,而且很容易在项目之间转移。 现在,如果您需要进行依赖注入或配置其他插件,则无需担心。
在评论中分享您对依赖管理的经验。 成功的项目!