Teleport&Suspense
Teleport
vue3 新添加了一个默认的组件就叫 Teleport,我们可以拿过来直接使用,它上面有一个 to 的属性,它接受一个css query selector 作为参数,这就是代表要把这个组件渲染到哪个 dom 元素中
<!-- ModalDemo.vue -->
<template>
<teleport to="#modal">
<div id="center" v-if="isOpen">
<h2>this is a modal</h2>
<button @click="buttonClick"> Close</button>
</div>
</teleport>
</template>
<script lang="ts">
import {defineComponent} from 'vue'
export default defineComponent({
props:{
isOpen:Boolean,
},
emits:{
// 'close-modal':(payload:any)=>{
// return payload.type=='close'
// }
'close-modal':null
},
setup(props,context){
const buttonClick=()=>{
context.emit('close-modal')
}
return {buttonClick}
// context.emit('close-modal',{
// type:'hello'
// })
}
})
</script>
<style scoped>
#center{
width: 200px;
height: 200px;
border: 2px solid black;
background: white;
position: fixed;
left: 50%;
top: 50%;
margin-left: -100px;
}
</style>
<!-- index.html -->
<div id="app"></div>
<div id="modal"></div>
<!-- App.vue -->
<template>
<img alt="Vue logo" src="./assets/logo.png">
<ModalDemo :isOpen="modalIsOpen" @close-modal="onModalClose">My Modal !!!</ModalDemo>
<button @click="openModal">openModal</button>
</template>
<script lang="ts">
import { ref } from 'vue';
import ModalDemo from './components/ModalDemo.vue';
export default {
components: { ModalDemo },
name: 'App',
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: #2c3e50;
margin-top: 60px;
}
</style>
参考文档
- https://v3.cn.vuejs.org/guide/teleport.html
- https://vuejs.org/guide/built-ins/teleport.html
- https://staging-cn.vuejs.org/guide/built-ins/teleport.html
Suspense
在正确渲染组件之前进行一些异步请求是很常见的事。组件通常会在本地处理这种逻辑,绝大多数情况下这是非常完美的做法。
<suspense>
组件提供了另一个方案,允许将等待过程提升到组件树中处理,而不是在单个组件中。
-
组件有两个插槽。它们都只接收一个直接子节点。default 插槽里的节点会尽可能展示出来。如果不能,则展示 fallback 插槽里的节点。 -
重要的是,异步组件不需要作为
的直接子节点。它可以出现在组件树任意深度的位置,且不需要出现在和 自身相同的模板中。只有所有的后代组件都准备就绪,该内容才会被认为解析完毕。 -
另一个触发 fallback 的方式是让后代组件从 setup 函数中返回一个 Promise。通常这是通过 async 实现的,而不是显式地返回一个 Promise
<!-- App.vue -->
<template>
<img alt="Vue logo" src="./assets/logo.png">
<Suspense>
<template #default>
<async-show />
</template>
<template #fallback>
<h1>Loading !!!...</h1>
</template>
</Suspense>
<Suspense>
<template #default>
<dog-show />
</template>
<template #fallback>
<h1>Loading DogShow!!!...</h1>
</template>
</Suspense>
</template>
<script lang="ts">
import AsyncShow from './components/AsyncShow.vue';
import DogShow from './components/DogShow.vue';
export default {
components: { AsyncShow,DogShow },
};
</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;
}
</style>
<!-- AsyncShow.vue -->
<template>
<h1>{{result}}</h1>
</template>
<script>
import {defineComponent} from 'vue'
export default defineComponent({
setup(){
return new Promise((resolve)=>{
setTimeout(()=>{
return resolve({result:'this is AsyncShow.vue'})
},3000)
})
}
})
</script>
<!-- DogShow.vue -->
<template>
<img :src="result&&result.message"/>
</template>
<script>
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>
-
一旦
的 default 插槽里的内容被解析,则它只有在 default 根结点被替换的时候才能被再次触发。而树里的深层嵌套组件不足以让 回到等待状态。 -
如果根结点发生了变化,它会触发 pending 事件。然而,默认情况下,它不会更新 DOM 以展示 fallback 内容。取而代之的是,它会继续展示旧的 DOM,直到新组件准备就绪。这个行为可以通过 timeout prop 进行控制。这个值是一个毫秒数,告诉
组件多久之后展示 fallback。如果这个值是 0 则表示它在 进入等待状态时会立即显示。
参考文档
- https://vuejs.org/guide/built-ins/suspense.html
- https://v3.cn.vuejs.org/guide/migration/suspense.html
- https://staging-cn.vuejs.org/guide/built-ins/suspense.html
onErrorCaptured
捕获suspense请求中的错误
import { onErrorCaptured,ref } from 'vue';
export default {
components: { AsyncShow,DogShow },
name: 'App',
setup(){
const error=ref(null)
onErrorCaptured((e:any)=>{
error.value=e
return true
})
return {
error
}
}
};
参考文档
作者:德乌姆列特
本博客所有文章仅用于学习、研究和交流目的,欢迎非商业性质转载。
博主的文章没有高度、深度和广度,只是凑字数。由于博主的水平不高,不足和错误之处在所难免,希望大家能够批评指出。
博主是利用读书、参考、引用、抄袭、复制和粘贴等多种方式打造成自己的文章,请原谅博主成为一个无耻的文档搬运工!