您當前位置: 南順網絡>> 官方資訊>> 行業動態

[Vue進階]為什么我的代碼讓別人看起來頭皮發麻?

前面的話

首先我想說的是,這篇文章不是介紹什么高深的技術,請各位熟知。涉及的都是日常開發當中一些不符合規范的案例,借此分享給諸位。如果你是小白,或許這篇文章對你有點幫助,如果你是老司機,看完請輕點拍!有什么建議或意見請留言斧正,謝謝!

有些同學在開發某個新功能時根據需求就哐哐哐(按照自己的代碼風格)一頓擼。寫完發現,另一個地方也有這個模塊功能,可能只是標題的顏色,字體大小不對。怎么辦? 于是很雞賊的復制粘貼過去,改吧改吧,提交代碼,萬事大吉!自己倒是爽了,功能是按照需求如期完成了啊,沒毛病??墒悄銋s忽視了一件很重要的東西:團隊。

記住,你不是一個人在寫代碼。

這篇文章有別于其他教程類的文章,不是教你如何制定代碼規范,也不是告訴你這樣寫就是錯的亦或說是正確的。本文是我這些天從優化別人代碼過程中的所見和所得,凝結成文。旨在分享給大家,對號入座,然后改之。三人行,必有我師??;擇其善者而從之,其不善者而改之。 由于我是做前端的,所以只說前端代碼規范,其他語言同樣適用!

目的

把一些常見的錯誤的不良的代碼示例分享給大家,希望有的改之,無則加勉??赐曛?,希望對你們有所幫助,提高自己的代碼質量,每個人都能寫出一手漂亮的代碼。這是這篇文章最大的目的了!

概述

本文將以我的親身項目經歷為例,來談談我們日常開發當中,就代碼層面來講,我們應該注意的一些小細節。希望各位看客能吸取精華去其糟粕。主要涉及的方面有:

  • 項目結構

  • 文件命名

  • 路由

  • Vue 組件

  • JavaScript

  • Html

  • Css

  • Git 代碼提交

我將會從以上幾個方面逐一枚舉和大家分享討論。

枚舉

1. 項目結構

沒說之前,您不妨看下自己的項目結構是什么樣的。目前我們的項目結構是這樣的:

my-project ├── .idea                  # 這個是編輯器生成的 ├── build                  # Webpack 配置文件放在這里 ├── config                 # Vue 基本配置文件放在這里 ├── node_modules           # 第三方依賴 ├── src                    # 項目源碼(核心文件) │   ├── assets             # 資源文件(js, css, scss) │   ├── components         # 所有組件 │   ├── js                 # 自己寫的 js,里面各種工具類方法等 │   ├── mixins             # 混合 │   ├── router             # 路由 │   ├── vuex               # 狀態管理 │   ├── App.vue            # 根組件 │   └── main.js            # 入口文件 ├── static                 # 靜態資源,一般放 img ├── theme                  # 主題文件,修改的 Element-UI 主題 ├── .babelrc               # babel 編譯配置 ├── .editorconfig          # 代碼格式 ├── .gitignore             # Git 提交忽略的文件配置 ├── .postcssrc.js          # 轉換 css 的工具配置文件 ├── element-variables.css  # Element 全局定義的變量,不明白為啥放這兒 ├── index.html             # 主頁模板 ├── package-lock.json      # 用來鎖定依賴的版本號(NPM 自動生成) ├── package.json           # 項目基本信息 └── README.md              # 項目介紹 復制代碼

都是用 vue-cli 生成的,目錄結構和命名規范也就沒啥可說的??赡茈S著時間的推移,自己會在項目里加一些東西(文件或文件夾)。拿上面我們的項目為例來說幾點吧:

  • 根目錄下不要有 css 文件

比如 element-variables.css 文件,雖然這個文件是 Element自定義主題 自動生產的,但是可以通過配置更換生成所在目錄。因為它屬于 theme 文件夾下的東西,所以應該放它下面的。

  • js 文件夾應該命名為 utils

