1. 程式人生 > >是你需要的前端編碼風格嗎?

是你需要的前端編碼風格嗎?

  • 一、HTML
    • 1、基本原則
    • 2、class 命名規則
  • 二、CSS
    • 1、基本規則
    • 2、註釋
    • 3、邊框
    • 4、Sass
  • 三、JavaScript
    • 1、基本格式化
      • 1.1 縮排層級
      • 1.2 語句結尾
      • 1.3 行的長度
      • 1.4 換行
      • 1.5 命名
        • 1.5.1 變數和函式
        • 1.5.2 常量
        • 1.5.3 函式
        • 1.5.3 建構函式
    • 2、註釋
      • 2.1 單行註釋
      • 2.2 多行註釋
    • 3、語句和表示式
      • 3.1 所有的塊語句都應當使用花括號,包括
      • 3.2 語句和表示式 前後加空格
      • 3.2 switch 語句
      • 3.3 with 語句
      • 3.4 for 迴圈
      • 3.5 for-in 迴圈
    • 4、彙總
      • 4.1 物件
      • 4.2 陣列
      • 4.3 解構
      • 4.4 字串
      • 4.5 使用模板字串代替字串連線
      • 4.5 函式
      • 4.6 箭頭函式
      • 4.7 構造器
      • 4.8 模組
      • 4.9 比較運算子和等號
      • 4.10 空格
      • 4.11 分號
      • 4.12 型別轉換
  • 四、針對vue的程式碼風格
    • 1、專案結構(vue-cli 3.0)
    • 2、api 資料夾
    • 3、assets 資料夾
    • 4、router 路由
    • 5、vue 檔案
  • 其他風格指南
  • 參考文獻:

程式是寫給人讀的,只是偶爾讓計算機執行一下 -- Donald Knuth

以下程式碼風格僅供參考,沒有明確規定那種書寫方式好,那種書寫方式一定就不好,程式碼風格的統一,目的就是提高程式碼的可讀性。

一、HTML

1、基本原則

  • html(結構)、css(樣式)、js(樣式)分離
  • 標籤具有語義化
  • 2個空格字元為一個縮排層級,設定敲入 Tab 鍵時插入2個空格
  • 標籤名使用一律小寫字母,vue元件名必須使用小寫
  • 標籤需閉合,自閉合(self-closing)標籤,無需閉合 ( 例如: img input br hr 等 );
  • 不要使用id選擇器,class命名多個單詞采用中劃線-連線
  • 屬性按照特定的順序出現保證易讀性,idclassnamesrcfortypehreftitlealt
  • 禁止行內元素巢狀塊級元素
  • <!--放註釋內容-->獨佔一行

2、class 命名規則

  • 不能出現中文
  • 以字母開頭,不能使用其他格式開頭
  • 以名見義 命名需要有規範,有含義、可以快速的理解這個標籤的具體意義

很早以前收藏的表格,具體出處自己記不清了,如有侵權,可與本人聯絡,謝謝

命名 說明
.wrapper 頁面外圍控制整體佈局寬度
.container或.content 容器,用於最外層
.layout 佈局
.head, .header 頁頭部分
.foot, .footer 頁尾部分
.nav 主導航
.subnav 二級導航
.menu 選單
.submenu 子選單
.sideBar 側欄
.sidebar_a, .sidebar_b 左邊欄或右邊欄
.main 頁面主體
.tag 標籤
.msg .message 提示資訊
.tips 小技巧
.vote 投票
.friendlink 友情連線
.title 標題
.summary 摘要
.loginbar 登入條
.searchInput 搜尋輸入框
.hot 熱門熱點
.search 搜尋
.searchBar 搜尋條
.search_results 搜尋結果
.copyright 版權資訊
.branding 商標
.logo 網站LOGO標誌
.siteinfo 網站資訊
.siteinfoLegal 法律宣告
.siteinfoCredits 信譽
.joinus 加入我們
.partner 合作伙伴
.service 服務
.regsiter 註冊
arr/arrow 箭頭
.guild 指南
.sitemap 網站地圖
.list 列表
.homepage 首頁
.subpage 二級頁面子頁面
.tool, .toolbar 工具條
.drop 下拉
.dorpmenu 下拉選單
.status 狀態
.scroll 滾動
.tab 標籤頁
.left .right .center 居左、中、右
.news 新聞
.download 下載
.banner 廣告條(頂部廣告條)

