【问题标题】:Vuejs: distribute code across multiple components or everything into a single component?Vuejs:跨多个组件分发代码还是将所有内容分发到单个组件中?
【发布时间】:2019-10-21 13:58:28
【问题描述】:

所以我用 Vue 玩了很多,现在我的应用程序变得很大,我对如何组织它有疑问。

我了解组件,并且当您需要在同一页面上多次重复使用它们时它们是有意义的,例如,“自定义选择框”组件可能在许多地方都需要。

但是那些只有一次实例的组件呢?示例:具有 3 个区域的管理仪表板界面:一个带有一些导航的侧边栏,一个包含您可以根据导航中选择的内容编辑的内容的主区域,另一个包含与主区域相关的内容的侧边栏。所有这些都需要单独的组件吗?因为如果页面上只有一个实例,我看不出这样做有什么好处。另一方面,如果我将所有代码都放在一个“应用”组件中,我可以简化一些代码(更少的变量)

【问题讨论】:

  • 如果你使用 webpack 这样的工具,代码拆分也意味着你可以延迟加载组件。这意味着您的应用速度更快,因为它只会加载当时需要的组件。

标签: javascript vue.js vue-component code-organization


【解决方案1】:

总结——使用组件的典型原因:

  1. 可维护性。
  2. 通过组件边界呈现性能。
  3. 通过分块加载性能。

如果您发现使用更少的组件可以提高可维护性,那很好。它可能是适合您的应用程序的正确设计。

详细版本如下。


使用组件的主要原因是为了提高可维护性。

在许多地方(例如选择框)重复使用的组件显然比一遍又一遍地重复相同的代码更容易维护。但是,值得考虑为什么会这样。不仅仅是重复使更改所有选择框变得更加困难。使用组件的另一个主要好处是额外的抽象级别可以减少心理开销。

假设有人试图维护代码看到这样的东西(伪代码):

<select-box :some-prop="blah">
  <select-box-option v-for="something" />
</select-box>

立即很明显这是select-boxselect-box 的所有血腥实现细节都被隐藏起来了,我们不需要担心它们。通过查看道具、子组件和事件,我们可以快速推断出父组件和select-box 之间来回传递的数据。这只是关注点分离

此好处也适用于未重用的组件。让我们以侧边栏为例。我们可能会在主要组件的模板中看到这一点:

<nav-sidebar @navigate="onNavigate" />

组件的名称可以让我们快速将其识别为侧边栏。如果我们当前的任务不涉及侧边栏,那么我们可以跳过模板的那一部分。由于代码已移至不同的文件,我们可以轻松确定哪些代码位是侧边栏的一部分,哪些位不是。

在这个例子中,nav-sidebar 没有任何道具,只有一个事件。由此我们可以开始得出关于这些组件如何交互的一些结论。 nav-sidebar 似乎不需要从主要组件传递任何东西,它可以很高兴地独立生活。如果我们需要调试数据以其他方式流动的问题,我们几乎肯定会从 onNavigate 开始。

如果所有东西都被拼凑成一个大的组成部分,我们就无法像这样快速地开始进行推理。

当然,我们的推论可能是错误的。可能是nav-sidebar 做了一些可怕的事情,涉及$parent 从其父组件中获取数据。然而,这只是说明了为什么使用这些技术被认为是不好的做法。可维护的代码应该允许开发人员根据似乎已经存在的抽象得出合理的结论。

但也有可能走得太远。

一个好的抽象可以让你通过隐藏标签后面的细节来释放一些心理能力。一个糟糕的抽象通过隐藏你想在一些间接后面看到的代码增加了精神开销。再加上命名的困难和额外的胶水代码的负担,你最好放弃额外的层并保持一切内联。

另一件可能出错的事情是以错误的方式拆分组件。分离关注点需要对这些关注点进行干净的分区。以稍微不同的方式进行拆分,您最终会发现一个问题被分散到多个组件中,由此产生的混乱通常比您根本不费心拆分事情更糟糕。

Vue 允许您以多种方式拆分 JavaScript 代码,组件只是其中一种。将.js 文件、插件、过滤器、Vuex、mixins 等分开。您可以使用多种选项。

另一方面,模板只能通过使用组件来真正拆分。如果您想将一个巨大的模板分解成更易于管理的块,那么组件确实是唯一的出路。

这给我们带来了使用组件的另一个关键原因。

模板被编译成render 函数。当 render 函数运行时,它会注册响应式依赖项,就像计算属性一样。如果这些依赖项中的任何一个发生更改,它将触发重新渲染。这将再次运行整个 render 函数。即使这不会导致 DOM 发生任何变化,它也需要生成所有相关的 VNode,并且差异算法将需要检查所有这些。

