爲何個人代碼讓別人看起頭髮麻?

面試官:談談大家項目當中的前端代碼規範吧?css

本身先想一分鐘。html

爲何個人代碼讓別人看起頭髮麻?

前面的話前端

有些同窗在開發某個新功能時根據需求就哐哐哐(按照本身的代碼風格)一頓擼。寫完發現,另外一個地方也有這個模塊功能,可能只是標題的顏色,字體大小不對。怎麼辦? 因而很雞賊的複製粘貼過去,改吧改吧,提交代碼,萬事大吉!本身卻是爽了,功能是按照需求如期完成了啊,沒毛病。但是你卻忽視了一件很重要的東西: 團隊vue

記住,你不是一我的在寫代碼。node

這篇文章有別於其餘教程類的文章,不是教你如何制定代碼規範,也不是告訴你這樣寫就是錯的亦或說是正確的。本文是我這些天從優化別人代碼過程當中的所見和所得,凝結成文。旨在分享給你們,對號入座,而後改之。 三人行,必有我師!;擇其善者而從之,其不善者而改之。 因爲我是作前端的,因此只說前端代碼規範,其餘語言一樣適用!ios

目的git

把一些常見的錯誤的不良的代碼示例分享給你們,但願有的改之,無則加勉。看完以後,但願對大家有所幫助,提升本身的代碼質量,每一個人都能寫出一手漂亮的代碼。這是這篇文章最大的目的了!github

概述web

本文將以個人親身項目經歷爲例,來談談咱們平常開發當中,就代碼層面來說,咱們應該注意的一些小細節。但願各位看客能吸收精華去其糟粕。主要涉及的方面有:面試

  • 項目結構
  • 文件命名
  • 路由
  • 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 生成的,目錄結構和命名規範也就沒啥可說的。可能隨着時間的推移,本身會在項目里加一些東西(文件或文件夾)。拿上面咱們的項目爲例來講幾點吧:

  • 根目錄下不要有 css 文件 :好比 element-variables.css 文件,它屬於 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 的時候是否是也不方便? 並且我發現 problemManagement 和 problemRetrieve 都屬於問題管理模塊,徹底能夠合併到一個文件夾裏啊。還有,文件夾已經代表是問題管理模塊了,因此文件就不要再以 problem*** 開頭了。不以爲囉嗦嗎? 下面是整理事後的樣子:

problemManagement
│ ├── index.vue
│ ├── retrieve.vue
qualityCheckAppeal
 └── index.vue

複製代碼

3. 路由

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

userManagement
├── add.vue
└── update.vue

複製代碼

用戶管理下有增改兩個功能,不使用彈框去作的前提下,假如說 add 和 update 對應兩個路由是 /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

複製代碼

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>

複製代碼
  • 使用兩個空格(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 != null || userId != undefined) {
 // ...
}

複製代碼

真不知道怎麼想的,簡單一句話不就搞定了嗎?

if (userId) {
 // ...
}

複製代碼
  • 對象聲明不當問題

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

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

複製代碼
  • 異常處理問題

咱們在處理異步請求的時候,必定要對 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 代碼提交

你們能夠看我沸點。同事寫的註釋。但願有問題的同窗能夠及時改正哦。另外,關於 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"

複製代碼

總結

最後,給你們找了幾個大廠的團隊規範文檔,但願你看完可以受益多多:

  • Vue風格指南
  • 騰訊團隊文檔
  • Bootstrap編碼規範
  • isobar前端代碼規範 及 最佳實踐
  • 書寫具有一致風格、通俗易懂 JavaScript 的原則
  • eslint-rules

以上就是我在項目當中發現的一些問題,記錄下來,暫時就記錄這麼多吧。但願正好看d到這篇文章的你若是也正好有以上的不良問題,請加油改正哦。當你的代碼質量又提高一個檔次的時候,我相信,你離前端大神之門又 

相關文章
相關標籤/搜索