⏳前言
这是我参与更文挑战的第26天,活动详情查看:
更文挑战
大家都知道,在我们平常的前端开发中,实现模态框和发起异步请求是再常见不过的事情了。但是呢,不管是用
vue2
和原生js的实现方式,从逻辑上来说都还不够独立,因此,
vue3
推出了新的方法来解决此问题。
下面就带领大家一起来了解vue3新推出的
teleport
究竟有多神奇?以及如何用
suspense
发起多个异步的请求?
一起来学习吧~📚
一、👋用teleport实现打开模态框操作
1、teleport是什么
teleport
,字面意思就是
远距离传送
,我们可以把它理解为传送门的意思。
大家都知道,传送门的意思就是从一个地方传送到了另外一个地方。而
vue3
为什么要用
teleport
来表达呢?
其实,有一个非常常见的需求就是,我们经常要通过点击一个按钮,来实现模态框的效果。而在
vue3
之前,我们基本上控制它都是点击后
上下会形成一个父子组件
的关系,这样子感觉独立性就没有那么强了。
因此,
vue3
为了解决该问题,就用了
teleport
来解决。
teleport
就仿佛一个传送门,像上图这样,比如我们点击了
打开按钮
,那么点击完了之后,使用
传送门
瞬间移动到另外一个地方(模态框
Model
)。再点击
关闭按钮
,
传送门
模态框
Modal
就消失了。
通过这样的解释,相信大家对
teleport
有了一个基础的认识。
2、实现模态框功能
接下来我们就来用这个功能,实现一个模态框,控制组件的显示和隐藏。
(1)设置锚点
我们现在
vue3
项目下的
/public/index.html
设置一个
锚点
,来放置组件的内容。具体代码如下:
<body>
<noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
//先行定义一个锚点
<div id="modal"></div>
<!-- built files will be auto injected -->
</body>
复制代码
(2)定义子组件
接下来我们在
/src/components
下定义一个
子组件
,命名为
Modal.vue
。
具体代码如下:
<template>
<teleport to="#modal">
<div id="center" v-if="isOpen">
<h2><slot>this is a modal</slot></h2>
<button class="btn2" @click="buttonClick">Close</button>
</teleport>
</template>
<script>
import { defineComponent } from 'vue'
export default defineComponent({
//父组件的数据需要通过props把数据传给子组件,props的取值可以是数组也可以是对象
props: {
isOpen: Boolean,
//子组件向父组件传递数据
//使用emits,更明确的显示组件的自定义事件有哪些
emits: {
'close-modal': null
//props对应props的内容
//context名字可以自定义,只要上下对应即可,用来触发emit的内容
setup(props, context){
const buttonClick = () => {
context.emit('close-modal')
return{
buttonClick
</script>
<style>
#center{
width:200px;
height:200px;
border:2px solid rgb(105, 165, 56);
text-align: center;
border-radius: 2px;
margin: 50px auto 0;
.btn2{
background: #1971c9;
border:none;
padding: 8px;
border-radius: 5px;
color: #fff;
cursor: pointer;
</style>
复制代码
(3)定义父组件
之后我们再来定义一个父组件,命名为
index.vue
。
具体代码如下:
<template>
<button class="btn1" @click="openModal">打开模态框</button>
<modal :isOpen="modalIsOpen" @close-modal="onModalClose">
My Modal!!!
</modal>
</template>
<script lang="ts">
import { ref, defineComponent} from 'vue'
import Modal from './components/Modal.vue'
export default defineComponent({
name: 'App',
components: {
Modal
setup(){
//添加响应式对象控制是否显示
const modalIsOpen = ref(false)
//打开模态框事件
const openModal = () => {
modalIsOpen.value = true
//关闭模态框事件
const onModalClose = () => {
modalIsOpen.value = false
return{
modalIsOpen,
openModal,
onModalClose
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2d4c6b;
margin-top: 60px;
.btn1{
background: #1971c9;
border:none;
padding: 16px;
border-radius: 5px;
color: #fff;
cursor: pointer;
</style>
复制代码
现在我们来看下浏览器的显示效果:
大家可以看到,通过
teleport
的方式,现在的模态框成功显示在
id
为
app
的
div
同一层下,达到了
相互独立
,而不再是父子层级的结果。
在上面的案例中,我们学习到了通过使用
vue3
新推出的
teleport
特性,将组件渲染到另外一个
DOM
节点的方法,这样使得组件之间的独立性更强。
二、🤚用Suspense发起一个异步请求
1、Suspense是什么
我们都知道,在
web
世界中,经常遇到很多的异步请求困境。在发起异步请求时,我们往往需要去判断这些异步请求的状态,然后呢,根据这些请求来展示不同的界面。
那现在呢,
vue3
推出了一个新的内置组件
Suspense
,
Suspense
是一个特殊的组件,它会有两个
template slot
,刚开始会渲染
feedback
内容,直到
达到某个条件以后
,才会渲染正式的内容,也就是default的内容。这样呢,进行异步内容的渲染就会变得特别简单。
同时值得注意的是,如果使用
Suspense
,要返回一个
promise
而不是一个对象。
2、用Suspense发起一个异步请求
接下来我们使用
Suspense
来
发起一个异步请求
。
首先我们在项目下定义一个
子组件
,命名为
AsyncShow.vue
,
具体代码如下:
<template>
<h1>{{result}}</h1>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
export default defineComponent({
setup() {
//使用Suspense需要返回一个对象
return new Promise((resolve) => {
setTimeout(() => {
return resolve({
result: '10000'
}, 3000)
</script>
复制代码
之后在项目下再定义一个
父组件
,命名为
DogShow.vue
,
具体代码如下:
<template>
<div id="app">
<Suspense>
<template #default>
<async-show />
</template>
<template #fallback>
<h1>Loading !...</h1>
</template>
</Suspense>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
import AsyncShow from './components/AsyncShow.vue'
export default defineComponent({
name: 'App',
components: {
AsyncShow,
setup() {
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
font-size: 6rem;
</style>
复制代码
最终浏览器的显示效果如下:
大家可以看到,通过
Suspense
,可以很轻易的
发起一个异步请求
。刚开始是
fallback状态
,之后达到
3s
的时间之后,切换到
default的状态
,显示出对应的异步请求内容。
3、用Suspense发起多个异步请求
我们不满足于现状,且互联网千奇百怪的,我们总不能一直只发送一个异步请求吧!所以,接下来我们就来实现发起多个异步请求的效果。
首先我们用一个免费的
在线API
,来发起一个请求。接下来我们在项目的
components
文件下,再定义一个子组件,命名为
DogShow.vue
,
具体代码如下:
<template>
<img :src="result && result.message">
</template>
<script lang="ts">
import axios from 'axios'
import { defineComponent } from 'vue'
export default defineComponent({
async setup() {
const rawData = await axios.get('https://dog.ceo/api/breeds/image/random')
return {
result: rawData.data
</script>
复制代码
接下来我们再把以上子组件的内容添加到父组件中,
具体代码如下:
<template>
<div id="app">
<Suspense>
<template #default>
<async-show />
<dog-show />
<template #fallback>
<h1>Loading !...</h1>
</template>
</Suspense>
</template>
<script lang="ts">
import AsyncShow from './components/AsyncShow.vue'
import DogShow from './components/DogShow.vue'
export default {
name: 'App',
components: {
AsyncShow,
DogShow
setup() {
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
font-size: 6rem;
</style>
复制代码
最终浏览器的显示效果如下:
大家可以看到,我们同时发起了两个异步请求,并且在Suspense中的default插槽里面同时使用。同样的,浏览器会先显示fallback的内容,之后等到时机到了,就显示我们请求的内容。
依据这样的例子,显示更多的请求也同样有效。这样对比起来,发送多个异步请求是不是就方便了许多。
4、如何抓取错误
学完上面的内容,相信大家对Suspense的用法已经有所了解。那么,网络请求千奇百怪的,总不能每次都能够很顺畅的发起请求对吧。所以呢,我们来需要再来学习一下,当网络请求失败时,
如何抓取Supsense包裹下的错误
。
这个时候我们可以使用一个钩子函数,这个函数叫做
onErrorCaptured
,接下来我们来看下怎么抓取。
我们将父组件
index.vue
进行改造,具体代码如下:
<template>
<div id="app">
<p>{{error}}</p>
<Suspense>
<template #default>
<async-show />
<dog-show />
<template #fallback>
<h1>Loading !...</h1>
</template>
</Suspense>
</template>
<script lang="ts">
import { onErrorCaptured } from 'vue'
import AsyncShow from './components/AsyncShow.vue'
import DogShow from './components/DogShow.vue'
export default {
name: 'App',
components: {
AsyncShow,
DogShow
setup() {
const error = ref(null)
onErrorCaptured((e: any) => {
error.value = e
return true
return{
error
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
font-size: 6rem;
</style>
复制代码
此时我们再将
DogShow.vue
的接口进行修改,让其变成一个无效的API。
代码如下:
const rawData = await axios.get('https://dog.ceo/api/breeds/image')
复制代码
接下来我们就来看一下
浏览器的运行效果:
大家可以看到,修改成无效的
API
后,狗狗的图片也不显示了,最后最上方就是通过
onErrorCaptured
这个生命周期捕捉到的错误,清晰明了。
三、🖐️结束语
到这里,
teleport
和
Suspense
的内容就讲解结束啦!相信大家对传送门的神奇之处也有了一定的了解,对
Suspense
的独到之处也感受了一番。
vue3持续学习,更新永不停歇……