一簡(jiǎn)介
- 此規(guī)范基于腳手架vue-cli3.+
- 從編寫(xiě)IDE,到項(xiàng)目結(jié)構(gòu),命名規(guī)范,代碼風(fēng)格,包括代碼邏輯等,都做了說(shuō)明
二更新日志
1.00.20190423
- 修訂人:癮
- 編寫(xiě)vue項(xiàng)目的開(kāi)發(fā)規(guī)范1.00.20190423版本(初步版本)
- 版本號(hào)規(guī)則:1 大版本記錄, .00 小版本記錄, .20190423 更新時(shí)間
三項(xiàng)目結(jié)構(gòu)
3.1目錄結(jié)構(gòu)
├── node_modules // 依賴包
├── public // 靜態(tài)資源目錄不會(huì)被webpack編譯
├── src
│ ├── assets // 存放公共圖片阁吝,css迈窟,js
│ ├────└── images
│ ├────└── style
│ ├────└── js
│ ├── components // 非路由組件目錄
│ ├────└── common // 非路由組件的全局公共組件
│ ├── router // 路由目錄
│ ├────└── index.js // 路由入口,只負(fù)責(zé)入口,路由鉤子账磺,不負(fù)責(zé)具體的路由代碼
│ ├────└── route // 路由文件夾撕阎,其下分模塊拜隧,對(duì)路由進(jìn)行管理
│ ├── service // 請(qǐng)求數(shù)據(jù)層文件
│ ├────└── api // 接口定義層文件阵苇,分模塊去定義
│ ├────└── request.js // (axios)請(qǐng)求封裝層,包括請(qǐng)求攔截
│ ├────└── env.js // 全局公共url的配置文件
│ ├── store // vuex
│ ├────└── modules // 開(kāi)啟命名空間洲拇,分模塊處理
│ ├────└── index.js // vuex入口文件
│ ├── views // 路由組件奈揍,分模塊曲尸,其模塊與非路由組件中一一對(duì)應(yīng)
│ ├── directive // 全局自定義指令層
│ ├── filtres // 全局自定義過(guò)濾層
│ ├── App.vue // 項(xiàng)目路由入口
│ ├── main.js // 入口文件
│ ├── .env.development // 開(kāi)發(fā)環(huán)境變量
│ ├── .env.production // 生產(chǎn)環(huán)境變量
│ ├── .env.test // 測(cè)試環(huán)境變量
│ ├── .eslintrc.js // eslint配置
│ ├── .gitignore // git忽略文件
│ ├── package.json // 安裝文件
│ ├── babel.config.js // babel配置
│ ├── postcss.config.js // css-loader配置
│ ├── readme.md // 項(xiàng)目介紹
│ ├── vue.config.js // 額外webpack配置
3.2運(yùn)行編譯命令
"scripts": {
"serve": "vue-cli-service serve --mode development",
"build": "vue-cli-service build --mode production",
"build:test": "vue-cli-service build --mode test",
"lint": "vue-cli-service lint"
},
環(huán)境變量配置
.env.development
NODE_ENV=development
VUE_APP_ENV=development
.env.production
NODE_ENV=production
VUE_APP_ENV=production
.env.test
NODE_ENV=production
VUE_APP_ENV=test
四代碼風(fēng)格
4.1代碼縮進(jìn)
四個(gè)空格縮進(jìn)
4.2代碼順序及要求
<template>
<ul>
<li @click=""></li>
<li :style=""></li>
<li>{{ data }}</li>
</ul>
</template>
<script>
export default{
name: 'TodoItem',
data() {
return {
// 定義的每個(gè)data 屬性必須有注釋?zhuān)⑨屢?guī)則: //
}
},
props: {
id: {
default: '',
type: String
}
},
components: {},
beforeRouteEnter() {},
beforeRouteUpdate() {},
beforeRouteLeave() {},
beforeCreate() {},
created() {},
beforeMount() {},
mounted() {},
beforeUpdate() {},
updated() {},
beforeDestroy() {},
destroyed() {},
watch: {},
computed: {},
directives: {},
filter: {},
methods: {
//方法調(diào)用不需要注釋?zhuān)椒ǘx需要注釋
// 方法注釋規(guī)則 /** */
}
}
</script>
<style lang="scss" scoped></style>
五命名規(guī)范
5.1文件夾命名
文件夾命名采用小駝峰命名
5.2組件命名
組件名為多個(gè)單詞
組件名應(yīng)該始終是多個(gè)單詞的,且大駝峰命名男翰,根組件 App 除外另患。
正例:
export default {
name: 'TodoItem',
// ...
}
反例:
export default {
name: 'Todo',
// ...
}
單文件組件文件的大小寫(xiě)
單文件組件的文件名應(yīng)該要始終是單詞大寫(xiě)開(kāi)頭 (PascalCase)
正例:
components/
|- MyComponent.vue
反例:
components/
|- myComponent.vue
|- mycomponent.vue
基礎(chǔ)組件名
應(yīng)用特定樣式和約定的基礎(chǔ)組件 (也就是展示類(lèi)的、無(wú)邏輯的或無(wú)狀態(tài)的組件) 應(yīng)該全部以一個(gè)特定的前綴開(kāi)頭蛾绎,比如 Base昆箕、App 或 V。
正例:
components/
|- BaseButton.vue
|- BaseTable.vue
|- BaseIcon.vue
反例:
components/
|- MyButton.vue
|- VueTable.vue
|- Icon.vue
單例組件名
只應(yīng)該擁有單個(gè)活躍實(shí)例的組件應(yīng)該以 The 前綴命名租冠,以示其唯一性为严。
這不意味著組件只可用于一個(gè)單頁(yè)面,而是每個(gè)頁(yè)面只使用一次肺稀。這些組件永遠(yuǎn)不接受任何 prop,因?yàn)樗鼈兪菫槟愕膽?yīng)用定制的应民,而不是它們?cè)谀愕膽?yīng)用中的上下文话原。如果你發(fā)現(xiàn)有必要添加 prop,那就表明這實(shí)際上是一個(gè)可復(fù)用的組件诲锹,只是目前在每個(gè)頁(yè)面里只使用一次繁仁。
正例:
components/
|- TheHeading.vue
|- TheSidebar.vue
反例:
components/
|- Heading.vue
|- MySidebar.vue
緊密耦合的組件名
和父組件緊密耦合的子組件應(yīng)該以父組件名作為前綴命名。
如果一個(gè)組件只在某個(gè)父組件的場(chǎng)景下有意義归园,這層關(guān)系應(yīng)該體現(xiàn)在其名字上黄虱。因?yàn)榫庉嬈魍ǔ?huì)按字母順序組織文件,所以這樣做可以把相關(guān)聯(lián)的文件排在一起庸诱。
正例:
components/
|- TodoList.vue
|- TodoListItem.vue
|- TodoListItemButton.vue
components/
|- SearchSidebar.vue
|- SearchSidebarNavigation.vue
反例:
components/
|- SearchSidebar.vue
|- NavigationForSearchSidebar.vue
組件名中的單詞順序
組件名應(yīng)該以高級(jí)別的 (通常是一般化描述的) 單詞開(kāi)頭捻浦,以描述性的修飾詞結(jié)尾。
正例:
components/
|- SearchButtonClear.vue
|- SearchButtonRun.vue
|- SearchInputQuery.vue
|- SearchInputExcludeGlob.vue
|- SettingsCheckboxTerms.vue
|- SettingsCheckboxLaunchOnStartup.vue
反例:
components/
|- ClearSearchButton.vue
|- ExcludeFromSearchInput.vue
|- LaunchOnStartupCheckbox.vue
|- RunSearchButton.vue
|- SearchInput.vue
|- TermsCheckbox.vue
模板中的組件名大小寫(xiě)
總是 PascalCase 的
正例:
<!-- 在單文件組件和字符串模板中 -->
<MyComponent/>
反例:
<!-- 在單文件組件和字符串模板中 -->
<mycomponent/>
<!-- 在單文件組件和字符串模板中 -->
<myComponent/>
完整單詞的組件名
組件名應(yīng)該傾向于完整單詞而不是縮寫(xiě)桥爽。
正例:
components/
|- StudentDashboardSettings.vue
|- UserProfileOptions.vue
反例:
components/
|- SdSettings.vue
|- UProfOpts.vue
組件文件
只要有能夠拼接文件的構(gòu)建系統(tǒng)朱灿,就把每個(gè)組件單獨(dú)分成文件。
當(dāng)你需要編輯一個(gè)組件或查閱一個(gè)組件的用法時(shí)钠四,可以更快速的找到它盗扒。
正例:
components/
|- TodoList.vue
|- TodoItem.vue
反例:
Vue.component('TodoList', {
// ...
})
Vue.component('TodoItem', {
// ...
})
5.3路由命名
path使用全小寫(xiě),多個(gè)單詞用 - 分開(kāi)缀去,name與path保持一致
先寫(xiě)name侣灶,再寫(xiě)path,component缕碎,meta
正例:
{
name: "home-detail",
path: "/home-detail",
component: () => import("@/views/HomeDetail"),
meta: {}
}
反例:
{
name: "homeDetail",
path: "/HomeDetail",
component: () => import("@/views/HomeDetail"),
meta: {}
}
5.4請(qǐng)求命名
所有定義的接口以api開(kāi)頭小駝峰命名褥影,盡量語(yǔ)義化,不要簡(jiǎn)寫(xiě)
正例:
export const apiHomeList = (pageInfo)=>ajax('/web/app/list.do',{pageInfo})
反例:
export const homeList = (pageInfo)=>ajax('/web/app/list.do',{pageInfo})
5.5class命名
Class 和 ID 的命名應(yīng)該語(yǔ)義化阎曹,通過(guò)看名字就知道是干嘛的栅贴;全部小寫(xiě),多個(gè)單詞用連接線 - 連接
正例:
.test-header{
font-size: 20px;
}
反例:
.testheader{
font-size: 20px;
}
5.6其他命名
以上規(guī)則沒(méi)有提到的統(tǒng)一采用小駝峰命名坛缕,語(yǔ)義化宠页,不簡(jiǎn)寫(xiě)
六代碼邏輯
6.1props定義
props 定義應(yīng)該盡量詳細(xì)俭嘁。
在你提交的代碼中捕虽,prop 的定義應(yīng)該盡量詳細(xì)晌端,至少需要指定其類(lèi)型梧奢。
正例:
props: {
status: String
}
// 更好的做法惦蚊!
props: {
status: {
type: String,
required: true,
validator: function (value) {
return [
'syncing',
'synced',
'version-conflict',
'error'
].indexOf(value) !== -1
}
}
}
反例:
props: ['status']
6.2循環(huán)和判斷
為v-for設(shè)置鍵值
總是用 key 配合 v-for。
在組件上總是必須用 key 配合 v-for,以便維護(hù)內(nèi)部組件及其子樹(shù)的狀態(tài)阅嘶。甚至在元素上維護(hù)可預(yù)測(cè)的行為惋耙,比如動(dòng)畫(huà)中的對(duì)象固化 (object constancy),也是一種好的做法蜂奸。
正例:
<ul>
<li
v-for="todo in todos"
:key="todo.id"
>
{{ todo.text }}
</li>
</ul>
反例:
<ul>
<li v-for="todo in todos">
{{ todo.text }}
</li>
</ul>
循環(huán)
for (var i = 0; i < arr.length; i++) {} 這樣的方式遍歷不是很好,尤其當(dāng) arr 是 Dom 對(duì)象的時(shí)候,這樣就會(huì)一直在訪問(wèn) Dom 層襟铭,訪問(wèn) Dom 層的代價(jià)是很大的漠嵌。for (var i = 0, j=arr.length; i < j; i++) {} 這樣的方式去用循環(huán)是比較好的植阴,只會(huì)訪問(wèn)一次 Dom 層(不適用于 Dom 節(jié)點(diǎn)會(huì)動(dòng)態(tài)更新的場(chǎng)景)。
避免 v-if 和 v-for 用在一起
永遠(yuǎn)不要把 v-if 和 v-for 同時(shí)用在同一個(gè)元素上狸捕。
一般我們?cè)趦煞N常見(jiàn)的情況下會(huì)傾向于這樣做:
為了過(guò)濾一個(gè)列表中的項(xiàng)目 (比如 v-for="user in users" v-if="user.isActive")喷鸽。在這種情形下,請(qǐng)將 users 替換為一個(gè)計(jì)算屬性 (比如 activeUsers)灸拍,讓其返回過(guò)濾后的列表做祝。
為了避免渲染本應(yīng)該被隱藏的列表 (比如 v-for="user in users" v-if="shouldShowUsers")。這種情形下鸡岗,請(qǐng)將 v-if 移動(dòng)至容器元素上 (比如 ul, ol)剖淀。
正例:
<ul v-if="shouldShowUsers">
<li
v-for="user in users"
:key="user.id"
>
{{ user.name }}
</li>
</ul>
反例:
<ul>
<li
v-for="user in users"
v-if="shouldShowUsers"
:key="user.id"
>
{{ user.name }}
</li>
</ul>
在 v-if/v-if-else/v-else 中使用 key
如果一組 v-if + v-else 的元素類(lèi)型相同,最好使用 key (比如兩個(gè)
<div>
元素)纤房。
正例:
<div
v-if="error"
key="search-status"
>
錯(cuò)誤:{{ error }}
</div>
<div
v-else
key="search-results"
>
{{ results }}
</div>
反例:
<div v-if="error">
錯(cuò)誤:{{ error }}
</div>
<div v-else>
{{ results }}
</div>
6.3多個(gè)特性的元素
多個(gè)特性的元素應(yīng)該分多行撰寫(xiě)纵隔,每個(gè)特性一行。
正例:
<img
src="https://vuejs.org/images/logo.png"
alt="Vue Logo"
>
<MyComponent
foo="a"
bar="b"
baz="c"
/>
反例:
<img src="https://vuejs.org/images/logo.png" alt="Vue Logo">
<MyComponent foo="a" bar="b" baz="c"/>
6.4computed
模板中簡(jiǎn)單的表達(dá)式
組件模板應(yīng)該只包含簡(jiǎn)單的表達(dá)式,復(fù)雜的表達(dá)式則應(yīng)該重構(gòu)為計(jì)算屬性或方法捌刮。
復(fù)雜表達(dá)式會(huì)讓你的模板變得不那么聲明式碰煌。我們應(yīng)該盡量描述應(yīng)該出現(xiàn)的是什么,而非如何計(jì)算那個(gè)值绅作。而且計(jì)算屬性和方法使得代碼可以重用芦圾。
正例:
<!-- 在模板中 -->
{{ normalizedFullName }}
// 復(fù)雜表達(dá)式已經(jīng)移入一個(gè)計(jì)算屬性
computed: {
normalizedFullName: function () {
return this.fullName.split(' ').map(function (word) {
return word[0].toUpperCase() + word.slice(1)
}).join(' ')
}
}
反例:
{{
fullName.split(' ').map(function (word) {
return word[0].toUpperCase() + word.slice(1)
}).join(' ')
}}
簡(jiǎn)單的計(jì)算屬性
正例:
computed: {
basePrice: function () {
return this.manufactureCost / (1 - this.profitMargin)
},
discount: function () {
return this.basePrice * (this.discountPercent || 0)
},
finalPrice: function () {
return this.basePrice - this.discount
}
}
反例:
computed: {
price: function () {
var basePrice = this.manufactureCost / (1 - this.profitMargin)
return (
basePrice -
basePrice * (this.discountPercent || 0)
)
}
}
6.5引號(hào)
帶引號(hào)的特性值
非空 HTML 特性值應(yīng)該始終帶引號(hào) (單引號(hào)或雙引號(hào),優(yōu)先使用 "" , JS 優(yōu)先使用 '' )俄认。
在 HTML 中不帶空格的特性值是可以沒(méi)有引號(hào)的个少,但這樣做常常導(dǎo)致帶空格的特征值被回避,導(dǎo)致其可讀性變差眯杏。
正例:
<AppSidebar :style="{ width: sidebarWidth + 'px' }">
反例:
<AppSidebar :style={width:sidebarWidth+'px'}>
在js中
在js不再使用雙引號(hào)夜焦,靜態(tài)字符串使用單引號(hào),動(dòng)態(tài)字符串使用反引號(hào)銜接岂贩。
正例:
const foo = '后除'
const bar = `${foo}茫经,前端工程師`
反例:
const foo = "后除"
const bar = foo + ",前端工程師"
6.6指令縮寫(xiě)
都用指令縮寫(xiě) (用 : 表示 v-bind: 和用 @ 表示 v-on:)
正例:
<input
@input="onInput"
@focus="onFocus"
>
反例:
<input
v-bind:value="newTodoText"
:placeholder="newTodoInstructions"
>
6.7scoped
元素選擇器應(yīng)該避免在 scoped 中出現(xiàn)萎津。
在 scoped 樣式中卸伞,類(lèi)選擇器比元素選擇器更好,因?yàn)榇罅渴褂迷剡x擇器是很慢的锉屈。
正例:
<template>
<button class="btn btn-close">X</button>
</template>
<style scoped>
.btn-close {
background-color: red;
}
</style>
反例:
<template>
<button>X</button>
</template>
<style scoped>
button {
background-color: red;
}
</style>
6.8隱性的父子組件通信
應(yīng)該優(yōu)先通過(guò) prop 和事件進(jìn)行父子組件之間的通信荤傲,而不是 this.$parent 或改變 prop。
正例:
Vue.component('TodoItem', {
props: {
todo: {
type: Object,
required: true
}
},
template: `
<input
:value="todo.text"
@input="$emit('input', $event.target.value)"
>
`
})
反例:
Vue.component('TodoItem', {
props: {
todo: {
type: Object,
required: true
}
},
methods: {
removeTodo () {
var vm = this
vm.$parent.todos = vm.$parent.todos.filter(function (todo) {
return todo.id !== vm.todo.id
})
}
},
template: `
<span>
{{ todo.text }}
<button @click="removeTodo">
X
</button>
</span>
`
})
6.9全局狀態(tài)管理
應(yīng)該優(yōu)先通過(guò) Vuex 管理全局狀態(tài)颈渊,而不是通過(guò) this.$root 或一個(gè)全局事件總線弃酌。
正例:
// store/modules/todos.js
export default {
state: {
list: []
},
mutations: {
REMOVE_TODO (state, todoId) {
state.list = state.list.filter(todo => todo.id !== todoId)
}
},
actions: {
removeTodo ({ commit, state }, todo) {
commit('REMOVE_TODO', todo.id)
}
}
}
<!-- TodoItem.vue -->
<template>
<span>
{{ todo.text }}
<button @click="removeTodo(todo)">
X
</button>
</span>
</template>
<script>
import { mapActions } from 'vuex'
export default {
props: {
todo: {
type: Object,
required: true
}
},
methods: mapActions(['removeTodo'])
}
</script>
反例:
// main.js
new Vue({
data: {
todos: []
},
created: function () {
this.$on('remove-todo', this.removeTodo)
},
methods: {
removeTodo: function (todo) {
var todoIdToRemove = todo.id
this.todos = this.todos.filter(function (todo) {
return todo.id !== todoIdToRemove
})
}
}
})
6.10關(guān)于es6
6.10.1塊級(jí)作用域
(1)let 取代 var
S6 提出了兩個(gè)新的聲明變量的命令:let和const。其中儡炼,let完全可以取代var激况,因?yàn)閮烧哒Z(yǔ)義相同虱疏,而且let沒(méi)有副作用,不存在變量提升。
(2)全局常量和線程安全
在let和const之間矢赁,建議優(yōu)先使用const豌研,尤其是在全局環(huán)境妹田,不應(yīng)該設(shè)置變量,只應(yīng)設(shè)置常量鹃共。
- const優(yōu)于let有幾個(gè)原因鬼佣。一個(gè)是const可以提醒閱讀程序的人,這個(gè)變量不應(yīng)該改變霜浴;另一個(gè)是const比較符合函數(shù)式編程思想晶衷,運(yùn)算不改變值,只是新建值,而且這樣也有利于將來(lái)的分布式運(yùn)算晌纫;最后一個(gè)原因是 JavaScript 編譯器會(huì)對(duì)const進(jìn)行優(yōu)化税迷,所以多使用const,有利于提高程序的運(yùn)行效率锹漱,也就是說(shuō)let和const的本質(zhì)區(qū)別箭养,其實(shí)是編譯器內(nèi)部的處理不同。
- const聲明常量還有兩個(gè)好處哥牍,一是閱讀代碼的人立刻會(huì)意識(shí)到不應(yīng)該修改這個(gè)值毕泌,二是防止了無(wú)意間修改變量值所導(dǎo)致的錯(cuò)誤。
- 所有的函數(shù)都應(yīng)該設(shè)置為常量嗅辣。
- 長(zhǎng)遠(yuǎn)來(lái)看撼泛,JavaScript 可能會(huì)有多線程的實(shí)現(xiàn)(比如 Intel 公司的 River Trail 那一類(lèi)的項(xiàng)目),這時(shí)let表示的變量辩诞,只應(yīng)出現(xiàn)在單線程運(yùn)行的代碼中坎弯,不能是多線程共享的,這樣有利于保證線程安全译暂。
6.10.2字符串
靜態(tài)字符串一律使用單引號(hào)或反引號(hào)抠忘,不使用雙引號(hào)。動(dòng)態(tài)字符串使用反引號(hào)外永。
// bad
const a = "foobar";
const b = 'foo' + a + 'bar';
// acceptable
const c = `foobar`;
// good
const a = 'foobar';
const b = `foo${a}bar`;
6.10.3解構(gòu)賦值
使用數(shù)組成員對(duì)變量賦值時(shí)崎脉,優(yōu)先使用解構(gòu)賦值。
const arr = [1, 2, 3, 4];
// bad
const first = arr[0];
const second = arr[1];
// good
const [first, second] = arr;
函數(shù)的參數(shù)如果是對(duì)象的成員伯顶,優(yōu)先使用解構(gòu)賦值囚灼。
// bad
function getFullName(user) {
const firstName = user.firstName;
const lastName = user.lastName;
}
// good
function getFullName(obj) {
const { firstName, lastName } = obj;
}
// best
function getFullName({ firstName, lastName }) {
}
如果函數(shù)返回多個(gè)值,優(yōu)先使用對(duì)象的解構(gòu)賦值祭衩,而不是數(shù)組的解構(gòu)賦值灶体。這樣便于以后添加返回值,以及更改返回值的順序掐暮。
// bad
function processInput(input) {
return [left, right, top, bottom];
}
// good
function processInput(input) {
return { left, right, top, bottom };
}
const { left, right } = processInput(input);
6.10.4對(duì)象
單行定義的對(duì)象蝎抽,最后一個(gè)成員不以逗號(hào)結(jié)尾。多行定義的對(duì)象路克,最后一個(gè)成員以逗號(hào)結(jié)尾
// bad
const a = { k1: v1, k2: v2, };
const b = {
k1: v1,
k2: v2
};
// good
const a = { k1: v1, k2: v2 };
const b = {
k1: v1,
k2: v2,
};
對(duì)象盡量靜態(tài)化樟结,一旦定義,就不得隨意添加新的屬性精算。如果添加屬性不可避免瓢宦,要使用Object.assign方法。
// bad
const a = {};
a.x = 3;
// if reshape unavoidable
const a = {};
Object.assign(a, { x: 3 });
// good
const a = { x: null };
a.x = 3;
如果對(duì)象的屬性名是動(dòng)態(tài)的灰羽,可以在創(chuàng)造對(duì)象的時(shí)候驮履,使用屬性表達(dá)式定義鱼辙。
// bad
const obj = {
id: 5,
name: 'San Francisco',
};
obj[getKey('enabled')] = true;
// good
const obj = {
id: 5,
name: 'San Francisco',
[getKey('enabled')]: true,
};
上面代碼中,對(duì)象obj的最后一個(gè)屬性名疲吸,需要計(jì)算得到座每。這時(shí)最好采用屬性表達(dá)式,在新建obj的時(shí)候摘悴,將該屬性與其他屬性定義在一起峭梳。這樣一來(lái),所有屬性就在一個(gè)地方定義了蹂喻。
另外葱椭,對(duì)象的屬性和方法,盡量采用簡(jiǎn)潔表達(dá)法口四,這樣易于描述和書(shū)寫(xiě)孵运。
var ref = 'some value';
// bad
const atom = {
ref: ref,
value: 1,
addValue: function (value) {
return atom.value + value;
},
};
// good
const atom = {
ref,
value: 1,
addValue(value) {
return atom.value + value;
},
};
6.10.5數(shù)組
使用擴(kuò)展運(yùn)算符(...)拷貝數(shù)組。
// bad
const len = items.length;
const itemsCopy = [];
let i;
for (i = 0; i < len; i++) {
itemsCopy[i] = items[i];
}
// good
const itemsCopy = [...items];
使用 Array.from 方法蔓彩,將類(lèi)似數(shù)組的對(duì)象轉(zhuǎn)為數(shù)組治笨。
const foo = document.querySelectorAll('.foo');
const nodes = Array.from(foo);chou
6.10.6函數(shù)
立即執(zhí)行函數(shù)可以寫(xiě)成箭頭函數(shù)的形式。
(() => {
console.log('Welcome to the Internet.');
})();
那些需要使用函數(shù)表達(dá)式的場(chǎng)合赤嚼,盡量用箭頭函數(shù)代替旷赖。因?yàn)檫@樣更簡(jiǎn)潔,而且綁定了 this更卒。
// bad
[1, 2, 3].map(function (x) {
return x * x;
});
// good
[1, 2, 3].map((x) => {
return x * x;
});
// best
[1, 2, 3].map(x => x * x);
箭頭函數(shù)取代Function.prototype.bind等孵,不應(yīng)再用 self/_this/that 綁定 this。
// bad
const self = this;
const boundMethod = function(...params) {
return method.apply(self, params);
}
// acceptable
const boundMethod = method.bind(this);
// best
const boundMethod = (...params) => method.apply(this, params);
簡(jiǎn)單的蹂空、單行的俯萌、不會(huì)復(fù)用的函數(shù),建議采用箭頭函數(shù)上枕。如果函數(shù)體較為復(fù)雜咐熙,行數(shù)較多,還是應(yīng)該采用傳統(tǒng)的函數(shù)寫(xiě)法辨萍。
所有配置項(xiàng)都應(yīng)該集中在一個(gè)對(duì)象棋恼,放在最后一個(gè)參數(shù),布爾值不可以直接作為參數(shù)分瘦。
// bad
function divide(a, b, option = false ) {
}
// good
function divide(a, b, { option = false } = {}) {
}
不要在函數(shù)體內(nèi)使用 arguments 變量,使用 rest 運(yùn)算符(...)代替琉苇。因?yàn)?rest 運(yùn)算符顯式表明你想要獲取參數(shù)嘲玫,而且 arguments 是一個(gè)類(lèi)似數(shù)組的對(duì)象,而 rest 運(yùn)算符可以提供一個(gè)真正的數(shù)組
// bad
function concatenateAll() {
const args = Array.prototype.slice.call(arguments);
return args.join('');
}
// good
function concatenateAll(...args) {
return args.join('');
}
使用默認(rèn)值語(yǔ)法設(shè)置函數(shù)參數(shù)的默認(rèn)值并扇。
// bad
function handleThings(opts) {
opts = opts || {};
}
// good
function handleThings(opts = {}) {
// ...
}
6.10.7Map結(jié)構(gòu)
注意區(qū)分 Object 和 Map去团,只有模擬現(xiàn)實(shí)世界的實(shí)體對(duì)象時(shí),才使用 Object。如果只是需要key: value的數(shù)據(jù)結(jié)構(gòu)土陪,使用 Map 結(jié)構(gòu)昼汗。因?yàn)?Map 有內(nèi)建的遍歷機(jī)制。
let map = new Map(arr);
for (let key of map.keys()) {
console.log(key);
}
for (let value of map.values()) {
console.log(value);
}
for (let item of map.entries()) {
console.log(item[0], item[1]);
}
6.10.8Class
總是用 Class鬼雀,取代需要 prototype 的操作顷窒。因?yàn)?Class 的寫(xiě)法更簡(jiǎn)潔,更易于理解源哩。
// bad
function Queue(contents = []) {
this._queue = [...contents];
}
Queue.prototype.pop = function() {
const value = this._queue[0];
this._queue.splice(0, 1);
return value;
}
// good
class Queue {
constructor(contents = []) {
this._queue = [...contents];
}
pop() {
const value = this._queue[0];
this._queue.splice(0, 1);
return value;
}
}
使用extends實(shí)現(xiàn)繼承鞋吉,因?yàn)檫@樣更簡(jiǎn)單,不會(huì)有破壞instanceof運(yùn)算的危險(xiǎn)励烦。
// bad
const inherits = require('inherits');
function PeekableQueue(contents) {
Queue.apply(this, contents);
}
inherits(PeekableQueue, Queue);
PeekableQueue.prototype.peek = function() {
return this._queue[0];
}
// good
class PeekableQueue extends Queue {
peek() {
return this._queue[0];
}
}
6.10.9模塊
首先谓着,Module 語(yǔ)法是 JavaScript 模塊的標(biāo)準(zhǔn)寫(xiě)法,堅(jiān)持使用這種寫(xiě)法坛掠。使用import取代require
// bad
const moduleA = require('moduleA');
const func1 = moduleA.func1;
const func2 = moduleA.func2;
// good
import { func1, func2 } from 'moduleA';
使用export取代module.exports赊锚。
// commonJS的寫(xiě)法
var React = require('react');
var Breadcrumbs = React.createClass({
render() {
return <nav />;
}
});
module.exports = Breadcrumbs;
// ES6的寫(xiě)法
import React from 'react';
class Breadcrumbs extends React.Component {
render() {
return <nav />;
}
};
export default Breadcrumbs;
如果模塊只有一個(gè)輸出值,就使用export default屉栓,如果模塊有多個(gè)輸出值舷蒲,就不使用export default,export default與普通的export不要同時(shí)使用系瓢。
不要在模塊輸入中使用通配符阿纤。因?yàn)檫@樣可以確保你的模塊之中,有一個(gè)默認(rèn)輸出(export default)夷陋。
// bad
import * as myObject from './importModule';
// good
import myObject from './importModule';
如果模塊默認(rèn)輸出一個(gè)函數(shù)欠拾,函數(shù)名的首字母應(yīng)該小寫(xiě)。
function makeStyleGuide() {
}
export default makeStyleGuide;
如果模塊默認(rèn)輸出一個(gè)對(duì)象骗绕,對(duì)象名的首字母應(yīng)該大寫(xiě)藐窄。
const StyleGuide = {
es6: {
}
};
export default StyleGuide;
七ESlint的使用
ESLint 是一個(gè)語(yǔ)法規(guī)則和代碼風(fēng)格的檢查工具,可以用來(lái)保證寫(xiě)出語(yǔ)法正確酬土、風(fēng)格統(tǒng)一的代碼荆忍。
首先,安裝 ESLint撤缴。
npm i -g eslint
然后刹枉,安裝 Airbnb 語(yǔ)法規(guī)則,以及 import屈呕、a11y微宝、react 插件。
npm i -g eslint-config-airbnb
npm i -g eslint-plugin-import eslint-plugin-jsx-a11y eslint-plugin-react
最后虎眨,在項(xiàng)目的根目錄下新建一個(gè).eslintrc文件蟋软,配置 ESLint镶摘。
{
"extends": "eslint-config-airbnb"
}
現(xiàn)在就可以檢查,當(dāng)前項(xiàng)目的代碼是否符合預(yù)設(shè)的規(guī)則岳守。
index.js文件的代碼如下凄敢。
var unusued = 'I have no purpose!';
function greet() {
var message = 'Hello, World!';
alert(message);
}
greet();
使用 ESLint 檢查這個(gè)文件,就會(huì)報(bào)出錯(cuò)誤湿痢。
$ eslint index.js
index.js
1:1 error Unexpected var, use let or const instead no-var
1:5 error unusued is defined but never used no-unused-vars
4:5 error Expected indentation of 2 characters but found 4 indent
4:5 error Unexpected var, use let or const instead no-var
5:5 error Expected indentation of 2 characters but found 4 indent
? 5 problems (5 errors, 0 warnings)
上面代碼說(shuō)明涝缝,原文件有五個(gè)錯(cuò)誤,其中兩個(gè)是不應(yīng)該使用var命令蒙袍,而要使用let或const俊卤;一個(gè)是定義了變量,卻沒(méi)有使用害幅;另外兩個(gè)是行首縮進(jìn)為 4 個(gè)空格消恍,而不是規(guī)定的 2 個(gè)空格。
八注釋
JS
屬性注釋?zhuān)? //
方法注釋?zhuān)? /**
* @desc 解釋
* @param {數(shù)據(jù)類(lèi)型} 參數(shù)名 參數(shù)解釋
*/
對(duì)象注釋舉例: /**
* @desc 查詢所有消息
* @param {Object} pageInfo 分頁(yè)對(duì)象
* @property {int} pageNum 頁(yè)號(hào)
* @property {int} pageSize 每頁(yè)條數(shù)
*/
組件
<!--公用組件:數(shù)據(jù)表格
/**
* @desc 組件名稱
* @module 組件存放位置
* @desc 組件描述
* @author 組件作者
* @date 2018年8月13日17:22:43
* @param {Object} [title] - 參數(shù)說(shuō)明
* @param {String} [columns] - 參數(shù)說(shuō)明
* @example 調(diào)用示例
* <hbTable :title="title" :columns="columns" :tableData="tableData"></hbTable>
*/
-->
九vscode插件
Auto Rename Tag // 自動(dòng)重命名配對(duì)的HTML / XML標(biāo)簽
Chinese (Simplified) Language Pack for Visual Studio Code // ide漢化
Color Highlight // css 顏色高亮
CSS Peek // 能夠查看CSS ID和類(lèi)的字符串作為HTML文件中相應(yīng)的CSS定義
CSScomb // css 格式化
Debugger for Chrome // 讓 vscode 映射 chrome 的 debug功能以现,用 vscode 來(lái)打斷點(diǎn)調(diào)試
language-stylus // 支持.styl樣式
Live Server // 項(xiàng)目服務(wù)端口5500 啟動(dòng)
Markdown All in One // 拓展md
Markdown Preview Enhanced // md 預(yù)覽
open in browser // 瀏覽器打開(kāi)html
px2rem // rem配置
TODO Highlight // TODO 高亮
TSLint // TS校驗(yàn)
TypeScript Importer // TS拓展
Vetur // vue 格式化配置 高亮
vscode-icons // 文件圖標(biāo)
Vue VSCode Snippets // vue 代碼提示