• 浅析Vue3新特性Teleport(任意传送门也称瞬间移动):为什么需要Teleport、与React的Portals特性、如何使用(直接使用、与组件搭配使用、使用多个teleport)、teleport API(to及disabled使用介绍)


      Teleport 是什么?它解决的是什么问题?

    一、使用场景 - 为什么我们需要 Teleport

      Teleport 是一种能够将我们的模板移动到 DOMVue app 之外的其他位置的技术。

    1、使用场景:

      业务开发的过程中,我们经常会封装一些常用的组件,例如 Modal 组件。相信大家在使用 Modal 组件的过程中,经常会遇到一个问题,那就是 Modal 的定位问题。

    (1)像 modalstoast 等这样的元素,很多情况下,我们将它完全的和我们的 Vue 应用的 DOM 完全剥离,管理起来反而会方便容易很多。原因在于如果我们嵌套在 Vue 的某个组件内部,那么处理嵌套组件的定位、z-index 和样式就会变得很困难。

    (2)另外,像 modalstoast 等这样的元素需要使用到 Vue 组件的状态(data 或者 props)的值。

    2、作用 - 这就是 Teleport 派上用场的地方:

      我们可以在组件的逻辑位置写模板代码,这意味着我们可以使用组件的 dataprops,然后在 Vue 应用的范围之外渲染它

    Teleport 提供了一种干净的方法,允许我们控制在 DOM 中哪个父节点下呈现 HTML,而不必求助于全局状态或将其拆分为两个组件。 -- Vue 官方文档
    3、多个 <teleport> 组件可以将其内容添加到同一目标元素。
    <teleport to="#modals">
      <div>A</div>
    </teleport>
    <teleport to="#modals">
      <div>B</div>
    </teleport>
    // result
    <div id="modals">
      <div>A</div>
      <div>B</div>
    </div>

    二、React 的 Portals 特性

      介绍了 Teleport 之后我们也来了解一下 React 的 Portals 特性。Portal 提供了一种将子节点渲染到存在于父组件以外的 DOM 节点的优秀的方案。

    ReactDOM.createPortal(child, container)

      第一个参数(child)是任何可渲染的 React 子元素,例如一个元素,字符串或 fragment。第二个参数(container)是一个 DOM 元素。

      通常来讲,当你从组件的 render 方法返回一个元素时,该元素将被挂载到 DOM 节点中离其最近的父节点。
    render() {
      // React 挂载了一个新的 div,并且把子元素渲染其中
      return (
        <div>
          {this.props.children}
        </div>
      );
    }

      然而,有时候将子元素插入到 DOM 节点中的不同位置也是有好处的:

    render() {
      // React 并没有创建一个新的 div。它只是把子元素渲染到 `domNode` 中。
      // `domNode` 是一个可以在任何位置的有效 DOM 节点。
      return ReactDOM.createPortal(
        this.props.children,
        domNode
      );
    }

      一个 portal 的典型用例是当父组件有 overflow: hidden 或 z-index 样式时,但你需要子组件能够在视觉上“跳出”其容器。例如,对话框、悬浮卡以及提示框。常见的情况是创建一个包含全屏模式的组件。

      对话框 position: absolute 的定位相对于父 div 作为参考。Teleport 提供了一种简单的方法,使我们可以控制要在DOM中哪个父对象下呈现HTML。

    三、Teleport 使用

    1、代码示例:直接使用

    // 1、index.html 中,我们加一个和 app 同级的 div
    <div id="app"></div>
    <div id="teleport-target"></div>
    // 2、HelloWorld.vue 中,添加如下,留意 to 属性跟上面的 id 选择器一致
    <button @click="showToast" class="btn">打开 toast</button>
      // to 属性就是目标位置
      <teleport to="#teleport-target">
        <div v-if="visible" class="toast-wrap">
        <div class="toast-msg">我是一个 Toast 文案</div>
      </div>
    </teleport>
    // 3、再使用 js 我们使用组件里的 变量 去控制 toast 显示隐藏
    import { ref } from 'vue';
    export default {
      setup() {
        // toast 的封装
        const visible = ref(false);
        let timer;
        const showToast = () => {
          visible.value = true;
          clearTimeout(timer);
          timer = setTimeout(() => {
            visible.value = false;
          }, 2000);
        }
        return {
          visible,
          showToast
        }
      }
    }

      可以看到,我们使用 teleport 组件:

    (1)通过 to 属性,指定该组件渲染的位置与 <div id="app"></div> 同级,也就是在 body 下,

    (2)但是 teleport状态 visible 又是完全由内部 Vue 组件控制

    2、代码示例:与 Vue 组件一起使用 - modal

      如果 <teleport> 包含 Vue 组件,则它仍将是 <teleport> 父组件的逻辑子组件

    <teleport to="#modal-container">
        // use the modal component, pass in the prop
        <modal :show="showModal" @close="showModal = false">
          <template #header>
            <h3>custom header</h3>
          </template>
        </modal>
    </teleport>
    
    import { ref } from 'vue';
    import Modal from './Modal.vue';
    export default {
      components: {
        Modal
      },
      setup() {
        // modal 的封装
        const showModal = ref(false);
        return {
          showModal
        }
      }
    }

      在这种情况下,即使在不同的地方渲染 Modal,它仍将是当前组件(调用 Modal 的组件)的子级,并将从中接收 prop,这也意味着来自父组件的注入按预期工作,并且子组件将嵌套在 Vue Devtools 中的父组件之下,而不是放在实际内容移动到的位置。

    3、在同一目标上使用多个teleport

      一个常见的用例场景是一个可重用的<Modal>组件,它可能同时有多个实例处于活动状态。

    四、Teleport API

    1、to - string,需要prop,必须是有效的查询选择器或HTMLElement(如果在浏览器环境中使用)。指定将在其中一栋<teleport>内容的目标元素

    2、disabled - boolean,此可选属性可用于禁用<teleport>的功能,这意味着其插槽内容将不会移动到任何位置,而是在您在周围父组件中指定了<teleport>的位置渲染。

    <teleport to="#popup" :disabled="displayVideoInline">
        <video src="./my-movie.mp4">
    </teleport>

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

  • 相关阅读:
    C语言进阶—— 单引号和双引号14
    C语言进阶——注释符号12
    C语言进阶——enum, sizeof, typedef 分析11
    算法01
    vim+软件安装——06
    if(xx)和(a==b) 关于数据类型的转换
    浏览器的渲染机制,白屏和FOUC
    BFC的概念和解决外边距合并
    CSS有哪几种引入方式
    块级元素和行内元素的区别,常见的块级元素和行内元素有哪些
  • 原文地址:https://www.cnblogs.com/goloving/p/15408083.html
Copyright © 2020-2023  润新知