因為它對外暴露的都是工具類方法,這樣更顯語義化。

關于項目結構,我發現的就這么多。每個項目的目錄可能會不同,這個就看你們的規范了。

2. 文件的命名

它包含文件的命名和文件夾的命名。依我們的項目為例,我重點說下 src/components 目錄下的命名,真的是五花八門:

2.1. 文件名不夠語義化


這個還算正常,但還是有些問題。這里是一些問題清單:


  • 這個模塊的中文叫,是關于機器人學習的,叫 knowledgeBaseManagement 雖然很好的翻譯了中文意思,但總覺的有點長,叫 robot 會不會好些?

  • 而且文件夾下的文件命名也不夠語義化

下面是整理過后的樣子:

robot ├── addQuestion.vue ├── editQuestion.vue ├── index.vue └── missedQuestion.vue 復制代碼


文件命名


這個我就不想說了,看的我頭皮發麻。從字面意思上來講,我就認識一個 TreeNode2.vue。后面還加個 2 是什么鬼?

2.2. 文件目錄不統一


文件命名文件命名文件命名


這屬于一類問題,即里面太亂了,不統一,問題清單:

  • src/components/moduleName/ 下除了子模塊外,盡量不要瞎放其他無關的文件夾,如上面的 src、component/common、top

  • callcenterList/src 下的圖片可以放到 static

  • 如果是功能型組件(上面的 color 是一個顏色選擇器組件),盡量放到一個叫 package 或者 lib 的文件夾下。因為  src/components 下的模塊都是系統模塊,不要混淆。

  • elvesSetting/top 如果是某幾個頁面頭部的公共部分盡量放到 components/common

2.3. 文件名過長


文件命名


如果一個模塊下就一個文件,盡量寫成 index.vue 。這里文件夾和文件同名,路由是不是很長?你在其他文件中 import 的時候是不是也不方便? 而且我發現 problemManagementproblemRetrieve 都屬于問題管理模塊,完全可以合并到一個文件夾里啊。還有,文件夾已經表明是問題管理模塊了,所以文件名就不要再以 problem*** 開頭了。不覺得啰嗦嗎? 下面是整理過后的樣子:

problemManagement │   ├── index.vue │   ├── retrieve.vue qualityCheckAppeal     └── index.vue 復制代碼

3. 路由

我們系統里的路由都是一級路由。舉個栗子:

userManagement ├── add.vue └── update.vue 復制代碼

用戶管理下有增改兩個功能,不使用彈框去做的前提下,假如說 addupdate 對應兩個路由是 /addUser,/updateUser。我們系統地址欄是這樣顯示的:

// 增加用戶 localhost:3030/addUser // 修改用戶 localhost:3030/updateUser?id=1 復制代碼

雖然地址欄路由短看起來會讓人舒服,但是模塊多的話,就不容易區分,其實應該這樣做:

// 增加用戶 localhost:3030/user/add // 修改用戶 localhost:3030/user/update?id=1 ... // 總結 localhost:3030/module/function?queryString 復制代碼

當然也可以使用最近流行的 RESTful API 設置規范,專門用于 Web 數據結構的設置。阮一峰老師有一篇非常不錯的文章,推薦給大家,我就不再贅述辣。傳送門->

4. Vue 組件

關于 Vue 組件開發規范可以參考官方的風格指南。下面是我們項目的一些問題清單和改正意見,我列舉一下作為對照:

  • 不要在 App.vue 中直接修改第三方樣式(比如:ElementUI)。請使用外部文件導入:

App.vue 文件:

<!-- incorrect --> ... <style>   .el-input__icon {     cursor: pointer   } </style> <!-- correct --> ... <style>   @import 'element-style-overwrite';   ... </style> 復制代碼

_element-style-overwrite.scss 外部樣式文件:

.el-input__icon {   cursor: pointer } 復制代碼
  • 給每個組件起個名字是個好習慣。例如 Dialog 組件:

// incorrect export default {   ... } // correct export default {   name: 'MyDialog', // 以大駝峰命名   ... } 復制代碼
  • 給組件樣式設置作用域 scoped

