学习Vue3.0笔记

Vue3简介

在这里插入图片描述
代号:One Piece(海贼王)

Vue3.0相对于Vue2多了些什么?

1.性能的提升

根据官方文档描述,Vue3.0性能的提升提升主要包括以下几个方面:

  • 打包大小减少了41%。
  • 初次渲染55%,更新渲染快了133%。
  • 内存减少54%。

2.源码改变

  • 响应式的实现。之前我们知道Vue2的响应式是通过Object.definePropetry()实现并且有些小瑕疵(对于对象属性的增加和删除),而Vue3.0则通过Es6Proxy函数实现响应式。
  • 重写了对虚拟DOM的实现和Tree-Shaking

3.拥抱TS

  • 更好的兼容TypeScript。

4.新特性(重点)

  • Composition API(组合式API)
    setup,ref,reactive,watch,watchEffect,provide,inject
  • 内置组件
    Fragment,Teleport,Suspense…
  • 其它改变
    生命周期函数等等…

常用的组合式API

Vue3工程创建

我们还可以和之前一样用Vue-Clil来创建Vue3.0的工程,但是我们Vue3.0还可以使用vite来创建。

  • vite
    之前我们的前端构建工具大多数用的都是webpack,但是我们尤大给我们提供了新的前端构建工具就是vite,主要的优势:开发环境无需打包可冷启动热重载

结构分析

我在这里还是使用我们Vue-Cli来创建Vue3的工程
其实大概结构还是和Vue2是差不多的,首先我们先看一下入口文件

// Vue3引入了一个名为createAPP的工厂函数,并对外壳组件App进行挂载
import { createApp } from 'vue'
import App from './App.vue'

createApp(App).mount('#app')

之前我们在Vue2中,我们是通过new Vue()的实例和渲染函数,通过$mount对外壳组件进行挂载。
其他包括外壳组件App,和其他配置比如 vue.config.js等等都是几乎一样的,我们遇到的时候再说。

组合式API-setup

setup是Vue3的一个新的配置项,值为一个函数。包含我们需要用到的数据,方法,计算属性,生命周期等等。同时需要返回一个包含数据方法计算属性等等的对象或者一个渲染函数
-------返回对象:

<template>
    <div>我是App组件</div>
    <h3>我的名字是{{person.name}}</h3>
    <h3>我的年龄是{{person.age}}</h3>
    <button @click="sayHello">点我SayHello</button>

</template>

<script>
export default {
    name: "App",
    setup() {
        let person = {
            name: "花生",
            age: 23,
        };
        function sayHello() {
            alert(`大家好,我的名字是${person.name},今年${person.age}岁了。`);
        }
        return { person, sayHello };
    },
};
</script>

在这里插入图片描述
-------返回渲染函数:

<template>
    <div>我是App组件</div>
    <!-- <h3>我的名字是{{person.name}}</h3>
    <h3>我的年龄是{{person.age}}</h3> -->
    <!-- <button @click="sayHello">点我SayHello</button> -->

</template>

<script>
import { h } from "@vue/runtime-core";
export default {
    name: "App",
    setup() {
        // let person = {
        //     name: "花生",
        //     age: 23,
        // };
        // function sayHello() {
        //     alert(`大家好,我的名字是${person.name},今年${person.age}岁了。`);
        // }
        // return { person, sayHello };
        return () => h("h2", "返回渲染函数");
    },
};
</script>

在这里插入图片描述
当返回是渲染函数的时候,不管我们模板中写了什么,都会被渲染函数替换掉。
我们看到上面代码的时候很当然的就会想到,这些数据目前都没有响应式,那Vue3 的响应式是怎么实现的呢?

实现响应式-ref和reactive

------ref:
在Vue2中我们使用ref为一个元素打标识,但是在Vue3 中我们的ref是一个函数,这两个可不是一个东西。而是在Vue3 中多出来一个ref函数。

<template>
    <div>我是App组件</div>
    <h3>我的名字是{{name}}</h3>
    <h3>我的年龄是{{age}}</h3>
    <button @click="changeInfo">修改人的信息</button>

</template>

<script>
export default {
    name: "App",
    setup() {
        let name = "花生";
        let age = 23;
        function changeInfo() {
            name = '土豆',
            age = 32
            console.log(name,age);
        }
        return {
            name,
            age,
            changeInfo,
        };
    },
};
</script>

