前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Vue3 | 父子组件间通信、组件间双向绑定的高级内容、插槽详解、动态组件、异步组件

Vue3 | 父子组件间通信、组件间双向绑定的高级内容、插槽详解、动态组件、异步组件

作者头像
凌川江雪
发布2021-03-23 14:47:28
6.2K0
发布2021-03-23 14:47:28
举报
文章被收录于专栏:李蔚蓬的专栏

完整原文地址见简书https://cloud.tencent.com/developer/article/1805447

本文内容提要

  • 父子组件可通过事件 进行通信
  • 携带参数的事件 发送和监听回调
  • 使用 组件的**emits**板块 整理组件事件
  • 使用 组件**emits**板块的 Object**形式 校验外传的参数值**
  • 结合**$emit**、**v-bind**与**v-model** 实现 父子组件通信(数据双向绑定)
  • 结合**$emit**、**v-bind**与**v-model** 实现 父子组件通信(多个字段的应用案例)
  • 自定义修饰符
代码语言:txt
复制
- **实验****`this.modelModifiers`****的作用**
代码语言:txt
复制
- **常规的利用****`双向绑定特性`****,通过点击事件切换UI的写法**
- **动态组件写法**
父子组件可通过事件 进行通信

前面的笔记 —— 《Vue3 | 组件的定义及复用性、局部组件、全局组件、组件间传值及其校验、单项数据流、Non-props属性》,单向数据流的概念,

即子组件无法修改来自父组件的数据字段,

如果确要修改,可以使用下面说的方式进行通信:

首先,在子组件的UI点击回调方法中,调用**this.$emit('【自定义事件名】')**,

向外发送一个**事件**;

接着各级父组件会收到这个事件,

则在父组件中 调用 子组件标签处,

@【事件名】= "回调方法名"**的形式,**监听**该事件以及配置**回调方法**;**

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

注意, 触发事件的命名,用**驼峰命名法**(如下heHeDa); 监听事件的命名,用**横杆间隔法(如下he-he-da)**。

代码:

代码语言:javascript
复制
<!DOCTYPE html>
<html lang="en">
<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**);**

代码:

代码语言:javascript
复制
<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()**按需添加参数位,

父组件的监听回调中,添加对应的形参 去接收即可:

代码语言:javascript
复制
<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)**);

代码语言:javascript
复制
<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系统会在运行时 给予**警告**:

代码语言:javascript
复制
<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**表示不同意,会给出警告;

代码语言:javascript
复制
<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>

运行,点击效果:

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

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

若不自定义**承接的字段名**,则需要用**modelValue**作为默认的**承接字段名**;

同时,**$emit()**的一参默认为**update:modelValue**,二参为绑定的数据;

如下代码,

子组件 的承接变量**modelValue** 同父组件的**count**字段 双向绑定,

(实际上就是**v-model**的特性 —— 将 子组件的内容即**modelValue** 同 父组件的**数据字段**双向绑定)

然后显示在子组件的DOM中(**{{modelValue}}**):

代码语言:javascript
复制
<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**的位置:

代码语言:javascript
复制
<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>

实现效果与上例相同;

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

如下代码,

父组件的**count**与子组件承接的**testField**字段,

父组件的**count1**与子组件承接的**testField1**字段,

分别实现了双向绑定:

代码语言:javascript
复制
<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);**将打印一个空对象**{}**】:**

代码语言:javascript
复制
<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.[自定义修饰符名]实现自定义修饰符逻辑

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

代码语言:javascript
复制
<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的传递;