二、CSS

1、基本規則

  • 使用 2 個空格作為縮排
  • 不要使用id選擇器,class命名多個單詞采用中劃線-連線
  • 在左大括號{前加上一個空格, 右大括號}獨佔一行
  • 在屬性的冒號:後面加上一個空格,前面不加空格

2、註釋

  • 建議使用行註釋 (在Sass中是//) 代替塊註釋。
  • 建議註釋獨佔一行。避免行末註釋。

3、邊框

在定義無邊框樣式時,使用0代替none

.nav {
  border: none;  
}

// good
.nav {
  border: 0;  
}

4、Sass

  • 使用.scss的語法,不使用.sass原本的語法。
  • 變數名使用駝峰命名$borderLine

三、JavaScript

1、基本格式化

1.1 縮排層級

2個空格字元為一個縮排層級,設定敲入 Tab 鍵時插入2個空格

1.2 語句結尾

語句結尾使用分號

1.3 行的長度

單行程式碼長度不超過80個字元

vscode配置如下:

{
  "editor.wordWrap": "wordWrapColumn",
  "editor.wordWrapColumn": 80
}

1.4 換行

當一行長度達到了單行最大字元數限制時,就需要手動將一行拆成兩行。通常我們會在運算子後換行,下一行會增加兩個層級的縮排。

1.5 命名

命名長度應儘可能短,並抓住重點,儘量在變數名中體現出值的資料型別。比如,命名 countlengthsize 表明資料型別是數字,而命名 nametitlemessage 表明資料型別是字串。但用單個字元命名的變數諸如i、j、和k通常在迴圈中使用。使用這些能夠體現出資料型別的命名,可以讓你的程式碼容易被別人和自己讀懂。

不要使用下劃線 _ 結尾或開頭來命名屬性和方法。

1.5.1 變數和函式

變數:遵守駝峰大小寫命名法,並且命名字首應當是名詞。

let count = 0;
let myName = 'sheng';
let visible = true;

函式:遵守駝峰大小寫命名法,並且命名字首應當是動詞。

function getName() {};

function setName() {};

使用動詞常見約定

動詞 含義
can 函式返回一個布林值
has 函式返回一個布林值
is 函式返回一個布林值
get 函式返回一個非布林值
set 函式用來儲存一個值

1.5.2 常量

常量: 必須使用 const 定義常量

const count = 10;
const url = 'http://baidu.com';

1.5.3 函式

  • 在控制語句( ifwhile 等)的小括號前放一個空格。在函式呼叫及宣告中,不在函式的引數列表前加空格。
// bad
function getName() {
    return userName;
}

// good
function getName() {
    return userName;
}
  • 別儲存 this 的引用。使用箭頭函式或 Function#bind。
// bad
function getName() {
    const self = this;
    return function() {
        console.log(self);
    }
}
// bad
function getName() {
    const that = this;
    return function() {
        console.log(that);
    };
}
// good
function getName() {
    return () => {
        console.log(this);
    };
}

1.5.3 建構函式

JavaScript 中,建構函式只不過是前面冠以new運算子的函式,用來建立物件

建構函式:遵照大駝峰命名法(Pascal Case)

function Person(name) {
    this.name = name
}

2、註釋

2.1 單行註釋

  • 縮排層級與下一行程式碼保持一致
  • 雙斜槓後敲入一個空格, 保持註釋文字有一定的偏移
  • 在程式碼行的尾部註釋,程式碼結束到註釋之間有一個縮排,超過單行最大字元限制,應移動當前程式碼行的上方。
// bad
//這是一個Person建構函式
function Person(name) {
    this.name = name
}

// good
// 這是一個Person建構函式
function Person(name) {
    this.name = name
}

// bad
const MAX_COUNT = 10; //這是一個常量

// good
const MAX_COUNT = 10; // 這是一個常量

2.2 多行註釋

// bad 註釋之前無空格
if (condition) {
    /**
     * 如果程式碼執行到這裡
     * 說明判斷條件成立,可以執行下面程式
     */
    console.log('Hello world!');
}

// bad 星號後無空格
if (condition) {

    /**
     *如果程式碼執行到這裡
     *說明判斷條件成立,可以執行下面程式
     */
    console.log('Hello world!');
}

// bad 錯誤的縮排
if (condition) {

    /**
     * 如果程式碼執行到這裡
     * 說明判斷條件成立,可以執行下面程式
     */
    console.log('Hello world!');
}

// good
if (condition) {

    /**
     * 如果程式碼執行到這裡
     * 說明判斷條件成立,可以執行下面程式
     */
    console.log('Hello world!');
}

3、語句和表示式

3.1 所有的塊語句都應當使用花括號,包括

  • if
  • for
  • while
  • do...while...
  • try...catch...finally
// bad
if (condition) console.log('Hello world!');

// good
if (condition) {
    console.log('Hello world!');
}

3.2 語句和表示式 前後加空格

// bad 前後無空格
if (condition) {
    doSomething();
} else {
    doElseSomething();
}

// good
if (condition) {
    doSomething();
} else {
    doElseSomething();
}

3.2 switch 語句

// bad
switch (condition) {
    case 0:
        console.log(0);
        break;
    case 1:
        console.log(1);
        break;
    default:
        console.log('default');
}

// good
switch (condition) {
    case 0:
        console.log(0);
        break;
    case 1:
        console.log(1);
        break;
    default:
        console.log('default');
}

3.3 with 語句

禁止使用with語句

3.4 for 迴圈

儘可能避免使用 continue

// bad
for (let i = 0; i < array.length; i++) {
    if (i === 2) {
        continue; // 跳過本次迭代
    };
    doSomething();
}

// good
for (let i = 0; i < array.length; i++) {
    if (i !== 2) {
        doSomething();
    };
}

3.5 for-in 迴圈

  • 必須使用 hasOwnProperty() 方法來為 for-in 迴圈過濾出例項屬性,除非想查詢原型鏈
  • 禁止使用 for-in 遍歷陣列
// bad
for (let k in obj) {
    console.log(obj[k]);
}

// good
for (let k in obj) {
    if (obj.hasOwnProperty(k)) {
        console.log(obj[k]);
    }
}

4、彙總

4.1 物件

  • 使用字面量建立物件
// bad
const obj = new Object();

// good
const obj = {};
  • 建立有動態屬性名物件時,使用可被計算的屬性名稱
function getKey(k) {
    return `a key name ${k}` ;
};

// bad
const obj = {
    id: 1,
    name: 'sheng'
};
obj[getKey('hidden')] = true;

// good
const obj = {
    id: 1,
    name: 'sheng',
    [getKey('hidden')] = true
}
  • 使用物件方法的簡寫
// bad
const obj = {
    name: 'sheng',
    setName: function(name) {
        return obj.name + name;
    }
}

// good
const obj = {
    name: 'sheng',
    setName(name) {
        return obj.name + name;
    }
}

4.2 陣列

  • 使用字面量建立陣列
// bad
const arr = new Array();

// good
const arr = [];
  • 使用擴充套件運算子 ... 複製陣列
// bad
let arr = [1, 2, 3];
let newArr = [];
for (let i = 0; i < arr.length; i++) {
    newArr[i] = arr[i];
};

// good
const newArry = [...arr];

4.3 解構

  • 使用解構存取和使用多屬性物件
// bad
function getUserInfo(user) {
    const userName = user.name;
    const userAge = user.age;
}

// good
function getUserInfo(user) {
    const {
        userName,
        userAge
    } = user;
}
  • 對陣列使用解構賦值
const arr = [1, 2, 3, 4];

// bad
const num0 = arr[0];
const num1 = arr[1];

// good
const [num0, num1] = arr;

4.4 字串

  • 字串使用單引號
// bad
const name = "sheng";

// good
const name = 'sheng';

4.5 使用模板字串代替字串連線

// bad
window.open(configService.domain + '/exportFile');

// good
window.open( `${configService.domain}/exportFile` );

4.5 函式

  • 使用函式宣告代替函式表示式
// bad
const getName = function() {

};

// good
function getName() {

}
  • 立即呼叫的函式
(() => {
    console.log('Hello world!');
})();
  • 不要使用arguments。可以使用rest語法 ... 替代
// bad
function getName() {
    const args = Array.prototype.slice.call(arguments);
    return args.join('')
}

// good
function getName(...args) {
    return args.join('');
}

4.6 箭頭函式

let arr = [1, 2, 3];

// bad
arr.map(function(x) {
    return x + 1;
})

// good
arr.map(x => {
    return x + 1;
})

// good
arr.map(x => x + 1);

4.7 構造器

  • 使用 class ,避免使用 prototype
// bad
function User(user) {
    this.userName = user.name
}
User.prototype.getName = function() {
    return this.userName;
}

// good
class User {
    constructor(user) {
        this.userNmae = user.name
    }
    getName() {
        return this.userName;
    }
}

4.8 模組

  • 使用( import / export )而不是其他模組系統, 除非特殊情況
// bad
const data = require('./data.js');
module.exports = data;

// good
import data from './data.js';
export default data;

4.9 比較運算子和等號

  • 優先使用 ===!== 而不是 ==!= ;
  • 條件表示式例如 if 語句通過抽象方法 ToBoolean 強制計算它們的表示式並且總是遵守下面的規則:
    • 物件被計算為 true
    • undefined 被計算為 false
    • null 被計算為 false
    • boolean 被計算為 boolean
    • 數字如果為+0、-0、或 NaN 被計算為 false , 否則為 true
    • 字串如果是空字串 '' 被計算為 false , 否則為 true
// bad
if (name !== '') {

}

// good
if (name) {

}

// bad
if (arr.length > 0) {

}

// good
if (arr.length) {

}

4.10 空格

  • 使用空格把運算子隔開
// bad 
const y = x + 1

// good
const y = x + 1;

4.11 分號

  • 使用分號
// bad
function getName() {}

// good
function getName() {};

4.12 型別轉換

// bad
const str = 0 + '';

// good
const str = String(0);

// bad
const num = +'4';

// good
const num = Number('4');

// bad
const b = new Boolean(0);

// good
const b = Boolean(0);

// good

const b = !!0;

四、針對vue的程式碼風格

僅適用於個人團隊,當然你也可以提出建議,一起交流學習。

1、專案結構(vue-cli 3.0)

以下示例專案結構適用於現階段的業務開發,後期根據業務場景可增刪,詳情個人github

src 資料夾

|-- api                          (請求介面的資料夾)   
    |-- rain-search
    |   |-- rian-search.js       (對應頁面的後端請求)
    |-- water-info
    |   |-- use-water-manage.js
    |   |-- use-water-search.js
|-- assets
|-- components                   (全域性通用元件)
|-- environments                 (環境配置,包括開發環境和生產環境)
    |-- environment.dev.js
    |-- environment.prod.js
|-- services
    |-- auth.service.js          (封裝和使用者授權相關函式)
    |-- config.service.js        (匯出開發環境和生成環境的配置項)  
    |-- request.service.js       (封裝axios,以及一些請求攔截)
|-- styles
    |-- element-ui.scss
    |-- index.scss
|-- utils                         (全域性通用的方法)
|-- views
    |-- errorPage
    |   |-- 404.vue
    |   |-- 401.vue
    |-- home
    |-- rain-search               (當前導航只有一級選單)
    |   |-- components            (只存放當前頁面使用的元件)
    |   |-- index.vue             (當前目錄的入口頁面,都命名index.vue)
    |-- water-info                (當前導航有二級選單)
    |   |-- use-water-manage
    |       |-- components
    |       |-- index.vue
    |   |-- use-water-search
    |       |-- components
    |       |-- index.vue
    |-- APP.vue
    |-- main.js
    |-- router.js
    |-- store.js
  • 頁面檔案不同單詞使用-連線符命名

2、api 資料夾

  • api資料夾中建立資料夾名稱要與views資料夾中頁面保持一致,方便快速頁面對應的後端介面
  • 匯出的檔名以Api作為字尾,可以明確檔案的作用, 如下:
import request from '../services/request.service';
const useWaterSearchApi = {
    getUserResources() {
        return request.get('/mock/getUserResources.json');
    }
};
export default useWaterSearchApi; // 以 Api作為字尾
  • 頁面引入介面名稱與匯出名稱保持一致

3、assets 資料夾

  • assets資料夾主要存放三個主要資料夾, 分別為fonts(字型)、images(圖片)、js(外部引入的js檔案)

4、router 路由

  • 路由的pathname值,是對應頁面檔案的駝峰命名, 有利於通過位址列找到對應的頁面

  • 頁面的一級和二級選單使用巢狀的children寫法
  • 路由物件新增meta物件, meta物件有兩個屬性,一個title是當前導航將要在頁面中顯示的名稱,另一個是hidden用來判斷是否在頁面顯示

示例

new Router({
  routes: [
    {
      path: '/',
      component: Home,
      redirect: '/rainSearch',
      meta: { title: '雨量查詢' },
      children: [
        {
          path: 'rainSearch',
          name: 'rainSearch',
          component: () => import('@/views/rain-search/index.vue'),
          meta: { title: '雨量查詢' }
        }
      ]
    },
    {
      path: '/waterInfo',
      component: Home,
      redirect: '/waterInfo/useWaterManage',
      meta: { title: '雨量資訊' },
      children: [
        {
          path: 'useWaterManage',
          name: 'useWaterManage',
          component: () => import('@/views/water-info/use-water-manage/index.vue'),
          meta: { title: '用水管理' }
        },
        {
          path: 'useWaterSearch',
          name: 'useWaterSearch',
          component: () => import('@/views/water-info/use-water-search/index.vue'),
          meta: { title: '用水查詢' }
        }
      ]
    },
    {
      path: '*',
      meta: { title: '404', hidden: true },
      component: () => import('@/views/errorPage/404')
    },
  ]
});

5、vue 檔案

  • 檔案結構總體安照templatejscss順序,
  • js檔案中,元件、屬性/狀態、生命週期、方法的順序,
  • 生命週期方法的順序依照執行順序排序
  • name以檔名命名
<template>
</template>
<script>
export default {
  name: 'use-water-search'
  components: {},
  props: {},
  filters: {},
  data () {
    return {}
  },
  computed: {},
  watch() {},
  beforeCreate () {},
  created () {},
  beforeMount () {},
  mounted () {},
  beforeUpdate () {},
  updated () {},
  beforeDestroy () {},
  destroyed () {},
  methods: {},
}
</script>
<style lang="scss" scoped>
</style>
  • 所有的引入的檔案字尾不要省略,如元件字尾.vue.js
  • 對引入的檔案.vue.js進行分組,.vue放在最前方,.js緊跟其後
import sideBar from './components/side-bar/side-bar.vue';
import navBar from './components/nav-bar/nav-bar.vue';
import useWaterSearchApi from '@/api/water-info/use-water-search.js'
  • css必須加上scoped屬性
  • 屬性按照特定的順序出現並換行保證易讀性,如下
 <el-pagination ref="pagination"
                class="bottom-pagination"
                layout="total, prev, pager, next"
                :current-page.sync="currentPage"
                :page-size="pageSize"
                :total="totalCount"
                @size-change="sizeChange"
                @current-change="handleCurrentChange"></el-pagination>
  • 引入檔案儘可能使用絕對路徑,當前頁面的元件使用相對路徑,這樣移動資料夾時,避免依賴檔案找不到

其他風格指南

  • Google JavaScript Style Guide
  • jQuery Core Style Guidelines
  • Principles of Writing Consistent, Idiomatic JavaScript

參考文獻:

  • 編寫可維護的JavaScript
  • yuche/javascript
  • css-style-guide