これからはじめるVue.js実践入門
posted with ヨメレバ
山田 祥寛 SBクリエイティブ 2019年08月23日頃
コンポーネント
new Vue()とコンポーネントの違い
- dataオプションはコンストラクタの場合はオブジェクトだが、コンポーネントの場合はオブジェクトを返す関数でなければならない。
※コンポーネントの場合は、それぞれが独立したdataを持つため
グローバル登録とローカル登録
グローバル登録
<script>
Vue.component('my-hello', {
template: '<p>グローバル登録されたコンポーネントです</p>',
}
})
</script>
ローカル登録
<script>
const app = new Vue({
el: '#app',
components: {
'my-hello2': {
template: '<p>ローカル登録されたコンポーネントです。</p>',
}
},
})
</script>
プロパティ(Props)
キャメルケースで定義し、ケバブケースで属性として指定する。
<script>
Vue.component('my-hello', {
template: '<p>testText:{{ testText }}</p>',
props: ['testText'],
})
</script>
<!-- と定義し、以下で呼び出し。 -->
<my-hello test-text="これはプロパティです。"></my-hello>
属性値としてxxx="yyy"と指定した場合は、全て文字列として扱われる。
xxx="1"
もpropsとしては文字列となる。- 数値として渡したい場合は
v-bind:xxx="1"
のようにv-bindを使う。 - 使うことは滅多にないと思うが、v-bindで文字列リテラルを渡す場合はシングルクォートを使って
v-bind:xxx="'hoge'"
とする必要がある。
プロパティの値は変更してはいけない。
- プロパティの値は親コンポーネントで任意のタイミングで変更される可能性があるため、受け取ったプロパティの値を変更してはいけない。
変更が必要な場合は、プロパティの値をdataの初期値とする。 - https://jp.vuejs.org/v2/guide/components-props.html#単方向のデータフロー
<script>
Vue.component('my-hello', {
template: '<div><p>text:{{ text }}</p><p>testText:{{ testText }}</p><p>newTestText:{{ newTestText }}</p></div>',
props: ['testText'],
data: function () {
return {
text: 'グローバル登録されたコンポーネントです。',
newTestText: this.testText,
}
},
mounted: function() {
this.newTestText = "warning"
}
})
</script>
プロパティの型制限
<script>
Vue.component('my-hello2', {
template: '<p>name: {{ name }} num: {{ num }} msg: {{ msg }}</p>',
props: {
name: {
type: String,
default: "hoge",
},
num: {
type: Number,
required: true,
},
msg: String
}
}
</script>
<!-- と定義し以下で呼び出し。-->
<my-hello2 v-bind:num="88" msg="zzz"></my-hello2>
<!--
型だけ指定する場合は
name: String
だが、requiredまたはdefaultも指定する場合はオブジェクトとする。
name: {
type: String,
default: "hoge",
},
defaultが配列またはオブジェクトの場合は規定値を返却する関数とする。
user: {
type: Object,
default: function() {
return {name: 'hoge'}
}
},
-->
$emitメソッド
- 子⇒親の伝達には$emitでカスタムメソッドを発生させる。
<!-- 親 -->
<my-hello v-on:plus="handleMyHelloPlus"></my-hello>
<p>count: {{ count }}</p>
<script>
{
methods: {
handleMyHelloPlus(num) {
this.count += num;
}
}
</script>
<!-- 子 -->
<script>
{
template: `<button v-on:click="handleButtonClick">$emit</button>`,
methods: {
handleButtonClick() {
this.$emit('plus', 2);
}
}
}
</script>
.native修飾子
- 親コンポーネントでは、子コンポーネントから$emitメソッドで通知されたイベントしか検知することができない。
例えば、以下は動作しない。<my-hello v-on:click="handleMyHelloClick"><my-hello>
clickなどのブラウザネイティブなイベントを受け取りたい場合は、v-onに.native修飾子を付与する。<my-hello v-on:click.native="handleMyHelloClick"><my-hello>
- .native修飾子はコンポーネントの構造に影響されやすいため、乱用するべきではない。
例えばtemplate: '<input type="text" />',
を<my-hello v-focus.native="handleMyHelloFocus"><my-hello>
と呼び出すと動作するが、template: '<label><input type="text" /></label>',
だとfocusイベントが検知できない。(focusイベントは上位要素に伝播しないため)
このように、.native修飾子は特定の条件で簡単に動作しなくなる。
スロット
スロット
呼び出し時にタグボディに指定した文字列を、コンポーネントのテンプレートに差し込むことができる。
定義
template: `<p>こんにちは<slot>ゲスト</slot>さん</p>`
呼び出し
<my-hello>テスト</my-hello>
<my-hello>{{ name }}</my-hello>
とした場合、親コンポーネントのnameが参照される。
※ 子コンポーネントのdetaオブジェクトにアクセスすることはできない
名前付きスロット
複数のスロットを埋め込む場合は名前付きスロットを利用する。
定義
template: `<div><p><slot name="header">ヘッダーです</slot></p> <p><slot name="footer">フッターです</slot></p></div>`,
呼び出し
<my-hello>
<template v-slot:header><strong>スロットにより差し込まれたヘッダーです。</strong></template>
<template v-slot:footer><strong>スロットにより差し込まれたフッターです。</strong></template>
</my-hello>
使い方
- slot要素にname属性を指定(付けない場合はname=”default”とみなされる)して定義する。
<slot name="xxx">初期値</slot>
- template要素のv-slotディレクティブで呼び出し。
<template v-slot:xxx>差し込むタグ</template>
- ※ Vue .js2.5以前はv-slotディレクティブではなくslot属性(slot属性はVue .js2.6以降では非推奨)
- 以下、あまり使うことはないと思うが。
- v-slot:[name]のように埋め込み先を動的にすることができる。
- v-slot:xxxの省略記法は#xxxである。
スコープ付きスロット
スロットを使って子コンポーネントの情報を取得することができる。
定義
template: `<p>こんにちは<slot v-bind:user="user">{{ user.name }}</slot>さん</p>`
呼び出し
<template v-slot="slotProp">{{ slotProp.user.id }}</template>
使い方
- slot要素に
v-bind:xxx="渡したいもの"
を指定して定義し、<slot v-bind:xxx="yyy">初期値</slot>
- template要素のv-slotディレクティブでスロットプロパティを受け取る。
<template v-slot="slotProp"> {{ slotProp.xxx }} </template>
- ※オブジェクトを渡す場合、呼び出し時に分割代入を使うと簡略化できる。
<template v-slot="{ user }">{{ user.name }}</template>
- ※ defaultスロットしかない場合、呼び出し時のv-slotディレクティブは<template>ではなくコンポーンネント要素に書くことができる。
<my-hello v-slot="slotProp">
コメント