在这里插入图片描述
当我们点击按钮修改数据后,数据其实已经改了,但是vue并没有捕获到,就是说我们现在定义的数据根本就不是响应式。
1.ref定义基本类型数据

<template>
    <div>我是App组件</div>
    <h3>我的名字是{{name}}</h3>
    <h3>我的年龄是{{age}}</h3>
    <button @click="changeInfo">修改人的信息</button>

</template>

<script>
import { ref } from '@vue/reactivity';
export default {
    name: "App",
    setup() {
        let name = ref("花生");
        let age = ref(23);
        function changeInfo() {
            name.value = '土豆',
            age.value = 32
            console.log(name,age);
        }
        return {
            name,
            age,
            changeInfo,
        };
    },
};
</script>

在这里插入图片描述
通过ref函数返回的其实是一个RefImpl(reference Implement)引用对象的实例对象,
其实,ref函数在实现基本类型的响应式的时候也是和Vue2的实现方法一样,通过Object.defineProperty()get/set进行数据劫持来实现的。

2.ref定义对象类型数据

<template>
    <div>我是App组件</div>
    <h3>我的名字是{{name}}</h3>
    <h3>我的年龄是{{age}}</h3>
    <h3>我的工作是{{job.type}}</h3>
    <h3>我的薪水是{{job.salary}}</h3>
    <button @click="changeInfo">修改人的信息</button>
    <button @click="changeSalary">修改人的薪水</button>

</template>

<script>
import { ref } from '@vue/reactivity';
export default {
    name: "App",
    setup() {
        let name = ref("花生");
        let age = ref(23);
        let job = ref({
            type:"前端工程师",
            salary:20
        })
        function changeInfo() {
            name.value = '土豆',
            age.value = 32
        }
        function changeSalary() {
            job.value.type = "Java工程师"
            job.value.salary ++
            console.log(job);
        }
        return {
            name,
            age,
            job,
            changeInfo,
            changeSalary
        };
    },
};
</script>

在这里插入图片描述
Vue3.0在处理对象类型的数据响应式时,使用的并不是Object.defineProperty()而是底层通过Es6的Proxy实现响应式。

  1. reactive定义对象类型数据
setup() {
        let person = reactive({
            name: "花生",
            age: 23,
            job: {
                type: "前端工程师",
                salary: 20,
            },
        });
        function changeInfo() {
            person.name = "土豆";
            person.age = 32;
        }
        function changeSalary() {
            person.job.type = "Java工程师";
            person.job.salary++;
            console.log(person);
        }
        return {
            person,
            changeInfo,
            changeSalary,
        };
    },

在这里插入图片描述

其实,我们使用ref来定义对象类型数据的时候,Vue3也是通过reactive来实现响应式的。

Vue2和Vue3的响应式实现对比

1.回顾一下Vue2 的响应式实现。

<html>

<body>
    <input id="input" name="value" type="text">
    <br>
    输入的是:<h3 id="myInput"></h3>

    <script>
        var data = {}

        document.getElementById('input').oninput = function (e) {
            data.name = e.target.value
        }
        Object.defineProperty(data, 'name', {
            get: function () {
                return data.name
                console.log("data被读取了");
            },
            set: function (val) {
                document.getElementById('myInput').innerHTML = val
                console.log("data被修改了");
            }
        })


    </script>
</body>

</html>

在这里插入图片描述

通过Object.defineProperty()的get/set进行数据劫持实现响应式。

2.Vue3.0实现响应式
Vue3.0对于基本类型使用ref函数实现响应式,原理还是之前的Object.defineProperty()的get/set 数据劫持。
我们这里主要说Vue3对于其他类型的数据的响应式的处理,Vue3在这里并没有跟之前一样使用Object.defineProperty()而是使用Es6的一个在Window上的新方法:Proxy

Proxy(代理)介绍

//target:需要被代理的对象
//handler:也是一个对象,用来定义被代理的行为
let proxy = new Proxy(target,handler)
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Vue3响应式</title>
</head>

<body>
    <script>
        let person = {
            name: "花生",
            age: 23
        }
        let p = new Proxy(person, {})

    </script>

</body>

</html>

在这里插入图片描述

Reflect

