Fragment
- 在Vue2中:组件必须有一个根标签
- 在Vue3中:组件可以没有根标签,但内部会将多个标签包含在一个
Fragment虚拟元素
中,该元素不会解析到页面上。
好处:减少标签层级,减小内存占用
Teleport
Teleport是一种能够将我们的组件html结构
移动到指定位置的技术。
eg:将弹窗移动到body中。
弹窗原本是嵌套在多级子组件中:
如果使用Teleport标签包裹,利用to属性可以跳转到任意位置
eg:跳转到body中:
<template>
<div>
<button @click="isShow=true">点我弹个窗</button>
<teleport to="body">
<div v-if="isShow" class="mask">
<div v-if="isShow" class="dialog">
<h3>我是一个弹窗</h3>
<button @click="isShow=false">关闭弹窗</button>
</div>
</div>
</teleport>
</div>
</template>
<script>
import {
ref} from "vue"
export default {
name: 'DialogVue',
setup() {
let isShow = ref(false)
return{
isShow}
}
}
</script>
<style>
.dialog{
text-align: center;
width: 300px;
height: 150px;
background-color:rgb(11, 59, 11);
position:absolute;
top:50%;
left:50%;
transform: translate(-50%,-50%);
}
.mask{
position: absolute;
top:0;
bottom:0;
left:0;
right:0;
background-color:rgba(0,0,0,0.5) ;
}
</style>
效果:
Suspense
异步组件引入
静态引入
我们之前都是使用 import Child from './components/Child'
这种方式引入组件的,这种方式叫做静态引入
。
静态引入的特点是只要引入的组件没出来页面就不进行显示。
eg:App组件中嵌套着Child子组件,使用静态引入的方式的话,如果child组件没有加载进来,app组件是不会显示在页面上的,所以App组件最终会和Child组件一同渲染到页面上
动态引入(异步引入)
// defineAsyncComponent定义一个异步组件
import {
defineAsyncComponent } from 'vue'
const Child = defineAsyncComponent(()=>import('./components/Child'))//动态引入(异步引入)
上述引入方法就是异步引入。
特点是哪个组件先加载好就先显示哪个组件。
eg:App组件中嵌套着Child子组件,使用异步引入的方式的话,如果child组件没有加载进来,app组件已经加载好了,那app组件就会先显示在页面上,Child组件什么时候加载完什么时候在进行显示。
所以异步引入组件可能会出现页面抖动
的现象,为了解决这个现象引入Suspense
Suspense
Suspense是一个标签,他底部的实现原理是使用插槽实现的。
使用格式:
<Suspense>
<template v-slot:default>
<组件名 />
</template>
<template v-slot:fallback>
<h3>如果组件加载不出来显示的内容</h3>
</template>
</Suspense>
使用:
eg:
App.vue:
<template>
<div class="app">
<h2>我是app组件</h2>
<Suspense>
<template v-slot:default>
<Child />
</template>
<template v-slot:fallback>
<h3>加载中...</h3>
</template>
</Suspense>
</div>
</template>
<script>
// import Child from './components/Child'//静态引入
// defineAsyncComponent定义一个异步组件
import {
defineAsyncComponent } from 'vue'
const Child = defineAsyncComponent(()=>import('./components/Child'))//动态引入(异步引入)
export default {
name: 'AppVue',
components: {
Child },
}
</script>
<style>
.app {
background: #333;
padding: 10px;
}
</style>
setup返回Promise对象
如果使用了Suspense和异步组件,那么setup也可以返回Promise对象了。
Child.vue:
<template>
<div class="child">
<h2>我是child组件</h2>
{
{sum}}
</div>
</template>
<script>
import {
ref } from '@vue/reactivity'
export default {
name: 'ChildVue',
setup() {
let sum = ref(0)
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve({
sum})
},1000)
})
}
}
</script>
<style>
.child {
background: rgb(225, 205, 148);
padding: 10px;
}
</style>
App.vue:
<template>
<div class="app">
<h2>我是app组件</h2>
<Suspense>
<template v-slot:default>
<Child />
</template>
<template v-slot:fallback>
<h3>加载中...</h3>
</template>
</Suspense>
</div>
</template>
<script>
// import Child from './components/Child'//静态引入
// defineAsyncComponent定义一个异步组件
import {
defineAsyncComponent } from 'vue'
const Child = defineAsyncComponent(()=>import('./components/Child'))//动态引入(异步引入)
export default {
name: 'AppVue',
components: {
Child },
}
</script>
<style>
.app {
background: #333;
padding: 10px;
}
</style>
那么setup也可以使用async修饰了,因为await的返回值就是Promise
child.vue
<template>
<div class="child">
<h2>我是child组件</h2>
{
{sum}}
</div>
</template>
<script>
import {
ref } from '@vue/reactivity'
export default {
name: 'ChildVue',
async setup() {
let sum = ref(0)
const p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve({
sum})
},1000)
})
return await p;
}
}
</script>
<style>
.child {
background: rgb(225, 205, 148);
padding: 10px;
}
</style>