コンポーネントの基本


目次


##基本的な例

Vue の例は次のとおりです。コンポーネントの:

// 定义一个名为 button-counter 的新组件
Vue.component('button-counter', {
  data: function () {
    return {
      count: 0
    }
  },
  template: '<button v-on:click="count++">You clicked me {{ count }} times.</button>'
})

コンポーネントは、名前:

<button-counter>

を持つ再利用可能な Vue インスタンスです。この例では。このコンポーネントは、

new Vue によって作成された Vue ルート インスタンスのカスタム要素として使用できます。

<div id="components-demo">
  <button-counter></button-counter>
</div>
new Vue({ el: '#components-demo' })

コンポーネントは再利用された Vue インスタンスであるため、 1.gifdata

computedwatchmethod、life など、new Vue と同じオプションを受け取ります。サイクルフックなど。唯一の例外は、el などのルート インスタンス固有のオプションです。


#コンポーネントの再利用

コンポーネントは何度でも再利用できます:
<div id="components-demo">
  <button-counter></button-counter>
  <button-counter></button-counter>
  <button-counter></button-counter>
</div>


ボタンをクリックすると、各コンポーネントはその

count1.jpg を個別に維持することに注意してください。コンポーネントを使用するたびに、そのコンポーネントの新しいインスタンスが作成されるためです。


#data

## 関数である必要があります この <button-counter> コンポーネントを定義すると、その data が次のようなオブジェクトを直接提供していないことがわかるかもしれません:

data: {
  count: 0
}

代わりに、 コンポーネントの data オプションは関数 でなければなりません。そのため、各インスタンスは返されたオブジェクトの個別のコピーを保持できます。

data: function () {
  return {
    count: 0
  }
}

Vue がそうする場合このルールがない場合、ボタンをクリックすると、次のコードのように他のすべてのインスタンスに影響を与える可能性があります:

2.gif


##コンポーネントの構成


通常、アプリケーションはネストされたコンポーネント ツリーの形式で編成されます。


1.png

例: 、ヘッダー、サイドバー、コンテンツ領域などのコンポーネントがあり、各コンポーネントにはナビゲーション リンクやブログ投稿などの他のコンポーネントが含まれています。

テンプレートで使用するには、これらのコンポーネントを Vue が認識できるように最初に登録する必要があります。コンポーネントの登録には、

グローバル登録ローカル登録の 2 つのタイプがあります。これまでのところ、コンポーネントは Vue.component を通じてのみグローバルに登録されています。

Vue.component('my-component-name', {
  // ... options ...
})

