【譯】VueJS 最佳實踐

amandakelake發表於2019-03-03

原文地址: Vue.js best practices ✓ – Noteworthy – The Journal Blog
原文作者: Riccardo Polacci
譯者: amandakelake

各位開發小夥伴們好! 

經過一段時間對VueJs官方文件以及網上其他相關vue資源的研究,我整理了一份最佳實踐和樣式指南列表,方便大家寫出更正確、更容易讓小夥伴接受的vue程式碼。
 

以下有幾點是一些功能/優化相關,其他是VueJs命名約定和元素排序相關。更多詳細資訊可以直接到最下方的總結中檢視。

在元件銷燬時用 $off 清除事件監聽

當我們使用$on進行事件監聽時,要記住在destroyed()鉤子中用$off移除事件監聽,可以有效防止記憶體洩漏。

使用短橫線分隔的形式命名事件

觸發/監聽自定義事件時,應該始終使用短橫線分隔。為什麼呢?因為無論如何最後事件名都會被自動轉換為短橫線分隔的形式。我們不應該用駝峰命名或者首字母大寫的形式給監聽事件命名,而是使用一種更清晰有意義的方式來宣告一個事件:短橫線分隔

// Emitting
this.$emit(`my-event`) // instead of myEvent
// Listening
v-on:my-event
複製程式碼

不要在created生命週期和watch中呼叫同一個方法

如果我們需要在元件初始化以及偵聽屬性變化時呼叫同一個方法,通常的做法像下面這樣

watch: {
  myProperty() {
    this.doSomething();
  }
},
created() {
  this.doSomething();
},
methods: {
  doSomething() {
     console.log(`doing something...`);
  }
},
複製程式碼

儘管上面這段程式碼看起來沒什麼問題,但created鉤子裡面執行的方法是多餘的。我們可以把所需要執行的方法放到watch裡面,避免在created鉤子裡寫重複程式碼,那將會在元件例項化的時候觸發多一次。 比如像下面這樣:

watch: {
  myProperty: {
    immediate: true, // 該回撥將會在偵聽開始之後被立即呼叫
    handler() {
      this.doSomething();
    }
  }
},
methods: {
  doSomething() {
     console.log(`doing something...`);
  }
},

// 更好的方案
watch: {
  myProperty: {
    immediate: true,
    handler() {
      console.log(`doing something...`); // 只用一次的方法沒必要在methods裡面宣告瞭
    }
  }
},
複製程式碼

不要忘記在 v-for 迴圈中使用 key 

最常見的做法是始終在模板迴圈中新增:key鍵。沒有:key鍵的v-for迴圈在錯誤定位的時候比較麻煩,特別是動畫相關

使用$_作為mixins的私有屬性字首

Mixins在程式碼複用上是個不錯的方法,它可以將重複程式碼組合成一個單獨的模組,然後按需引入。但是(極大可能),會出現一些問題。下面,我們重點解決屬性名重複衝突的問題。

當我們將mixin混入元件時,也就是將mixin內的程式碼與元件自身的程式碼進行合併,如果碰到同名屬性,會發生什麼?元件優先順序更高,元件屬性的優先順序自然更高。

如果我想讓mixin程式碼的優先順序更高,應該怎麼辦?我們無法分配優先順序,但可以通過正確的命名規範來避免屬性重疊或者覆蓋。

為了區分mixin屬性和元件的屬性,我們通常使用`$_`作為屬性字首,為什麼呢?主要有下面幾個原因:

  1. 來自VueJs風格指南的建議 
  2. Vue 使用_字首來定義其自身的私有屬性
  3. $是Vue生態系統暴露給使用者的特殊例項屬性 

風格指南 — Vue.js中,他們建議像這樣給mixin新增屬性名稱:$_myMixin_updateUser 

相對於可讀性,我發現給mixin新增名稱有時候也會產生一些混淆。但這也取決於mixin本身程式碼,特殊情況或者開發人員本身。 

通過新增一個簡單的$_,就像$_updateUser一樣,程式碼更具可讀性,可以輕鬆分辨出元件私有屬性和mixin的屬性。

mixin中使用的方法或者屬性應該直接在mixin中讀取

mixin上一點,還有另一點要注意的。

假設我們建立了一個mixin,它使用了this.language屬性,但這個屬性並不是在mixin內部定義或獲取的,那麼混入了這個mixin的元件就必須包含這個language屬性。
 

正如你已經知道的,這非常容易出錯。為了提前避免錯誤的發生,mixin內使用到的屬性或者方法最好只在mixin內部定義獲取。不必擔心重複獲取屬性的問題,因為VueJs在這點上很聰明,如果檢測到重複讀取屬性,將會自動處理(大部分情況下是直接從Vuex裡直接讀取)。

