从Vue2到Vue3【五】——新的组件(Fragment、Teleport、Suspense)

系列文章目录

内容 链接
从Vue2到Vue3【零】 Vue3简介
从Vue2到Vue3【一】 Composition API(第一章)
从Vue2到Vue3【二】 Composition API(第二章)
从Vue2到Vue3【三】 Composition API(第三章)
从Vue2到Vue3【四】 Composition API(第四章)

文章目录


前言

随着Vue 3的发布,我们迎来了一套强大且令人兴奋的组合式API ,这为开发者带来了更多灵活性和可维护性 。Vue 3的组合式API不仅改变了我们编写Vue组件的方式,还引入了一些新的组件 和一些小的但实用的改变 。在这篇文章中,我们将深入探讨vue3新的组件以及带来的一些其他小的变化,让我们一起开始这个令人兴奋的学习之旅吧!

一、Fragment

  • Fragment(片段)
    • 它允许我们在Vue模板中返回多个元素,而无需添加额外的包裹元素。(不再需要根标签)

      我们可以将多个元素作为Fragment的子元素来返回,并且Fragment本身不会被渲染到DOM中。这样可以避免引入不必要的父元素,减少标签层级,使得模板结构更加清晰, 减小内存占用。

二、Teleport

  • Teleport(传送门)

    • Teleport组件允许我们将子元素渲染到DOM树的指定位置,而不是直接在当前组件的模板中渲染。

    这对于需要在组件外的指定元素中渲染内容(比如弹出层、模态框等)非常有用。我们可以使用Teleport组件的to属性来指定目标元素的选择器或DOM节点。

    案例:将dialog组件中的弹出层传送到body身上

    dialog.vue组件代码

html 复制代码
<template>
	<div>
		<button @click="isShow = true">点我弹个窗</button>
		<teleport to="body">   
			<div v-if="isShow" class="mask">
				<div class="dialog">
					<h3>我是一个弹窗</h3>
					<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>
	.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: green;
	}
</style>

传送到body身上的mask遮罩层和#app同级,但是即使设置样式时有加scoped,样式依然生效
Teleport只改变了渲染的 DOM 结构,它不会影响组件间的逻辑关系 。也就是说,如果 Teleport包含了一个组件,那么该组件始终和这个使用了 teleport 的组件保持逻辑上的父子关系传入的 props 和触发的事件也会照常工作。

这也意味着来自父组件的注入也会按预期工作,子组件将在 Vue Devtools 中嵌套在父级组件下面,而不是放在实际内容移动到的地方。

  • 禁用 Teleport
    在某些场景下可能需要视情况禁用 Teleport。举例来说,我们想要在桌面端将一个组件当做浮层来渲染 ,但在移动端则当作行内组件 。我们可以通过对 Teleport动态地传入一个 disabled prop 来处理这两种不同情况。
html 复制代码
<Teleport :disabled="isMobile">
  ...
</Teleport>

disabled为true则禁止传送,并且teleport内的内容在原地照常显示

复制代码
这里的 isMobile 状态可以根据 CSS media query 的不同结果动态地更新。
  • 多个 Teleport 共享目标
    一个可重用的模态框组件可能同时存在多个实例。对于此类场景,多个 Teleport 组件可以将其内容挂载在同一个目标元素上,而顺序就是简单的顺次追加,后挂载的将排在目标元素下更后面的位置上。

比如下面这样的用例:

child组件

html 复制代码
<template>
	<div class="child">
		<h3>我是Child组件</h3>
		<teleport to = ".modals">
			<div>1</div>
		</teleport>
		<teleport to=".modals">
			<div>2</div>
		</teleport>
		<teleport to=".modals">
			<div>3</div>
		</teleport>
		<Son/>
	</div>
</template>

App组件

html 复制代码
<template>
	<div class="app">
		<h3>我是App组件</h3>
		<div class="modals"></div>
		<Child/>
	</div>
</template>

渲染的结果为(依次传送):

  • 注意点
    teleport在使用时,传送(to)的地方一定要先挂载好,否则当你未挂载好就要to时,会找不到要传送的地方,就会报错


    比如说:to的地方后渲染,在传送时就会找不到目标节点
html 复制代码
		<teleport to=".header">
			<div>3</div>
		</teleport>
		<div class="header">
		</div>

