グローバル・コンポーネント
- コンポーネント・コンストラクタ・オブジェクトの作成
- コンポーネントの登録
- コンポーネントの使用
<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>スロットについて
最後に書く
書くのは簡単じゃないからね。