ES6 中将 Object 的一些明显属于语言内部的方法移植到了 Reflect 对象上。
在这里插入图片描述
Proxy相对应。我们的Vue3的响应式就可以这样实现:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Vue3响应式</title>
</head>

<body>
    <script>
        let person = {
            name: "花生",
            age: 23
        }
        let p = new Proxy(person, {
            get(target, propName) {
                console.log(`p身上的${propName}属性被读取了`);
                return Reflect.get(person, propName)
            },
            set(target, propName, value) {
                console.log(`p身上的${propName}属性被修改了,要去更新页面了!`);
                Reflect.set(person, propName, value)
            },
            deleteProperty(target, propName) {
                console.log(`p身上的${propName}属性被删除了`);
                return Reflect.deleteProperty(target, propName)
            },
        })

    </script>

</body>

</html>

在这里插入图片描述

setup的两个参数

export default {
    name: "Test",
    props: {
        job: {
            type: String,
            default: "",
        },
        salary: {
            type: Number,
            default: 0,
        },
    },
    emits: ["sayHello"],
    setup(props, context) {
        console.log(props, context);
        let person = reactive({
            name: "花生",
            age: 23,
        });
        function sayHello() {
            context.emit("sayHello", person.name);
        }
        return {
            person,
            sayHello,
        };
    },
};

在这里插入图片描述
第一个参数props:值为对象,都组件外部传进来且组件内部声明接收了的参数
第二个参数context:
1.attrs:值为对象,由组件外部传进来但是组价内部没有声明接收的属性。
2.emit:分发自定义事件函数。
3.slots:收到的插槽内容(虚拟DOM)。

计算属性

  • 简写形式(只读)
<template>
    <div class="app">
        <h3>我是App组件</h3>
        姓:<input v-model="person.fristName">
        <br>
        名:<input v-model="person.lastName">
        <br>
        全名:{{person.fullName}}

    </div>
</template>

<script>
import { reactive } from "@vue/reactivity";
import { computed } from "@vue/runtime-core";
export default {
    name: "App",
    setup() {
        let person = reactive({
            fristName: "花",
            lastName: "生",
        });
        //简写形式(只读)
        person.fullName = computed(() => {
            return person.fristName + "-" + person.lastName;
        });

        return {
            person,
        };
    },
};
</script>
<style scoped>
.app {
    background: orange;
    padding: 10px;
    height: 300px;
}
</style>

在这里插入图片描述

  • 完整形式(读写)
person.fullName = computed({
            get() {
                return person.fristName + "-" + person.lastName;
            },
            set(value) {
                let nameArr = value.split("-");
                person.fristName = nameArr[0];
                person.lastName = nameArr[1];
            },
        });

在这里插入图片描述

watch监听

  • 监听单个ref定义的基本类型数据
<template>
    <div class="app">
        <h3>我是App组件</h3>
        <h3>{{sum}}</h3><br>
        <button @click="sum++">点我+1</button>

    </div>
</template>

<script>
import { ref } from "@vue/reactivity";
import { watch } from "@vue/runtime-core";
export default {
    name: "App",
    setup() {
        let sum = ref(0);
        watch(sum, (newValue, oldValue) => {
            console.log(`sum改变`, newValue, oldValue);
        },{immediate:true});

        return {
            sum,
        };
    },
};
</script>
<style scoped>
.app {
    background: orange;
    padding: 10px;
    height: 300px;
}
</style>

在这里插入图片描述

  • 监听多个ref定义的基本类型数据
		watch([sum, name], (newValue, oldValue) => {
            console.log(`sum或name改变`, newValue, oldValue);
        });

在这里插入图片描述
newValue和oldValue都变成了数组。

  • 监听单个reactive定义的数据
watch(person, (newValue, oldValue) => {
            console.log(`person改变`, newValue, oldValue);
        });

在这里插入图片描述
newValue和oldValue值相同,同时默认强制开启了深度监听

  • 监听reactive定义的响应式数据中的某个属性
		watch(()=>person.age, (newValue, oldValue) => {
            console.log(`person.age改变`, newValue, oldValue);
        });
  • 监听reactive定义的响应式数据中的多个属性
		watch(
            () => [person.age, person.name],
            (newValue, oldValue) => {
                console.log(`person.age改变`, newValue, oldValue);
            }
        );

在这里插入图片描述

