「これからはじめるVue.js実践入門」の感想・備忘録3

スポンサーリンク
「これからはじめるVue.js実践入門」の感想・備忘録2の続き

コンポーネント

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'"とする必要がある。

プロパティの値は変更してはいけない。

<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">

コメント