Vue2-插件安装与组件生命周期+主应用程序、Mixins、服务、Vuex操作-组织初始启动时运行的代码



有时需要在外部API和应用程序之间添加桥接。这有两部分——从API检索数据和将数据写入存储区。并根据用户操作将数据发送到API,并更新客户端上的存储。此外,有时您需要此代码才能在应用程序启动时立即运行。在Vue中实现这一点的干净编码模式是什么?

这段代码(在我的例子中)是应用程序的全局代码,因此直接将其添加到UI组件中没有多大意义。

添加此代码最简单的地方是主要的应用程序安装回调函数。

new Vue({
render: h => h(App),
}).$mount('#app');
// App.vue
mounted() {
//run startup code here.
}

但随着应用程序的发展,如果app.vue文件是";"中央";用于此类型功能的位置。

选择和权衡

  • Mixin存在碰撞问题,这使得它们不理想,尤其是在您正在向主父组件添加几个
  • 插件可能是处理这类事情的好地方,但如果插件希望某个东西存在,但它还没有存在,则可能会遇到操作顺序问题
  • 无模板组件可能感觉像黑客。您正在向模板中添加一个组件,该组件实际上不会渲染空<div>之外的任何内容。除此之外,它们还能发挥作用
  • Vuex Actions似乎是该代码的理想位置,但商店缺乏内部触发机制,因此该操作仍需发送到其他地方,如果这是应用程序的安装回调,我们将回到垃圾场问题
  • Service/Utility(本质上是将函数抽象到另一个文件中,并使用ES6模块导入/导出)是另一种抽象和组织代码的方式,但仅凭他们自己对Vue实例以及所有状态和原型(其他服务,i18n等)一无所知;Vue";方式

在插件的安装回调中触发的Vuex操作的组合可能是这里的最佳选择。有人有更好的建议吗?

这个问题需要两部分的答案。问题的第一部分是,这个代码中有趣的部分应该放在哪里?对API的调用以及调用成功/失败后要运行的后续逻辑应在应用程序中的何处进行?

第二部分是,哪种Vue机制最适合在初始应用程序启动时触发代码运行?

让我们探讨一些选择。

应用程序安装的生命周期内联代码

Vue组件是整个应用程序的起点(通常称为App.Vue)

new Vue({
render: h => h(App),
}).$mount('#app');
// App.vue
mounted() {
//run startup code here.
}

优点:我们可以访问vue-vm实例及其所有属性,并且可以从DOM中读取,因为我们的应用程序已经呈现。安装的生命周期功能在应用程序启动时自动运行。不需要其他管道来触发对代码的调用。

缺点:任何副作用都会导致应用程序在初次启动时立即重新渲染。理想情况下,某些更改会在第一次渲染之前发生。App.vue可以成为任何需要在应用程序启动时运行一些代码的新功能的垃圾场。

无渲染组件

// App.vue (SFC Pattern)
<template>
...
<someRenderlessComponent />
</teamplate>
// someRenderlessComponent.vue
<template>
<div><!-- empty because I'm not rendering anything.--></div>
</template>
<script>
mounted() {
//run startup code here
}
</script>

优点:与App.vue相同,加上逻辑可以抽象并组成单独的文件,防止App.vue变得混乱。代码更易于阅读、测试和维护。安装的生命周期功能在应用程序启动时自动运行。不需要其他管道来触发对代码的调用。

缺点:一个毫无意义的DOM元素被呈现到页面上,在使用DEV工具进行调试时会增加混乱,并且(如果完成足够的时间)会降低CSS和JS的页面性能。这假设所有这些组件的存在都是为了成为应用程序商店和某些外部API之间的桥梁。

Vue Mixin

mixin就像一个组件分部。您可以定义组件的一部分,例如本地状态、计算道具、生命周期方法等,并且可以将这些预定义的部分与其他组件混合(因此混合)。

Mixin Docs

优点:如果mixin和组件定义了相同的选项,包括生命周期方法,Vue会进行一些自动合并。两个生命周期函数都会启动,mixin生命周期函数将首先启动——这对我们的"启动场景"很好。

缺点:在Vue2中,mixin选项不会自动命名。如果你不小心,你可能会出现意外的冲突,两段数据或计算的道具同名。与生命周期方法不同,其他选项是递归合并的,组件的版本将覆盖mixin。如果有几个部分设计为协同工作,这可能会破坏mixin中定义的功能。

