«

Vue3父子组件间通信和组件间双向绑定怎么实现

时间:2024-4-19 13:52     作者:韩俊     分类: Javascript


本篇内容主要讲解“Vue3父子组件间通信和组件间双向绑定怎么实现”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Vue3父子组件间通信和组件间双向绑定怎么实现”吧!


假如确要修改,可以使用下面说的方式进行通信:
首先,在子组件的UI点击回调方法中,调用

this.$emit('【自己设置事件名】')

向外发送一个
事件


接着各级父组件会收到这个事件,
则在父组件中 调用 子组件标签处,
@【事件名】= "回调方法名"
的形式,
监听
该事件以及配置
回调方法

回调方法
中就可 对 子组件用意修改 的 父组件数据字段 进行修改;

注意,
触发事件的命名,用

驼峰命名法
(如下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('counter', {        props: ['count'],        methods: {            handleItemClick() {                this.$emit('heHeDa');            }        },        template:`        <div @click="handleItemClick">{{count}}</div>        `    });    const vm = app.mount('#heheApp');</script></html>

运行,点击组件:

携带参数的事件 发送和监听回调

this.$emit()
可以增加参数位,
父组件的监听回调中,
则可加形参位 用于接收参数(如
handleItemEvent(param)
中的
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('counter', {        props: ['count'],        methods: {            handleItemClick() {                this.$emit('addCount', 8);            }        },        template:`        <div @click="handleItemClick">{{count}}</div>        `    });    const vm = app.mount('#heheApp');</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('counter', {        props: ['count'],        methods: {            handleItemClick() {                this.$emit('addCount', 8, 2, 6);            }        },        template:`        <div @click="handleItemClick">{{count}}</div>        `    });    const vm = app.mount('#heheApp');</script>

效果:



当然 父组件 接收 子组件参数 后的 计算逻辑,
可以在 子组件传参 的时候 计算完成 再传给

this.$emit()

父组件接收时,直接 受值就可(
handleItemEvent(count)
);

<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('counter', {        props: ['count'],        methods: {            handleItemClick() {                this.$emit('addCount', this.count + 16);            }        },        template:`        <div @click="handleItemClick">{{count}}</div>        `    });    const vm = app.mount('#heheApp');</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('counter', {        props: ['count'],        emits: ['hehehe'],        methods: {            handleItemClick() {                this.$emit('addCount', this.count + 16);            }        },        template:`        <div @click="handleItemClick">{{count}}</div>        `    });    const vm = app.mount('#heheApp');</script>

假如

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

使用 组件

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('counter', {        props: ['count'],        emits: {            addCount: (count) => {                if (count < 0) {                    return true;                }                return false;            }        },        methods: {            handleItemClick() {                this.$emit('addCount', this.count + 16);            }        },        template:`        <div @click="handleItemClick">{{count}}</div>        `    });    const vm = app.mount('#heheApp');</script>

运行,点击效果:

结合

$emit
v-bind
v-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('counter', {        props: ['modelValue'],        methods: {            handleItemClick() {                this.$emit('update:modelValue', this.modelValue + 16);                console.log(vm.$data.count);            }        },        template:`        <div @click="handleItemClick">{{modelValue}}</div>        `    });    const vm = app.mount('#heheApp');</script>

效果:

当然也可以

自己设置字段名

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

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

实现效果与上例相同;

结合

$emit
v-bind
v-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('counter', {        props: ['testField','testField1'],        methods: {            handleItemClick() {                this.$emit('update:testField', this.testField + 16);                console.log("vm.$data.count", vm.$data.count);            },            handleItemClick1() {                this.$emit('update:testField1', 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('#heheApp');</script>

效果:

自己设置修饰符

机制:在父组件调用处,在

v-model
后 使用
自己设置修饰符

实现修饰符逻辑
的地方,如点击事件中,
通过
this.modelModifiers.[自己设置修饰符名]
返回的
布尔值

判断客户能否使用了修饰符,
进而分别对使用与否做相应的解决;
另外
'modelModifiers'
板块中可以
指定默认值
(下代码指定为一个空对象
{}
);

试验

this.modelModifiers
的作用

首先下面是一个空的解决,

'modelModifiers'
板块中
指定默认值
(下代码指定为一个空对象
{}
),
mounted
函数中打印 子组件
modelModifiers
属性的内容,

代码如下,
运行后,可以见打印了一个对象
{captalize: true}

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

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

下面在子组件的点击回调

handleClick()
中,通过
this.modelModifiers.[自己设置修饰符名]
实现自己设置修饰符逻辑

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

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

效果:

插槽【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('myform', {        template:`        <div>            <input />            <slot></slot>            <br><br>        </div>        `    });    const vm = app.mount('#heheApp');</script></html>

运行效果:

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

<script>    const app = Vue.createApp({        template: `            <myform>                <div>提交</div>            </myform>            <myform>                <button>提交</button>            </myform>`    });    app.component('myform', {        methods: {            handleClick() {                console.log("heheda!!===");            }        },        template:`        <div>            <input />            <span @click="handleClick">                <slot></slot>            </span>                <br><br>        </div>        `    });    const vm = app.mount('#heheApp');</script&

标签: javascript vue

热门推荐