vue元件最佳實踐
看了老外的一篇關於元件開發的建議(強烈建議閱讀英文原版),感覺不錯翻譯一下加深理解。
這篇文章制定一個統一的規則來開發你的vue程式,以至於達到一下目的。
1.讓開發者和開發團隊更容易發現一些事情。
2.讓你更好的利用你的IDE.
3.讓你更加容易的使用打包工具
4.讓你的程式碼更容易碎片化以達到複用的目的。
基於模組開發
用一些功能單一的小模組來組織你的應用
Why?
對於你自己和你團隊的人來說較小的模組更容易看懂 維護 複用和除錯。
How?
每個元件應該保持單一 獨立 可複用 可測試
把你很大的元件拆分成功能單一的小元件,儘量不讓一個元件的程式碼超過100行,保持元件獨立。最好是寫個元件應用的小demo
元件命名
元件命名應該遵從以下幾點原則
- 有意義: 名字不要太詳細,也不要太抽象。
- 短: 名字最好是2-3個單詞。
- 可讀的:容易讓人能讀出來以便我們可以更容易的討論它。
vue元件也應該遵循以下原則
- 遵從元素命名規範 包括連字元,不要使用保留字
- 為了在其他專案中複用,應該以某個模組名字作為名稱空間
Why?
- 為了讓我們更好地通過名字來交流這個元件,這個元件必須 短 有意義 可讀
How?
<!-- 建議這樣 --> <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。當著這些js很有效,但是也很複雜。因此你應該保持行內表示式簡潔
Why?
- 複雜的行內表示式可讀性差
- 這些行內表示式不能任意地方複用,這樣會導致程式碼冗餘
- IDE不支援行內式js的語法校驗
How?
把複雜的語法移動到methods或者計算屬性中
<!-- recommended --> <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> <!-- avoid --> <template> <h1> {{ `${(new Date()).getUTCFullYear()}-${('0' + ((new Date()).getUTCMonth()+1)).slice(-2)}` }} </h1> </template>
保證元件的props簡單
儘管vue支援通過props傳遞複雜的object,但是你要儘量保持props傳遞的資料簡單,儘量只傳遞基本資料型別(strings, numbers, booleans)
Why?
- 簡潔的props讓你的介面api比較簡單
- props只傳遞簡單型別資料和函式,讓我們元件的api看起來更像原生html的屬性。
- props只傳遞簡單型別資料,讓其他開發者容易明白傳什麼引數。
- props傳遞複雜資料型別,讓你的元件很難重構,也會造成程式碼冗餘。
How?
vue component 只傳遞簡單資料型別或者函式如下
<!-- recommended -->
<range-slider
:values="[10, 20]"
min="0"
max="100"
step="5"
:on-slide="updateInputs"
:on-end="updateResults">
</range-slider>
<!-- avoid -->
<range-slider :config="complexConfigObject"></range-slider>
對你元件的props做一些限制
vue 元件中props就是api,健壯且可預測的api讓別人更容易使用你的元件
元件的props通過html屬性來編寫,這些值可以是vue的簡答字串(:attr="value" or v-bind:attr="value")也可以不寫。你應該對props做一些限制
Why?
對props做一些限制保證你的元件正常工作,即使別人沒有按照你預想的方式呼叫你的元件。
How?
- 屬性設定預設值
- 屬性設定資料型別校驗
- 使用元件之前檢查props是否存在
<template>
<input type="range" v-model="value" :max="max" :min="min">
</template>
<script type="text/javascript">
export default {
props: {
max: {
type: Number, // [1*] This will validate the 'max' prop to be a Number.
default() { return 10; },
},
min: {
type: Number,
default() { return 0; },
},
value: {
type: Number,
default() { return 4; },
},
},
};
</script>
將元件設定為this
在元件內部上下文中,this指的是vue元件例項,因此在其他上下文中使用它的時候保證'this'在元件中可以使用
換句話說,不要這樣寫 const self = this;
Why?
- 通過把
this
分配給會改變名字的元件,告訴開發者this是一個元件例項。
How?
元件結構
讓你的元件程式碼按照一定的順序編寫
Why?
- 用export匯出一個清晰的物件,提高程式碼可讀性,同時讓開發著統一程式碼結構
- 按一下順序排列,讓程式碼容易被找到 (name; extends; props, data and computed; components; watch and methods; lifecycle methods, etc.);
- 增加
name
屬性,這樣再使用vue devtools時便於開發測試。 - 按照一定的規則寫css
- 按照如下順序組織程式碼template-script-style
How?
<template lang="html">
<div class="Ranger__Wrapper">
<!-- ... -->
</div>
</template>
<script type="text/javascript">
export default {
// Do not forget this little guy
name: 'RangeSlider',
// compose new components
extends: {},
// component properties/variables
props: {
bar: {}, // Alphabetized
foo: {},
fooBar: {},
},
// variables
data() {},
computed: {},
// when component uses other components
components: {},
// methods
watch: {},
methods: {},
// component Lifecycle hooks
beforeCreate() {},
mounted() {},
};
</script>
<style scoped>
.Ranger__Wrapper { /* ... */ }
</style>
元件事件命名
vue提供的vue處理函式和表示式是嚴格繫結在vm上的。每個元件事件應該遵循一個良好的命名規範從而避免開發中出現的問題。
Why?
- 開發者任意使用事件名稱會導致混亂,例如用了原生的事件名。
- 隨意命名事件會導致dom模板不協調。
How?
- 事件命名按照kebab-cased(不用駝峰法)規範(例如download-success)
- 一個事件名稱對應唯一的事件
- 事件名應該已動詞(例如client-api-load)或名詞(例如 drive-upload-success)結尾
避免使用this.$patent
vue支援元件巢狀,子元件獲得父元件上下文,但是獲得外部上下文違反了元件獨立的規定,所有不要使用this.$patent
Why?
- 就像其他元件一樣vue元件也應該獨立工作
- 如果元件依賴他的父元件那麼他將難以複用。
How?
- 通過attribute/properties將資料從父元件傳遞給子元件
- 在屬性表示式中把在父元件中定義的會掉函式傳遞到子元件
- 從子元件emit事件到父元件
謹慎使用this.$refs
vue 支援元件通過 this.$refs
來獲得元件或者dom元素的上下文,大部分情況下這中用法應該被禁止。當你用他的時候也應該謹慎防止錯誤的元件api。
Why?
- 就像其他元件一樣,vue的元件應該是獨立的,不能適應所有應用場景的元件是一個不好的元件
- 大部分情況下屬性和事件已經足夠用了
How?
- 設計好的元件api
- 多考慮一些元件在其餘業務場景下的重用
- 不要寫一些特殊的程式碼,如果你需要些說明你需要設計一個新的元件
- 檢查是否有props缺失,如果是的話補全這些缺陷。
- 檢查所有的事件(event)大多數時候開發者只記得通過props實現父子元件通訊嗎,而忘記通過自定義事件。
- 以設計好的api和元件獨立性為目的來更新你的元件
- 當props和自定義事件實在達不到目的再用
this.$refs
- 當元素不能用資料繫結或者指令操作時,用
this.$refs
是比jquery和document.getElement*
好一些的選擇
<!-- good, no need for ref -->
<range :max="max"
:min="min"
@current-value="currentValue"
:step="1"></range>
<!-- good example of when to use 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>
<!-- avoid accessing something that could be emitted -->
<template>
<range :max="max"
:min="min"
ref="range"
:step="1"></range>
</template>
<script>
export default {
// ...
methods: {
getRangeCurrentValue() {
return this.$refs.range.currentValue;
},
},
// ...
};
</script>
使用元件名稱作為css作用域
vue 元件的名字作為css根作用域類名是極好的。
Why?
- css在style標籤加上scoped能有效的防止元件內css汙染外部元件的css
- css根作用域類名和元件名相同,讓開發者容易理解他們是一個元件中的。
How?
把元件名作為css名稱空間依賴BEM和OOCSS(面向物件css)。在style標籤上加scoped。加了scoped告訴vue在編譯時給每個類名都加一個字尾,從而避免汙染其餘元件或者全域性樣式。
<style scoped>
/* recommended */
.MyExample { }
.MyExample li { }
.MyExample__item { }
/* avoid */
.My-Example { } /* not scoped to component or module name, not BEM compliant */
</style>
為你的元件寫api文件
一個vue例項通過例項化應用中的元件而來。這個例項通過元件屬性配置而來。如果元件要提供給其他開發者使用,這些定製的屬性也就是元件的api應該寫在readme.md中。
Why?
- 文件提供給開發者一個關於元件的概要,使開發者不需要看元件的原始碼。這樣元件比較容易讓人接受和使用。
- 元件的api是使用元件需要配置項的指導。特別是對於那些只使用這個元件的開發者。
- 元件正式的文件告訴開發者當元件程式碼變化了怎麼去做相容
README.md
是一個文件應該先被閱讀的。github等程式碼倉庫通過README.md 來展示程式碼內容
How?
給一個元件增加README.md
range-slider/
├── range-slider.vue
├── range-slider.less
└── README.md
其餘還包括給你的元件寫小demo,對元件做eslint程式碼審查。。