グローバルに登録されたコンポーネントは、(

new Vue## を通じて) 登録された後は何にでも使用できます # ) 新しく作成された Vue ルート インスタンスは、そのコンポーネント ツリー内のすべてのサブコンポーネントのテンプレートにも含まれます。 これまでのところ、コンポーネントの登録について知っておくべきことはこれだけです。このページを読み終えて内容を理解したら、戻ってきて

コンポーネントの登録

を読むことをお勧めします。


Props を介して子コンポーネントにデータを渡す

先ほど、ブログの作成について説明しました。ポストコンポーネント。問題は、ブログ投稿のタイトルやコンテンツなど、表示したいデータをこのコンポーネントに渡せない場合、使用できないことです。ここから小道具が生まれます。

Props は、コンポーネントに登録できるカスタム プロパティです。値が prop 属性に渡されると、その値はそのコンポーネント インスタンスのプロパティになります。ブログ投稿コンポーネントにタイトルを渡すには、

props

オプションを使用して、コンポーネントが受け入れる props のリストにそのタイトルを含めることができます。

Vue.component('blog-post', {
  props: ['title'],
  template: '<h3>{{ title }}</h3>'
})
コンポーネントは、次のように任意の数の props を持つことができます。デフォルトでは、任意の値を任意のプロパティに渡すことができます。上記のテンプレートでは、データ内の値にアクセスするのと同じように、コンポーネント インスタンス内のこの値にアクセスできることがわかります。

プロップが登録された後、次のようにカスタム特性としてデータを渡すことができます:

<blog-post title="My journey with Vue"></blog-post>
<blog-post title="Blogging with Vue"></blog-post>
<blog-post title="Why Vue is so fun"></blog-post>

2.jpgただし、一般的なアプリケーションでは、次のようになります。

data

:

new Vue({
  el: '#blog-post-demo',
  data: {
    posts: [
      { id: 1, title: 'My journey with Vue' },
      { id: 2, title: 'Blogging with Vue' },
      { id: 3, title: 'Why Vue is so fun' }
    ]
  }
})
内のブログ投稿の配列。各ブログ投稿のコンポーネントをレンダリングしたい:

<blog-post
  v-for="post in posts"
  v-bind:key="post.id"
  v-bind:title="post.title"
></blog-post>

上に示したように、v-bind を使用して props を動的に渡すことができることがわかります。これは、API からブログ投稿 のリストを取得する場合など、最初にレンダリングする特定のコンテンツがわからない場合に非常に便利です。

これまでのところ、prop について知っておくべきことはこれだけです。このページを読み終えて内容を理解したら、戻ってきて prop をもう一度読むことをお勧めします。


##単一ルート要素


##<blog-post> ;# を構築する場合## コンポーネントを使用すると、テンプレートにはタイトル以外にも多くのものが含まれることになります:

<h3>{{ title }}</h3>
少なくとも、ブログ投稿の本文は含まれます:
<h3>{{ title }}</h3>
<div v-html="content"></div>

ただし、これをテンプレートに記述しようとすると、Vue はエラーを表示し、

すべてのコンポーネントには単一のルート要素が必要です (各コンポーネントにはルート要素が 1 つだけ必要です)

という説明が表示されます。この問題は、テンプレートのコンテンツを親要素でラップすることで解決できます。例:

<div class="blog-post">
  <h3>{{ title }}</h3>
  <div v-html="content"></div>
</div>
コンポーネントがますます複雑になるにつれて、ブログ投稿にはタイトルとコンテンツだけでなく、出版日、レビューなども必要です。関連するメッセージごとに prop を定義するのは面倒になる可能性があります:
<blog-post
  v-for="post in posts"
  v-bind:key="post.id"
  v-bind:title="post.title"
  v-bind:content="post.content"
  v-bind:publishedAt="post.publishedAt"
  v-bind:comments="post.comments"
></blog-post>

そこで、この

<blog-post>

コンポーネントをリファクタリングして、個別の

post prop を受け入れるようにします。

<blog-post
  v-for="post in posts"
  v-bind:key="post.id"
  v-bind:post="post"
></blog-post>
Vue.component('blog-post', {
  props: ['post'],
  template: `
    <div class="blog-post">
      <h3>{{ post.title }}</h3>
      <div v-html="post.content"></div>
    </div>
  `
})
この例と次の例の一部では、複数行のテンプレートを読みやすくするために JavaScript の

テンプレート文字列
を使用しています。これらは IE ではサポートされていないため、(Babel や TypeScript などのツールを使用して) コンパイルせずに IE をサポートする必要がある場合は、代わりに

ブレークライン エスケープ文字 を使用してください。 これで、

post
オブジェクトに新しいプロパティを追加すると、そのプロパティは

<blog-post> 内で自動的に使用できるようになります。


サブコンポーネント イベントのリッスン

開発中

<ブログ- post>
コンポーネントの一部の機能では、親コンポーネントと通信する必要がある場合があります。たとえば、ページの残りの部分をデフォルトのフォント サイズに保ちながら、ブログ投稿のフォント サイズを大きくする補助機能を導入するかもしれません。

その親コン​​ポーネントで、
postFontSize

データ属性を追加することでこの機能をサポートできます:

new Vue({
  el: '#blog-posts-events-demo',
  data: {
    posts: [/* ... */],
    postFontSize: 1
  }
})
これをテンプレートで使用して、すべてのフォントを制御できます。ブログ投稿のサイズ:
<div id="blog-posts-events-demo">
  <div :style="{ fontSize: postFontSize + 'em' }">
    <blog-post
      v-for="post in posts"
      v-bind:key="post.id"
      v-bind:post="post"
    ></blog-post>
  </div>
</div>

次に、各ブログ投稿のテキストの前に、フォント サイズを拡大するボタンを追加します:

Vue.component('blog-post', {
  props: ['post'],
  template: `
    <div class="blog-post">
      <h3>{{ post.title }}</h3>
      <button>
        Enlarge text
      </button>
      <div v-html="post.content"></div>
    </div>
  `
})

問題は、このボタンが何も行わないことです。

<button>
  Enlarge text
</button>

このボタンをクリックすると、すべてのブログ投稿のテキストを拡大するように親コンポーネントに指示する必要があります。幸いなことに、Vue インスタンスは、この問題を解決するカスタム イベント システムを提供します。親コンポーネントは、ネイティブ DOM イベントを処理するのと同じように、v-on を通じて子コンポーネント インスタンスのあらゆるイベントをリッスンできます。

<blog-post
  ...
  v-on:enlarge-text="postFontSize += 0.1"
></blog-post>

同時に、子コンポーネントは、ビルドされた $emit メソッド でイベント名を渡してイベントをトリガーします:

<button v-on:click="$emit('enlarge-text')">
  Enlarge text
</button>

With thisv-on:enlarge-text="postFontSize = 0.1" リスナーの場合、親コンポーネントはイベントを受信し、 postFontSize の値を更新します。

3.gif


#イベントを使用して値をスローする

いくつかの方法イベントを使用して特定の値をスローする場合に便利です。たとえば、<blog-post> コンポーネントでテキストをどの程度拡大するかを決定したい場合があります。現時点では、$emit の 2 番目のパラメーターを使用して次の値を指定できます:

<button v-on:click="$emit('enlarge-text', 0.1)">
  Enlarge text
</button>

その後、親コンポーネントでこのイベントをリッスンするときに、$event を渡すことができます。 スローされる値にアクセスします:

<blog-post
  ...
  v-on:enlarge-text="postFontSize += $event"
></blog-post>

または、イベント ハンドラーがメソッドの場合:

<blog-post
  ...
  v-on:enlarge-text="onEnlargeText"
></blog-post>

この値は最初のパラメーターとしてこのメ​​ソッドに渡されます:

methods: {
  onEnlargeText: function (enlargeAmount) {
    this.postFontSize += enlargeAmount
  }
}


コンポーネントの v-model

を使用してカスタマイズします イベントも使用できますv-model をサポートするカスタム入力コンポーネントを作成します。覚えておいてください:

<input v-model="searchText">

は次と同等です:

<input
  v-bind:value="searchText"
  v-on:input="searchText = $event.target.value"
>

コンポーネントで使用すると、v-model は次のようになります:

<custom-input
  v-bind:value="searchText"
  v-on:input="searchText = $event"
></custom-input>

In order to make正しく動作するには、このコンポーネント内の <input> が必要です:

  • その value 属性が # という名前の変数にバインドされている必要があります。

  • # の #value
  • プロパティは、

    input イベントがトリガーされると、カスタム input イベントを通じて新しい値を渡します。

コードを書くと、次のようになります:

Vue.component('custom-input', {
  props: ['value'],
  template: `
    <input
      v-bind:value="value"
      v-on:input="$emit('input', $event.target.value)"
    >
  `
})

これで、

v-model はこのコンポーネントで完全に動作できるはずです。

<custom-input v-model="searchText"></custom-input>

これまでのところ、コンポーネントのカスタム イベントについて知っておくべきことはこれだけです。このページを読み終えて内容をマスターしたら、もう一度戻ってくることをお勧めします

カスタム イベント は読む。


スロットを介したコンテンツの配布


HTML 要素と同様に、多くの場合、A コンポーネントが必要になります。次のようなコンテンツを渡すと:

<alert-box>
  Something bad happened.
</alert-box>

は次のように表示されます:

3.jpg

幸いなことに、Vue のカスタム <slot> 要素を使用すると、これが非常に簡単になります:

Vue.component('alert-box', {
  template: `
    <div class="demo-alert-box">
      <strong>Error!</strong>
      <slot></slot>
    </div>
  `
})

ご覧のとおり、必要なのはスロットを追加するだけです。必要に応じて - とても簡単です!

これまでのところ、スロットについて知っておくべきことはこれだけです。このページを読み終えて内容をマスターしたら、戻ってきて SLOT読んでください。


#動的コンポーネント


異なるコンポーネント間の動的切り替えは非常に便利です。たとえば、マルチタブ インターフェイスの場合:


4.gif

上記のコンテンツは、Vue の

<component> 要素を介して追加できます。特殊な is 属性が実装されています:

<!-- 组件会在 `currentTabComponent` 改变时改变 -->
<component v-bind:is="currentTabComponent"></component>

上記の例では、

currentTabComponent には

  • 登録されたコンポーネントの名前、または

  • コンポーネントのオプション オブジェクト

完全なコードは、

ここ、または で表示して体験できます。このバージョンでは、登録されたコンポーネント名の代わりにコンポーネント オプション オブジェクトをバインドする例について学習します。

これまでのところ、動的コンポーネントについて知っておくべきことはこれだけです。このページを読み終えて内容を理解したら、戻ってきて

動的コンポーネントと非同期コンポーネントについて学ぶことをお勧めします。 読み終えてください。


#DOM テンプレートを解析する際の注意事項


などの一部の HTML 要素<ul>

<ol><table>、および <select> の中に要素を含めることができます。厳しい制限。 <li><tr><option> などの一部の要素は、他の特定の要素内にのみ表示できます。 これにより、これらの制約された要素を使用するときにいくつかの問題が発生します。例:

<table>
  <blog-post-row></blog-post-row>
</table>

このカスタム コンポーネント

<blog-post-row>

は無効なコンテンツとして外部に昇格され、最終的なレンダリング結果でエラーが発生します。幸いなことに、この特別な is 機能により回避策が得られます。

<table>
  <tr is="blog-post-row"></tr>
</table>
次のソースからのテンプレートを使用する場合、

この制限は

であることに注意してください。 が存在しません:

文字列 (例:
    template: '...'
  • )

  • #単一ファイル コンポーネント (.vue)

  • ##<スクリプト タイプ = "text/x-template">

  • この時点で、DOM テンプレートを解析するときの注意事項を知っておく必要があります。実際には、これはおそらく Vue のすべてです。必要な内容。おめでとう!次に学ぶべきことはたくさんありますが、まず、休憩して Vue を試し、自分でランダムに楽しいものを作成することをお勧めします。

この知識を習得したと思われる場合は、サイドバーにある詳細なコンポーネントの章を含め、完全なコンポーネント ガイドのすべてのページに戻って読むことをお勧めします。