watchEffect

		watchEffect(() => {
            const x1 = person.name;
            const x2 = person.age;
            console.log(`watchEffect被调用了!`);
        });

watch和watchEffect对比

  • watch:既要指明被监听的属性,也要指明监听的回调。
  • watchEffect:不需要指明监听的属性,监听的回调中用到那个属性,就监听哪个属性。

生命周期

  • Vue2的生命周期钩子

在这里插入图片描述

  • Vue3.0的生命周期钩子

在这里插入图片描述
整体观察,我们发现,Vue3.0因为先判断了是否挂载成功而少了一个判断环节,也减少了两个生命周期钩子(brforeCreate,created)资源的浪费。同时,beforeUNmount和unmounted的名字的更改。
我们来实际体验一下各个生命周期函数被调用的顺序。

  • 通过配置项的方式使用生命周期钩子

Demo.vue


<template>
    <div class="demo">
        <h3>我是App组件</h3>
        <h3>{{sum}}</h3>
        <button @click="sum++">点我+1</button>

    </div>
</template>

<script>
import { reactive, ref } from "@vue/reactivity";
export default {
    name: "App",
    setup() {
        let sum = ref(0);

        return {
            sum,
        };
    },

    beforeCreate() {
        console.log("------beforeCreate------");
    },
    created() {
        console.log("------created------");
    },
    beforeMount() {
        console.log("------beforeMount------");
    },
    mounted() {
        console.log("------creamountedted------");
    },
    beforeUpdate() {
        console.log("------beforeUpdate------");
    },
    updated(){
        console.log("------updated------");
    },
    beforeUnmount(){
        console.log("------beforeUnmount------");
    },
    unmounted(){
        console.log("------unmounted------");
    }
};
</script>
<style scoped>
.demo {
    background: orange;
    padding: 10px;
    height: 200px;
}
</style>

App.vue

<template>
    <div class="app">
        <Demo v-if="isShowDemo" />
        <button @click="isShowDemo = !isShowDemo">是否展示Demo</button>

    </div>
</template>

<script>
import { reactive, ref } from "@vue/reactivity";
import Demo from "./components/Demo.vue";
export default {
    components: { Demo },
    name: "App",
    setup() {
        let isShowDemo = ref(true);

        return {
            isShowDemo,
        };
    },
};
</script>
<style scoped>
.app {
    background: gray;
    padding: 10px;
    height: 300px;
}
</style>

Demo初始化挂载时

在这里插入图片描述

数据修改时
在这里插入图片描述
卸载之后重新挂载时
在这里插入图片描述

  • 使用组合式API
    官网给出的在setup()内部调用的生命周期钩子(只截取了部分)。
    在这里插入图片描述

<template>
    <div class="demo">
        <h3>我是App组件</h3>
        <h3>{{sum}}</h3>
        <button @click="sum++">点我+1</button>

    </div>
</template>

<script>
import { reactive, ref } from "@vue/reactivity";
import {
    onBeforeMount,
    onBeforeUnmount,
    onBeforeUpdate,
    onMounted,
    onUnmounted,
    onUpdated,
} from "@vue/runtime-core";
export default {
    name: "App",
    setup() {
        console.log("------setup------");
        let sum = ref(0);
        onBeforeMount(() => {
            console.log("------onBeforeMount------");
        });
        onMounted(() => {
            console.log("------onMounted------");
        });
        onBeforeUpdate(() => {
            console.log("------onBeforeUpdate------");
        });
        onUpdated(() => {
            console.log("------onUpdated------");
        });
        onBeforeUnmount(() => {
            console.log("------onBeforeUnmount------");
        });
        onUnmounted(() => {
            console.log("------onUnmounted------");
        });

        return {
            sum,
        };
    },
};
</script>
<style scoped>
.demo {
    background: orange;
    padding: 10px;
    height: 200px;
}
</style>

自定义hook函数

本身是一个函数,对setup()中的组合式API进行了封装,实现代码复用类似于Vue2.x的mixin。我们还是用最经典的例子——屏幕打点。

Demo.vue


<template>
    <div class="demo">
        <h3>我是Demo组件</h3>
        <h3>打点坐标是: x:{{point.x}},y:{{point.y}}</h3>
    </div>
</template>