如果你在某個子組件中修改了全局樣式,本來只想在該組件中使用,沒想到造成了全局污染。等進行代碼 review 的時候是很難排查的。

例如,用戶管理(UserManagement.vue)組件:

<style scoped> ... </style> 復制代碼
  • 組件名要么單詞大寫開頭 (PascalCase),要么橫線連接(kebab-case):

// incorrect components/ └── mycomponent.vue components/ └── myComponent.vue // correct components/ └── MyComponent.vue // 或者 components/ └── my-component.vue 復制代碼
  • .vue 單文件中的 <template>、<script>、<style> 標簽的順序問題

有的人喜歡這樣寫:

<style>...</style> <template>...</template> <script>...</script> 復制代碼

也有人喜歡這樣寫:

<script>...</script> <style>...</style> <template>...</template> 復制代碼

如果你想寫,那好,不阻攔,拜托你統一下行不?別這個組件這個順序,那個組件那個順序。累不累? 這里我強力推薦大家按照官方的寫法,即下面的順序來寫:

<template>...</template> <script>...</script> <style scoped>...</style> 復制代碼
  • 組件中的字體圖標(icon)不要用 png 圖片

不知道你們項目里有沒有很多 icon 圖標。反正我們項目不少且都是 png 圖片。靜態文件夾里好多小圖標。本來左側菜單也都是 png 圖標的,被我看著不爽重構了一下。把所有的 png 圖標換成了 fontIcon 字體。

字體圖標的優勢:

  • 減少 http 請求和項目體積

  • 樣式容易控制

  • 用戶體驗好

如何制作 fontIcon 字體圖標呢?其實很簡單:

  • 1、可以先去阿里圖庫找自己喜歡的或者讓你自己家的UI小姐姐做。

  • 2、下載 svg 格式的,如果是UI做的,記得讓她轉換下。

  • 3、去 icomoon 字體圖標生成網站導入剛才所有的 svg 圖標,設置字體名稱導出即可。

  • 4、再在文件中引用,大功告成。

  • 使用兩個空格(space)進行縮進

這個放在全局規范會比較好一些。為什么是兩個空格? 大神們都是這樣做的!而且更重要的是,使用兩個空格開發項目,傳到 github 或者 gitlab 上排版會很好看。什么?不會設置?百度??!你用的什么編輯器就查這個編輯器怎么設置的。

一般是統一把全局規范設置放到一個叫 .editorconfig 的文件夾里,有的編輯器支持這個文件,比如:webstorm。有的則不支持,對于不支持的編輯器,可以下載安裝 editorConfig 插件,如:atom、sublime、vscode 等。

  • 代碼中不用的注釋都刪掉

  • 調試結束,把不用的 console.log(...) 及時刪掉,它會影響性能

  • data 中的屬性命名和初始化問題

// incorrect export default {   data () {     return {       text: 'wwwwwwww', // 這是啥?       editBoxId: null, // 很明顯Id是String,這里他初始化一個 null       flag: '',    // 這個表示的啥?看意思應該是個 Boolean 類型,為啥弄個 String ?       pSize: 10,   // pSize 是啥?       cPage: 1,    // cPage 是啥?       popCsr:true, // popCsr 是啥,恐怕現在連那個開發者自己都不知道了吧       callcenterAuthority: false, // 這么長你告訴是一個 Boolean 類型的     }   } } // correct export default {   data () {     return {       text: '', // 'wwwwwwww' 沒卵用刪掉       editBoxId: -1,  // 它應該是個 Number 類型       flag: false,    // 它應該是個 Boolean 類型啊       pageSize: 10,   // pSize -> pageSize 多好       currentPage: 1, // 完整寫法更易懂,不是嗎?       isPopcsr: true,    // Boolean 類型的總是前面加個 is       isAuthority: false, // 是否授權。     }   } } 復制代碼

其實還有好多問題,我就不一一列舉了。諸如此類的問題,希望各位看客們都能吸取精華,去其糟粕。

  • Props 中的屬性聲明要明確類型

