format_list_bulleted
【Vue.js】Vue.jsのスタイルガイドをわかりやすく解説
最終更新日時:2020-05-08 11:03:48



Vue.jsを使っていてhtmlファイルやtemplate内部でディレクティブを描く順番はどうすればいいんだろうか?や、コンポーネントを定義する際にはpropsやcomputed、templateはどんな順番で書けば良いのだろうとお持ったことはないですか?

このような細かいことはプログラムに支障が出ることはさることながら、そうでないものも可読性をあげる意味で統一した方がベターです。Vue.jsではこのような疑問に対してスタイルガイドを提供しています。本記事ではこのスタイルガイドを例も挙げてわかりやすく書いてみました。是非参考にしてみてください。

Vueインスタンスのオプションの書き順について

コンポーネント/インスタンス オプションは、一貫した順序になるべき

  1. 副作用 (コンポーネント外への影響)
    el
  2. グローバルな認識 (コンポーネントを超えた知識が必要)
    name
    parent
  3. コンポーネントの種類 (コンポーネントの種類を変更)
    functional
  4. テンプレートの修飾子 (テンプレートのコンパイル方法を変更)
    delimiters
    comments
  5. テンプレートの依存関係 (テンプレートで使用されるアセット)
    components
    directives
    filters
  6. 合成 (プロパティをオプションにマージ)
    extends
    mixins
  7. インタフェース (コンポーネントへのインタフェース)
    inheritAttrs
    model
    props/propsData
  8. ローカルの状態 (ローカル リアクティブ プロパティ)
    data
    computed
  9. イベント (リアクティブなイベントによって引き起こされたコールバック)
    watch
  10. ライフサイクルイベント (呼び出される順)
    beforeCreate
    created
    beforeMountmounted
    beforeUpdate
    updated
    activated
    deactivated
    beforeDestroy
    destroyed
  11. リアクティブではないプロパティ (リアクティブシステムから独立したインスタンス プロパティ)
    methods
  12. レンダリング (コンポーネント出力の宣言的な記述)
    template/render
    renderError

Vueの要素の属性の順番について

Vueの要素の属性 (コンポーネントを含む) は、一貫した順序になるべき

  1. 定義 (コンポーネントオプションを提供)
    is
  2. リスト描画 (同じ要素の複数のバリエーションを作成する)
    v-for
  3. 条件 (要素が描画/表示されているかどうか)
    v-if
    v-else-if
    v-else
    v-show
    v-cloak
  4. 描画修飾子 (要素の描画方法を変更)
    v-pre
    v-once
  5. グローバルな認識 (コンポーネントを超えた知識が必要)
    id
  6. 一意の属性 (一意の値を必要とする属性)
    ref
    key
  7. 双方向バインディング (バインディングとイベントの結合)
    v-model
  8. その他の属性 (すべての指定されていないバインドされた属性とバインドされていない属性)
  9. イベント (コンポーネントのイベントリスナ)
    v-on
  10. コンテンツ (要素のコンテンツを上書きする)
    v-html
    v-text

ディレクティブに関すること

常にv-forに対してはkeyを設定する

data: function () {
  return {
    todos: [
      {
        id: 1,
        text: 'Learn to use v-for'
      },
      {
        id: 2,
        text: 'Learn to use key'
      }
    ]
  }
}
<ul>
  <li
    v-for="todo in todos"
    :key="todo.id"
  >
    {{ todo.text }}
  </li>
</ul>

v-forとv-ifを一緒に使うのを避ける

(ダメな例)

<ul>
  <li
    v-for="user in users"
    v-if="user.isActive"
    :key="user.id"
  >
    {{ user.name }}
  </li>
</ul>

(いい例)

<ul v-if="shouldShowUsers">
  <li
    v-for="user in users"
    :key="user.id"
  >
    {{ user.name }}
  </li>
</ul>

プロパティ名は、定義の時は常にキャメルケース(camelCase)にするべき

props: {
  greetingText: String
}

プロパティ名は、テンプレートではケバブケース(kebab-case)にするべき

<WelcomeMessage greeting-text="hi"/>

