您现在的位置是:首页 >学无止境 >Vue3技术8之Fragment、Suspense、Vue3中其他的改变网站首页学无止境
Vue3技术8之Fragment、Suspense、Vue3中其他的改变
简介Vue3技术8之Fragment、Suspense、Vue3中其他的改变
Vue3技术8
Fragment
- 在Vue2中:组件必须有一个根标签
- 在Vue3中:组件可以没有根标签,内部会将多个标签包含在一个Fragment虚拟元素中
- 好处:减少标签层级,减少内存占用
Teleport
弹窗案例
目录结构
App.vue
<template>
<div class="app">
<h1>我是App组件</h1>
<Child></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">
<h1>我是Child组件</h1>
<Son></Son>
</div>
</template>
<script>
import Son from "@/components/Son";
export default {
name: "Child",
components: {Son}
}
</script>
<style scoped>
.child{
background-color: orange;
padding: 10px;
}
</style>
Son.vue
<template>
<div class="son">
<h1>我是Son组件</h1>
<Dialog></Dialog>
</div>
</template>
<script>
import Dialog from "@/components/Dialog";
export default {
name: "Son",
components: {Dialog},
}
</script>
<style scoped>
.son{
background-color: pink;
padding: 10px;
}
</style>
Dialog.vue
<template>
<div>
<button @click="isShow=true">点我弹个窗</button>
<teleport to="body">
<div class="mask" v-if="isShow">
<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{
width: 300px;
height: 300px;
background-color: skyblue;
text-align: center;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%,-50%);
}
</style>
总结
- 什么是Teleport?——Teleport是一种能将我们的
组件html结构
移动到指定位置的技术
<teleport to="移动位置">
<div v-if="isShow" class="mask">
<div class="dialog">
<h3>我是一个弹窗</h3>
<button @click="isShow=false">关闭弹窗</button>
</div>
</div>
</teleport>
Suspense
普通写法
App组件和Child组件是一起加载出来的
App.vue
<template>
<div class="app">
<h1>我是App组件</h1>
<Child></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">
<h1>我是Child组件</h1>
</div>
</template>
<script>
export default {
name: "Child",
}
</script>
<style scoped>
.child{
background-color: orange;
padding: 10px;
}
</style>
使用suspense之后
App.vue
<template>
<div class="app">
<h1>我是App组件</h1>
<suspense>
<template v-slot:default>
<Child></Child>
</template>
<template v-slot:fallback>
<h3>稍等,加载中...</h3>
</template>
</suspense>
</div>
</template>
<script>
// import Child from "@/components/Child"; //静态引入
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
<template>
<div class="child">
<h1>我是Child组件</h1>
</div>
</template>
<script>
export default {
name: "Child",
}
</script>
<style scoped>
.child{
background-color: orange;
padding: 10px;
}
</style>
不再自己调整网络低速
Child.vue
<template>
<div class="child">
<h1>我是Child组件</h1>
<div>{{sum}}</div>
</div>
</template>
<script>
import {ref} from "vue";
export default {
name: "Child",
async setup(){
let sum=ref(0)
const p= new Promise((resolve, reject) => {
setTimeout(() => {
resolve({sum})
},3000)
})
return await p
}
}
</script>
<style scoped>
.child{
background-color: orange;
padding: 10px;
}
</style>
App.vue
<template>
<div class="app">
<h1>我是App组件</h1>
<suspense>
<template v-slot:default>
<Child></Child>
</template>
<template v-slot:fallback>
<h3>稍等,加载中...</h3>
</template>
</suspense>
</div>
</template>
<script>
// import Child from "@/components/Child"; //静态引入
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>
总结
补充setup的一个知识点
- setup不能是一个async函数,因为返回值不再是return的对象,而是promise,模板看不到return对象中的属性。(后期也可以返回一个Promise实例,但需要Suspense和异步组件的配合)
Suspense总结
- 等待异步组件时渲染一些额外内容,让应用有更好的用户体验
- 使用步骤
(1)异步引入组件
import {defineAsyncComponent} from 'vue'
const Child=defineAsyncComponent(()=>import('@/components/Child')) //异步引入
(2)使用Suspense包裹组件,并配置好default与fallback
<template>
<div class="app">
<h1>我是App组件</h1>
<suspense>
<template v-slot:default>
<Child/>
</template>
<template v-slot:fallback>
<h3>稍等,加载中...</h3>
</template>
</suspense>
</div>
</template>
Vue3中其他的改变
全局API的转移
- Vue 2.x 有许多全局 API 和配置。
例如:注册全局组件、注册全局指令等
//注册全局组件
Vue.component('MyButton', {
data: () => ({
count: 0
}),
template: '<button @click="count++">Clicked {{ count }} times.</button>'
})
//注册全局指令
Vue.directive('focus', {
inserted: el => el.focus()
}
-
Vue3中对这些API做了调整
将全局的API,即:Vue.xxx调整到应用实例(app)2.x 全局 API( Vue
)3.x 实例 API ( app
)Vue.config.xxxx app.config.xxxx Vue.config.productionTip 移除 Vue.component app.component Vue.directive app.directive Vue.mixin app.mixin Vue.use app.use Vue.prototype app.config.globalProperties
其他改变
- data选项应始终被声明为一个函数。
- 过度类名的更改:
-
Vue2.x写法
.v-enter, .v-leave-to { opacity: 0; } .v-leave, .v-enter-to { opacity: 1; }
-
Vue3.x写法
.v-enter-from, .v-leave-to { opacity: 0; } .v-leave-from, .v-enter-to { opacity: 1; }
移除
keyCode作为 v-on 的修饰符,同时也不再支持config.keyCodes
移除
修饰符
-
父组件中绑定事件
<my-component v-on:close="handleComponentEvent" v-on:click="handleNativeClickEvent" />
-
子组件中声明自定义事件
<script> export default { emits: ['close'] } </script>
移除
过滤器(filter)
过滤器虽然这看起来很方便,但它需要一个自定义语法,打破大括号内表达式是 “只是 JavaScript” 的假设,这不仅有学习成本,而且有实现成本!建议用方法调用或计算属性去替换过滤器。
- …
风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。