From Vue2 to Vue3 [5] - new components (Fragment, Teleport, Suspense)

Series Article Directory

content Link
From Vue2 to Vue3 [zero] Introduction to Vue3
From Vue2 to Vue3 [1] Composition API (Chapter 1)
From Vue2 to Vue3 [2] Composition API (Chapter 2)
From Vue2 to Vue3 [3] Composition API (Chapter 3)
From Vue2 to Vue3 [4] Composition API (Chapter 4)


foreword

With the release of Vue 3, we ushered in a powerful and exciting composition API , which brings more flexibility and maintainability to developers . Vue 3's composition API not only changed the way we write Vue components, but also introduced some new components and some small but practical changes . In this article, we will delve into the new components of vue3 and some other small changes brought about , let us start this exciting learning journey together!

1. Fragment

  • Fragment (fragment)
    • It allows us to return multiple elements in a Vue template without adding an extra wrapper element. (the root tag is no longer needed)

      We can return multiple elements as children of the Fragment, and the Fragment itself will not be rendered into the DOM. This can avoid introducing unnecessary parent elements, reduce label levels, make the template structure clearer, and reduce memory usage.
      insert image description here

2. Teleport

  • Teleport

    • The Teleport component allows us to render child elements to specified positions in the DOM tree instead of rendering directly in the current component's template.

    This is useful when you need to render content in a specific element outside the component (such as popovers, modals, etc.). We can use the to attribute of the Teleport component to specify the selector or DOM node of the target element.

    Case: Transfer the pop-up layer in the dialog component to the body of
    the dialog.vue component code

<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>

Please add a picture description

The mask layer sent to the body is at the same level as #app, but even if scoped is added when setting the style, the style still takes effect

Teleport only changes the rendered DOM structure, it does not affect the logical relationship between components . That is to say, if Teleport contains a component, then the component always maintains a logical parent-child relationship with the component that uses Teleport . Incoming props and fired events will work as usual.
This also means that injections from parent components will also work as expected, and child components will be nested under the parent component in Vue Devtools instead of where the actual content moves.

  • Disable Teleport
    ​In some scenarios, it may be necessary to disable Teleport as appropriate. For example, we want to render a component as an overlay on desktop , but as an inline component on mobile . We can handle these two different situations by dynamically passing in a disabled prop to Teleport.
<Teleport :disabled="isMobile">
  ...
</Teleport>

Disabled is true to prohibit the transmission, and the content in the teleport is displayed as usual

这里的 isMobile 状态可以根据 CSS media query 的不同结果动态地更新。
  • Multiple Teleport Shared Targets ​Multiple instances of
    a reusable modal component may exist at the same time. For such scenarios, multiple Teleport components can mount their content on the same target element, and the order is simply to append sequentially, and the ones mounted later will be placed at a later position under the target element.

For example, the following use case:
child component

<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 component

<template>
	<div class="app">
		<h3>我是App组件</h3>
		<div class="modals"></div>
		<Child/>
	</div>
</template>

The rendered result is (delivered sequentially):

insert image description here

  • Note that when teleport is in use, the teleport (to) place must be mounted first, otherwise
    , when you want to to, you will not be able to find the place to teleport, and an error will be reported .
    insert image description here
    insert image description here
		<teleport to=".header">
			<div>3</div>
		</teleport>
		<div class="header">
		</div>

Changed to this, it will be sent normally

		<div class="header">
		</div>
		<teleport to=".header">
			<div>3</div>
		</teleport>

3. Suspense

  • Suspense
    • Render some extra content while waiting for asynchronous components, so that the application has a better user experience

The Suspense component allows us to display a placeholder when the component is loaded asynchronously until the component is loaded. This placeholder can be a custom loading component or something else. When the asynchronous component is loaded, the Suspense component will automatically replace the placeholder with the actual component. This provides a more elegant way to handle asynchronously loaded components and conveniently displays loading status.

Usage scenario: When the data has not been requested back, make a loading scenario
Usage steps:

  • 1. Asynchronously introduce components
import {
    
    defineAsyncComponent} from 'vue'
const Child = defineAsyncComponent(()=>import('./components/Child.vue'))
  • 2. Use Suspensethe package component and configure it to display the content in the default, and the content in the fallback is defaultloadingfallback
<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>

In the child component, it can be used with setup

<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>

Since the data returned by the child component here is asynchronous, the child component has not been loaded well, so during the child loading period, the loading page is always displayed

Please add a picture description

It is not necessary to use Suspense with setup when there is an asynchronous request. Sometimes a component is too large and the loading is very slow. You can use asynchronous loading to load this huge component.

Assuming that the child.vue component is a very large component, due to the "barrel effect", the speed of loading the page depends on the one that takes the longest time, so the time-consuming component can be loaded asynchronously, and its position is replaced by loading first

<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>

Please add a picture description

Summarize

This article explains this, and explained in detail the three new components ( Fragment, Teleport, Suspense ) in vue3. These new components bring more flexibility and convenience to Vue 3. They make component-based development easier and more feature-rich, giving developers more choices and tools to build efficient, maintainable applications.

Guess you like

Origin blog.csdn.net/m0_57524265/article/details/131879894