Vue插件

插件中的安装功能在应用程序启动时立即运行,并可以访问Vue实例。

插件文档

优点:插件被抽象到自己的文件中,以保持App.vue的干净。一旦调用Vue.use(),安装函数就会自动运行,因此不需要编写或维护额外的管道。

缺点:我们可以访问Vue实例,但我们无法访问以前插件尚未添加到Vue实例中的任何内容。秩序变得很重要。我们也无法访问商店、路由器、i18n或任何DOM元素,因为vue应用程序还没有实例化。因此,在这里所能做的是非常有限的。在API调用结果之后需要提交存储突变的情况下,这是不够的。

Vuex动作

Vuex中的操作是异步函数,您可以在其中调用API,然后提交突变。它们就像是一些业务逻辑和商店后续更新的混合体,尽管它们不会直接更新商店的状态,但会触发突变来实现这一点。

Vuex Actions文档

优点:与API通信的代码与因此发生变异的存储模块位于同一位置。需要更少的查找。Vuex存储与Vue的反应性挂钩,这意味着对状态的任何更改都将触发引用该状态的任何下游组件自动重新渲染。

缺点:流量模式(Vuex所基于的)在进入商店时期望纯度。一旦更新了存储状态,存储中的任何逻辑都将结束。这意味着您可能需要添加任何后续逻辑,而不是在其他地方的商店更新后发生的逻辑。这在某些方面是一种优势。在这种情况下,这意味着根据定义,您需要将业务逻辑代码的一部分拆分到多个文件中,这可能会使现在和将来更难理解和推理。操作本身也不会触发,您仍然需要确定如何在应用程序启动时触发此操作。

注意:对于新的Vue项目,Vue团队现在正式推荐Pinia而不是Vuex进行国家管理。部分原因是它比Vuex更易于使用,也不那么固执己见。

一个单独的JS/TS文件(又名服务)

这只是将一些逻辑抽象到一个单独的JS/TS模块中。这不是Vue结构,它只是ES6模块在发挥作用。

// someService.ts
export class someService = {
someFunction() {
// run startup code here
}
};

优点:将所有与你正在做的事情相关的代码分开,并且易于测试。它只是简单的JavaScript/Typescript,所以任何背景的人都很容易理解他们是否了解JS/TS。服务可以使用上面描述的任何构造。这是一个不带偏见的抽象概念。

缺点:该服务没有对Vue实例的直接作用域访问权限。你必须将Vue实例作为一个参数传入,这对我来说真的很笨拙——尤其是当你试图在商店上运行提交并期望反应时。作为一个未绑定的抽象——它与Vue的生命周期没有任何联系——如果没有额外的管道,它不会在应用程序启动时自动运行。你仍然需要弄清楚从哪里调用这个服务,无论是前面提到的挂载调用之一,还是插件安装函数。因此,这可能是解决方案的一部分,但仅凭它本身是不够的。

最后建议

注意:这两种解决方案都假设您已经设置了一个Vuex模块,该模块具有用于修改该状态的状态和突变。它还假设您有一个UI组件对该状态做出反应(通过引用)。

TL;DR:我认为有趣的部分(如上所述)应该放在Vuex Action中。Vue插件应该在其安装功能中的应用程序启动时触发该操作。强烈建议使用有助于解释这些内容是如何粘合在一起以及为什么粘合在一起的注释。

如果你更喜欢使用生命周期方法来触发,我的第二个选择是将感兴趣的部分添加到无模板组件中,并使用组件自己的生命周期方法触发该功能,这是最有意义的(创建或安装是最有可能的选择)。它的缺点没有mixin那么严重,但基本上完成了相同的事情——从主应用程序中抽象出一些有状态的逻辑。

如果您和其他参与该项目的人都很勤奋地手动命名mixin的内部,那么mixin就可以工作。但要小心,这是一个潜在的步兵。

Vue没有与Angular相同的服务API。我不建议通过管道胶带之类的东西来对抗图书馆,但有些人不同意我的观点。这不是ES模块的翻版,它们在Vue项目的其他环境中非常有用。

无论你做什么,都不要把所有东西都倒进App.vue。你稍后会感谢我的。