ホームページ > ウェブフロントエンド > Vue.js > Vue3 の親コンポーネントと子コンポーネント間の通信およびコンポーネント間の双方向バインディングのメソッド

Vue3 の親コンポーネントと子コンポーネント間の通信およびコンポーネント間の双方向バインディングのメソッド

PHPz
リリース: 2023-05-15 09:28:05
転載
2986 人が閲覧しました

この記事の概要

  • 親コンポーネントと子コンポーネントはイベントを通じて通信できます

  • # #Carry Parameter イベントの送信と待機コールバック

  • コンポーネントの emis セクションを使用してコンポーネント イベントを整理します

  • コンポーネントemisObjectフォームを使用して、渡されたパラメータ値を確認します

  • $emitv-bindv-model を組み合わせて、親子コンポーネント通信 (双方向データ バインディング) を実現します

  • $emitv-bindv-model を組み合わせて親子コンポーネント通信を実現します (アプリケーション)複数のフィールドの場合)

  • 独自の修飾子を設定

    • ##実験
    • this.modelModifiers

    の役割は、サブコンポーネントのクリック コールバック
  • handleClick()

    内にあります。 this.modelModifiers. [モディファイア名を自分で設定する]モディファイアを自分で設定するロジックを実装

  • Slot【スロット】【コンポーネントの受け渡し例】
  • イベント(修飾子)をスロットタグに直接追加することはできないので、必要に応じてタグを囲むことができます。 <slot> の外側に追加し、event
  • スロット【渡す文字列の例】
  • # スロット【 サブコンポーネントを自分で設定する例】
  • #スロット スコープの問題
  • #スロット UI のデフォルト値

  • スロットの柔軟な分割と適用 [名前付きスロット]

  • ##v-slot

    コマンドの省略形
  • 共通v-for

    リスト表示の例
  • v-for

    combination
  • v-bind
  • v-slotDo リスト レンダリング省略形には deconstruction

    概念を使用します
  • ##動的コンポーネント

  • 従来の

    双方向バインディング機能
  • の使用、クリック イベントによる UI 記述方法の切り替え
    • 動的コンポーネントの作成方法

    • ##非同期コンポーネント

  • 親コンポーネントと子コンポーネントはイベントを通じて通信できます

    前のノート - 「Vue3 | コンポーネントの定義と再利用性、ローカル コンポーネント、グローバル コンポーネント、コンポーネント 中級」値と検証、単一のデータ フロー、Non-props 属性」、一方向のデータ フローの概念、
  • は、子コンポーネントが親コンポーネントのデータ フィールドを変更できないことを意味します。
本当に必要な場合を変更するには、次の方法で通信できます。

まず、サブコンポーネントの UI クリック コールバック メソッドで、

this.$emit('[イベント名を自分で設定する]')

, # を呼び出します。 ## イベント
を外の世界に送信します;

その後、すべてのレベルの親コンポーネントがこのイベントを受信し、
その後、親コンポーネント内の子コンポーネントのラベルを呼び出します、 @[イベント名] = "コールバック メソッド名" の形式で終了し、
, イベントをリッスンし、コールバック メソッド
を構成します。

Callback メソッド
子コンポーネントが変更する親コンポーネントのデータ フィールドを変更できます。トリガー イベントには # を使用して名前が付けられていることに注意してください。 ##camel case
(以下に示すように heHeDa); リスニング イベントに名前を付けるには、 水平バー間隔メソッド (以下に示すように、he-he-da)
を使用します。

コード:

<!DOCTYPE html><html><head>    <meta charset="UTF-8">    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <title>Hello World! heheheheheheda</title>    <script src="https://unpkg.com/vue@next"></script></head><body>    <div id="heheApp"></div></body><script>    const app = Vue.createApp({        data() {            return {count: 1}        },        methods: {            handleItemEvent() {                this.count += 1;            }        },        template: `        <div>            <counter :count="count" @he-he-da="handleItemEvent"/>        </div>`    });    app.component(&#39;counter&#39;, {        props: [&#39;count&#39;],        methods: {            handleItemClick() {                this.$emit(&#39;heHeDa&#39;);            }        },        template:`        <div @click="handleItemClick">{{count}}</div>        `    });    const vm = app.mount(&#39;#heheApp&#39;);</script></html>
ログイン後にコピー
実行し、コンポーネントをクリックします:
パラメータを使用したコールバックの送信と待機のイベント

##this.$emit()
パラメータ ビットを追加できます。

親コンポーネントのリッスン コールバックで、

パラメータを受け取るための形式的なパラメータ ビットを追加できます (## など) #handleItemEvent(param )

in Vue3 の親コンポーネントと子コンポーネント間の通信およびコンポーネント間の双方向バインディングのメソッドparam

);

コード:

<script>    const app = Vue.createApp({        data() {            return {count: 1}        },        methods: {            handleItemEvent(param) {                this.count += param;            }        },        template: `        <div>            <counter :count="count" @add-count="handleItemEvent"/>        </div>`    });    app.component(&#39;counter&#39;, {        props: [&#39;count&#39;],        methods: {            handleItemClick() {                this.$emit(&#39;addCount&#39;, 8);            }        },        template:`        <div @click="handleItemClick">{{count}}</div>        `    });    const vm = app.mount(&#39;#heheApp&#39;);</script>
ログイン後にコピー
実行、クリック効果:

サブコンポーネントは複数のパラメーターを送信することもできます。必要に応じて
this.$emit()

のリッスン コールバックにパラメーター ビットを追加するだけです。親コンポーネントに、対応する仮パラメータを追加して受け取るだけです:

<script>    const app = Vue.createApp({        data() {            return {count: 1}        },        methods: {            handleItemEvent(param1, param2, param3) {                this.count = this.count + param1 + param2 + param3;                console.log(this.count);            }        },        template: `        <div>            <counter :count="count" @add-count="handleItemEvent"/>        </div>`    });    app.component(&#39;counter&#39;, {        props: [&#39;count&#39;],        methods: {            handleItemClick() {                this.$emit(&#39;addCount&#39;, 8, 2, 6);            }        },        template:`        <div @click="handleItemClick">{{count}}</div>        `    });    const vm = app.mount(&#39;#heheApp&#39;);</script>
ログイン後にコピー
効果:

Vue3 の親コンポーネントと子コンポーネント間の通信およびコンポーネント間の双方向バインディングのメソッド
もちろん、その後の計算は親コンポーネントは子コンポーネントのパラメーター ロジックを受け取ります。 は、サブコンポーネントがパラメーターを渡すときに計算され、this.$emit()
に渡されます。
親コンポーネントがそれを受け取ったら、値を直接受け入れるだけです (

handleItemEvent(count)

); Vue3 の親コンポーネントと子コンポーネント間の通信およびコンポーネント間の双方向バインディングのメソッド

<script>    const app = Vue.createApp({        data() {            return {count: 1}        },        methods: {            handleItemEvent(count) {                this.count = count;                console.log(this.count);            }        },        template: `        <div>            <counter :count="count" @add-count="handleItemEvent"/>        </div>`    });    app.component(&#39;counter&#39;, {        props: [&#39;count&#39;],        methods: {            handleItemClick() {                this.$emit(&#39;addCount&#39;, this.count + 16);            }        },        template:`        <div @click="handleItemClick">{{count}}</div>        `    });    const vm = app.mount(&#39;#heheApp&#39;);</script>
ログイン後にコピー

効果は前の例と同じです;

使用 组件的emits板块 整理组件事件

实际开发场景中,我们一个组件自己设置的触发事件可能会很多,
我们不可能一个一个去梳理核实,
这个时候即可以使用 组件的emits板块 来整理组件的事件;

可以把组件中 自己设置到的事件都写在这里,方便梳理,提高可读性
或者者把 想要定义的事件 写在这里,
如此一来,假如不记得编写对应的自己设置事件,
Vue系统会在运行时 给予警告

<script>    const app = Vue.createApp({        data() {            return {count: 1}        },        methods: {            handleItemEvent(count) {                this.count = count;                console.log(this.count);            }        },        template: `        <div>            <counter :count="count" @add-count="handleItemEvent"/>        </div>`    });    app.component(&#39;counter&#39;, {        props: [&#39;count&#39;],        emits: [&#39;hehehe&#39;],        methods: {            handleItemClick() {                this.$emit(&#39;addCount&#39;, this.count + 16);            }        },        template:`        <div @click="handleItemClick">{{count}}</div>        `    });    const vm = app.mount(&#39;#heheApp&#39;);</script>
ログイン後にコピー

假如不记得编写对应的自己设置事件,Vue系统会在运行时 给予警告

Vue3 の親コンポーネントと子コンポーネント間の通信およびコンポーネント間の双方向バインディングのメソッド

使用 组件emits板块的 Object形式 校验外传的参数值

可以根据需要,使用 组件emits板块的 Object形式 校验外传的参数值,
如下,子组件的emits板块,
‘key’值定义对应的事件名,‘value’值定义一个校验函数,

返回true表示同意数值外传,
返回false表示不同意,会给出警告;

<script>    const app = Vue.createApp({        data() {            return {count: 1}        },        methods: {            handleItemEvent(count) {                this.count = count;                console.log(this.count);            }        },        template: `        <div>            <counter :count="count" @add-count="handleItemEvent"/>        </div>`    });    app.component(&#39;counter&#39;, {        props: [&#39;count&#39;],        emits: {            addCount: (count) => {                if (count < 0) {                    return true;                }                return false;            }        },        methods: {            handleItemClick() {                this.$emit(&#39;addCount&#39;, this.count + 16);            }        },        template:`        <div @click="handleItemClick">{{count}}</div>        `    });    const vm = app.mount(&#39;#heheApp&#39;);</script>
ログイン後にコピー

运行,点击效果:Vue3 の親コンポーネントと子コンポーネント間の通信およびコンポーネント間の双方向バインディングのメソッド

结合$emitv-bindv-model 实现 父子组件通信(数据双向绑定)

v-model可以实现数据字段与DOM节点内容的双向绑定,
也可以实现数据字段与数据字段之间的双向绑定;
v-bind只能是实现单向数据流

若不自己设置承接的字段名,则需要用modelValue作为默认的承接字段名
同时,$emit()的一参默认为update:modelValue,二参为绑定的数据;

如下代码,
子组件 的承接变量modelValue 同父组件的count字段 双向绑定,
(实际上就是v-model的特性 —— 将 子组件的内容即modelValue 同 父组件的数据字段双向绑定)
而后显示在子组件的DOM中({{modelValue}}):

<script>    const app = Vue.createApp({        data() {            return {count: 1}        },        template: `            <counter v-model="count"/>`    });    app.component(&#39;counter&#39;, {        props: [&#39;modelValue&#39;],        methods: {            handleItemClick() {                this.$emit(&#39;update:modelValue&#39;, this.modelValue + 16);                console.log(vm.$data.count);            }        },        template:`        <div @click="handleItemClick">{{modelValue}}</div>        `    });    const vm = app.mount(&#39;#heheApp&#39;);</script>
ログイン後にコピー

效果:Vue3 の親コンポーネントと子コンポーネント間の通信およびコンポーネント間の双方向バインディングのメソッド

当然也可以自己设置字段名
这种方式需要给v-model字段接一个字段名,
同时将这个字段名替代子组件中所有modelValue的位置:

<script>    const app = Vue.createApp({        data() {            return {count: 1}        },        template: `            <counter v-model:testField="count"/>`    });    app.component(&#39;counter&#39;, {        props: [&#39;testField&#39;],        methods: {            handleItemClick() {                this.$emit(&#39;update:testField&#39;, this.testField + 16);                console.log(vm.$data.count);            }        },        template:`        <div @click="handleItemClick">{{testField}}</div>        `    });    const vm = app.mount(&#39;#heheApp&#39;);</script>
ログイン後にコピー

实现效果与上例相同;

结合$emitv-bindv-model 实现 父子组件通信(多个字段的应用案例)

如下代码,
父组件的count与子组件承接的testField字段,
父组件的count1与子组件承接的testField1字段,
分别实现了双向绑定:

<script>    const app = Vue.createApp({        data() {            return {                count: 1,                count1: 1            }        },        template: `            <counter v-model:testField="count" v-model:testField1="count1"/>`    });    app.component(&#39;counter&#39;, {        props: [&#39;testField&#39;,&#39;testField1&#39;],        methods: {            handleItemClick() {                this.$emit(&#39;update:testField&#39;, this.testField + 16);                console.log("vm.$data.count", vm.$data.count);            },            handleItemClick1() {                this.$emit(&#39;update:testField1&#39;, this.testField1 + 8);                console.log("vm.$data.count1", vm.$data.count1);            }        },        template:`        <div @click="handleItemClick">{{testField}}</div>        <div @click="handleItemClick1">{{testField1}}</div>        `    });    const vm = app.mount(&#39;#heheApp&#39;);</script>
ログイン後にコピー

效果:Vue3 の親コンポーネントと子コンポーネント間の通信およびコンポーネント間の双方向バインディングのメソッド

自己设置修饰符

机制:在父组件调用处,在v-model后 使用自己设置修饰符
实现修饰符逻辑的地方,如点击事件中,
通过this.modelModifiers.[自己设置修饰符名]返回的布尔值
判断客户能否使用了修饰符,
进而分别对使用与否做相应的解决;
另外&#39;modelModifiers&#39;板块中可以指定默认值(下代码指定为一个空对象{});

试验this.modelModifiers的作用

首先下面是一个空的解决,&#39;modelModifiers&#39;板块中指定默认值(下代码指定为一个空对象{}),
mounted函数中打印 子组件modelModifiers属性的内容,

代码如下,
运行后,可以见打印了一个对象{captalize: true}
正是我们传入的自己设置修饰符.captalize(这里未做解决)
【假如这里v-model不接修饰符,
console.log(this.modelModifiers);将打印一个空对象{}】:

<script>    const app = Vue.createApp({        data() {            return {                char: &#39;a&#39;            }        },        template: `            <counter v-model.captalize="char"/>`    });    app.component(&#39;counter&#39;, {        props: {            &#39;modelValue&#39;: String,            &#39;modelModifiers&#39;: {                default: () => ({})            }        },        mounted() {            console.log(this.modelModifiers);        },        methods: {            handleClick() {                this.$emit(&#39;update:modelValue&#39;, this.modelValue + &#39;h&#39;);                console.log("vm.$data.count", vm.$data.char);            }        },        template:`        <div @click="handleClick">{{modelValue}}</div>        `    });    const vm = app.mount(&#39;#heheApp&#39;);</script>
ログイン後にコピー

Vue3 の親コンポーネントと子コンポーネント間の通信およびコンポーネント間の双方向バインディングのメソッド

下面在子组件的点击回调handleClick()中,通过this.modelModifiers.[自己设置修饰符名]实现自己设置修饰符逻辑

实现效果即 点击之后使得对应的字符串 全变大写;

<script>    const app = Vue.createApp({        data() {            return {                testString: &#39;a&#39;            }        },        template: `            <counter v-model.heheda="testString"/>`    });    app.component(&#39;counter&#39;, {        props: {            &#39;modelValue&#39;: String,            &#39;modelModifiers&#39;: {                default: () => ({})            }        },        mounted() {            console.log(this.modelModifiers);        },        methods: {            handleClick() {                let newValue = this.modelValue + &#39;h&#39;;                if(this.modelModifiers.heheda) {                    newValue = newValue.toUpperCase();                }                this.$emit(&#39;update:modelValue&#39;, newValue);                console.log("vm.$data.count", vm.$data.testString);            }        },        template:`        <div @click="handleClick">{{modelValue}}</div>        `    });    const vm = app.mount(&#39;#heheApp&#39;);</script>
ログイン後にコピー

效果:

Vue3 の親コンポーネントと子コンポーネント間の通信およびコンポーネント間の双方向バインディングのメソッド

插槽【slot】【传组件示例】

使用关键 主要分两个部分:
自己设置子组件:
在需要 被父组件插入组件的位置,
使用<slot></slot>标签对临时占位;

父组件:
在调用子组件标签对时,
子组件标签对
写上 要替换子组件标签对<slot></slot>位置的组件

【slot】的出现,
方便父子组件之间数据的传递,
方便DOM的传递;

<!DOCTYPE html><html><head>    <meta charset="UTF-8">    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <title>Hello World! heheheheheheda</title>    <script src="https://unpkg.com/vue@next"></script></head><body>    <div id="heheApp"></div></body><script>    const app = Vue.createApp({        template: `            <myform>                <div>提交</div>            </myform>            <myform>                <button>提交</button>            </myform>`    });    app.component(&#39;myform&#39;, {        template:`        <div>            <input />            <slot></slot>            <br><br>        </div>        `    });    const vm = app.mount(&#39;#heheApp&#39;);</script></html>
ログイン後にコピー

运行效果:Vue3 の親コンポーネントと子コンポーネント間の通信およびコンポーネント間の双方向バインディングのメソッド

注意,slot标签上是无法直接增加事件(修饰符)的,如有需要,可以在<slot>外层包裹一层标签,再加上事件

<script>    const app = Vue.createApp({        template: `            <myform>                <div>提交</div>            </myform>            <myform>                <button>提交</button>            </myform>`    });    app.component(&#39;myform&#39;, {        methods: {            handleClick() {                console.log("heheda!!===");            }        },        template:`        <div>            <input />            <span @click="handleClick">                <slot></slot>            </span>                <br><br>        </div>        `    });    const vm = app.mount(&#39;#heheApp&#39;);</script>
ログイン後にコピー

运行,点击提交文本或者按钮:Vue3 の親コンポーネントと子コンポーネント間の通信およびコンポーネント間の双方向バインディングのメソッド

插槽【传 字符串示例】

<script>    const app = Vue.createApp({        template: `            <myform>                66666            </myform>            <myform>                88888            </myform>`    });    app.component(&#39;myform&#39;, {        methods: {            handleClick() {                console.log("heheda!!===");            }        },        template:`        <div>            <input />            <span @click="handleClick">                <slot></slot>            </span>                <br><br>        </div>        `    });    const vm = app.mount(&#39;#heheApp&#39;);</script>
ログイン後にコピー

Vue3 の親コンポーネントと子コンポーネント間の通信およびコンポーネント間の双方向バインディングのメソッド

插槽【传 自己设置子组件 示例】

<script>    const app = Vue.createApp({        template: `            <myform>                <test />            </myform>            <myform>                88888            </myform>`    });    app.component(&#39;test&#39;, {        template: `<div>test component</div>`    })    app.component(&#39;myform&#39;, {        methods: {            handleClick() {                console.log("heheda!!===");            }        },        template:`        <div>            <input />            <span @click="handleClick">                <slot></slot>            </span>                <br><br>        </div>        `    });    const vm = app.mount(&#39;#heheApp&#39;);</script>
ログイン後にコピー

运行:Vue3 の親コンポーネントと子コンポーネント間の通信およびコンポーネント間の双方向バインディングのメソッド

插槽作用域问题

尽管,父组件中 往子组件标签间 插入的组件 会替换子组件的插槽位,
但是父组件中 往子组件标签间 插入的组件,
其所使用的数据字段,依然是父组件的,而非子组件

父组件的template中 调用的数据是 父组件中的 data;
子组件的template中 调用的数据是 子组件中的 data;

<script>    const app = Vue.createApp({        data() {            return {                text: &#39;提交&#39;            }        },        template: `            <myform>                <div>{{text}}</div>            </myform>            <myform>                <button>{{text}}</button>            </myform>`    });    app.component(&#39;myform&#39;, {        methods: {            handleClick() {                console.log("heheda!!===");            }        },        template:`        <div>            <input />            <span @click="handleClick">                <slot></slot>            </span>                <br><br>        </div>        `    });    const vm = app.mount(&#39;#heheApp&#39;);</script>
ログイン後にコピー

Vue3 の親コンポーネントと子コンポーネント間の通信およびコンポーネント間の双方向バインディングのメソッド

插槽 UI默认值

可以在子组件的插槽<slot>标签间 编写默认值
假如父组件没有使用 组件 注入插槽
则对应位置 会显示默认值

<script>    const app = Vue.createApp({        data() {            return {                text: &#39;提交&#39;            }        },        template: `            <myform>                <div>{{text}}</div>            </myform>            <myform>                <button>{{text}}</button>            </myform>            <myform>            </myform>`    });    app.component(&#39;myform&#39;, {        methods: {            handleClick() {                console.log("heheda!!===");            }        },        template:`        <div>            <input />            <span @click="handleClick">                <slot>default value</slot>            </span>                <br><br>        </div>        `    });    const vm = app.mount(&#39;#heheApp&#39;);</script>
ログイン後にコピー

效果:Vue3 の親コンポーネントと子コンポーネント間の通信およびコンポーネント間の双方向バインディングのメソッド

插槽的灵活拆分与应用【具名插槽】

  • 使得插槽的 父组件注入部分 和 子组件占位部分,能够更加灵活的布局,

    可以通过v-slot:[插槽名]来对一组插槽命名,
    父组件定义之后 插槽名及其对应的组件之后,

    子组件只要要在要占位的地方,
    配合name属性 使用对应命名的<slot>标签,
    就可将对应的父组件插槽组件占用过来;

  • 父组件 的插槽注入部分的组件,
    需要用