改成这样,就正常传送了

html 复制代码
		<div class="header">
		</div>
		<teleport to=".header">
			<div>3</div>
		</teleport>

三、Suspense

  • Suspense(悬念)
    • 等待异步组件时渲染一些额外内容,让应用有更好的用户体验

Suspense组件允许我们在异步加载组件时显示一个占位符,直到组件加载完成。这个占位符可以是一个自定义的loading组件或者其他内容。当异步组件加载完成后,Suspense组件会自动替换占位符为实际组件。这提供了更优雅的方式来处理异步加载的组件,并且可以方便地显示加载状态。

使用场景:当数据还没请求回来时,做一个loading的场景

使用步骤:

  • 1.异步引入组件
js 复制代码
import {defineAsyncComponent} from 'vue'
const Child = defineAsyncComponent(()=>import('./components/Child.vue'))
  • 2.使用Suspense包裹组件,并配置好defaultfallback
    default里的内容是要显示的,fallback里的内容是loading的
html 复制代码
<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 Child from './components/Child'//静态引入
	import {defineAsyncComponent} from 'vue' 
	const Child = defineAsyncComponent(()=>import('./components/Child')) //异步引入
	export default {
		name:'App',
		components:{Child},
	}
</script>

<style>
	.app{
		background-color: gray;
		padding: 10px;
	}
</style>

child组件里,可以搭配setup使用

html 复制代码
<template>
	<div class="child">
		<h3>我是Child组件</h3>
		{{sum}}
	</div>
</template>

<script>
	import {ref} from 'vue'
	export default {
		name:'chIld',
		async setup(){
			let sum = ref(0)
			// 模拟请求服务器数据 服务器返回sum
			let p = new Promise((resolve)=>{
				setTimeout(()=>{
					resolve({sum})
				},3000)
			})
			return await p
		}
	}
</script>

<style>
	.child{
		background-color: skyblue;
		padding: 10px;
	}
</style>

由于这里child的组件返回的数据是异步的,child组件一直加载不好,所以在child加载期间,一直显示loading的页面

也不一定要有异步请求的时候搭配setup用Suspense,有时候一个组件太庞大了,加载的很慢,就可以利用异步加载这个庞大的组件

假设这个child.vue组件是一个很庞大的组件,由于"木桶效应",加载页面的速度取决于耗时最长的那个,所以耗时长的组件可以异步加载,先用loading代替其的位置

html 复制代码
<template>
	<div class="child">
		<h3>我是Child组件</h3>
		{{sum}}
	</div>
</template>

<script>
	import {ref} from 'vue'
	export default {
		name:'chIld',
		setup(){
			let sum = ref(0)
			return {
				sum
			}
		}
	}
</script>

<style>
	.child{
		background-color: skyblue;
		padding: 10px;
	}
</style>

总结

本文讲解到这,详细讲解完了vue3中新增的三个组件(Fragment、Teleport、Suspense),这些新增的组件为Vue 3带来了更多的灵活性和便利性。它们使得组件化开发更加简单且功能更丰富,为开发者提供更多的选择和工具来构建高效、可维护的应用程序。

相关推荐
腾讯TNTWeb前端团队5 小时前
helux v5 发布了,像pinia一样优雅地管理你的react状态吧
前端·javascript·react.js
范文杰8 小时前
AI 时代如何更高效开发前端组件?21st.dev 给了一种答案
前端·ai编程
拉不动的猪9 小时前
刷刷题50(常见的js数据通信与渲染问题)
前端·javascript·面试
拉不动的猪9 小时前
JS多线程Webworks中的几种实战场景演示
前端·javascript·面试
FreeCultureBoy9 小时前
macOS 命令行 原生挂载 webdav 方法
前端
uhakadotcom10 小时前
Astro 框架:快速构建内容驱动型网站的利器
前端·javascript·面试
uhakadotcom10 小时前
了解Nest.js和Next.js:如何选择合适的框架
前端·javascript·面试
uhakadotcom10 小时前
React与Next.js:基础知识及应用场景
前端·面试·github
uhakadotcom10 小时前
Remix 框架:性能与易用性的完美结合
前端·javascript·面试
uhakadotcom10 小时前
Node.js 包管理器:npm vs pnpm
前端·javascript·面试