优秀的编程知识分享平台

网站首页 > 技术文章 正文

vue项目的目录结构,大型项目结构和组件封装

nanyue 2024-10-17 11:23:22 技术文章 5 ℃

一、为什么要划分

使用vue构建项目,项目结构清晰会提高开发效率,熟悉项目的各种配置同样会让开发效率更高

在划分项目结构的时候,需要遵循一些基本的原则:

  • 文件夹和文件夹内部文件的语义一致性
  • 单一入口/出口
  • 就近原则,紧耦合的文件应该放到一起,且应以相对路径引用
  • 公共的文件应该以绝对路径的方式从根目录引用
  • /src 外面的文件不应该被引入

文件夹和文件夹内部文件的语义一致性

我们的目录结构都会有一个文件夹是按照路由模块来划分的,如pages文件夹,这个文件夹里面应该包含我们项目所有的路由模块,并且仅应该包含路由模块,而不应该有别的其他的非路由模块的文件夹

这样做的好处在于一眼就从 pages文件夹看出这个项目的路由有哪些

单一入口/出口

举个例子,在pages文件夹里面存在一个seller文件夹,这时候seller 文件夹应该作为一个独立的模块由外部引入,并且 seller/index.js 应该作为外部引入 seller 模块的唯一入口

// 错误用法
import sellerReducer from 'src/pages/seller/reducer'

// 正确用法
import { reducer as sellerReducer } from 'src/pages/seller'

这样做的好处在于,无论你的模块文件夹内部有多乱,外部引用的时候,都是从一个入口文件引入,这样就很好地实现了隔离,如果后续有重构需求,你就会发现这种方式的优点

就近原则,紧耦合的文件应该放到一起,且应以相对路径引用

使用相对路径可以保证模块内部的独立性

// 正确用法
import styles from './index.module.scss'
// 错误用法
import styles from 'src/pages/seller/index.module.scss'


举个例子

假设我们现在的 seller 目录是在 src/pages/seller,如果我们后续发生了路由变更,需要加一个层级,变成 src/pages/user/seller

如果我们采用第一种相对路径的方式,那就可以直接将整个文件夹拖过去就好,seller 文件夹内部不需要做任何变更。

但是如果我们采用第二种绝对路径的方式,移动文件夹的同时,还需要对每个 import 的路径做修改

公共的文件应该以绝对路径的方式从根目录引用

公共指的是多个路由模块共用,如一些公共的组件,我们可以放在src/components

在使用到的页面中,采用绝对路径的形式引用

// 错误用法
import Input from '../../components/input'
// 正确用法
import Input from 'src/components/input'


同样的,如果我们需要对文件夹结构进行调整。将 /src/components/input 变成 /src/components/new/input,如果使用绝对路径,只需要全局搜索替换

再加上绝对路径有全局的语义,相对路径有独立模块的语义

/src 外的文件不应该被引入

vue-cli脚手架已经帮我们做了相关的约束了,正常我们的前端项目都会有个src文件夹,里面放着所有的项目需要的资源,js,css, png, svg 等等。src 外会放一些项目配置,依赖,环境等文件

这样的好处是方便划分项目代码文件和配置文件

二、目录结构

单页面目录结构

project
│  .browserslistrc
│  .env.production
│  .eslintrc.js
│  .gitignore
│  babel.config.js
│  package-lock.json
│  package.json
│  README.md
│  vue.config.js
│  yarn-error.log
│  yarn.lock
│
├─public
│      favicon.ico
│      index.html
│
|-- src
    |-- components
        |-- input
            |-- index.js
            |-- index.module.scss
    |-- pages
        |-- seller
            |-- components
                |-- input
                    |-- index.js
                    |-- index.module.scss
            |-- reducer.js
            |-- saga.js
            |-- index.js
            |-- index.module.scss
        |-- buyer
            |-- index.js
        |-- index.js


多页面目录结构

