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

NO IMAGE

詳見個人博客:shengchangwei.github.io/js-style/

程序是寫給人讀的,只是偶爾讓計算機執行一下 — 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

// bad
.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 name = user.name;
const age = user.age;
}
// good
function getUserInfo(user) {
const {
name,
name
} = 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.api.js       (對應頁面的後端請求)
|-- water-info
|   |-- use-water-manage.api.js
|   |-- use-water-search.api.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>
  • 引入文件儘可能使用絕對路徑,當前頁面的組件使用相對路徑,這樣移動文件夾時,避免依賴文件找不到

其他風格指南

參考文獻

相關文章

使用curator實現分佈式master選舉

Docker學習筆記(三)——Docker常用命令

繼HTML、CSS和JavaScript之後,WebAssembly正式成為Web的第四種語言

從一道面試題簡單談談發佈訂閱和觀察者模式