複数の属性をもつ要素は、1 行に 1 要素ずつ、複数の行にわたって書くべき

(ダメな例)

<img src="https://vuejs.org/images/logo.png" alt="Vue Logo">

(いい例)

<img
  src="https://vuejs.org/images/logo.png"
  alt="Vue Logo"
>

複雑な式は算出プロパティかメソッドにリファクタリングして、コンポーネントのテンプレートには単純な式だけを含むようにするべき

(ダメな例)

{{
  fullName.split(' ').map(function (word) {
    return word[0].toUpperCase() + word.slice(1)
  }).join(' ')
}}

(いい例)

<!-- テンプレート内 -->
{{ normalizedFullName }}

// 複雑な式を算出プロパティに移動
computed: {
  normalizedFullName: function () {
    return this.fullName.split(' ').map(function (word) {
      return word[0].toUpperCase() + word.slice(1)
    }).join(' ')
  }
}

複雑な算出プロパティは、できる限りたくさんの単純なプロパティに分割するべき

(ダメな例)

computed: {
  price: function () {
    var basePrice = this.manufactureCost / (1 - this.profitMargin)
    return (
      basePrice -
      basePrice * (this.discountPercent || 0)
    )
  }
}

(いい例)

computed: {
  basePrice: function () {
    return this.manufactureCost / (1 - this.profitMargin)
  },
  discount: function () {
    return this.basePrice * (this.discountPercent || 0)
  },
  finalPrice: function () {
    return this.basePrice - this.discount
  }
}

空ではない HTML 属性の値は常に引用符(シングルコーテーションかダブルコーテーション、 JS の中で使われていない方)でくくるべき

<input type="text">
<AppSidebar :style="{ width: sidebarWidth + 'px' }">

ディレクティブの短縮記法 (v-bind: に対する : 、 v-on: に対する @ 、 v-slot: に対する #)は、常に使うか、まったく使わないかのどちらかにするべき

コンポーネントに関すること(コンポーネントを使わない場合は読まなくても良い)

コンポーネント名は一部を除き常に複数単語にするべき

Vue.component('todo-item', {
  // ...
})

export default {
  name: 'TodoItem',
  // ...
}

コンポーネントのデータは関数でなくてはならない

Vue.component('some-comp', {
  data: function () {
    return {
      foo: 'bar'
    }
  }
})

プロパティの定義はできるだけ詳細にする(statusのみで大丈夫)

props: {
  status: String
}

各コンポーネントは別のファイルに書く(ファイルを統合できるビルドシステムがある時なのでWebpackなどを扱わない問題は不要)

components/
|- TodoList.js
|- TodoItem.js

コンポーネントのファイル名は全てパスカルケースかケバブケースにする

components/
|- MyComponent.vue

または

components/
|- my-component.vue

コンポーネント名はケバブケースで記述する(パスカルケースは使い分けがめんどくさいので使用しない)

<!-- どこでも -->
<my-component></my-component>

中身を持たないコンポーネントは、 単一ファイルコンポーネント 、文字列テンプレート、および JSX の中では自己終了形式で書く

<my-component/>

中身を持たないコンポーネントは、DOMテンプレート中(HTMLファイルに直接各形式)では自己終了形式で書くことができないので空の要素として記述する

<my-component></my-component>

コンポーネント名には、略語よりも完全な単語を使うべき

(ダメな例)

components/
|- SdSettings.vue
|- UProfOpts.vue

(いい例)

components/
|- StudentDashboardSettings.vue
|- UserProfileOptions.vue

単一ファイルコンポーネントでは、 <script> 、 <template> 、 <style> タグを一貫した順序にするべき <style> は最後

親子間のやりとりは、this.$parent や変化するプロパティよりも、プロパティとイベントが推奨される

グローバル状態管理には、this.$root やグローバルイベントバスよりも、Vuex が推奨される

さいごに

本記事ではVue.jsのスタイルガイドについて紹介しました。全て覚えるのは大変ですが、一度読んでおくと後から参照もできるのでいいでしょう。皆さんも読みやすいコード書いていきましょう!