blog

Vueコンポーネントの使用

Global ComponentCreating ComponentConstructorObjectRegistering ComponentUsing ComponentLocal Compone...

Sep 6, 2020 · 14 min. read
シェア

グローバル・コンポーネント

    1. コンポーネント・コンストラクタ・オブジェクトの作成
    1. コンポーネントの登録
    1. コンポーネントの使用
    <div id="app">
     <!--3.コンポーネントを使う--。>
     <my-cpn></my-cpn>
     <div>
     <div>
     <!--3.コンポーネントを使う--。>
     <my-cpn></my-cpn>
     </div>
     </div>
    </div>
    <div id="app2">
     <!--3.コンポーネントを使う--。>
     <my-cpn></my-cpn>
    </div>
     <!--ここでコンポーネントを使うのは無効だ。Vueにマウントされたインスタンスはすべてスコープ外にあり、Vueの管理対象外だからだ--。>
    <my-cpn></my-cpn>
    <script src="../js/vue.js"></script>
    <script>
     // 1.コンポーネントのコンストラクタ・オブジェクトを作る
     const cpnC = Vue.extend({
     template: `
     <div>
     <h2> </h2>
     <p>内容、ハハハ</p>
     <p>内容、へっへっへ</p>
     </div>`
     })
     // 2.はグローバル・コンポーネントを登録するので、マウントされた#app #app2のどれかを使えばいい。
     Vue.component('my-cpn', cpnC)
     const app = new Vue({
     el: '#app',
     data: {
     message: 'こんにちは。
     }
     })
     const app2 = new Vue({
     el: '#app2'
     })
    </script>
    

ローカルコンポーネント

<div id="app">
 <!--3.コンポーネントを使う--。>
 <my-cpn></my-cpn>
 <div>
 <div>
 <!--3.コンポーネントを使う--。>
 <my-cpn></my-cpn>
 </div>
 </div>
</div>
<div id="app2">
 <!--ここでのコンポーネントの使用は有効ではない-。>
 <my-cpn></my-cpn>
</div>
 <!--ここでのコンポーネントの使用は有効ではない-。>
<my-cpn></my-cpn>
<script src="../js/vue.js"></script>
<script>
 // 1.コンポーネントのコンストラクタ・オブジェクトを作る
 const cpnC = Vue.extend({
 template: `
 <div>
 <h2> </h2>
 <p>内容、ハハハ</p>
 <p>内容、へっへっへ</p>
 </div>`
 })
 const app = new Vue({
 el: '#app',
 data: {
 message: 'こんにちは。
 },
 components: {
 // 2.ローカルコンポーネントを登録するので、Vueインスタンスがマウントしているdomでしか使えない。
 myCpn: cpnC
 }
 })
 const app2 = new Vue({
 el: '#app2'
 })
</script>

親子コンポーネント

  • 親子コンポーネントの誤用:子タグとしてのVueインスタンスで
    • なぜなら、子コンポーネントが親コンポーネントのコンポーネントに登録されるときに、Vueは親コンポーネントのモジュールをコンパイルするからです。
    • このテンプレートの内容は、親コンポーネントによってレンダリングされる HTML をすでに決定しています。
    • <child-cpn></child-cpn>は親コンポーネントでのみ認識可能です。
    • <child-cpn></child-cpn>この場合、ブラウザによって無視されます。
  • 正しい使い方
<div id="app">
 <cpn2></cpn2>
 <!--<cpn1></cpn1>-->
</div>
<script src="../js/vue.js"></script>
<script>
 // 1.最初のコンポーネント・コンストラクタを作る
 const cpnC1 = Vue.extend({
 template: `
 <div>
 <h2> </h2>
 <p>内容、ハハハ</p>
 </div>
 `
 })
 // 2.つ目のコンポーネント・コンストラクタを作る
 const cpnC2 = Vue.extend({
 template: `
 <div>
 <h2> </h2>
 <p>内容、へっへっへ</p>
 <cpn1></cpn1>
 </div>
 `,
 components: {
 cpn1: cpnC1
 }
 })
 // root 
 const app = new Vue({
 el: '#app',
 data: {
 message: 'こんにちは。
 },
 components: {
 cpn2: cpnC2
 }
 })
