这些是我构建大型Vue项目得出的最佳实践,这些技巧将帮助你更高效的编码,而且使其更容易维护和协做。
在我今年的自由职业生涯中我有幸开发了一些大型Vue程序。我所说的这些项目使用了大量Vuex stores 😰 ,不少Vue组件(有数百个)和不少视图(pages)😄。对我而言这是很是有意义的经历,我发现了不少使扩展的方法。同时我还须要修复一些乱七八糟的错误用法。🍝javascript
因此我将分享个人10个最佳实践,若是你有大型项目须要开发推荐你使用他们。html
最近我写了一篇文章some important things you need to know regarding slots in Vue.js。 主要讲了为何使用Slots能够提升组件复用且易于维护。vue
🧐 可是这和大型Vue项目有啥关系呢。我将描绘一个使用他们解决你痛点的蓝图。java
假如我要开发一个popup。起初看起来没有什么难点,仅仅是包括标题,描述和一些按钮。 因此把全部东西都看成props不就完了吗。 我用了三个自定义props,而且click按钮的时候触发一个事件。 就是这么简单! 😅ios
随着项目的不断发展,业务须要显示许多其余新内容:表单字段,不一样的按钮(取决于显示在哪一个页面上)、卡片、页脚和列表。经过添加更多的props能够解决这个问题。😩可是随着业务发展,组件变的太复杂了。由于他包含了不少子组件,须要触发不少个事件。🌋我遇到了坑爹的问题,修改了一个功能后影响了其余page上的功能。我创造了一个怪物而不是一个可维护的组件!🤖git
可是,一开始使用slots可能会更好。最终我使小组件来重构这个组件。使他更容易维护、好理解、好扩展。github
<template> <div class="c-base-popup"> <div v-if="$slot.header" class="c-base-popup__header"> <slot name="header"> </div> <div v-if="$slot.subheader" class="c-base-popup__subheader"> <slot name="subheader"> </div> <div class="c-base-popup__body"> <h1>{{ title }}</h1> <p v-if="description">{{ description }}</p> </div> <div v-if="$slot.actions" class="c-base-popup__actions"> <slot name="actions"> </div> <div v-if="$slot.footer" class="c-base-popup__footer"> <slot name="footer"> </div> </div> </template> <script> export default { props: { description: { type: String, default: null }, title: { type: String, required: true } } } </script>
根据经验在我看来,由熟练使用slots的开发人员构建项目对未来项目的可维护性有更重要的意义。vuex
⚠️ 经验规则,当子组件中使用了父组件的props时,应该使用slots。
一般,一个新的Vue开发人员学习Vuex是由于两个问题:npm
这样他建立第一个Vuex store,学习moudles的用法而且组织程序时。💡
问题是建立modules时没有单一模式可循。我强烈建议必定要想清楚如何组织他们。据我所知,不少人更喜欢按照功能来组织他们(我也是:译者注)。例如:json
就我来讲,用从API得到的数据模型组织更容易理解。例子:
用那个取决于本身,可是从长远来看组织良好的Vuex store更具生产力。这样也容易是新人融入而且继承你的初衷。
个人大部分(不是所有)API调用都在Vuex的actions中,你必定想知道为何这样作。🤨
🤷🏼简单的说是由于拉取数据时须要在store中commit。还有就是他提供了我喜欢的封装和复用。其余缘由就是:
当你在组件中访问state/getters或者调用actions/mutations时一般须要建立多个计算属性。使用mapState,mapGetters,mapMutations和mapActions能够未来自store modules中的数据集中在一个地方,这样能够精简代码而且更好理解。
// NPM import { mapState, mapGetters, mapActions, mapMutations } from "vuex"; export default { computed: { // Accessing root properties ...mapState("my_module", ["property"]), // Accessing getters ...mapGetters("my_module", ["property"]), // Accessing non-root properties ...mapState("my_module", { property: state => state.object.nested.property }) }, methods: { // Accessing actions ...mapActions("my_module", ["myAction"]), // Accessing mutations ...mapMutations("my_module", ["myMutation"]) } };
你想要的这里都有Vuex官方文档。🤩
我一般会建立this.$api助手,能够在任何地方访问个人API入口。个人项目根目录有一个api
文件夹有个人全部类(以下)。
api ├── auth.js ├── notifications.js └── teams.js
每个都是一类接口的分组,这是我在Nuxt应用中使用插件的方式初始化。(和标准Vue应用程序中的过程很是类似)。
// PROJECT: API import Auth from "@/api/auth"; import Teams from "@/api/teams"; import Notifications from "@/api/notifications"; export default (context, inject) => { if (process.client) { const token = localStorage.getItem("token"); // Set token when defined if (token) { context.$axios.setToken(token, "Bearer"); } } // Initialize API repositories const repositories = { auth: Auth(context.$axios), teams: Teams(context.$axios), notifications: Notifications(context.$axios) }; inject("api", repositories); };
export default $axios => ({ forgotPassword(email) { return $axios.$post("/auth/password/forgot", { email }); }, login(email, password) { return $axios.$post("/auth/login", { email, password }); }, logout() { return $axios.$get("/auth/logout"); }, register(payload) { return $axios.$post("/auth/register", payload); } });
这样我能够方便的在组件或Vuex操做中调用他们,以下:
export default { methods: { onSubmit() { try { this.$api.auth.login(this.email, this.password); } catch (error) { console.error(error); } } } };
项目中定义了一些全局配置变量:
config ├── development.json └── production.json
我一般使用this.$config
获取,尤为是当我在模板中时。 一如既往扩展Vue对象很是容易:
// NPM import Vue from "vue"; // PROJECT: COMMONS import development from "@/config/development.json"; import production from "@/config/production.json"; if (process.env.NODE_ENV === "production") { Vue.prototype.$config = Object.freeze(production); } else { Vue.prototype.$config = Object.freeze(development); }
在项目发展的过程当中,常常须要关注组件的变动历史。若是团队中有人没有遵照commit惯例,那么将很难理解他们所作的事情。
我老是使用并推荐Angular commit message guidelines。我全部的项目中都会使用他,一般团队中的其余人也会发现他的好处。
遵照这些规则使commit更加可读,在查看项目历史时使得commit更加容易追踪。简言之,他是这样用的:
git commit -am "<type>(<scope>): <subject>" # Here are some samples git commit -am "docs(changelog): update changelog to beta.5" git commit -am "fix(release): need to depend on latest rxjs and zone.js"
看他们的README file更新更多。
我知道...全部软件包都应遵循 the semantic versioning rules.。但实际状况并不是如此。😅
为了不一个依赖影响了整个项目在半夜被拖起来,冻结全部程序包的版本可使你一觉睡到天明而且工做愉快。 😇
这很简单:避免以^开头的版本:
{ "name": "my project", "version": "1.0.0", "private": true, "dependencies": { "axios": "0.19.0", "imagemin-mozjpeg": "8.0.0", "imagemin-pngquant": "8.0.0", "imagemin-svgo": "7.0.0", "nuxt": "2.8.1", }, "devDependencies": { "autoprefixer": "9.6.1", "babel-eslint": "10.0.2", "eslint": "6.1.0", "eslint-friendly-formatter": "4.0.1", "eslint-loader": "2.2.1", "eslint-plugin-vue": "5.2.3" } }
在页面中显示多行或须要循环大量数据时,你已经注意到该页面渲染速度很快变慢。 要解决此问题,您可使用vue-virtual-scoller。
npm install vue-virtual-scroller
他只渲染列表中的可见项而且复用组件和dom元素,以使其尽量高效。 如此简单就像一个魔法! ✨
<template> <RecycleScroller class="scroller" :items="list" :item-size="32" key-field="id" v-slot="{ item }" > <div class="user"> {{ item.name }} </div> </RecycleScroller> </template>
多人合做一个项目时,若是没人关注安装的依赖包数量很快变的难以置信。为了不程序变慢(尤为是在移动网络环境),我这VSC中使用import cost package这样就能够编辑器中看到导入的包有多大,而且找出大的缘由。
例如在最近的项目中,导入了整个lodash库(压缩后24kB)。 有啥子问题? 仅仅使用cloneDeep方法。 经过import cost package找到了问题,咱们经过如下方式解决了该问题:
npm remove lodash npm install lodash.clonedeep
在使用的地方导入:
import cloneDeep from "lodash.clonedeep";
⚠️ 为了进一步优化,咱们还可使用Webpack Bundle Analyzer包经过树状图来可视化Webpack输出文件的大小。
在大型Vue项目中还有其余最佳实践吗? 请在下面的评论中告诉我,或者在Twitter @RifkiNada上与我联系。 🤠