Fragment(无需配置)
区别及好处
在 vue2 中:组件必须有一个根标签
在 vue3 中:组件可以没有根标签,内部会将多个标签包含在一个 Fragment 虚拟元素中
好处:减少标签层级,减少内存占用
Teleport
什么是 Teleport ?
是一种能够将我们的组件 html 结构移动到指定位置的技术。
实例
App.vue
<template> <div class="app"> <h3>我是App组件</h3> <Child /> </div> </template> <script> import Child from "./components/Child"; export default { name: "App", components: { Child }, }; </script> <style scoped> .app { background-color: gray; padding: 10px; } </style>
Child.vue
<template> <div class="child"> <h3>我是Child组件</h3> <Son/> </div> </template> <script> import Son from './Son'; export default { name: "Child", components: { Son } }; </script> <style scoped> .child { background-color: skyblue; padding: 10px; } </style>
Son.vue
<template> <div class="son"> <h3>我是Son组件</h3> <Dialog/> </div> </template> <script> import Dialog from './Dialog.vue'; export default { name: "Son", components: { Dialog } }; </script> <style scoped> .son { background-color: orange; padding: 10px; } </style>
Dialog.vue
- to = "body",把结构放在 body 里面
<template> <div> <button @click="isShow = true">点我弹窗</button> <teleport to="body"> <div v-if="isShow" class="mask"> <div class="dialog"> <h3>我是一个弹窗</h3> <h4>一些内容</h4> <h4>一些内容</h4> <h4>一些内容</h4> <button @click="isShow = false">关闭弹窗</button> </div> </div> </teleport> </div> </template> <script> import { ref } from "vue"; export default { name: "Dialog", setup() { let isShow = ref(false); return { isShow }; }, }; </script> <style scoped> .mask { position: absolute; top: 0; bottom: 0; left: 0; right: 0; background-color: rgba(0, 0, 0, 0.5); } .dialog { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); text-align: center; width: 300px; height: 300px; background-color: greenyellow; } </style>
实现效果:
https://www.bilibili.com/video/BV1Va411D7r7?t=1.0
Teleport
Suspense
作用
等待异步组件时渲染一些额外内容,让应用有更好的用户体验
使用步骤
- 异步引入组件
- 使用 Suspense 包裹组件,并配置好 default 与 fallback
App.vue
- import 引入组件
- 用 Suspense 包裹组件,default 里面为默认的值,fallback 里面为没加载出来的提示
<template> <div class="app"> <h3>我是App组件</h3> <Suspense> <template v-slot:default> <Child /> </template> <template v-slot:fallback> <h3>稍等,加载中...</h3> </template> </Suspense> </div> </template> <script> import { defineAsyncComponent } from "vue"; const Child = defineAsyncComponent(() => import("./components/Child")); //异步引入 export default { name: "App", components: { Child }, }; </script> <style scoped> .app { background-color: gray; padding: 10px; } </style>
Child.vue
用 Suspense 和异步组件配合,也可以在 setup 里返回一个 Promise 实例
<template> <div class="child"> <h3>我是Child组件</h3> {{sum}} </div> </template> <script> import {ref} from 'vue' export default { name: "Child", setup(){ let sum = ref(200) return new Promise((resolve)=>{ setTimeout(()=>{ resolve({sum}) },1000) }) } }; </script> <style scoped> .child { background-color: skyblue; padding: 10px; } </style>
效果如下:
https://www.bilibili.com/video/BV1FY4y1j7p9?t=0.9
suspense
全局 API 的转移
其他改变
- data 选项应始终被声明为一个函数
- 过渡类名的更改 v-enter ==> v-enter-to
- 移除 keyCode 作为 v-on 的修饰符,同时也不再支持 config.keyCodes
- 移除 v-on.native 修饰符
父组件中绑定事件
<my-component v-on:click="xxx">
子组件中声明自定义事件
export default{ emits: ['click'] }
- 移除过滤器(filter)
不积跬步无以至千里 不积小流无以成江海