</script>
  • 統語糖

    主な点は、Vue.extend()を呼び出すステップがなくなり、代わりにオブジェクトを使用できることです。

    <div id="app">
     <cpn1></cpn1>
     <cpn2></cpn2>
    </div>
    <script src="../js/vue.js"></script>
    <script>
     // 1.グローバル・コンポーネント登録のための構文シュガー
     // 1.コンポーネント・コンストラクタを作る
     // const cpn1 = Vue.extend()
     // 2.コンポーネントを登録する
     Vue.component('cpn1', {
     template: `
     <div>
     <h2> </h2>
     <p>内容、ハハハ</p>
     </div>
     `
     })
     // 2.ローカル・コンポーネントを登録するための構文上の砂糖
     const app = new Vue({
     el: '#app',
     data: {
     message: 'こんにちは。
     },
     components: {
     'cpn2': {
     template: `
     <div>
     <h2> </h2>
     <p>内容, へへへ</p>
     </div>
     `
     }
     }
     })
    </script>
    
  • コンポーネント・テンプレートは個別に記述します。

    使用

    <div id="app">
     <cpn></cpn>
     <cpn></cpn>
     <cpn></cpn>
    </div>
    <!-- 1.scriptタグ, ノート:タイプはtext/x-template--でなければならない。>
    <!--<script type="text/x-template" id="cpn">-->
    <!--<div>-->
     <!--<h2> </h2>-->
     <!--<p>内容は、ハハハ</p>-->
    <!--</div>-->
    <!--</script> -->
    <!--2.templateタグ ->
    <template id="cpn">
     <div>
     <h2> </h2>
     <p>内容は、へっへっへ</p>
     </div>
    </template>
    <script src="../js/vue.js"></script>
    <script>
     // 1.グローバル・コンポーネントを登録する
     Vue.component('cpn', {
     template: '#cpn'
     })
     const app = new Vue({
     el: '#app',
     data: {
     message: 'こんにちは。
     }
     })
    </script>
    
  • データ保存の問題

    コンポーネントは、別の機能モジュールのパッケージであり、独自の属性データを持って、データ内の親コンポーネントに直接アクセスすることはできません。

    <div id="app">
     <cpn></cpn>
     <cpn></cpn>
     <cpn></cpn>
    </div>
    <!--1.scriptタグ, ノート:タイプはtext/x-template--でなければならない。>
    <!--<script type="text/x-template" id="cpn">-->
    <!--<div>-->
     <!--<h2> </h2>-->
     <!--<p>内容は、ハハハ</p>-->
    <!--</div>-->
    <!--</script>-->
    <!--2.templateタグ ->
    <template id="cpn">
     <div>
     <h2>{{title}}</h2>
     <p>内容は、へっへっへ</p>
     </div>
    </template>
    <script src="../js/vue.js"></script>
    <script>
     // 1.グローバル・コンポーネントを登録する
     Vue.component('cpn', {
     template: '#cpn',
     data() {
     return {
     title: 'abc'
     }
     }
     })
     const app = new Vue({
     el: '#app',
     data: {
     message: 'こんにちは。,
     // title: ' 
     }
     })
    </script>
    
  • なぜコンポーネント内のデータは関数で、その中にデータを保持するオブジェクトを返すのですか?

    それが関数でない場合、それはデータを操作するために別のコンポーネントにつながるデータの他のコンポーネントにつながる一緒に変更し、関数は、データを返すコンポーネント自体に属しており、他のコンポーネントとは何の関係もありません。

    <!--コンポーネント・インスタンス・オブジェクト>
    <div id="app">
     <cpn></cpn>
     <cpn></cpn>
     <cpn></cpn>
    </div>
    <template id="cpn">
     <div>
     <h2>現在のカウント: {{counter}}</h2>
     <button @click="increment">+</button>
     <button @click="decrement">-</button>
     </div>
    </template>
    <script src="../js/vue.js"></script>
    <script>
     // 1.コンポーネントを登録する
     const obj = {
     counter: 0
     }
     Vue.component('cpn', {
     template: '#cpn',
     // この種のデータでは、各コンポーネントは独自のデータを持ち、コンポーネントの各インスタンスは新しいメモリ・アドレスに対応する新しいオブジェクトを受け取る
     data() {
     return {
     counter: 0
     }
     },
     // この種のデータでは、objがアドレスを返すので、各コンポーネントがデータを共有し、各コンポーネント・インスタンスは単一のアドレスを受け取る
     // data() {
     // return obj
     // },
     methods: {
     increment() {
     this.counter++
     },
     decrement() {
     this.counter--
     }
     }
     })
     const app = new Vue({
     el: '#app',
     data: {
     message: 'こんにちは。
     }
     })
    </script>
    
  • 親コンポーネントは子コンポーネントにデータを渡します。

    propsを介したサブコンポーネントへのデータの受け渡し

    • 方法1:文字列配列。
    • モード2:パスのタイプやデフォルト値などを設定できるオブジェクト。
    <div id="app">
     <!--<cpn v-bind:cmovies="movies"></cpn>-->
     <!--<cpn cmovies="movies" cmessage="message"></cpn>-->
     <cpn :cmessage="message" :cmovies="movies"></cpn>
    </div>
    <template id="cpn">
     <div>
     <ul>
     <li v-for="item in cmovies">{{item}}</li>
     </ul>
     <h2>{{cmessage}}</h2>
     </div>
    </template>
    <script src="../js/vue.js"></script>
    <script>
     //  : props
     const cpn = {
     template: '#cpn',
     // props: ['cmovies', 'cmessage'],
     props: {
     // 1.タイプ制限
     // cmovies: Array,
     // cmessage: String,
     // 2.デフォルト値、必須値をいくつか用意する。
     cmessage: {
     type: String,
     default: 'aaaaaaaa',
     required: true //cmessageに値を渡すたびにサブコンポーネントを使うとエラーを報告する
     },
     // 型がオブジェクトや配列の場合、デフォルト値は関数でなければならない。
     cmovies: {
     type: Array,
     default() {
     return []
     }//デフォルト値が配列やオブジェクトの場合、関数で返さないとエラーになる。
     },
     cmessage: {
     // カスタムバリデーション関数
     validtor: function (value){
     return ['こんにちは』、『お元気ですか』。].indexOf(value) !== -1
     }
     },
     },
     data() {
     return {}
     },
     methods: {
     }
     }
     const app = new Vue({
     el: '#app',
     data: {
     message: 'こんにちは。,
     movies: ['海王」「盗賊王」「ヘイル兄弟]
     },
     components: {
     cpn
     }
     })
    </script>
    
  • propsのhumpロゴとテンプレートの下に複数のタグがある場合、ルート・ノードが必要です。

    <div id="app">
     <!-- 下のハンプ識別子は使えない--。>
     <cpn :c-info="info" :child-my-message="message" v-bind:class></cpn>
    </div>
    <template id="cpn">
     <div><!-- 複数の属性を持つテンプレートはdom要素でラップする必要があり、そうしないとエラーになる--。>
     <h2>{{cInfo}}</h2>
     <h2>{{childMyMessage}}</h2>
     </div>
    </template>
    <script src="../js/vue.js"></script>
    <script>
     const cpn = {
     template: '#cpn',
     props: {
     cInfo: {
     type: Object,
     default() {
     return {}
     },
     required:true
     // この属性を使う場合、呼び出さないとエラーになる。
     },
     childMyMessage: {
     type: String,
     default: ''
     }
     }
     }
     const app = new Vue({
     el: '#app',
     data: {
     info: {
     name: 'CodingKid',
     age: 18,
     height: 1.88
     },
     message: 'Hello, Vue.js!'
     },
     components: {
     cpn
     }
     })
    </script>
    
  • 子コンポーネントから親コンポーネントへのカスタムイベントの受け渡し

    イベントの送信と同時に、親コンポーネントにパラメータを渡すことができます。

    <!--親コンポーネントのテンプレート>
    <div id="app">
     <!-- サブコンポーネントが発したイベントを受け付け、渡されたパラメータはデフォルトでcpnClickに渡される。$event,もし$event,パススルーはアイテムであって、イベントそのものではない--。>
     <!-- ここではこぶのように書くことはできないが、足場の内側では可能だ--。>
     <cpn @item-click="cpnClick"></cpn>
    </div>
    <!--サブコンポーネントのテンプレート>
    <template id="cpn">
     <div>
     <button v-for="item in categories"
     @click="btnClick(item)">
     {{item.name}}
     </button>
     </div>
    </template>
    <script src="../js/vue.js"></script>
    <script>
     // 1. 
     const cpn = {
     template: '#cpn',
     data() {
     return {
     categories: [
     {id: 'aaa', name: 'トップピックの},
     {id: 'bbb', name: '携帯電話のデジタルの},
     {id: 'ccc', name: '家電の},
     {id: 'ddd', name: 'コンピューターオフィスの},
     ]
     }//オブジェクトを返さなければならない
     },
     methods: {
     btnClick(item) {
     // 打ち上げイベント: カスタムイベント
     this.$emit('item-click', item)//(発射イベントの名前、渡されるパラメーター)
     }
     }
     }
     // 2. 
     const app = new Vue({
     el: '#app',
     data: {
     message: 'こんにちは。
     },
     components: {
     cpn
     },
     methods: {
     cpnClick(item) {
     console.log('cpnClick', item);
     }
     }
     })
    </script>
    
  • 親子コンポーネント・コミュニケーション・ケース

<div id="app">
 <cpn :number1="num1"
 :number2="num2"
 @num1change="num1change"
 @num2change="num2change"/>
</div>
<template id="cpn">
 <div>
 <h2>props:{{number1}}</h2>
 <h2>data:{{dnumber1}}</h2>
 <!--<input type="text" v-model="dnumber1">-->
 <input type="text" :value="dnumber1" @input="num1Input">
 <h2>props:{{number2}}</h2>
 <h2>data:{{dnumber2}}</h2>
 <!--<input type="text" v-model="dnumber2">-->
 <input type="text" :value="dnumber2" @input="num2Input">
 </div>
</template>
<script src="../js/vue.js"></script>
<script>
 const app = new Vue({
 el: '#app',
 data: {
 num1: 1,
 num2: 0
 },
 methods: {
 num1change(value) {
 this.num1 = parseFloat(value)
 },
 num2change(value) {
 this.num2 = parseFloat(value)
 }
 },
 components: {
 cpn: {
 template: '#cpn',
 props: {
 number1: Number,
 number2: Number
 },
 data() {
 return {
 dnumber1: this.number1,
 dnumber2: this.number2
 }
 },
 methods: {
 num1Input(event) {
 // 1.入力された値をdnumberに代入する。
 this.dnumber1 = event.target.value;//この文は欠かすことができない,
 // 2.親コンポーネントが値を変更できるようにするには、イベントを発生させる
 this.$emit('num1change', this.dnumber1)
 // 3.dnumber2の値も修正する
 this.dnumber2 = this.dnumber1 * 100;
 this.$emit('num2change', this.dnumber2);
 },
 num2Input(event) {
 this.dnumber2 = event.target.value;
 this.$emit('num2change', this.dnumber2)
 // dnumber1の値も修正する
 this.dnumber1 = this.dnumber2 / 100;
 this.$emit('num1change', this.dnumber1);
 }
 }
 }
 }
 })
</script>
  • ウォッチ属性のVモデルを使って実装
<div id="app">
 <cpn :number1="num1"
 :number2="num2"
 @num1change="num1change"
 @num2change="num2change"/>
</div>
<template id="cpn">
 <div>
 <h2>props:{{number1}}</h2>
 <h2>data:{{dnumber1}}</h2>
 <input type="text" v-model="dnumber1">
 <h2>props:{{number2}}</h2>
 <h2>data:{{dnumber2}}</h2>
 <input type="text" v-model="dnumber2">
 </div>
</template>
<script src="../js/vue.js"></script>
<script>
 const app = new Vue({
 el: '#app',
 data: {
 num1: 1,
 num2: 0
 },
 methods: {
 num1change(value) {
 this.num1 = parseFloat(value)
 },
 num2change(value) {
 this.num2 = parseFloat(value)
 }
 },
 components: {
 cpn: {
 template: '#cpn',
 props: {
 number1: Number,
 number2: Number,
 name: ''
 },
 data() {
 return {
 dnumber1: this.number1,
 dnumber2: this.number2
 }
 },
 watch: {
 dnumber1(newValue) {
 this.dnumber2 = newValue * 100;
 this.$emit('num1change', newValue);
 },
 dnumber2(newValue) {
 this.number1 = newValue / 100;
 this.$emit('num2change', newValue);
 }
 }
 }
 }
 })
</script>
  • 親コンポーネントは子コンポーネントにアクセスします: $children, $refs

    <div id="app">
     <cpn></cpn>
     <cpn></cpn>
     <cpn ref="aaa"></cpn>
     <button @click="btnClick"> </button>
    </div>
    <template id="cpn">
     <div> </div>
    </template>
    <script src="../js/vue.js"></script>
    <script>
     const app = new Vue({
     el: '#app',
     data: {
     message: 'こんにちは。
     },
     methods: {
     btnClick() {
     // 1.$children使うコンポーネントを全部取って配列にする。
     // console.log(this.$children);それは配列だ
     // for (let c of this.$children) {各コンポーネントを反復する
     // console.log(c.name);属性を使う
     // c.showMessage();使用方法
     // }
     // console.log(this.$children[3].name);
     // 2.$refs => オブジェクト・タイプは、デフォルトでは空のオブジェクトだ。
     console.log(this.$refs.aaa.name);//コンポーネントは、ここで参照されている属性と一致するref属性を持つ必要がある。
     }
     },
     components: {
     cpn: {
     template: '#cpn',
     data() {
     return {
     name: 'サブコンポーネント名'
     }
     },
     methods: {
     showMessage() {
     console.log('showMessage');
     }
     }
     },
     }
     })
    </script>
    
  • 子コンポーネントが親コンポーネントにアクセス: $parent, $root

    • Vueの開発では$parentを使った親コンポーネントへのアクセスは認められていますが、実際の開発では行わないようにしましょう!
    • サブコンポーネントは、親コンポーネントのデータへの直接アクセスを避けるようにすべきです。なぜならカップリングが高すぎるからです。
    • 子コンポーネントが別のコンポーネントの中に配置されている場合、親コンポーネントが対応するプロパティを持っていない可能性が高く、多くの場合、問題が発生します。
    <div id="app">
     <cpn></cpn>
    </div>
    <template id="cpn">
     <div>
     <h2>cpn </h2>
     <ccpn></ccpn>
     </div>
    </template>
    <template id="ccpn">
     <div>
     <h2> </h2>
     <button @click="btnClick"> </button>
     </div>
    </template>
    <script src="../js/vue.js"></script>
    <script>
     const app = new Vue({
     el: '#app',
     data: {
     message: 'こんにちは。
     },
     components: {
     cpn: {
     template: '#cpn',
     data() {
     return {
     name: 'cpnコンポーネントの名前の
     }
     },
     components: {
     ccpn: {
     template: '#ccpn',
     methods: {
     btnClick() {
     // 1.親コンポーネントにアクセスする$parent
     // console.log(this.$parent);
     // console.log(this.$parent.name);
     // 2.ルート・コンポーネントにアクセスする$root
     console.log(this.$root);
     console.log(this.$root.message);
     }
     }
     }
     }
     }
     }
     })
    </script>
    

スロットの使い方

  • スロットの基本的な使い方

    • スロットの基本的な使い方 <slot></slot>
    • スロットのデフォルト値 <slot> </slot>
    • 複数の値がある場合、それらを同時にコンポーネントに入れ替えると、入れ替え要素として一緒に使用されます。
    <div id="app">
     <cpn></cpn>
     <div>-----------------------------</div><!--- 行を分ける--。>
     <cpn><span> </span></cpn>
     <div>-----------------------------</div>
     <cpn>
     <i> </i>
     <div>div </div>
     <p>p </p>
     </cpn>
    </div>
    <template id="cpn">
     <div>
     <h2> </h2>
     <slot><button> </button></slot>
     <!--<button> </button>-->
     </div>
    </template>
    <script src="../js/vue.js"></script>
    <script>
     const app = new Vue({
     el: '#app',
     data: {
     message: 'こんにちは。
     },
     components: {
     cpn: {
     template: '#cpn'
     }
     }
     })
    </script>
    
  • 指名スロットの使用

    <div id="app">
     <cpn>
     <span slot="center"> </span>
     <button slot="left"> </button>
     </cpn>
    </div>
    <template id="cpn">
     <div>
     <slot name="left"><span> </span></slot>
     <slot name="center"><span> </span></slot>
     <slot name="right"><span> </span></slot>
     </div>
    </template>
    <script src="../js/vue.js"></script>
    <script>
     const app = new Vue({
     el: '#app',
     data: {
     message: 'こんにちは。
     },
     components: {
     cpn: {
     template: '#cpn'
     }
     }
     })
    </script>
    
  • スコープをコンパイルするスロットの使い方

    ケース

    <div id="app">
     <cpn></cpn>
     <cpn>
     <!--ゴールは、サブコンポーネントのpLanguagesを取得することだ。>
     <div slot-scope="slot"><!--slot名前だけ-。>
     <!--<span v-for="item in slot.data"> - {{item}}</span>-->
     <span>{{slot.data.join(' - ')}}</span>
     </div>
     </cpn>
     <cpn>
     <!--目標はサブコンポーネントのpLanguagesを--。>
     <div slot-scope="slot">
     <!--<span v-for="item in slot.data">{{item}} * </span>-->
     <span>{{slot.data.join(' * ')}}</span>
     </div>
     </cpn>
     <!--<cpn></cpn>-->
    </div>
    <template id="cpn">
     <div>
     <slot :data="pLanguages">
     <ul>
     <li v-for="item in pLanguages">{{item}}</li>
     </ul>
     </slot>
     </div>
    </template>
    <script src="../js/vue.js"></script>
    <script>
     const app = new Vue({
     el: '#app',
     data: {
     message: 'こんにちは。
     },
     components: {
     cpn: {
     template: '#cpn',
     data() {
     return {
     pLanguages: ['JavaScript', 'C++', 'Java', 'C#', 'Python', 'Go', 'Swift']
     }
     }
     }
     }
     })
    </script>
    
  • スロットについて

最後に書く

書くのは簡単じゃないからね。

Read next