VUE項(xiàng)目規(guī)范

一簡(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è)置常量鹃共。

  1. 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)部的處理不同。
  2. const聲明常量還有兩個(gè)好處哥牍,一是閱讀代碼的人立刻會(huì)意識(shí)到不應(yīng)該修改這個(gè)值毕泌,二是防止了無(wú)意間修改變量值所導(dǎo)致的錯(cuò)誤。
  3. 所有的函數(shù)都應(yīng)該設(shè)置為常量嗅辣。
  4. 長(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 代碼提示
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末狠怨,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子邑遏,更是在濱河造成了極大的恐慌佣赖,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,183評(píng)論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件记盒,死亡現(xiàn)場(chǎng)離奇詭異憎蛤,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)纪吮,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,850評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)俩檬,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人碾盟,你說(shuō)我怎么就攤上這事棚辽。” “怎么了冰肴?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,766評(píng)論 0 361
  • 文/不壞的土叔 我叫張陵屈藐,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我熙尉,道長(zhǎng)联逻,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,854評(píng)論 1 299
  • 正文 為了忘掉前任检痰,我火速辦了婚禮包归,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘攀细。我一直安慰自己箫踩,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,871評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布谭贪。 她就那樣靜靜地躺著境钟,像睡著了一般。 火紅的嫁衣襯著肌膚如雪俭识。 梳的紋絲不亂的頭發(fā)上慨削,一...
    開(kāi)封第一講書(shū)人閱讀 52,457評(píng)論 1 311
  • 那天,我揣著相機(jī)與錄音套媚,去河邊找鬼缚态。 笑死,一個(gè)胖子當(dāng)著我的面吹牛堤瘤,可吹牛的內(nèi)容都是我干的玫芦。 我是一名探鬼主播,決...
    沈念sama閱讀 40,999評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼本辐,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼桥帆!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起慎皱,我...
    開(kāi)封第一講書(shū)人閱讀 39,914評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤老虫,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后茫多,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體祈匙,經(jīng)...
    沈念sama閱讀 46,465評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,543評(píng)論 3 342
  • 正文 我和宋清朗相戀三年天揖,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了夺欲。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,675評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡宝剖,死狀恐怖洁闰,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情万细,我是刑警寧澤扑眉,帶...
    沈念sama閱讀 36,354評(píng)論 5 351
  • 正文 年R本政府宣布,位于F島的核電站赖钞,受9級(jí)特大地震影響腰素,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜雪营,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,029評(píng)論 3 335
  • 文/蒙蒙 一弓千、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧献起,春花似錦洋访、人聲如沸镣陕。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,514評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)呆抑。三九已至,卻和暖如春汁展,著一層夾襖步出監(jiān)牢的瞬間鹊碍,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,616評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工食绿, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留侈咕,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,091評(píng)論 3 378
  • 正文 我出身青樓器紧,卻偏偏與公主長(zhǎng)得像耀销,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子铲汪,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,685評(píng)論 2 360