代码语言:javascript
复制
<!DOCTYPE html>
<html lang="en">
<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>标签,再加上事件
代码语言:javascript
复制
<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
复制
<script>
    const app = Vue.createApp({
        template: `
            <myform>
                66666
            </myform>
            <myform>
                88888
            </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
复制
<script>
    const app = Vue.createApp({
        template: `
            <myform>
                <test />
            </myform>
            <myform>
                88888
            </myform>`
    });

    app.component('test', {
        template: `<div>test component</div>`
    })

    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>

运行:

插槽作用域问题

虽然,父组件中 往子组件标签间 插入的组件 会替换子组件的插槽位, 但是父组件中 往子组件标签间 插入的组件, 其所使用的数据字段,仍然是父组件的,而非子组件父组件的template中 调用的数据是 父组件中的 data; 子组件的template中 调用的数据是 子组件中的 data;

代码语言:javascript
复制
<script>
    const app = Vue.createApp({
        data() {
            return {
                text: '提交'
            }
        },
        template: `
            <myform>
                <div>{{text}}</div>
            </myform>
            <myform>
                <button>{{text}}</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>
插槽 UI默认值

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

代码语言:javascript
复制
<script>
    const app = Vue.createApp({
        data() {
            return {
                text: '提交'
            }
        },
        template: `
            <myform>
                <div>{{text}}</div>
            </myform>
            <myform>
                <button>{{text}}</button>
            </myform>
            <myform>
            </myform>`
    });

    app.component('myform', {
        methods: {
            handleClick() {
                console.log("heheda!!===");
            }
        },
        template:`
        <div>
            <input />
            <span @click="handleClick">
                <slot>default value</slot>
            </span>    
            <br><br>
        </div>
        `
    });

    const vm = app.mount('#heheApp');
</script>

效果:

插槽的灵活拆分与应用【具名插槽】
  • 使得插槽的 父组件注入部分 和 子组件占位部分,能够更加灵活的布局,

可以通过**v-slot:[插槽名]**来对一组插槽命名,

父组件定义之后 插槽名**及其对应的**组件**之后,**

子组件只需要在要占位的地方,

配合**name**属性 使用对应命名的<slot>标签,

即可将对应的父组件插槽组件占用过来;

  • 父组件 的插槽注入部分的组件, 需要用<template>标签组包裹起来, 使用**v-slot:[插槽名]**命名一组插槽;
  • 子组件使用**<slot name="[插槽名]"></slot>**的形式,进行插槽组件块的临时占用;
代码语言:javascript
复制
<script>
    const app = Vue.createApp({
        template: `
            <layout>
                <template v-slot:header>
                    <div>头部</div>
                </template>
                <template v-slot:footer>
                    <div>尾部</div>
                </template>
            </layout>`
    });

    app.component('layout', {
        template:`
        <div>
            <slot name="header"></slot>
            <div>content</div>
            <slot name="footer"></slot>
        </div>
        `
    });

    const vm = app.mount('#heheApp');
</script>

效果:

v-slot指令的简写

v-slot:[插槽名] 可以简写成 #[插槽名]

代码语言:javascript
复制
<script>
    const app = Vue.createApp({
        template: `
            <layout>
                <template #header>
                    <div>头部</div>
                </template>
                <template #footer>
                    <div>尾部</div>
                </template>
            </layout>`
    });

    app.component('layout', {
        template:`
        <div>
            <slot name="header"></slot>
            <div>content</div>
            <slot name="footer"></slot>
        </div>
        `
    });

    const vm = app.mount('#heheApp');
</script>

实现的效果同上例;

普通的v-for例子 进行 列表渲染

下面在子组件中,

使用v-for指令 循环 子组件的数据,创建DOM组件:

代码语言:javascript
复制
<script>
    const app = Vue.createApp({
        template: `
            <test-list />`
    });

    app.component('test-list', {
        data(){
            return { 
                list: ["heheda", "xixi" , "lueluelue"]
            }
        },
        template:`
        <div>
            <div v-for="item in list">{{item}}</div>
        </div>
        `
    });

    const vm = app.mount('#heheApp');
</script>

运行效果:

v-for结合v-bindv-slot<slot>做列表渲染

作用:给**数据**由**子组件**提供, 但**列表UI实现** 由**父组件**调用处提供, 类似于**回调接口**的设计逻辑!!!

子组件使用**v-for**循环获取数据,

每一轮迭代 获得的子项数据,

通过**v-bind**设置到**占位的<slot>标签**中,

父组件中,在引用的 子组件标签上,

使用**v-slot**承接 子组件通过**v-bind**传来的所有数据字段,

同时将这些字段打包成一个类似**JSONObject**的**结构 字段**,

并为这个**字段** 指定一个**形参名**(如下代码中的**mySlotProps**);

【注意! 前面是, 使用**v-slot**命名父组件中 拟填充插槽的组件, 子组件在**<slot>标签**上,通过**name=**使用 父组件的命名,灵活填充插槽; 而这里是, 的**slot**反而是起到了类似**props**的作用,而非之前的命名组件作用!】

拟填充插槽**的DOM组件中,**

使用方才 v-slot**指定的形参,用于**开箱取数据**:**

代码语言:javascript
复制
<script>
    const app = Vue.createApp({
        template: `
            <test-list v-slot="mySlotProps"> 
                <div>{{mySlotProps.item}}</div>
            </test-list>`
    });

    app.component('test-list', {
        data(){
            return { 
                list: ["heheda", "xixi" , "lueluelue"]
            }
        },
        template:`
        <div>
            <slot v-for="item in list" :item="item" />
        </div>
        `
    });

    const vm = app.mount('#heheApp');
</script>

运行效果同上例;

使用解构概念进行简写

使用**v-slot="{item}"**替代前面的**props**的结构逻辑形式;

意义是,把**mySlotProps**这个承接属性的字段,

里面的**item**属性直接**解构 剥取**出来,直接拿来用;

代码语言:javascript
复制
<script>
    const app = Vue.createApp({
        template: `
            <test-list v-slot="{item}"> 
                <div>{{item}}</div>
            </test-list>`
    });

    app.component('test-list', {
        data(){
            return { 
                list: ["heheda", "xixi" , "lueluelue"]
            }
        },
        template:`
        <div>
            <slot v-for="item in list" :item="item" />
        </div>
        `
    });

    const vm = app.mount('#heheApp');
</script>

运行效果同上例;

动态组件
常规的利用双向绑定特性,通过点击事件切换UI的写法:
代码语言:javascript
复制
<script>
    const app = Vue.createApp({
        data() {
            return {
                currentItem: 'input-item'
            }
        },
        methods: {
            handlerClick() {
                this.currentItem === 'input-item'?
                this.currentItem = 'div-item': this.currentItem = 'input-item'
            }
        },
        template: `
            <input-item v-show="currentItem === 'input-item'" />
            <div-item v-show="currentItem === 'div-item'" />
            <button @click="handlerClick">切换DOM组件</button>`
    });

    app.component('input-item', {
        template:`
        <input />`
    });

    app.component('div-item', {
        template:`<div>heheda</div>`
    });

    const vm = app.mount('#heheApp');
</script>

运行效果:

动态组件写法
  • 语法: 一般在父组件中, 使用占位标签**<component :is="[需显示的 子组件名]" />**, 效果即 占位位置,会显示 is**属性 指定组件名的子组件;** 另外, 使用**<keep-alive>**标签,包裹**<component :is="[需显示的 子组件名]" />**, 可以是切换组件的时候,能够缓存组件的数据, 如一个有**输入数据**的<input> 切换成一个其他组件 再切换 回来的时候, 可以保留一开始的**输入数据**:
代码语言:javascript
复制
<script>
    const app = Vue.createApp({
        data() {
            return {
                currentItem: 'input-item'
            }
        },
        methods: {
            handlerClick() {
                console.log("handlerClick ----- ");
                this.currentItem === 'input-item'?
                this.currentItem = 'div-item': this.currentItem = 'input-item'
            }
        },
        template: `
            <keep-alive>
                <component :is="currentItem" />
            </keep-alive>
            <button @click="handlerClick">切换DOM组件</button>`
    });

    app.component('input-item', {
        template:`
        <input />`
    });

    app.component('div-item', {
        template:`<div>heheda</div>`
    });

    const vm = app.mount('#heheApp');
</script>

运行效果:

初始为有输入数据的输入框:

点击切换为文本组件:

再次点击,切换为**有输入数据的输入框**,

由于**<keep-alive>**的作用,数据缓存下来,没有丢失,

如果没加**<keep-alive>**,这里会是空的输入框:

异步组件

首先,

本文在此案例之前的所有案例,都是**同步组件**,

即随即渲染,一个线程运行;

下面是**异步(自定义子)组件**,

可以设定在某个时刻开始,延迟一个时延后,再执行渲染:

代码语言:javascript
复制
<script>
    const app = Vue.createApp({
        template: `
            <div>
                <div-item />
                <my-async-item />
            </div>`        
    });

    app.component('div-item', {
        template:`<div>heheda heheda</div>`
    });

    app.component('my-async-item', Vue.defineAsyncComponent(() => {
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve({
                    template: `<div>this is my async component</div>`
                })
            }, 4000)
        })
    }))

    const vm = app.mount('#heheApp');
</script>

关键代码【**异步(自定义子)组件**】:

代码语言:javascript
复制
    app.component('my-async-item', Vue.defineAsyncComponent(() => {
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve({
                    template: `<div>this is my async component</div>`
                })
            }, 4000)
        })
    }))

运行效果:

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 本文内容提要
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档