组件边界也是渲染边界。每个组件根据其依赖关系是否发生变化来决定是否渲染。

因此,以nav-sidebar 为例,假设nav-sidebar 发生了一些变化,因此需要更新渲染。如果nav-sidebar 是一个单独的组件,那么它只需要为该组件运行模板/render 函数。相反,如果我们将所有 nav-sidebar 代码捆绑到主模板中,那么我们将不得不重新渲染所有内容。

Vue 还支持延迟加载组件,以减少页面的初始加载时间。这个想法是,许多应用程序都有很大的部分,例如管理界面,与大多数用户无关。您可以将组件拆分为块并在需要时下载这些块,而不是产生下载所有这些组件的开销。这通常通过 Vue 路由器配置来实现。

抛开分块不谈,使用路由器的典型方法是为不同的页面设置单独的组件。虽然理论上可以为所有路由使用相同的组件,这不太可能导致更易于维护的东西。我要补充一点,'page' 的定义在这里有点模糊,但在大多数应用程序中,什么构成不同的页面很清楚,从而导致不同的组件。

如果不提及测试,任何关于创建代码单体的著作都是不完整的。单元测试应该被认为是一种重用形式,并且是一种特别极端的形式。测试有一个不屈不挠的诀窍,可以揭露隐藏在你认为漂亮、干净的设计背后的意大利面条的混乱。我不会对测试发表任何看法,但我只想说除非你把东西分成合适的单元,否则你将无法编写单元测试。

组件的另一个关键特性是它有自己的一组属性。它自己的data 和它自己的计算属性。这听起来很明显,但当您考虑通过v-for 循环时,它会变得很重要。

<div v-for="item in items">...</div>

上面的例子使用内联元素而不是组件。任何状态都只能依赖于父状态。需要为每个循环项保存该状态,因此我们最终可能会得到多个数组来保存状态的不同方面。在使用循环时,计算属性同样难以实现。我们通常最终会使用方法:

<div v-for="item in items" :class="getClassesFor(item)">...</div>

现在考虑组件版本:

<my-component v-for="item in items" :item="item" />

每个my-component 都可以保持自己的状态。例如,假设my-component 具有展开/折叠功能。现在可以将其存储在每个实例中的本地 data 属性中。同样,每个实例都有自己的计算属性。

可以说这只是重用,因为v-for 创建了多个实例。但是,鉴于我们专门引入了一个新组件只是为了提供一种属性范围,我认为它值得特别提及。

【讨论】:

    【解决方案2】:

    我个人喜欢有 3 种类型的组件。

    1. 可重复使用的系统组件。它们用于通用布局、自定义按钮、自定义选择框……它们可以在代码中多次重复使用,并且用途广泛。

    2. 页面/视图组件。路由通常路由到特定组件。该组件是多个组件的某种组合。这种区别允许快速识别应用程序的“页面”。

    3. 逻辑除法。这些是最难找到的。我倾向于隔离彼此无关的事物。例如,页脚可能不会被重用,但页脚中的修改应该只涉及页脚。其他示例包括导航栏、菜单、管理员的每个部分。这些组件应该尽可能地可重用,但有时它们会是特定的。

    另一个例子:评论系统。 “评论”将是类型 3 的组件。“评论线程”显示将是使用“评论”组件的类型 3 的另一个组件。 cmets 线程的主题将存在一个页面,该页面的类型为 2。 请注意,类型 3 和 2 的每个组件都可以使用其他类型的其他组件。 如果我想改变评论线程的显示排列,我只需要改变“评论线程”组件。

    【讨论】:

      【解决方案3】:

      Vue 组件的使用不仅是为了重用。您可以将组件拆分为逻辑块。以水疗为例。您可以基于 vue 组件创建网格。

      【讨论】:

        【解决方案4】:

        这就是为什么即使只使用一次代码也需要拆分代码的原因。

        拥有成百上千行代码,毫无疑问 将代码拆分为不同的文件有助于使其更易于管理。 虽然,如果 事先没有考虑拆分。

        分码越多,越清晰。

        它不仅适用于 Vue JS,还适用于几乎所有编程语言。

        【讨论】:

        • "拆分代码越多,代码就越清晰。"需要引用。
        • 没有引用那句话。这只是我的想法。
        猜你喜欢
        • 2016-05-10
        • 2021-08-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-01-31
        • 2019-08-09
        • 2022-11-23
        • 1970-01-01
        相关资源
        最近更新 更多