Edited at

vue.jsのcomponentをwebpackで.vueにして単一ファイルコンポーネントにする

More than 1 year has passed since last update.

vue.jsのcomponentを .vue という独立した1つのファイルで管理する方法のまとめです。

vue.js公式のガイドではちらっと出たくらいで、vue-loaderなどのドキュメントを読む必要があります。

Rails5.1beta ではいきなりこの形式のhello worldが入っているので戸惑う方が多かったのではないでしょうか。

僕もその一人です。

コンポーネントと単一ファイルコンポーネントを並べて見比べる形の備忘録的なまとめです。


環境


  • vue: 2.2.6

  • vue-loader: 11.3.4

  • vue-style-loader: 2.0.5

  • vue-template-compiler: 2.2.6

  • webpack: 2.3.3

当方はjsフレームワークはvue.jsが初めてなのでreactなどとの比較は出てこないです。


componentとは

公式によると


コンポーネントは Vue.js の最も強力な機能の 1 つです。基本的な HTML 要素を拡張して再利用可能なコードのカプセル化を助けます。高いレベルでは、コンポーネントは Vue.js のコンパイラが指定された振舞いを加えるカスタム要素です。場合によっては、特別な is 属性で拡張されたネイティブな HTML 要素の姿をとることもあります。


コンポーネント - Vue.js

つらつら書かれていますが、要するに「拡張したHTMLを一塊にして独立させたもの」なイメージ。

パーツ(機能)単位で HTMLをまとめて どこで使っても同じように再利用できるようにする強力な機能。

vue.js本体のMVVMと相まってjQueryでは面倒そうなものをすっきり書けてしかも使いまわせる。やばい。 :thumbsup:


単一ファイルコンポーネント

基本的には普通のコンポーネントと同じで、パーツ単位でHTMLをまとめられる。

ただし、違うところは、名称の通り、その「パーツを構成するために必要な HTML・CSS・JSをひとまとめ に」して独立した1つのファイルで扱える。


単一ファイルコンポーネントは何が嬉しいのか

ざっくりこんな感じ。

コンポーネント
単一ファイルコンポーネント

Vueのグローバル汚染
あり
なし

シンタックスハイライト
なし
あり

CSS
無視される ※
有効

Javascript制限
あり ※
なし

この表だけだと語弊が生まれる(特に※があるもの)ので公式も見てね。

単一ファイルコンポーネント - Vue.js

特に個人的に嬉しいところは、さっきのこれ

「パーツを構成するために必要な HTML・CSS・JSをひとまとめ に」

これまではHTML・CSS・JSをそれぞれ別のファイルで管理して、id・class、詳細度、グローバル汚染に悩み、悩まされることが多々ありました。

ですが、これがあると、そんな悩みは吹き飛ぶわけですね。 :open_hands:

なぜなら、それら全てがコンポーネントの .vue ファイルの中で閉じられるからですね。 :earth_asia:


コード比較

単一ファイルコンポーネントをべた褒めしてきましたが、学習するのは面倒です。

見なければならないファイルの数が増えるわけですから。

なので、通常のコンポーネントと比較して単一ファイルコンポーネントを追っていきます。


コンポーネントを使うときはこう


app.js

// 登録する

Vue.component('my-component', {
template: '<div>A custom component!</div>'
})

// root インスタンスを作成する
new Vue({
el: '#example'
})


Vue オブジェクトに対して my-component という名前で template 部分のHTMLを登録(作成)する。

メインのインスタンスで vue.js が対象とするのは #example

<div id="example">

<my-component></my-component>
</div>

<script src="./app.js"></script>

HTMLは、 root要素に id="example" をつける。

その中のコンポーネントを挿入したいところに、呼び出すコンポーネントの名前と同じタグ(のようなもの)を記述する。

そして app.js を読み込む。

と、結果は次の通り。

<div id="example">

<div>A custom component!</div>
</div>

コンポーネントを Vue オブジェクトを拡張する形で登録(作成)し、メインのインスタンスを作るとコンポーネントの名前でHTMLが置換される。


単一ファイルコンポーネントを使うときはこう


my-component.vue

<!-- 登録する -->

<template>
<div>A custom component!</div>
</template>

.vue ファイルに <template> タグを埋め込んでその中にHTMLを書き込む


app.js

import MyComponent from './my-component.vue';

// root インスタンスを作成する
new Vue({
el: '#example',
components: { MyComponent },
template: '<my-component></my-component>'
})


ここは変わらず、メインのインスタンスで vue.js が対象とするのは #example

違うのは、 components で使いたいコンポーネントのオブジェクトを指定して、 template でコンポーネントと置き換えるタグ(のようなもの)を指定する。

もちろん、 my-component.vue は読み込む必要がありますので、 import で読み込みます。

<div id="example">

<my-component></my-component>
</div>

<script src="./app.js"></script>

ここも変わらず、HTMLは、 root要素に id="example" をつける。

その中のコンポーネントを挿入したいところに、呼び出すコンポーネントの名前と同じタグ(のようなもの) <my-component> を記述する。

そして app.js を読み込む。

結果は同じ。

ただし、コンパイルが必要です。


単一ファイルコンポーネントを拡張する

先の例だと、HTMLしか出てきませんでしたが、もちろんJSとCSSも記述できます。


my-component.vue

<template>

<div><p v-if="isVisible">{{ message }}</p></div>
</template>

<script>
export default {
data: function() {
return {
message: 'hello'
}
},
computed: {
isVisible: function() {
if (this.message) {
return true;
} else {
return false;
}
}
}
}
</script>

<style lang="scss" scoped>
// langを指定すると、scsssassでかける。その時は、scss-loaderが必要になる
// scoped をつけると、そのスタイルはこのファイル内にとどまります。
div {
text-align: center;
p {
color: red;
}
}
</style>



webpack設定

コンパイルが必要になるのでその件。

ローダーとか

Rails 5.1beta の場合は rails new hogehoge --wabpack=vue ってやれば揃えてくれる。


まとめ

また後で