在这里插入图片描述

Author:Gorit

Date:2021年12月5日

Website:CodingGorit 的小站

2021年发表博文:25/30

我们用 vite 搭建一个 Vue3 + TS 项目,我会使用 <script setup lnag="ts"><script lang="ts"> 混合编程的方式来实现

一、Teleport

Teleport 官方文档

1.1 Teleport 介绍

  1. Vue 鼓励我们通过将 UI 和相关行为封装到组件中来构建我们的 UI。我们可以将它们相互嵌套以构建构成应用程序 UI 的树。
  2. 但是,有时组件模板的一部分在逻辑上属于该组件,而从技术角度来看,最好将模板的这部分移动到 DOM 中的其他位置,即 Vue 应用程序之外。

上面的话是不是看起来很懵逼,其实是翻译自 官方文档

其实我理解的 Teleport 就是将一个组件挂载在 Vue app 之外,我们知道,Vue 属于 SPA(单页面)应用。所有的渲染都在 id 为 app 的标签里面,这样的话,我们就创建一个和 app 是同级 的组件,并且通过 teleport 标签引用,就可以任意页面使用了

1.2 使用 Teleport

  1. 我们这里也是实现一个全局模态框
  2. 通过 父子组件通信 机制,来使用 teleport 的挂载的特性
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" href="/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Vite App</title>
  </head>
  <body>
    <div id="app"></div>
    <div id="modal"></div> <!-- 定义一个和 app 同级的标签 modal -->
    <script type="module" src="/src/main.ts"></script>
  </body>
</html>

  1. 定义一个 Modal 组件
<template>
	<!-- teleport 有个一个 to 属性,挂载在 id为modal的标签上 -->
    <teleport to="#modal">
        <div id="center" v-if="isOpen">
            <div class="modal-header" v-if="title">
                <h2>{{ title }}</h2>
                <hr />
            </div>
            <div class="modal-content">
                <!-- 我们使用插槽,来支持外部插入内容 -->
                <slot></slot>
            </div>
            <button @click="buttonClick">Close</button>
        </div>
    </teleport>
</template>

<script lang="ts">
// defineProps<{ msg: string }>() Vue3 setup 定义 props
import { defineComponent } from 'vue';
export default defineComponent({
    props: {
        isOpen: Boolean,
        title: String
    },
    // 验证
    emits: {
        'close-modal': null
        // (payload: any) => {
        //     return payload.type === 'close'
        // }
    },
    setup(props, context) {
        const buttonClick = () => {
            context.emit('close-modal');
        }

        return {
            buttonClick
        }
    }
});

</script>

<style>
#center {
    width: 200px;
    height: 200px;
    border: 2px solid black;
    background-color: white;
    position: fixed;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
}
</style>
  1. 使用 Modal 组件
<script setup lang="ts">
import { ref } from 'vue';
import Modal from './components/Modal.vue';
const modalTitle = ref('你好,世界');
const modalIsOpen = ref(false);

const openModal = () => {
  modalIsOpen.value = true;
}
const onModalClose = () => {
  modalIsOpen.value = false;
}
</script>

<template>
  <img alt="Vue logo" src="./assets/logo.png" />
  <div class="test-useURLLoader">
    <button @click="openModal">modal</button>
    <Modal :title="modalTitle" :isOpen="modalIsOpen" @close-modal="onModalClose">
      My modal
    </Modal>
  </div>
</template>

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

1.3 预览效果

请添加图片描述

二、Suspense

Suspense 官方文档

Waring:作为 Vue3 中实验性的功能,随时都有可能修改,所以不建议用于生成环境的应用

2.1 介绍

  1. Suspense 是可以用来异步数据,它拥有一个本地的处理方法用来适配多种情形
  2. 提供了二选一(加载完成 和 失败的插槽)

更详细的内容大家可以自行翻阅官方文档,我只是进行一部分的挑选

2.2 使用 Suspense

  1. 为了实现异步效果,我们可以使用 Promise 来实现异步操作。

  2. 我们定义如下组件 AsyncShow.vue 组件

<template>
	<!-- 等待3秒显示数据 -->
    <h1>{{ result }}</h1>
</template>

<script lang="ts">
import { defineComponent } from 'vue';
export default defineComponent({
    setup() {
        return new Promise((resolve) => {
            setTimeout(() => {
                return resolve({
                    result: 43
                })
            }, 3000);
        });
    }
});
</script>

<style>
</style>
  1. 在 App.vue 里面使用该组件
<script setup lang="ts">
import AsyncShow from './components/AsyncShow.vue';
</script>

<template>
  <img alt="Vue logo" src="./assets/logo.png" />
  <div class="test-useURLLoader">
    <!-- Promise 未执行完成时,就会显示 Loding... 执行完毕后,就会显示数值 -->
    <Suspense>
      <template #default>
        <AsyncShow />
      </template>
      <template #fallback>
        <h2>
          Loading...
        </h2>
      </template>
    </Suspense>
  </div>
</template>

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

2.3 预览效果

请添加图片描述

Logo

前往低代码交流专区

更多推荐