Vue.js 組件編碼規範

Vue.js 組件編碼規範(最下文附有本人寫的demo地址

 

目標

本規範提供了一種統一的編碼規範來編寫 Vue.js 代碼。這使得代碼具備以下的特性:javascript

  • 其它開發者或是團隊成員更容易閱讀和理解。
  • IDEs 更容易理解代碼,從而提供高亮、格式化等輔助功能
  • 更容易使用現有的工具
  • 更容易實現緩存以及代碼包的分拆

本指南爲 De Voorhoede 參考 RiotJS 編碼規範 而寫。css

目錄

  • 將 this 賦值給 component 變量
  • 使用組件名做爲樣式做用域空間
  • 對組件文件進行代碼校驗

基於模塊開發

始終基於模塊的方式來構建你的 app,每個子模塊只作一件事情。html

Vue.js 的設計初衷就是幫助開發者更好的開發界面模塊。一個模塊是應用程序中獨立的一個部分。vue

怎麼作?

每個 Vue 組件(等同於模塊)首先必須專一於解決一個 單一的問題 , 獨立的 , 可複用的 , 微小的 and 可測試的 。java

若是你的組件作了太多的事或是變得臃腫,請將其拆分紅更小的組件並保持單一的原則。通常來講,儘可能保證每個文件的代碼行數不要超過 100 行。也請保證組件可獨立的運行。比較好的作法是增長一個單獨的 demo 示例。nginx

Vue 組件命名

組件的命名需聽從如下原則:git

  • 有意義的 : 不過於具體,也不過於抽象
  • 簡短 : 2 到 3 個單詞
  • 具備可讀性 : 以便於溝通交流

同時還須要注意:github

  • 必須符合 自定義元素規範 : 使用連字符 分隔單詞,切勿使用保留字。
  • app- 前綴做爲命名空間 : 若是很是通用的話可以使用一個單詞來命名,這樣能夠方便於其它項目裏複用。

爲何?

  • 組件是經過組件名來調用的。因此組件名必須簡短、富有含義而且具備可讀性。

如何作?

<!-- 推薦 -->
<app-header></app-header> <user-list></user-list> <range-slider></range-slider> <!-- 避免 --> <btn-group></btn-group> <!-- 雖然簡短可是可讀性差. 使用 `button-group` 替代 --> <ui-slider></ui-slider> <!-- ui 前綴太過於寬泛,在這裏意義不明確 --> <slider></slider> <!-- 與自定義元素規範不兼容 -->

組件表達式簡單化

Vue.js 的表達式是 100% 的 Javascript 表達式。這使得其功能性很強大,但也帶來潛在的複雜性。所以,你應該儘可能 保持表達式的簡單化 。vue-cli

爲何?

  • 複雜的行內表達式難以閱讀。
  • 行內表達式是不可以通用的,這可能會致使重複編碼的問題。
  • IDE 基本上不能識別行內表達式語法,因此使用行內表達式 IDE 不能提供自動補全和語法校驗功能。

怎麼作?

若是你發現寫了太多複雜並難以閱讀的行內表達式,那麼可使用 method 或是 computed 屬性來替代其功能。django

<!-- 推薦 --> <template> <h1> {{ `${year}-${month}` }} </h1> </template> <script type="text/javascript"> export default { computed: { month() { return this.twoDigits((new Date()).getUTCMonth() + 1); }, year() { return (new Date()).getUTCFullYear(); } }, methods: { twoDigits(num) { return ('0' + num).slice(-2); } }, }; </script> <!-- 避免 --> <template> <h1> {{ `${(new Date()).getUTCFullYear()}-${('0' + ((new Date()).getUTCMonth()+1)).slice(-2)}` }} </h1> </template>

組件 props 原子化

雖然 Vue.js 支持傳遞複雜的 JavaScript 對象經過 props 屬性,可是你應該儘量的使用原始類型的數據。儘可能只使用 JavaScript 原始類型 (字符串、數字、布爾值) 和 函數。儘可能避免複雜的對象。

爲何?

  • 使得組件 API 清晰直觀
  • 只使用原始類型和函數做爲 props 使得組件的 API 更接近於 HTML(5) 原生元素。
  • 其它開發者更好的理解每個 prop 的含義,做用
  • 傳遞過於複雜的對象使得咱們不可以清楚的知道哪些屬性或方法被自定義組件使用,這使得代碼難以重構和維護。

怎麼作?

組件的每個屬性單獨使用一個 props,而且使用函數或是原始類型的值。

<!-- 推薦 -->
<range-slider :values="[10, 20]" min="0" max="100" step="5" :on-slide="updateInputs" :on-end="updateResults"> </range-slider> <!-- 避免 --> <range-slider :config="complexConfigObject"></range-slider>

驗證組件的 props

在 Vue.js 中,組件的 props 即 API,一個穩定並可預測的 API 會使得你的組件更容易被其餘開發者使用。

組件 props 經過自定義標籤的屬性來傳遞。屬性的值能夠是 Vue.js 字符串( :attr="value" 或v-bind:attr="value" )或是不傳。你須要保證組件的 props 能應對不一樣的狀況。

爲何?

驗證組件 props 能夠保證你的組件永遠是可用的(防護性編程)。即便其餘開發者並未按照你預想的方法使用時也不會出錯。

怎麼作?

  • 提供默認值
  • 使用 type 屬性 校驗類型
  • 使用 props 以前先檢查該 prop 是否存在
<template> <input type="range" v-model="value" :max="max" :min="min"> </template> <script type="text/javascript"> export default { props: { max: { type: Number, // 這裏添加了數字類型的校驗 default() { return 10; }, }, min: { type: Number, default() { return 0; }, }, value: { type: Number, default() { return 4; }, }, }, }; </script>

將 this 賦值給 component 變量(

在 Vue.js 組件上下文中, this 指向了組件實例。所以當你切換到了不一樣的上下文時,要確保this 指向一個可用的 component 變量。

換句話說,不要在編寫這樣的代碼 const self = this; ,而是應該直接使用變量 component

爲何?

  • 將組件 this 賦值給變量 component 可用讓開發者清楚的知道任何一個被使用的地方,它表明的是組件實例。

怎麼作?

<script type="text/javascript"> export default { methods: { hello() { return 'hello'; }, printHello() { console.log(this.hello()); }, }, }; </script> <!-- 避免 --> <script type="text/javascript"> export default { methods: { hello() { return 'hello'; }, printHello() { const self = this; // 沒有必要 console.log(self.hello()); }, }, }; </script>

組件結構化

按照必定的結構組織,使得組件便於理解。

爲何?

  • 導出一個清晰、組織有序的組件,使得代碼易於閱讀和理解。同時也便於標準化。
  • 按首字母排序properties, data, computed, watches 和 methods使得這些對象內的屬性便於查找。
  • 合理組織,使得組件易於閱讀。(name; extends; props, data and computed; components; watch and methods; lifecycle methods, 等.);
  • 使用 name 屬性。藉助於 vue devtools 可讓你更方便的測試
  • 合理的 CSS 結構,如 BEM 或 rscss -;
  • 使用單文件 .vue 文件格式來組件代碼

怎麼作?

組件結構化

<template lang="html"> <div class="Ranger__Wrapper"> <!-- ... --> </div> </template> <script type="text/javascript"> export default { // 不要忘記了 name 屬性 name: 'RangeSlider', // 組合其它組件 extends: {}, // 組件屬性、變量 props: { bar: {}, // 按字母順序 foo: {}, fooBar: {}, }, // 變量 data() {}, computed: {}, // 使用其它組件 components: {}, // 方法 watch: {}, methods: {}, // 生命週期函數 beforeCreate() {}, mounted() {}, }; </script> <style scoped> .Ranger__Wrapper { /* ... */ } </style>

組件事件命名

Vue.js 提供的處理函數和表達式都是綁定在 ViewModel 上的,組件的每個事件都應該按照一個好的命名規範來,這樣能夠避免很多的開發問題,具體可見以下 ** 爲何**。

爲何?

  • 開發者能夠隨意給事件命名,即便是原生事件的名字,這樣會帶來迷惑性。
  • 過於寬鬆的事件命名可能與 DOM模板不兼容 。

怎麼作?

  • 事件命名也連字符命名
  • 一個事件的名字對應組件外的一組意義操做,如:upload-success, upload-error 以及 dropzone-upload-success, dropzone-upload-error (若是須要前綴的話)。
  • 事件命名應該以動詞(如 client-api-load) 或是 形容詞(如 drive-upload-success)結尾。( 出處 )

避免 this.$parent

Vue.js 支持組件嵌套,而且子組件可訪問父組件的上下文。訪問組件以外的上下文違反了 基於模塊開發 的 第一原則 。所以你應該儘可能避免使用 this.$parent 

爲何?

  • 組件必須相互保持獨立,Vue 組件也是。若是組件須要訪問其父層的上下文就違反了該原則。
  • 若是一個組件須要訪問其父組件的上下文,那麼該組件將不能再其它上下文中複用。

怎麼作?

  • 經過 props 將值傳遞給子組件
  • 經過 props 傳遞迴調函數給子組件來達到調用父組件方法的目的
  • 經過在子組件觸發事件來通知父組件

謹慎使用 this.$refs

Vue.js 支持經過 ref 屬性來訪問其它組件和 HTML 元素。並經過 this.$refs 能夠獲得組件或 HTML 元素的上下文。在大多數狀況下,經過 this.$refs 來訪問其它組件的上下文是能夠避免的。在使用的的時候你須要注意避免調用了不恰當的組件 API,因此應該儘可能避免使用 this.$refs 。

爲何?

  • 組件必須是保持獨立的,若是一個組件的 API 不可以提供所需的功能,那麼這個組件在設計、實現上是有問題的。
  • 組件的屬性和事件必須足夠的給大多數的組件使用

怎麼作?

  • 提供良好的組件 API
  • 老是關注於組件自己的目的
  • 拒絕定製代碼。若是你在一個通用的組件內部編寫特定需求的代碼,那麼表明這個組件的 API 不夠通用,或者你可能須要一個新的組件來應對該需求
  • 檢查全部的 props 是否有缺失的,若是有提一個 issue 或是完善這個組件
  • 檢查全部的事件。子組件向父組件通訊通常是經過事件來實現的,可是大多數的開發者更多的關注於 props 從忽視了這點。
  • Props向下傳遞,事件向上傳遞! 。以此爲目標升級你的組件,提供良好的 API 和 獨立性。
  • 當遇到 props 和 events 難以實現的功能時,經過 this.$refs 來實現。
  • 當須要操做 DOM 沒法經過指令來作的時候可以使用 this..$ref 而不是 JQuery , document.getElement* , document.queryElement 。
<!-- 推薦,並未使用 this.$refs -->
<range :max="max" :min="min" @current-value="currentValue" :step="1"></range>
<!-- 使用 this.$refs 的適用狀況-->
<modal ref="basicModal"> <h4>Basic Modal</h4> <button class="primary" @click="$refs.basicModal.close()">Close</button> </modal> <button @click="$refs.basicModal.open()">Open modal</button> <!-- Modal component --> <template> <div v-show="active"> <!-- ... --> </div> </template> <script> export default { // ... data() { return { active: false, }; }, methods: { open() { this.active = true; }, hide() { this.active = false; }, }, // ... }; </script>
<!-- 若是可經過 emited 來作則避免經過 this.$refs 直接訪問 -->
<template> <range :max="max" :min="min" ref="range" :step="1"></range> </template> <script> export default { // ... methods: { getRangeCurrentValue() { return this.$refs.range.currentValue; }, }, // ... }; </script>

使用組件名做爲樣式做用域空間

Vue.js 的組件是自定義元素,這很是適合用來做爲樣式的根做用域空間。能夠將組件名做爲 css 類的命名空間。

爲何?

  • 給樣式加上做用域空間能夠避免組件樣式影響外部的樣式
  • 保持模塊名、目錄名、樣式根做用域名同樣,能夠很好的將其關聯起來,便於開發者理解。

怎麼作?

使用組件名做爲樣式命名的前綴,可基於 BEM 或 OOCSS 範式。同時給style標籤加上 scoped 屬性。加上 scoped 屬性編譯後會給組件的 class 自動加上惟一的前綴從而避免樣式的衝突。

<style scoped> /* 推薦 */ .MyExample { } .MyExample li { } .MyExample__item { } /* 避免 */ .My-Example { } /* not scoped to component or module name, not BEM compliant */ </style>

提供組件 API 文檔

使用 Vue.js 組件的過程當中會建立 Vue 組件實例,這個實例是經過自定義屬性配置的。爲了便於其餘開發者使用該組件,對於這些自定義屬性即組件API應該在 README.md 文件中進行說明。

爲何?

  • 良好的文檔可讓開發者比較容易的對組件有一個總體的認識,而不用去閱讀組件的源碼,也更方便開發者使用
  • 組件配置屬性即組件的 API,對於組件的用戶來講他們更感興趣的是 API 而不是實現原理。
  • 正式的文檔會告訴開發者組件 API 變動以及向後的兼容性狀況
  • README.md 是標準的咱們應該首先閱讀的文檔文件。代碼託管網站 (github/bitbucket/gitlab 等) 會默認在倉庫中展現 該文件做爲倉庫的介紹。

怎麼作?

在模塊目錄中添加 README.md 文件:

range-slider/
├── range-slider.vue ├── range-slider.less └── README.md

在 README 文件中說明模塊的功能以及使用場景。對於 vue 組件來講,比較有用的描述是組件的自定義屬性即 API 的描述介紹。

Range slider

功能

range slider 組件可經過拖動的方式來設置一個給定範圍內的數值。

該模塊使用 noUiSlider 來實現誇瀏覽器和 touch 功能的支持。

如何使用

<range-slider> 支持以下的自定義屬性:

attribute type description
min Number 可拖動的最小值.
max Number 可拖動的最大值.
values Number[] optional 包含最大值和最小值的數組. 如. values="[10, 20]" . Defaults to [opts.min, opts.max] .
step Number optional 增長減少的數值單位,默認爲 1.
on-slide Function optional 用戶拖動開始按鈕或者結束按鈕時的回調函數,函數接受 (values, HANDLE) 格式的參數。 如: on-slide={ updateInputs } , component.updateInputs = (values, HANDLE) => { const value = values[HANDLE]; } .
on-end Function optional 當用戶中止拖動時觸發的回調函數,函數接受 (values, HANDLE) 格式的參數。

如須要自定義 slider 的樣式可參考 noUiSlider 文檔

提供組件 demo

添加 index.html 文件做爲組件的 demo 示例,並提供不一樣配置狀況的效果,說明組件是如何使用的。

爲何?

  • demo 能夠說明組件是獨立可以使用的
  • demo 可讓開發者預覽組件的功能效果
  • demo 能夠展現組件各類配置參數下的功能

對組件文件進行代碼校驗

代碼校驗能夠保持代碼的統一性以及追蹤語法錯誤。.vue 文件能夠經過使用 eslint-plugin-html 插件來校驗代碼。你能夠經過 vue-cli 來開始你的項目, vue-cli 默認會開啓代碼校驗功能。

爲何?

  • 保證全部的開發者使用一樣的編碼規範。
  • 更早的感知到語法錯誤

怎麼作?

爲了校驗工具可以校驗 *.vue 文件,你須要將代碼編寫在 <script> 標籤中,並使,由於校驗工具沒法理解行內表達式,配置校驗工具能夠訪問全局變量 vue 和組件的 props 。

ESLint

ESLint 須要經過 ESLint HTML 插件 來抽取組件中的代碼。

經過 .eslintrc 文件來配置 ESlint,這樣 IED 能夠更好的理解校驗配置項。 ESlint,這樣.

{
  "extends": "eslint:recommended", "plugins": ["html"], "env": { "browser": true }, "globals": { "opts": true, "vue": true } }

運行 ESLint

eslint src/**/*.vue

JSHint

JSHint 能夠解析 HTML (使用 --extra-ext 命令參數) 和 抽取代碼(使用 --extract=auto 命令參數).

經過 .jshintrc 文件來配置 ESlint,這樣 IED 能夠更好的理解校驗配置項。

{
  "browser": true, "predef": ["opts", "vue"] }

運行 JSHint

jshint --config modules/.jshintrc --extra-ext=html --extract=auto modules/

注:JSHint 不接受 vue 擴展名的文件,只支持 html 。

本人demo地址:

        https://github.com/HerbertKarajan/H5Platform 

        https://github.com/HerbertKarajan/Vue-smallGame

相關文章
相關標籤/搜索