建立和維護大型 Vue-js 項目的 10 個最佳實踐
這是我在使用大型代碼庫進行 Vue 項目時開發的最佳實踐。這些技巧將幫助您開發更有效的代碼,更易於維護和共享。
今年的自由職業生涯中,我有機會從事一些大型 Vue 應用程序的工作。我所談論的項目有超過 12 個 Vuex 存儲,大量組件(有時數百個)和許多視圖(頁面)。實際上,這對我來說是非常有意義的經歷,因爲我發現了許多有趣的模式來使代碼可擴展。我還必須修復一些導致著名的意大利麪條代碼難題的錯誤做法。🍝
因此,今天,我將與您分享 10 個最佳實踐,如果您要處理大量的代碼庫,我建議您遵循這些最佳實踐。
- 使用插槽(slot)使組件更易於理解並且功能更強大
我最近寫了一篇文章,介紹有關 Vue.js 中的插槽您需要了解的一些重要事項。它着重說明插槽如何使您的組件更可重用且更易於維護,以及爲什麼要使用它們。
🧐但是,這與大型 Vue.js 項目有什麼關係?一圖勝千言,所以我將爲您畫一張圖片,這是我第一次後悔不使用它們。
有一天,我只需要創建一個彈出窗口。乍一看,沒有什麼真正複雜的,只是包括標題,描述和一些按鈕。所以我要做的就是把所有東西都當作屬性。最後,我用了三個屬性來定製組件,當人們單擊按鈕時會發出一個事件。十分簡單!😅
但是,隨着項目的不斷髮展,團隊要求我們在其中顯示許多其他新內容:表單字段,不同的按鈕(取決於顯示在哪個頁面上),卡片,頁腳和列表。我發現,如果我繼續使用屬性來使這個組件不斷擴展,似乎也可以。但是上帝,😩我錯了!該組件很快變得太複雜了,以至於無法理解,因爲它包含了無數的子組件,使用了太多的屬性併發出了大量事件。🌋我經歷了一種可怕的情況,當您在某處進行更改時,它最終以某種方式破壞了另一頁上的其他內容。我搞了個科學怪人的怪物,而不是一個可維護的組件!🤖
但是,如果我從一開始就依賴插槽,情況可能會更好。最後,我重構了所有東西以提供這個小組件。易於維護,更快地理解並且可擴展性更高!
<template>
<div class="c-base-popup">
<div v-if="$slots.header" class="c-base-popup__header">
<slot >
</div>
<div v-if="$slots.subheader" class="c-base-popup__subheader">
<slot >
</div>
<div class="c-base-popup__body">
<h1>{{ title }}</h1>
<p v-if="description">{{ description }}</p>
</div>
<div v-if="$slots.actions" class="c-base-popup__actions">
<slot >
</div>
<div v-if="$slots.footer" class="c-base-popup__footer">
<slot >
</div>
</div>
</template>
<script> export default {
props: {
description: {
type: String,
default: null
},
title: {
type: String,
required: true
}
}
} </script>
我的觀點是,根據經驗,由知道何時使用插槽的開發人員構建的項目確實對其未來的可維護性有很大的影響。這樣就可以減少發出事件的次數,使代碼更易於理解,並且可以在內部顯示所需的任何組件時提供更大的靈活性。
⚠️作爲一個經驗法則,請記住,當最終在子組件的父組件中複製子組件的屬性時,應該從這一點開始使用插槽。
- 正確組織您的 Vuex 存儲
通常,新的 Vue.js 開發人員開始學習 Vuex,因爲他們偶然發現了以下兩個問題:
-
他們要麼需要從樹結構中實際上相距太遠的另一個組件訪問給定組件的數據,要麼
-
他們需要數據在組件銷燬後繼續存在。
那是他們創建第一個 Vuex 存儲,瞭解模塊並開始在應用程序中進行組織的時候。💡
問題是創建模塊時沒有單一模式可以遵循。但是,👆🏼我強烈建議您考慮如何組織它們。據我瞭解,大多數開發人員都喜歡按功能組織它們。例如:
-
驗證碼
-
博客
-
收件箱
-
設定
就我而言,我發現根據它們從 API 提取的數據模型來組織它們時更容易理解。例如:
-
用戶數
-
隊伍
-
留言內容
-
小部件
-
文章
您選擇哪一個取決於您。唯一要記住的是,從長遠來看,組織良好的 Vuex 存儲將使團隊更具生產力。這也將使新來者更容易在加入您的團隊時就將您的想法圍繞您的代碼庫。
- 使用操作(Vuex Actions)進行 API 調用和提交數據
我的大多數 API 調用(如果不是全部)都在我的 Vuex 操作(vuex actions)中進行。您可能想知道:爲什麼這裏調用更好?🤨
僅僅因爲它們中的大多數都提取了我需要在存儲(vuex store)中提交的數據。此外,它們提供了我真正喜歡的封裝性和可重用性。我這樣做還有其他一些原因:
-
如果我需要在兩個不同的地方(例如博客和首頁)獲取文章的首頁,則可以使用正確的參數調用適當的調度程序。數據將被提取,提交和返回,除了調度程序調用外,沒有重複的代碼。
-
如果我需要創建一些邏輯來避免在提取第一頁時提取它,則可以在一個地方進行。除了減少服務器上的負載之外,我還有信心它可以在任何地方使用。
-
我可以在這些操作 (vuex actions) 中跟蹤我的大多數 Mixpanel 事件,從而使分析代碼庫真正易於維護。我確實有一些應用程序,其中所有 Mixpanel 調用都是在操作中單獨進行的。當我不必瞭解跟蹤什麼不跟蹤什麼以及何時發送時,😂這種方式工作會給我帶來有多大的快樂。
譯註:Mixpanel 是一家數據跟蹤和分析公司,允許開發者跟蹤各種用戶行爲,比如用戶瀏覽的頁面數,iPhone 應用分析,Facebook 應用互動情況,以及 Email 分析。類似 Firebase 一樣的埋點分析工具。
- 使用 mapState,mapGetters,mapMutations 和 mapAction 簡化代碼庫
當您只需要訪問 state/getter 或在組件內部調用 action/mutation 時,通常無需創建多個計算屬性或方法。使用mapState
,mapGetters
,mapMutations
和mapActions
可以幫助你縮短你的代碼,通過分組來化繁爲簡,從你存儲裏模塊一個地方就能掌握全局。
// 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 官方文檔中提供了您在這些便捷幫助器上所需的所有信息。🤩
- 使用 API 工廠
我通常喜歡創建一個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);
};
的 JavaScript
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);
}
});
的 JavaScript
現在,我可以簡單地在我的組件或 Vuex 操作中調用它們,如下所示:
export default {
methods: {
onSubmit() {
try {
this.$api.auth.login(this.email, this.password);
} catch (error) {
console.error(error);
}
}
}
};
的 JavaScript
- 使用 $config 訪問您的環境變量(在模板中特別有用)
您的項目可能在某些文件中定義了一些全局配置變量:
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);
}
- 遵循一個約定來寫提交註釋
隨着項目的發展,您將需要定期瀏覽組件的提交歷史記錄。如果您的團隊沒有遵循相同的約定來書寫他們的提交說明,那麼將很難理解每個團隊成員的行爲。
我總是使用並推薦 Angular 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 文件以瞭解更多約定。
- 始終在生產項目時凍結軟件包的版本
我知道... 所有軟件包都應遵循語義版本控制規則。但實際情況是,其中一些並非如此。😅
爲避免因您的一個依賴項在半夜醒來破壞了整個項目,鎖定所有軟件包的版本會使您的早晨工作壓力減輕。😇
它的意思很簡單:避免使用以^
開頭的版本:
{
"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 虛擬滾動條
當您需要在給定頁面中顯示很多行或需要循環訪問大量數據時,您可能已經注意到該頁面的呈現速度很快。要解決此問題,可以使用 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>
的 HTML
- 跟蹤第三方程序包的大小
當很多人在同一個項目中工作時,如果沒有人關注它們,那麼已安裝軟件包的數量會迅速增加,令人難以置信。爲了避免您的應用程序變慢(尤其是在移動網絡變慢的情況下),我在 Visual Studio Code 中使用了導入費用包。這樣,我可以從編輯器中直接看到導入的模塊庫有多大,並且可以查看導入的模塊庫過大時出了什麼問題。
例如,在最近的項目中,導入了整個 lodash 庫(壓縮後大約 24kB)。問題在於,項目裏僅僅使用 cloneDeep 一個方法。通過在導入費用包中識別此問題後,我們通過以下方式解決了該問題:
npm remove lodash
npm install lodash.clonedeep
然後可以在需要的地方導入 clonedeep 函數:
import cloneDeep from "lodash.clonedeep";
的 JavaScript
爲了進一步優化,您還可以使用 Webpack Bundle Analyzer 軟件包通過交互式可縮放樹狀圖來可視化 Webpack 輸出文件的大小。
處理大型 Vue 代碼庫時,您還有其他最佳實踐嗎?請在下面的評論中告訴我,或者在 Twitter @RifkiNada 上與我聯繫。🤠
關於作者
娜達 · 裏基(Nada Rifki)
Nada 是一位 JavaScript 開發人員,他喜歡使用 UI 組件來創建具有出色 UX 的界面。她專門研究 Vue.js,喜歡分享任何可以幫助她的前端 Web 開發人員的東西。Nada 還涉足數字營銷,舞蹈和中文領域。
本文:Yujiaao
來自:https://segmentfault.com/a/1190000040712187
譯自:https://www.telerik.com/blogs/all-you-need-to-know-about-slots-in-vuejs
最後
歡迎關注【前端瓶子君】✿✿ヽ (°▽°) ノ✿
回覆「算法」,加入前端編程源碼算法羣,每日一道面試題(工作日),第二天瓶子君都會很認真的解答喲!
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/XHQ8aNZqMWwFbcAeN34tww