my-vue-test:.
│  .browserslistrc
│  .env.production
│  .eslintrc.js
│  .gitignore
│  babel.config.js
│  package-lock.json
│  package.json
│  README.md
│  vue.config.js
│  yarn-error.log
│  yarn.lock
│
├─public
│      favicon.ico
│      index.html
│
└─src
    ├─apis //接口文件根据页面或实例模块化
    │      index.js
    │      login.js
    │
    ├─components //全局公共组件
    │  └─header
    │          index.less
    │          index.vue
    │
    ├─config //配置(环境变量配置不同passid等)
    │      env.js
    │      index.js
    │
    ├─contant //常量
    │      index.js
    │
    ├─images //图片
    │      logo.png
    │
    ├─pages //多页面vue项目,不同的实例
    │  ├─index //主实例
    │  │  │  index.js
    │  │  │  index.vue
    │  │  │  main.js
    │  │  │  router.js
    │  │  │  store.js
    │  │  │
    │  │  ├─components //业务组件
    │  │  └─pages //此实例中的各个路由
    │  │      ├─amenu
    │  │      │      index.vue
    │  │      │
    │  │      └─bmenu
    │  │              index.vue
    │  │
    │  └─login //另一个实例
    │          index.js
    │          index.vue
    │          main.js
    │
    ├─scripts //包含各种常用配置,工具函数
    │  │  map.js
    │  │
    │  └─utils
    │          helper.js
    │
    ├─store //vuex仓库
    │  │  index.js
    │  │
    │  ├─index
    │  │      actions.js
    │  │      getters.js
    │  │      index.js
    │  │      mutation-types.js
    │  │      mutations.js
    │  │      state.js
    │  │
    │  └─user
    │          actions.js
    │          getters.js
    │          index.js
    │          mutation-types.js
    │          mutations.js
    │          state.js
    │
    └─styles //样式统一配置
        │  components.less
        │
        ├─animation
        │      index.less
        │      slide.less
        │
        ├─base
        │      index.less
        │      style.less
        │      var.less
        │      widget.less
        │
        └─common
                index.less
                reset.less
                style.less
                transition.less


小结

项目的目录结构很重要,因为目录结构能体现很多东西,怎么规划目录结构可能每个人有自己的理解,但是按照一定的规范去进行目录的设计,能让项目整个架构看起来更为简洁,更加易用

1.使用Vue Slots使代码易于理解

父子关系是组件之间相互连接的最常用方法之一,但有时这可能并不是最佳选择。想象一下,如果出现在单个父组件中有大量子组件的情况,那么可能就不得不使用大量道具和发出事件来处理这些子组件,很快一切会变得一团糟。

这就是在大型项目中将要面临的真实情况,不过,Vue.js可以提供针对此问题的现场解决方案。

我们可以在Vue.js中使用slots来提供表示父子关系的另一种方法,slots提供了将内容放置在新位置的渠道。slots的基本操作示例如下所示:

<div>
<slot></slot>
</div>

当上面的组件呈现的<slot> </ slot>标签将被demo-content替换时:

<demo-content>
<h2>Hi!</h2>
<class-name name="Welcome toVue!"></class-name>
</demo-content>

你可以在Vue项目中使用多种不同类型的slots。但最重要的一点是,当slots在增多时,项目也会随之受到巨大的影响,slots可以使得整个项目中的代码维持完整且易于理解。

2.建立并共享独立的组件

AddyOsmani:“有效构建‘大型'事物的秘诀通常是避免从一开始就抱着直接构建大型事物的想法。相反,可以用更小、更集中的作品来构成大型事物。这样一来,就更容易看到小的事物是如何组成大的事物的了。”

你可以遵循F.I.R.S.T原则,将自己的组件构建为:专注的、独立的、可重复使用的以及小型且可测试的。

还可以使用Bit(Github)之类的工具对每个项目的组件进行独立式源代码管理,并将其共享给Bit的组件中心。共享的组件、自动生成的文档和实时示例将一起显示在Bit的组件中心上。可以使用NPM进行安装或使用Bit对其进行“克隆”和修改,这会使查找、使用和维护组件变得更加容易(因此,也更易于维护项目)。

Vue components shared on Bit.dev

3.维护良好的VUEX仓库

Vuex是Vue.js中的状态管理模式,它负责应用程序中所有组件的集中存储功能。我看到有些评论说:“Vuex限制了开发人员根据需要构造项目”。但事实是,Vuex可以通过使用一组原则来帮助开发人员以更有条理的方式组织他们的项目。

在了解这些原理之前,首先应该先了解以下4个Vuex仓库中的主要组件:

· States:用于保存应用程序的数据

· Getters:用于访问仓库外部的状态对象

· Mutations:用于修改状态对象

· Actions:用于处理mutations

那么接下来看看需要遵循的原则:

· 需要将应用程序级别的状态集中在仓库中。

· states应始终通过处理mutations来进行改变。

· 异步逻辑应该被封装,并且只能与actions一起使用。

