はじめに
今日もとりあえずVueの内容について殴り書きしていく。
componentとは
Webサイトの画面はヘッダー、メイン、フッターなど色々な部品から構成されている。そこで、コンポーネントという機能を使えば、ヘッダーなどの部品(コンポーネント)ごとに、HTML, CSS, JSを1セットにしたものを作れる。しかもコンポーネントは再利用が可能。
コンポーネントの基本の書き方
<script> Vue.component('コンポーネント名(タグ名)', { data() { // 処理 }, template: '描画したいHTMLの内容' }) </script>
ex.)ボタンをクリックするとカウントが増えていく処理
<script src="https://cdn.jsdelivr.net/npm/vue"></script> <div id="app"> <button-counter></button-counter> </div> <script> Vue.component('button-counter', { data() { return { count: 0 } }, template: '<button v-on:click="count ++">{{ count }}</button>' }) new Vue({ el: '#app' }) </script>
以下のように、登録したコンポーネントは再利用できる。
<div id="app">
<button-counter></button-counter>
<button-counter></button-counter>
<button-counter></button-counter>
</div>
親コンポーネントから子コンポーネントへのデータの渡し方
コンポーネントを登録するとコンポーネント名が与えられるが、そのコンポーネント名は Vue.component の第一引数で指定すること(以下ではtodo-item)。
そして、Vueインスタンス(親コンポーネント)のdataは、子コンポーネントに記述しているprops
で受け取ることができる。
ちなみにprops: ['val']
のvalは何でもおk。val
に親のデータ(=data)が入ってくることは忘れないようにしたい。
templateには利用したいHTMLを記述する。以下ではtemplate: '<li>{{ val.text }}</li>'
と記述している。
(index.html) <div id="app"> <ol> <todo-item v-for="item in groceryList" v-bind:val="item" ></todo-item> </ol> </div>
(main.js) <script> // 子コンポーネント Vue.component('todo-item', { props: ['val'], template: '<li>{{ val.text }}</li>' }) // 親コンポーネント new Vue({ el: '#app', data: { groceryList: [ { id: 0, text: 'Vegetables' }, { id: 1, text: 'Cheese' }, { id: 2, text: 'Whatever else humans are supposed to eat' } ] } }) </script>
>> 出力結果 1. Vegetables 2. Cheese 3. Whatever else humans are supposed to eat
上記のmain.js
のtemplate内でval.id
とすれば、描画内容が変わる。
(main.js) <script> // 子コンポーネント Vue.component('todo-item', { props: ['val'], template: '<li>{{ val.id }}</li>' }) ... ..... </script>
>> 出力結果 1. 0 2. 1 3. 2
グローバル登録とローカル登録
- グローバル登録...全ての(ルート)Vueインスタンス(new Vue({ ... }))で利用できる。 グローバル登録したコンポーネントは使用しない場合でもビルドされるので、ダウンロードするJSのファイルサイズが大きくなり負荷がかかる。
- ローカル登録..登録したVueインスタンスでのみ利用できる。
グローバル登録
<div id="app1"> <h1>app1</h1> <hello-component></hello-component> </div> <div id='app2'> <h2>app2</h2> <hello-component></hello-component> </div>
<script> // hello-component を登録 Vue.component('hello-component', { template: '<div>Hello Vue.js</div>' }) // 複数のVueインスタンス new Vue({ el: '#app1' }) new Vue({ el: '#app2' }) </script>
>> 出力結果 app1 Hello Vue.js app2 Hello Vue.js
ローカル登録
el: '#app1'
で紐付けたDOM要素(<div id="app1">
)にlocal-component1を登録。
<div id="app1"> <h1>app1</h1> <local-component1></local-component1> </div> <div id="app2"> <h2>app2</h2> <local-component1></local-component1> </div>
<script> // elで紐付けたapp1にだけ、local-component1を登録 new Vue({ el: '#app1', components: { 'local-component1': { template: '<div>local 1</div>' } } }) </script>
>> 出力結果 app1 local1 app2
子コンポーネントから親コンポーネントへのデータの渡し方
子でemitを使って、親にデータを渡す。
$emit('イベント名', 渡すデータA, 渡すデータB, ...);
以下では、子コンポーネントのボタンのクリック数を、親コンポーネントで参照している。
<script> // 子コンポーネント Vue.component('button-counter', { template: '<button v-on:click="childEvent">{{ counter }}</button>', data: ()=> { return { counter: 0 } }, methods: { childEvent: function () { this.counter += 1 this.$emit('increment') } }, }) // 親コンポーネント new Vue({ el: '#counter-event', data: { total: 0 }, methods: { parentEvent: function () { this.total += 1 } } }) </script>
<div id="counter-event"> <p>クリック数:{{ total }}</p> <button-counter v-on:increment="parentEvent"></button-counter> </div>
処理の流れ
- 子コンポーネントでボタンが押され、childEventが発火→子コンポーネントの数値が加算される。
this.$emit('increment')
でincrementイベントが発火→親コンポーネント(counter-eventというプロパティで紐付けたVueインスタンス)のparentEventメソッドが実行される。- parentEventメソッドで親コンポーネントの数値が加算される。
出力結果
https://i.gyazo.com/a65dc8188bdfe157b4680f500131a376.mp4