// incorrect export default {   props: ['node', 'size'] } // correct export default {   props: {     node: Object, // 對象     size: [String, Number], // 兩種類型都可以   } } 復制代碼
  • Vue 生命周期函數按順序放在 methods 之前

為什么說這個呢? 我們項目中有的組件就 methods 中的代碼就上千行。如果生命周期函數放在 methods 之后,拉來拉去非常不方便:

// incorrect export default {   ...   created () {},   methods: {     // 省略 1000 行代碼     // ...   },   mounted () {},   beforeDestroy () {},   destroy () {}, } // correct export default {   ...   created () {},   mounted () {},   beforeDestroy () {},   destroy () {},   methods: {     // 省略 1000 行代碼     // ...   } } 復制代碼
  • Vue 組件中的 this 賦值要統一

代碼中,有時候我們需要把 this 賦給一個變量,你要么統一賦值給變量 vm ,要么統一賦值給變量 self。別一個組件里,變來變去。

// incorrect export default {   ...   methods: {     one () {      let vm = this     },     two () {       let self = this     }   } } // incorrect export default {   ...   methods: {     one () {      let vm = this      // 或者      let self = this     },     two () {       let vm = this       // 或者       let self = this     }   } } 復制代碼
  • Vue 組件中 Html 如果過長,請換行

<!-- incorrect --> <el-input v-model="ruleForm.maskInput" size="small" class="nodeIpt" :icon="ruleForm.maskInput ? 'circle-close':''"  @click="ruleForm.maskInput = ''" @keyup.enter.native="nodesure($event,'ruleForm')"></el-input> <!-- correct --> <el-input    v-model="ruleForm.maskInput"    size="small"    class="nodeIpt"    :icon="ruleForm.maskInput ? 'circle-close':''"     @click="ruleForm.maskInput = ''"    @keyup.enter.native="nodesure($event,'ruleForm')"> </el-input> 復制代碼
  • Vue 中監聽的事件記得垃圾回收

舉個例子,如果我們在 Vue 組件的 created 聲明周期鉤子中監聽了一個點擊事件,那么,當組件銷毀(beforeDestroy)之前記得把這個事件釋放,看代碼:

export default {   ...   created () {     document.addEventListener('click', this.handleClick)   },   beforeDestroy () {     document.removeEventListener('click', this.handleClick)   } } 復制代碼
  • Vue 組件中不要直接操作異步請求(axios)

把所有的異步請求方法封裝成一個獨立 js 文件,或者放到 Vuex 中,千萬不要耦合到 Vue 組件中。因為代碼量太多,會加重組件的后期維護,各司其職不好嗎?

不好的范例:

// User.vue export default {   ...   mounted () {     this.getUsers()   },   methods: {     getUsers () {       this.axios(url, data, (response) => {         // Do something       }).catch(err => {         console.error(err)       })     }   } } 復制代碼

如果項目比較小還好,我沒意見,如果項目較復雜,千萬別這么干。下面是推薦的做法:

// server.js // 專門處理數據請求的文件,也就是我沒常說的MVC中的 M 層 import axios from 'axios' export default {   /**    * 獲取用戶列表    */    getUsers (url, data) {       return axios.get(url, data)    } } // User.vue import api from '@/api/server.js' export default {   ...   data () {     return {       users: null     }   },   mounted () {     api.getUsers((response) => {       this.users = response.data.data     }).catch(err => {       console.log(err)     })   } } 復制代碼

5. JavaScript

下面所有的錯誤代碼示例都是從我們的項目中發現的,撿主要的列出來一些。希望犯同樣錯誤的你能及時改正哦~

  • 變量命名

要語義化命名

// incorrect var a = document.getElementById(this.lastid) // 這里的 a var aa = true // 這是啥你們知道嗎? // corrent let orderId = this.order.id let currentTime = Date.now() 復制代碼
  • 多個單詞要駝峰命名