遵循这三个原则,项目就可以被顺利地组织出来,并且如果你觉得存储文件越来越大,可以将它们拆分成单独的文件。示例项目结构如下所示:

├── index.html

├── main.js

├── api

├── components

└── store

├── index.js

├── actions.js

├── mutations.js

└── modules

模块化VUEX仓库

本文中讨论的是大型项目,此类项目中的项目文件会非常大而复杂。你需要以自己的方式管理仓库,并且需要避免商店仓库,因此最好以易于他人理解的方式对Vuex仓库进行模块化。

在此我们没有定义项目中模块的定义方法,有些开发人员会根据功能进行模块化,有些则根据数据模型进行模块化。关于模块化的最终决定完全取决于你自己,这将对个人和团队有长期帮助。

store/

├── index.js

└── modules/

├── module1.store.js

├── module2.store.js

├── module3.store.js

├── module4.store.js

└── module5.store.js

使用助手来简化代码

前文提到了Vuex仓库中使用的4个组件。假设如果出现需要访问这些states、getters或需要调用actions或组件中的mutations的情况,那么无需创建多个计算属性或方法,就可以轻松使用辅助方法(mapState, mapGetters, mapMutations 和 mapActions)来减少代码。

来看看这四个辅助工具:

· mapState

如果需要在一个组件中调用多个存储状态属性或getters,就可以使用mapState帮助生成一个getter函数,这将大大减少代码行的数量。

import { mapState } from 'vuex'export default {
    computed: mapState({
        count: state => state.count,
        countAlias: 'count',
        countPlusLocalState (state) {
        		return state.count +this.localCount
        }
    })
}

· mapGetters

mapGetters可帮助将仓库getters映射到本地计算属性。

import { mapGetters } from 'vuex'export default {
    computed: {
      ...mapGetters([
        'count1',
        'getter1',
      ])
    }
}

· mapMutations

mapMutations可以用于帮助提交组件中的mutations,它将组件方法映射到store.commit调用。同样,也可以使用mapMutations传递有效载荷。

import { mapMutations } from 'vuex'export default {
methods: {
...mapMutations({
cal: 'calculate' // map`this.cal()` to `this.$store.commit('calculate')`
})
}
}
· mapActions

可以用于帮助在组件中分派操作,并将组件方法映射到store.dispatch调用。

import { mapActions } from 'vuex'export default {
methods: {
...mapActions({
cal: 'calculate' // map`this.cal()` to `this.$store.dispatch('calculate')`
})
}
}

4.不要忘记编写单元测试

测试在任何项目中都很重要。作为开发人员,无论项目的重要性或规模如何,我们都必须测试开发的内容。尤其是在涉及大型项目中,往往有成千上万的小型功能,因此我们有责任测试每个功能。

这就是单元测试的必要性,它可以使开发人员测试单个代码单元。单元测试不仅可以避免错误,而且每当开发人员进行更改时,修改的结果也可以提升开发团队对其工作的信心。随着项目的进行,开发人员可以从项目的开始就遵循良好的单元测试机制来添加新功能,不必担心会破坏其他功能。

在Vue.js中进行的单元测试与所有其他框架的单元测试方法大同小异,你可以轻松地将Jest,Karma或Mocha与Vue.js结合使用。尽管有测试框架,但是在编写单元测试时,还是有些需要记住的一般性事项:

· 编写单元测试以涵盖每个Vue组件。

· 测试必须提供清晰的失败错误消息ID。

· 使用良好的断言库。例如:在Jest框架中内置了断言库,Chai断言库与Mocha一起使用。

通过从项目开始就遵循这些步骤的方法,随着项目结构的发展,开发人员可以大大减少调试和手动测试所花费的时间。

除了单元测试之外,Vue.js与其他任何框架一样都支持E2E测试和集成测试。因此,你也可以将这些也结合到项目中。通常,路由部分不会使用单元测试进行测试,并且通过端到端测试进行覆盖。Vue仓库是最难测试的部分,对states,actions或getters的单独测试往往被认为是无用的,我推荐的方法是集成测试。

看看这优秀的技术能力,我认为Vue.js用于大规模项目完全没问题,它可以轻松地管理这些项目而不会造成混乱。

给大家分享我收集整理的各种学习资料,前端小白交流、学习交流,也可以直接问我,组织大家一起做项目练习,帮助大家匹配一位学习伙伴互相监督学习-下面是学习资料参考。

前端学习交流、自学、学习资料等推荐 - 知乎

最近发表
标签列表