Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

Vue.jsのスタイルガイドを読んだ

More than 1 year has passed since last update.

先日、神戸三宮を中心に関西を盛り上げているVue.jsコミュニティ、三宮.vueの勉強会に初めて参加して来ました。

そこで、「Vue.jsのスタイルガイドをちゃんと読もう!」という発表に触発され、改めて自分でもスタイルガイドを読んでみました。

読んでみて、「当たり前ではないか!へのつっぱりはいらんですよ!」と思うことから、「へーー!そら知らなんだ!」ということもありましたが、どれも「エラーを防止する」「可読性を上げる」「一貫性を持たせる」「保守性を上げる」という面で大事です。

実際にスタイルガイドを読むのが一番ですが、折角なので優先度Aの必須項目をメモとして書きました。

複数単語コンポーネント名を使う

ルートの App コンポーネントや、Vue が提供する <transition><component> のようなビルトインコンポーネントを除き、コンポーネント名は常に複数単語とするべきです。

example1.vue
Vue.component('todo-item', {
  // ...
})
example2.vue
export default {
  name: 'TodoItem',
  // ...
}

これは、HTML要素の名前とコンポート名が衝突するのを防ぐのが目的です。

全ての HTML 要素は 1 単語となっているので、コンポート名として複数単語を使っているとHTMLの要素名と衝突することはないということです。

例えば todoTodo というコンポート名をつけると将来 todo というHTML要素が出て来たときに名前が被ってしまうので、コンポート名としては example1example2 のように todo-itemTodoItem というような名前にすると良いです。

コンポートのデータは関数でなければならない

コンポーネントで data プロパティを使用する際 (つまり new Vue 以外のどこでも)、その値はオブジェクトを返す関数でなければなりません。

例えば、data の値がオブジェクトの場合、それはコンポーネントの全てのインスタンスで共有されます。

bad-example.vue
export default {
  data: {
    listTitle: '',
    todos: []
  }
}

このように書き、このコンポーネントを再利用しようとした場合、コンポーネントの全てのインスタンスが同じデータオブジェクトを参照するので、1つのリストのタイトルを変えると、他のリストのタイトルも変わってしまいます。

そこで、各コンポーネントのインスタンスには自身のデータだけを管理してもらおうとすると、各インスタンスは一意のデータオブジェクトを生成する必要があります。

good-example1.vue
export default {
  data: function () {
    return {
      listTitle: '',
      todos: []
    }
  }
}

もしくは

good-example.vue
export default {
  data () {
    return {
      listTitle: '',
      todos: []
    }
  }
}

このように、関数内でオブジェクトを返すと、各インスタンスが一意のデータオブジェクトを生成することができます。(※ ルートで直接オブジェクトを使うのは OK です)

プロパティの定義はできる限り詳細とする

コミットされたコード内で、プロパティの定義は常に少なくとも1つのタイプを指定し、できる限り詳細とするべきです。

example.vue
export default {
  props: {
    status: {
      type: String,
      required: true,
    }
  }
}

typerequired を明記することで、ミスを防いだり、エラーの原因の特定をし易くするという話ですね。

v-for に対して常に key を使用する

good-example.vue
<ul>
  <li
    v-for="todo in todos"
    :key="todo.id"
  >
    {{ todo.text }}
  </li>
</ul>

このように一意のキーを振りましょう。
もし、

bad-example.vue
<li
    v-for="(item, index) in items"
    :key="index"
 >

とすると、キーの値が書き換わった場合に意図しない挙動に繋がる可能性があります。そのため、キーにはgood-exampleのように一意のidを設定するのが基本です。(参考: Vue.js: v-forで項目インデックスをkey属性にしていいのか)

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

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

good-exampleの場合、v-if をコンテナ要素に置いているので、shouldShowUsersfalse の場合は v-for を評価しません。

もしこれを、

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

このように書くと、

v-forは v-if よりも優先度が高いので、このテンプレートは、

this.users.map(function (user) {
  if (user.isActive) {
    return user.name
  }
})

と同様に評価されます。
アクティブユーザーが変更されたかどうかに関わらず、再レンダリングするたびにリスト全体を繰り返し処理する必要があります。

コンポーネントをスコープにする

アプリケーションにとって、トップレベルの App コンポーネントとレイアウトコンポーネント内のスタイルはグローバルかもしれませんが、他のすべてのコンポーネントは常にスコープされているべきです。

good-example.vue
<template>
  <button class="button button-close">X</button>
</template>

<style scoped>
.button {
  border: none;
  border-radius: 2px;
}

.button-close {
  background-color: red;
}
</style>

上の例は stylescoped 属性を使用しています。

これは、スタイルの汚染を防ごうということです。

scoped 属性を使わなくても、BEMなどを用いることで汚染を防ぐ方が良い場合もあります。

プライベートなプロパティ名を使う

プライベートな関数に外部からアクセスできないようにするために、モジュールスコープを使用してください。それが難しい場合は、プラグインやミックスインなどのプライベートなカスタムプロパティには常に$_ プレフィックスを使用してください。さらに、他の著者によるコードとの衝突を避けるため、名前付きのスコープを含めてください (例 $_yourPluginName_ )。

good-example.vue
var myGreatMixin = {
  // ...
  methods: {
    publicMethod() {
      // ...
      myPrivateFunction()
    }
  }
}

function myPrivateFunction() {
  // ...
}

export default myGreatMixin

以上がVue.jsスタイルガイドの中で、優先順位が最も高い必須7項目です。

これまでちゃんと読んだことがなかったのですが、読んだ方が良いですね。

最初に書いたように、当たり前だと思うことも知らなかったことも書いてありますが、使う上での共通認識として理解しておくべきだと感じました。

本記事で紹介している優先度Aの必須7項目以外にも優先度B(強く推奨)、C(推奨)、D(使用注意)の項目があるので、是非スタイルガイドに目を通してみてください。

そう言えば、Nuxtを使ったときにESLintに Require self-closing on Vue.js custom components”:value” should go before “〜”のように言われることがありました。これらも、優先度Bの項目の自己終了形式のコンポーネントコンポーネント名における単語の順番 に則ったルールに基づいているんですね。

知らなんだ。


三宮.vue 楽しかったので、関西にいる方は是非参加してみてください!

参考

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away