<script>
import { reactive, ref } from "@vue/reactivity";
import { onBeforeUnmount, onMounted } from "@vue/runtime-core";
import usePoint from "../hooks/usePoint";
export default {
    name: "App",
    setup() {
        let point = usePoint();

        return {
            point,
        };
    },
};
</script>
<style scoped>
.demo {
    background: orange;
    padding: 10px;
    height: 200px;
}
</style>

hooks—>usePoint.js

import { reactive, ref } from "@vue/reactivity";
import { onBeforeUnmount, onMounted } from "@vue/runtime-core";

export default function () {
    let point = reactive({
        x: 0,
        y: 0,
    });

    function getPoint(event) {
        point.x = event.pageX;
        point.y = event.pageY;
        console.log(point.x, point.y);
    }
    onMounted(() => {
        window.addEventListener("click", getPoint);
    });
    onBeforeUnmount(() => {
        window.removeEventListener("click", getPoint);
    });
    return point
}

在这里插入图片描述

toRef和toRefs

  • toRef
<template>
    <div class="app">
        <h3>我是App组件</h3>
        <h4>{{person}}</h4>
        <h3>姓名:{{name}}</h3>
        <h3>年龄:{{age}}</h3>
        <h3>工作:{{salary}}块大洋</h3>
        <button @click="name+='~'">修改姓名</button>
        <button @click="age++">年龄+1</button>
        <button @click="salary++">涨薪</button>
    </div>
</template>

<script>
import { reactive, ref, toRef } from "@vue/reactivity";
export default {
    name: "App",
    setup() {
        let person = reactive({
            name: "花生",
            age: 23,
            job: {
                salary: 20,
            },
        });

        return {
            person,
            name:toRef(person,'name'),
            age:toRef(person,'age'),
            salary:toRef(person.job,'salary')
        };
    },
};
</script>
<style scoped>
.app {
    background: orange;
    padding: 10px;
    height: 300px;
}
</style>

在这里插入图片描述

  • toRefs
<template>
    <div class="app">
        <h3>我是App组件</h3>
        <h4>{{person}}</h4>
        <h3>姓名:{{name}}</h3>
        <h3>年龄:{{age}}</h3>
        <h3>工作:{{job.salary}}块大洋</h3>
        <button @click="name+='~'">修改姓名</button>
        <button @click="age++">年龄+1</button>
        <button @click="job.salary++">涨薪</button>
    </div>
</template>

<script>
import { reactive, ref, toRef, toRefs } from "@vue/reactivity";
export default {
    name: "App",
    setup() {
        let person = reactive({
            name: "花生",
            age: 23,
            job: {
                salary: 20,
            },
        });

        return {
            person,
            ...toRefs(person)
        };
    },
};
</script>
<style scoped>
.app {
    background: orange;
    padding: 10px;
    height: 300px;
}
</style>

在这里插入图片描述

其他组合式API

shallowReactive

浅层次的实现响应式,接着上面的例子,使用shallowReactive

setup() {
        let person = shallowReactive({
            name: "花生",
            age: 23,
            job: {
                salary: 20,
            },
        });

        return {
            person,
            ...toRefs(person)
        };
    },

name,age都是响应式数据,但是深层次的salary则没有响应式。

shallowRef

ref对于对象类型数据借助了reactive,shallowRef而不对对象类型的数据进行响应式处理。

setup() {
        let refX = ref({
            x:0
        })
        let shallowRefX = shallowRef({
            x:0
        })
        console.log('ref',refX);
        console.log('shallowRef',shallowRefX);
        let person = shallowReactive({
            name: "花生",
            age: 23,
            job: {
                salary: 20,
            },
        });

        return {
            person,
            ...toRefs(person)
        };
    },

在这里插入图片描述

readonly

使用readonly之后,无论是浅层次的,还是深层次的的数据都不能被修改。

setup() {
        let sum = ref(0);

        let person = reactive({
            name: "花生",
            age: 23,
            job: {
                salary: 20,
            },
        });
        person = readonly(person)


        return {
            sum,
            ...toRefs(person),
        };
    },

shallowReadonly

使用readonly之后,第一层次的数据不能被修改,但是深层次的的数据时可以被修改的。
在这里插入图片描述

toRaw

将reactive定义的响应式数据类型,抓换成普通的对象。

