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>

参考文档

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 则表示它在 进入等待状态时会立即显示。

参考文档

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

参考文档

posted @ 2022-03-26 16:41  德乌姆列特  阅读(60)  评论(0编辑  收藏  举报