前言
在當今的前端開發領域,Vue.js 是極受歡迎的框架之一。其簡潔的語法和強大功能使得開發者能夠快速構建可維護、可擴展的應用。然而,隨著項目規模擴大,維護性和可讀性常常成為挑戰。此時,清晰、簡潔、易讀的代碼結構就顯得尤為重要。
這篇文章將分享幾個運用「Clean Code」的技巧來提升Vue.js開發質量。這些技巧不僅能幫助工程師寫出更高效、易於維護的代碼,還能提高團隊合作效率,讓代碼更具可讀性和可理解性,從而在長期開發過程中減少技術負擔、降低錯誤風險。
1. 使用Composition API(組合式 API)編寫程式
傳統的 Options API 元件,相信寫過Vue的大家都不陌生,在編寫小專案或剛起步時,可能會覺得這架構還不錯,變數在同一塊、函式在同一塊,但當專案架構開始變大時,使用的變數及函式越來越多,此時會漸漸覺得每次要找某一個相關聯的變數 & 函式時,它們好像散落在遠方。
Composition API 就可以做到「功能切割」,將同一功能相關的內容都集中在一個區塊,提高可讀性 及 維護性。

2. 遵守 Vue 命名規則
- 大駝峰 (PascalCase)
- 用於元件檔案名稱,應為多個單詞組合而成
- 可使用於 template 中,無底線,ex. LoginModal
- props中變數命名
1props: {2welcomeMessage: {3type: String,4default: '歡迎來到網站'5}6} - 烤串命名 (kebab-case)
- 可使用於 template 中,全使用橫線連接,ex. login-modal
- 父元素代入值至子元件時,需使用橫線連接
1<ChildComponent :welcome-message="嗨嗨" />
3. 多使用複用元件 及 搭配 Slot
‘複製’ & ‘貼上’,應是工程師做起來最舒暢的事情,當對一個專案越來越熟悉,一旦有新需求、新元件需要製作時,第一直覺會開始搜尋腦中資料庫,思考以前有沒有做過類似的功能和元件,找到後就會很快樂的複製貼上,再稍微小改一下符合需求。
以前的我的確也會這樣,只想在短時間內達成目的就好,但發現專案越來越大時,若需求改動頻率高,且同樣的代碼於不同頁出現的次數過高,對於維護者而言是滿滿的技術債。 幸好曾踩過這樣的坑,便養成非必要時,同質性極高的功能,能組合成元件複用,盡可能製成元件。
於Vue中製作元件,可採用slot
提昇其彈性,亦可於複用元件中,寫入document,以表明其用途,以下為一複用卡片元件實例:
1<template>2 <div class="card">3 <!-- Slot for the card header -->4 <header class="card-header">5 <slot name="header">我是標頭~</slot>6 </header>7
8 <!-- Slot for the card body -->9 <main main class="card-body">10 <slot name="body">最亮眼的卡片~</slot>11 </main>12
13 <!-- Slot for the card footer -->14 <footer class="card-footer">53 collapsed lines
15 <slot name="footer">地基是我</slot>16 </footer>17 </div>18</template>19
20<script lang="ts">21 /**22 * Card Component23 *24 * This component provides a flexible layout using named slots for the header, body, and footer sections.25 *26 * ## Usage:27 *28 * ```vue29 * <Card>30 * <template #header>31 * <h1>客製化標頭</h1>32 * </template>33 * <template #body>34 * <p>卡片內容寫於此</p>35 * </template>36 * <template #footer>37 * <button>點我點我</button>38 * </template>39 * </Card>40 * ```41 *42 * ## Slots:43 * - `header`: Slot for the card's header content (optional, defaults to "Default Header").44 * - `body`: Slot for the card's main content (optional, defaults to "Default Body").45 * - `footer`: Slot for the card's footer content (optional, defaults to "Default Footer").46 */47 export default {48 name: 'Card',49 };50</script>51
52<style scoped>53.card {54 border: 1px solid #ddd;55 border-radius: 8px;56 overflow: hidden;57 box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);58}59.card-header,60.card-footer {61 padding: 1em;62 background-color: #f5f5f5;63}64.card-body {65 padding: 1em;66}67</style>
4. 利用Composable,將共用邏輯抽出函式
與製作複用組件同樣的觀念,能不重複寫,盡可能抽出、封裝,使狀態與功能便於管理,當分析出接下來要開發的功能會重複使用於此專案,即可利用Composable函式,寫入共用邏輯,以減少重複的代碼。例如像時間轉換功能,於論壇內可能會需要顯示’剛剛’、‘2小時前’、‘昨天’、‘2024-11-29’…等非正規化的時間格式,因此可編寫複用函式,並於多個地方引入使用。
重點項:
- 文件名應以 use 開頭,例如
useContentWidthControl.ts
- Composable函式約定用PascalCase命名,並以”use”作為開頭,例如
useLinkList()
- 一定要於
setup()
或<script setup>
中使用,否則程式會報錯誤,就算Composable的函式還有包其它的Composable函式,也務必於function內進行引用。
5. 使用Lint維持代碼品質
ESLint
&Prettier
是編寫Code時的好夥伴,於團隊中協作時,每一位工程師多少會有自己的編寫習慣,例如雙引號 or 單引號、兩個空白為縮排 or 四個空白為縮排。一個專案除了邏輯上正確、精簡外,代碼的格式化也很重要,否則在維護、閱讀上會需要多花時間理解,可能還會造成誤解。- 也可將Linting加入CI/CD流程中,使之自動化檢測 & code review
- 而之前會常常遇到CI/CD時,因Linter沒通過而無法deploy新commit,因此找了自動化檢復的工具 - 搭配Husky。可於每次提交代碼前,自動執行檢查 & 修復。
pnpm install husky
- 配置 package.json,
scripts:"prepare": "husky install"
$ pnpm prepare
- 於.husky資料夾下新增
pre-commit
檔案,貼上以下內容:
1#!/usr/bin/env sh2. "$(dirname -- "$0")/_/husky.sh"34npx lint-staged- 接下來於每次commit時,系統即會採用
.eslintrc.js
配置的標準進行檢查
6. 保持Template簡潔
- 避免使用過於複雜的邏輯判斷於Template中,可免除將js & 網頁架構太常混雜一起,降低閱讀性,於後續的維護中即可於同一區塊進行更新。
- 若不將邏輯判斷寫於Template中,即可善用
Computed
方法,創建易可理解的函式名,納入邏輯判斷,也可重複使用此函式於多個地方。
不佳範例:
1<template>2 <div3 v-if="isLogin && !isManageOn && !hasFirstFloor"4 class="lg:hidden mt-4 py-5 border-y border-solid border-mean"5 :class="6 floorDataList.list.length === 1 &&7 floorDataList.list[0].isFavorite8 ? 'border-b-black'9 : ''10 "11 >12 <ToggleBtn />13 </div>14</template>
修正後範例:
1<script>2 const isShowToggleBtnBlock = computed(() => {3 return !isLogin.value && !isManageOn.value && !hasFirstFloor.value4 })5
6 const bottomBorderStyle = computed(() =>7 data.list.length === 1 && data.list[0].isFavorite ? 'border-b-black' : '')8</script>9
10<template>11 <div12 v-if="isShowToggleBtnBlock"13 class="lg:hidden mt-4 py-5 border-y border-solid border-mean"14 :class="bottomBorderStyle"15 >3 collapsed lines
16 <ToggleBtn />17 </div>18</template>
結語
以上是看過網路上其它人分享的文章後,篩選出自己其實滿需要的幾個要點,以及經歷過的一些專案經驗,再與大家分享,希望上述內容對讀者有所幫助。