// incorrent vm.timedefault = timedvalue vm.currentsessionid = id // corrent vm.timeDefault = timedValue vm.currentSessionId = id 復制代碼
  • 變量要加注釋


不加注釋上面那一坨你們知道啥意思嗎?如果這個開發人員離職了,那可是坑了后來人了。所以,做開發不能自己爽了,做一個帥氣和代碼于一身的工程師,難道不更好嗎?


  • 不要重復使用 var 聲明變量

// incorrect var name = 'test'; var age = 12; var hobby = 'sport'; // correct var name = 'test',   age  = 12,  hobby = 'sport'; 復制代碼
  • === 之間要保留一個空格

錯誤的范例:

// 變量 var name='test' var arr=[] var obj={   id:1 } // if 判斷 if(this.id==currentId){   // Do something } // for 循環 for(let i=0;i<arr.length;i++){   // Do something } 復制代碼

上面三種情況是最常見的,其他雷同。下面是正確的范例:

// 變量 var name = 'test' var arr = [] var obj = {   id: 1 } // if 判斷 if(this.id == currentId) {   // Do something } // for 循環 for(let i = 0; i < arr.length; i++) {   // Do something } 復制代碼
  • 右括號 ) 遇到 左大括號 { 時要空一格

下面是錯誤的范例:

// if if(a === b){   // Do something } // for for(let i = 0; i < arr.length; i++){...} // 函數 var T = function(params){   ... } 復制代碼

常見的幾種情況,其他情況不再列舉。下面是正確的范例:

// if if (a === b) {   // Do something } // for for (let i = 0; i < arr.length; i++) {...} // 函數 var T = function(params) {   ... } 復制代碼
  • 非空判斷問題

在我們項目里,有人這樣寫:

// 假如 Vue 組件中有一個叫 userId 的 data 屬性 if (userId != '' || userId != 0 || userId != false || userId != null || userId != undefined) {   // ... } 復制代碼

當遇到上面幾種情況的時候,下面代碼實現的效果是一樣的:

if (!userId) {   // ... } 復制代碼
  • 對象聲明問題

不要用下面的方式之一去聲明一個對象:

// incorrect var arr = new Array() // 數組 var arr = '' // 雖然 js 是弱類型,也不能這樣聲明 var obj = new object() // 對象 var obj = '' 復制代碼

下面是推薦做法,也是大眾做法:

// 聲明數組 let arr = [] // 聲明對象 let obj = {}  // or let obj = null 復制代碼
  • 異常處理問題

我們在處理異步請求的時候,一定要對 response 中的數據進行異常處理,不然控制臺回報 response.data is not undefined,我們項目我看了下,有些地方沒做處理,結果在做測試的時候,瀏覽器控制臺一頓報錯。那叫一個難看??!

// incorrect this.axios(url, data, (response) => {   let result = response.data.data }) // correct this.axios(url, data, (response) => {   if (response.data && response.data.code === 1) {     let result = response.data.data   } }).catch(err => {   console.error(err) }) 復制代碼
  • 如果這個取值過長且多次用到,請賦給一個變量

export default {   ...   methods: {     handleClick (evt) {       // incorrect       evt.target.parentNode.innerHTML = 'test'       evt.target.style.width = '100px'       evt.target.style.height = '200px'              // correct       let target = evt.target       target.parentNode.innerHTML = 'test'       target.style.width = '100px'       target.style.height = '200px'     }   } } 復制代碼

6. HTML

  • 正確的使用標簽

項目中我見有人寫個按鈕居然用 span 標簽,或者一個 div 。

下面是錯誤的范例:

// 用 div 當按鈕 <div class="btn">搜索</div> // 在 span 里 嵌套 el-input 組件 // 這樣做的同學,肯定不知道 el-input 編譯后的代碼是啥樣的! <span>   <el-input></el-input> </span> // 用 label 當標題 // label 標簽是配合表單使用的 <label>標題</label> // 加粗字體沒有用原生標簽 <span class="bold">我是加粗字體</span> 復制代碼

下面是改正后的范例:

// 用 H5 的 button <button class="btn">搜索</button> // 如果要包含 el-input 組件請使用塊級元素,并加上合適的 class <div class="el-input__wrapper">   <el-input></el-input> </div> // h1-h6 才是標題的正確打開方式 <h2>標題</h2> // 加粗字體請使用原生標簽 // 然后使用 class 控制字體樣式 <strong class="bold">我是加粗字體</strong> 復制代碼
  • 所有的按鈕,超鏈接,鼠標的 :hover 狀態都應該是手形。

a, button {   cursor: pointer } 復制代碼
  • id 和 class 或者其他的屬性,命名要語義化

不要命個名只有你自己知道。這樣會帶來后期維護困難。

<!-- incorrect --> <div class="dfdf">   <el-form class="loginForm">...</el-form> </div> <!-- correct --> <div class="login-form__wrapper">   <el-form class="loginForm">...</el-form> </div> 復制代碼
  • 把代碼縮進改成 2 個空格

  • Html 中的屬性之間保留一個空格距離

<!-- incorrect --> <el-input v-model="form.loginUser"  size="small"   placeholder="請輸入用戶名"></el-input> <!-- 不覺的上面的代碼很丑嗎,我知道你或許不會這樣做 --> <!-- 但還真有人這樣做 --> <!-- 下面是改進后的代碼 --> <el-input v-model="form.loginUser" size="small" placeholder="請輸入用戶名"></el-input> 復制代碼
  • 每個代碼快盡量加上注釋

代碼量少尚且不說,如果一個 .vue 文件很長的話,找起來就很痛苦了。你還別說,我們項目里就是這樣沒注釋。

<!-- 正確的示范 --> <template>   <div class="user-managerment__wrapper">     <!-- Header -->     <div class="header">...</div>          <!-- User table -->     <div class="user-table__wrapper">       <el-table>...</el-table>     </div>          <!-- Add user dialog -->     <div class="add-user__dialog">       <el-dialog title="新增用戶">...</el-dialog>     </div>   </div> </template> 復制代碼

7. CSS

  • { 和選擇器保持一個空格距離

.selector {   ... } 復制代碼
  • 給每個樣式模塊加上注釋有助于區分

// Global style html, body, a, div {   margin: 0 } // Login style .login button {   ... } // User manager style .user-manager__wrapper {   ... } 復制代碼
  • 每個獨立樣式間保留一行距離

見上面的示例

  • 選擇器不要嵌套太多層級

嵌套太多層級會影響性能,盡量保證在三層以下:

// incorrect .user-management .user-box .user-form .el-form-item .remark {   color: #42b983 } // correct .user-management .user-form .remark {   color: #42b983 } 復制代碼

8. Git 代碼提交

  • 提交前先 pull 代碼

寫代碼前記得先 pull 下別人的代碼,這是個好習慣。別等到自己寫完 push 后才發現代碼有沖突。

# pull git pull # modified git add someFiles git commit -m "..." git push 復制代碼
  • 寫好提交注釋

大家可以看我 沸點。同事寫的注釋。希望有問題的同學可以及時改正哦。另外,關于 Git 如何正確的寫好注釋,這里有幾篇文章講的很好,大家可以看看:

下面舉個例子,比如我這次在用戶管理模塊中修改了兩個 bug。如何以清單的方式提交呢? 看代碼:

# add file git add src/components/userManager/index.vue # commit git commit -m 'fix: 用戶管理模塊bug修改。 修改內容: - 修改了列表分頁的bug - 修改了當用戶點擊編輯按鈕彈框無法顯示的bug ' # push code git push 復制代碼

你千萬別用下面的方式之一去提交你的代碼說明:

# 說一些毫無意義的內容 git commit -m "fix: ok!" # or 不加 fix、feat、refactor、doc、style等前綴 # 為什么要加這些前綴呢?問得好! # 是方便日后檢索,當我們以這些前綴去搜索修改日志的時候 # 是很容易的哦,微笑。 git commit -m "修改用戶模塊bug"


編輯:--ns868