欢迎来到我的博客

vuePress-theme-reco hbbaly    2021
欢迎来到我的博客

Choose mode

  • dark
  • auto
  • light
首页
时间轴
标签
分类
  • 前端
GitHub
author-avatar

hbbaly

31

Article

18

Tag

首页
时间轴
标签
分类
  • 前端
GitHub
  • 【vue3】Suspense && Teleport

    • Suspense
      • 捕获组件错误
        • Teleport

        【vue3】Suspense && Teleport

        vuePress-theme-reco hbbaly    2021

        【vue3】Suspense && Teleport


        hbbaly 2020-10-15 18:23:00 Vue3

        # Suspense

        Suspense组件是vue3新增的内置组件,主要作为在等待异步组件时渲染一些后备内容,创建一个平滑的用户体验。

        说到这里是不是很熟悉,这不就是类似于骨架图或者占位图。

        // parent.vue
        <template>
          <div id="app">
            <Suspense>
              <template #default>
                <hello-world />
              </template>
              <template #fallback> 
                <div>
                  loading......
                </div>
              </template>
            </Suspense>
          </div>
        </template>
        
        <script>
        import HelloWorld from './components/HelloWorld.vue';
        export default {
          components: {
            HelloWorld,
          },
          setup() {
          }
        };
        </script>
        

        这里需要注意Suspense组件内部的template需要有一个根节点,而不是多个

        // HelloWorld
        <template>
          <div>
            <div>{{msg}}</div>
          </div>
        </template>
        
        <script>
        
        export default {
          async setup() {
            
            const fetchMsg = (timeout) => {
              return new Promise((resolve) => {
                setTimeout(() => {
                  resolve('Hello Suspense')
                }, timeout);
              });
            };
            const msg = await fetchMsg(2000)
            return { msg }
          },
        };
        </script>
        

        简单的suspense就成功了,在2000ms之前都是现实的loading......,之后显示Hello Suspense

        # 捕获组件错误

        // parent.vue
        <template>
          <div id="app">
            <div v-if="error">{{ error }}</div>
            <Suspense v-else>
              <template #default>
                <hello-world />
              </template>
              <template #fallback> 
                <div>
                  loading......
                </div>
              </template>
            </Suspense>
          </div>
        </template>
        
        <script>
        import { onErrorCaptured, ref } from "vue";
        
        import HelloWorld from './components/HelloWorld.vue';
        export default {
          components: {
            HelloWorld,
          },
          setup() {
            const error = ref(null);
            onErrorCaptured((e) => {
              error.value = e;
              // 不对错误进行拦截
              return true;
            });
            return {error}
          }
        };
        </script>
        

        onErrorCaptured钩子函数都会在捕获到任何后代组件的错误时运行。如果出现问题,我们可以将其与Suspense一起使用以渲染错误。

        # Teleport

        • to - string。需要 prop,必须是有效的查询选择器或 HTMLElement (如果在浏览器环境中使用)。指定将在其中移动 <teleport> 内容的目标元素
        <!-- 正确 -->
        <teleport to="#some-id" />
        <teleport to=".some-class" />
        <teleport to="[data-teleport]" />
        
        <!-- 错误 -->
        <teleport to="h1" />
        <teleport to="some-string" />
        
        • disabled - boolean。此可选属性可用于禁用 <teleport> 的功能,这意味着其插槽内容将不会移动到任何位置,而是在您在周围父组件中指定了 <teleport> 的位置渲染
        <teleport to="#popup" :disabled="displayVideoInline">
          <video src="./my-movie.mp4">
        </teleport>
        

        Teleport 提供了一种干净的方法,允许我们控制在 DOM 中哪个父节点下呈现 HTML,而不必求助于全局状态或将其拆分为两个组件。

        <template>
          <h1>teleport</h1>
          <div class="top" @click="getTop">top</div>
          <div class="bot" @click="getBot">bot</div>
          <teleport :to="pos">
            <div>I'm a teleported!</div>
          </teleport>
        </template>
        
        <script>
        import { ref } from "vue";
        export default {
          setup() {
            // 这里pos需要一个不为空的默认值, 不然会导致元素两次加载
            const pos = ref(".top");
            const getTop = () => {
              console.log("click top");
              pos.value = ".top";
            };
            const getBot = () => {
              console.log("click bot");
              pos.value = ".bot";
            };
            return {
              pos,
              getTop,
              getBot,
            };
          },
        };
        </script>
        

        请注意,这将移动实际的 DOM 节点,而不是被销毁和重新创建,并且它还将保持任何组件实例的活动状态。所有有状态的 HTML 元素 (即播放的视频) 都将保持其状态。