使用首字母大寫或者短橫線分隔命名單檔案元件

編輯器對首字母大寫命名的整合度更好,對在常用IDE中實現自動完成/匯入功能更友好。
 

如果我們想要避免檔案系統大小寫不敏感的問題,那麼最好選擇短橫線分隔

給基礎元件名加字首

對於展示元件、純元件,應該給它們加上字首,以區別於其他的非純元件。這可以大大提高專案可讀性,提高團隊協同開發體驗。 

使用首字母大寫命名命名JS中的元件

在JavaScript中,類和原型建構函式有預設約定使用首字母大寫命名,在Vue元件中使用首字母大寫命名有相同的意義。 如果我們只通過`Vue.component`使用全域性元件定義,建議使用短橫線分隔命名

宣告 prop 名時使用駝峰命名,但在模板中應使用短橫線分隔命名

遵循每種語言的慣例:JavaScript(駝峰)和HTML(短橫線分割),在JS中定義prop時用駝峰命名,在HTML中用於短橫線分割命名。

遵循樣式指南中的元件選項順序

這樣做可能看起來有點死板,但是在整個專案中對元件的所有選項執行相同的順序,在查詢內容和建立新元件時有很大幫助。

 VueJs樣式指南可以檢視這裡風格指南 — Vue.js

不要在使用v-for的同一元素上使用v-if

這種做法堪稱效能殺手,列表資料越大,這種做法對效能的影響越大。

用程式碼來看下問題吧,看以下場景:

<ul>
  <li
    v-for="game in games"
    v-if="game.isActive"
    :key="game.slug"
  >
    {{ game.title }}
  <li>
</ul>

複製程式碼

類似於執行下面的程式碼:

this.games.map(function (game) {
  if (game.isActive) {
    return game.title
  }
})
複製程式碼

我們可以在這裡看到,我們將不得不迭代整個games陣列,無論game.isActive是否已經改變

在像Angular這樣的其他框架中,這種做法不會被編譯(`* ngIf`不能進入有`* ngFor`的同一元素)

Actions必須有返回值

這跟async/await和 Vuex的 actions有關

看以下例子:

// Store
[SOME_ACTION] () {
   // 做點什麼,需要一段時間才能執行完
   console.log(`Action done`);
}
// Consuming action
async doSomething() {
  await dispatch(SOME_ACTION);
  console.log(`Do stuff now`);
}
This will output:
// Do stuff now
// Action done
複製程式碼

發生這種情況是因為await不知道要等待什麼,相反,如果我們實際上返回了Promise.resolve(),則await將等待解析,然後再繼續

// Store
[SOME_ACTION] () {
   // 做點什麼,需要一段時間才能執行完
   console.log(`Action done`);
   Promise.resolve();
}
// Consuming action
async doSomething() {
  await dispatch(SOME_ACTION);
  console.log(`Do stuff now`);
}
This will output:
// Action done
// Do stuff now
複製程式碼

在actions和getters中使用選擇器

建立選擇器時,不單只是在應用邏輯中使用,還要在Vuex store中使用

直接用程式碼會更容易解釋: 

// 假設我們讀取以下language屬性
export const language = (state) => state.userConfig.language;
// 在其中一個actions中, 需要用到language:

// 不好的例子
[GET_GAMES]({ commit, rootState }) {
   const lang = rootState.userConfig.language;
   // Do stuff...
}

// 正確的例子
[GET_GAMES]({ commit, rootState }) {
   const lang = language(rootState);
   // Do stuff...
}
複製程式碼

總結

  1. 不要忘記在v-for迴圈中使用key
  2. 使用$_作為mixins的私有屬性字首
  3. mixin中使用的方法或者屬性應該直接在mixin中讀取
  4. 使用首字母大寫或者短橫線分隔命名單檔案元件
  5. 給基礎元件名加字首
  6. 使用首字母大寫命名命名JS中的元件
  7. 宣告 prop名時使用駝峰命名,但在模板中應使用短橫線分隔命名
  8. 遵循樣式指南中的元件選項順序
  9. 不要在使用v-for的同一元素上使用v-if
  10. Actions必須有返回值
  11. actionsgetters中使用選擇器

來源

  • https://vuejs-tips.github.io/cheatsheet/
  • https://learn-vuejs.github.io/vue-patterns/patterns/
  • https://vuejs.org/v2/style-guide/

感謝

這篇文章是由多個在同一專案中使用VueJs的開發人員合作完成的,遵循這份樣式指南和最佳實踐有助於讓每個新開發人員都能儘快熟悉並上手專案程式碼。 

如果你有什麼意見或者更好的提議,歡迎隨時評論。

相關文章