<template>
    <div class="app">
        <h3>我是App组件</h3>
        <h3>求和为:{{sum}}</h3>
        <hr>
        <h3>姓名:{{name}}</h3>
        <h3>年龄:{{age}}</h3>
        <h3>工作:{{job.salary}}块大洋</h3>
        <button @click="name+='~'">修改姓名</button>
        <button @click="handleAgeChange">年龄+1</button>
        <button @click="job.salary++">涨薪</button>
    </div>
</template>

<script>
import { reactive, ref, toRaw, toRefs } from "@vue/reactivity";
export default {
    name: "App",
    setup() {
        let sum = ref(0);

        let person = reactive({
            name: "花生",
            age: 23,
            job: {
                salary: 20,
            },
        });
        function handleAgeChange() {
            person.age++;
            console.log(toRaw(person));
        }

        return {
            sum,
            ...toRefs(person),
            handleAgeChange
        };
    },
};
</script>
<style scoped>
.app {
    background: orange;
    padding: 10px;
    height: 300px;
}
</style>

在这里插入图片描述

markRaw

被标记的对象,将不会变成响应式数据。

<template>
    <div class="app">
        <h3>我是App组件</h3>
        <h3>求和为:{{sum}}</h3>
        <hr>
        <h3>姓名:{{name}}</h3>
        <h3>年龄:{{age}}</h3>
        <h3>工作:{{job.salary}}块大洋</h3>
        <h3>车辆信息:{{person.car}}</h3>
        <button @click="name+='~'">修改姓名</button>
        <button @click="age++">年龄+1</button>
        <button @click="job.salary++">涨薪</button>
        <button @click="person.car.name+='!'">车改名</button>
        <button @click="person.car.price++">车涨价</button>
    </div>
</template>

<script>
import { markRaw, reactive, ref, toRaw, toRefs } from "@vue/reactivity";
export default {
    name: "App",
    setup() {
        let sum = ref(0);

        let person = reactive({
            name: "花生",
            age: 23,
            job: {
                salary: 20,
            },
        });
        person.car = markRaw({
            name:'跑跑卡丁车',
            price:40
        })
        console.log(person);


        return {
            sum,
            person,
            ...toRefs(person),
        };
    },
};
</script>
<style scoped>
.app {
    background: orange;
    padding: 10px;
    height: 400px;
}
</style>

customRef

自定义ref,官方例子

<template>
    <div class="app">
        <h3>我是App组件</h3>
        <input
            type="text"
            v-model="keyWord"
        >
        <h3>{{keyWord}}</h3>
    </div>
</template>

<script>
import { customRef, ref } from "@vue/reactivity";
export default {
    name: "App",
    setup() {
        let keyWord = myRef("hello", 1000);
        function myRef(value, delay) {
            return customRef((track, trigger) => {
                return {
                    get() {
                        console.log("数据被读取了");
                        track(); //通知vue数据需要被追踪
                        return value;
                    },
                    set(newValue) {
                        console.log("数据被修改了", newValue);
                        value = newValue;
                        setTimeout(() => {
                            trigger(); //通知vue去更新模板
                        }, delay);
                    },
                };
            });
        }
        return {
            keyWord,
        };
    },
};
</script>
<style scoped>
.app {
    background: orange;
    padding: 10px;
    height: 200px;
}
</style>

provide和inject

用于实现组件间的通信,尤其是祖孙组件之间。祖先组件使用provide提供数据,后代组件通过inject注入来获取数据。
在这里插入图片描述
App.vue


	name: "App",
    setup() {
        let person = reactive({
            name: "花生",
            age: 23,
        });
        provide("info", person);

        return {
            person,
        };
    },

Test.vue

name: "Test",
    setup() {
        let person = inject("info");
        let car = inject("car");
        return {
            person,
            car,
        };
    },

在这里插入图片描述
且数据是响应式的。

新的组件

Fragment(片段)

Vue3.0新增了Fragment组件。在Vue2.x中我们只能有一个根标签,而在Vue3,0中我们可以写多个根标签,然后Vue3将其包在Fragment这一虚拟元素中。

Teleport(瞬移)

Teleport 提供了一种干净的方法, 让组件的html在父组件界面外的特定标签(很可能是body)下插入显示

Suspense(不确定的)

它们允许我们的应用程序在等待异步组件时渲染一些后备内容,可以让我们创建一个平滑的用户体验

  • 7
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值