Vue.jsでコンポーネント用のオブジェクト(オプションオブジェクト)をマウントする方法のまとめです。
オプションオブジェクトは別ファイルに分けましょう
Vue.jsのサイトや入門書では、次のように new Vue
にオブジェクトを丸ごと入れる書き方が紹介されています。
var app = new Vue({
el: '#app',
data() {
return {
message: 'hello'
};
}
});
これはよい方法ではありません。実際に運用されるアプリケーションでこの書き方をすると、オブジェクトの内容が長くなったときに、ソースコードが読みづらくなります。
オプションオブジェクトは別のjsファイルまたはvueファイルにしてエクスポート、インポートするようにしましょう。
<div id="app"></div>
<template>
<div>
{{message}}
</div>
</template>
<script>
export default {
data() {
return {
message: 'hello'
};
}
})
</script>
import Vue from 'vue';
import App from './app.vue';
new Vue(App).$mount('#app');
この書き方をするにはWebpackが必要で面倒ですが、Vue.jsの学習を始めるときにも、最初からファイルを分ける書き方で行くのがおすすめです。これは、仕事で作ったプロジェクトに入門用の書き方を持ち込んでしまい、メンテしづらいコードにしてしまったという私の反省です。
学習用にWebpackを使うには、Vue CLIを使うのが簡単です。Railsの人はWebpackerを使えばいいでしょう。手作業でスクラッチからWebpackを使うこともできます。
マウントの基本形
繰り返しになりますが、オプションオブジェクトをマウントするには、最初は次の形だけ覚えればよいでしょう。
import Vue from 'vue';
import App from './app.vue';
new Vue(App).$mount('#app');
Vue 3では、次のようになります。mount
に$
が付かないことに注意しましょう。
import { createApp } from 'vue';
import App from './app.vue';
createApp(App).mount('#app');
テンプレートがHTML内にある場合
VueのテンプレートをHTML内に置く場合も、同じような形になります。オプションオブジェクトのファイルはjsファイルでもいいですし、<script> ... </script>
だけのvueファイルでもいいです。
<div id="app">
{{message}}
</div>
export default {
data() {
return {
message: 'hello'
};
}
})
import Vue from 'vue';
import App from './app.js';
new Vue(App).$mount('#app');
この場合は、マウント時にHTML内の <div id="app"> ... </div>
はDOMツリーから削除され、テンプレートを元に作られた新しいdiv要素が埋め込まれます(jQueryであれこれしたいときは、mounted
メソッドに書かなければならないのはこのためです)。
elオプション
どのHTML要素にマウントするのかを指定するのにel
オプションを使うこともできます。el
オプションがあると、$mount
メソッドを呼ばなくても自動的にマウントされます。
import Vue from 'vue';
import App from './app.js';
new Vue({ ...App, el: '#app' });
Vue 3のcreateApp
ではel
オプションが効きません。Vue 3に備えるために、el
オプションは使わずに上記の基本形を使うとよいでしょう。
propsを渡す方法
次のようにプロパティ(props)のあるVueコンポーネントもマウントできます。
<template>
<div>
<h1 :style="{color: color}">{{message}}</h1>
</div>
</template>
<script>
export default {
props: ['color'],
data() {
return {
message: 'hello'
};
}
}
</script>
マウントするときは、render
だけのオブジェクトを作り、その中でh
メソッドの第1引数にインポートしたオブジェクト、第2引数にプロパティを渡す、という形にします。
Vue.jsのマウントのしかたについては、これと上記の基本形の2パターンだけ覚えればいいと思います。
import Vue from 'vue';
import App from './app.js';
new Vue({
render: h => h(App, { props: { color: 'red' } })
}).$mount('#app');
Vue 3では次のようにします。記述量がちょっと減りました。
import { createApp, h } from 'vue';
import App from './app.js';
createApp({
render: () => h(App, { color: 'red' })
}).mount('#app');
propsDataオプションとVue 3での書き方
上記のようにプロパティを渡すと、親コンポーネント(render
だけのオブジェクトによる)とその子コンポーネント(インポートしたオブジェクトによる)の2つが作られます。これはちょっと無駄な感じがします。
また、テンプレートのないオブジェクト(HTML内にテンプレートを置く場合など)では、上記のrender
を使ったマウントはできません。
あまり紹介されることのないpropsData
というオプションでプロパティを渡すことができます。この場合はコンポーネントが1つだけで済みます。
import Vue from 'vue';
import App from './app.js';
new Vue({ ...App, propsData: { color: 'red' } }).$mount('#app');
ただし、Vue 3のcreateApp
ではpropsData
が効きません。その代わり、createApp
の第2引数にプロパティを渡せるようになりました。これは便利。
import { createApp } from 'vue';
import App from './app.js';
createApp(App, { color: 'red' }).mount('#app');
おまけ
引数を渡さずに$mount
メソッドを読んでもVueコンポーネントができます。この場合、$el
は親のないDOMオブジェクトとなるので、appendChild
などで追加します。
この例はRailsのrails webpacker:install:vue
でできるファイルで見つけました。
import Vue from 'vue';
import App from './app.js';
let app = new Vue(App1).$mount();
document.getElementById('app1').appendChild(app.$el);
なお、この方法はVue 3では使えません。