vue基于Teleport实现Modal组件

 更新时间:2021年05月31日 10:57:57   作者:小蝉儿  
Teleport 提供了一种干净的方法,允许我们控制在 DOM 中哪个父节点下渲染了 HTML,而不必求助于全局状态或将其拆分为两个组件。

1.认识Teleport

像我们如果写Modal组件、Message组件、Loading组件这种全局式组件,没有Teleport的话,将它们引入一个.vue文件中,则他们的HTML结构会被添加到组件模板中,这是不够完美的。

  • 没有Teleport

  • 有Teleport

下面就实战介绍一下如何用Teleport开发Modal组件

2.Teleport的基本用法

Teleport的写法十分简单,只需要用<Teleport></Teleport>将内容包裹,并用to指定将HTML挂到哪个父节点下,就可以啦。

<teleport to="#modal">
内容
</teleport>

3.第一步优化

如果我们在代码中将Teleport要挂载的DOM写死,那么每创建一个全局式组件,就需要有一个DOM节点,会越来越多,并且一直存在,这样的写法不是很优雅。比较好的解决方案就是:

  • 在创建组件的时候,动态创建一个dom节点document.createElement(),
  • 并添加到body中,document.body.appendChild(),
  • 在组件卸载的时候销毁这个dom document.body.removeChild(),
setup(){
  const node = document.createElement('div')
  node.id = 'modal'
  document.body.appendChild(node)
  onUnmounted(() => {
    document.body.removeChild(node)
  })
}

4.第二步优化

如果我们后续还要添加Message组件,Loading组件等功能,同样要用到Teleport,在每一个组件内部都写这么一段代码,实在有点冗余,vue3使我们能够很方便的将逻辑功能提取出来,从而达到逻辑复用的目的。

我们在src-hooks文件夹下创建useDOMCreate.ts文件,来封装这一块逻辑

// hooks/useDOMCreate.ts
import { onUnmounted } from 'vue'

function useDOMCreate(nodeId:string):void {
  const node = document.createElement('div')
  node.id = nodeId
  document.body.appendChild(node)
  onUnmounted(() => {
    document.body.removeChild(node)
  })
}
export default useDOMCreate

使用:

import useDOMCreate from '../hooks/useDOMCreate'
setup(props, ctx) {
    useDOMCreate('modal')
}

5.实现Modal组件

具体封装Modal组件的细节这里就不讲啦,也没有什么复杂的逻辑。直接上代码。

//Modal.vue
<template>
  <teleport to="#modal">
    <div class="modal d-block" tabindex="-1" v-if="isVisible">
      <div class="modal-dialog">
        <div class="modal-content">
          <div class="modal-header">
            <h5 class="modal-title">{{title}}</h5>
            <button type="button" class="close" data-dismiss="modal" aria-label="Close">
              <span aria-hidden="true" @click="onClose">&times;</span>
            </button>
          </div>
          <div class="modal-body">
            <slot></slot>
          </div>
          <div class="modal-footer">
            <button type="button" class="btn btn-secondary" data-dismiss="modal"  @click="onClose">取消</button>
            <button type="button" class="btn btn-primary"  @click="onConfirm">确定</button>
          </div>
        </div>
      </div>
    </div>
  </teleport>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
import useDOMCreate from '../hooks/useDOMCreate'
export default defineComponent({
  name: 'Modal',
  emits: ['model-close', 'model-confirm'],
  props: {
    title: {
      type: String,
      default: ''
    },
    isVisible: {
      type: Boolean,
      default: false
    }
  },
  setup(props, ctx) {
    useDOMCreate('modal')
    const onClose = () => {
      ctx.emit('model-close')
    }
    const onConfirm = () => {
      ctx.emit('model-confirm')
    }
    return {
      onClose,
      onConfirm
    }
  }
})
</script>

使用示例

<template>
  <div class="post-detail-page">
    <button type="button" class="btn btn-danger" @click="handleDelete">删除</button>
    <modal title='是否确认删除?' :isVisible="modalVisible" @model-close="hanldeModalClose" @model-confirm="handleModalConfim">
      <p>确认要删除这篇文章吗?</p>
    </modal>
  </div>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue'
import Modal from '../components/Modal.vue'

export default defineComponent({
  name: 'post-detail',
  components: { Modal },
  setup() {
    const modalVisible = ref(false)
    const handleDelete = () => {
      modalVisible.value = true
    }
    const hanldeModalClose = () => {
      modalVisible.value = false
    }
    const handleModalConfim = () => {
      modalVisible.value = false
      ...
     / /后续逻辑处理
    }
    return {
      hanldeModalClose,
      handleModalConfim,
      handleDelete,
      modalVisible
    }
  }
})
</script>

以上就是vue基于Teleport实现Modal组件的详细内容,更多关于vue Teleport实现Modal组件的资料请关注脚本之家其它相关文章!

相关文章

  • vue+VeeValidate 校验范围实例详解(部分校验,全部校验)

    vue+VeeValidate 校验范围实例详解(部分校验,全部校验)

    validate()可以指定校验范围内,或者是全局的 字段。而validateAll()只能校验全局。这篇文章主要介绍了vue+VeeValidate 校验范围(部分校验,全部校验) ,需要的朋友可以参考下
    2018-10-10
  • Vue2.0利用 v-model 实现组件props双向绑定的优美解决方案

    Vue2.0利用 v-model 实现组件props双向绑定的优美解决方案

    本篇文章主要介绍了Vue2 利用 v-model 实现组件props双向绑定的优美解决方案,具有一定的参考价值,感兴趣的小伙伴们可以参考一下。
    2017-03-03
  • 解决element-ui的el-select选择器的@blur事件失效的坑

    解决element-ui的el-select选择器的@blur事件失效的坑

    这篇文章主要介绍了解决element-ui的el-select选择器的@blur事件失效的坑,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-09-09
  • vant组件库之tag渐变色不起作用的原因及解决

    vant组件库之tag渐变色不起作用的原因及解决

    这篇文章主要介绍了vant组件库之tag渐变色不起作用的原因及解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-04-04
  • Vue高级用法实例教程之动态组件

    Vue高级用法实例教程之动态组件

    让多个组件使用同一个挂载点,并动态切换,这就是动态组件,下面这篇文章主要给大家介绍了关于Vue高级用法实例教程之动态组件的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2021-11-11
  • Vue 实现前端权限控制的示例代码

    Vue 实现前端权限控制的示例代码

    这篇文章主要介绍了Vue 实现前端权限控制的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-07-07
  • vue中使用cookies和crypto-js实现记住密码和加密的方法

    vue中使用cookies和crypto-js实现记住密码和加密的方法

    这篇文章给大家介绍一下关于vue中使用cookies和crypto-js如何实现密码的加密与记住密码,有一定的参考价值,有需要的朋友可以参考一下,希望对你们有所帮助。
    2018-10-10
  • 在Vue中使用CSS3实现内容无缝滚动的示例代码

    在Vue中使用CSS3实现内容无缝滚动的示例代码

    这篇文章主要介绍了在Vue中使用CSS3实现内容无缝滚动的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-11-11
  • axios 发 post 请求,后端接收不到参数的完美解决方案

    axios 发 post 请求,后端接收不到参数的完美解决方案

    这篇文章主要介绍了axios 发 post 请求,后端接收不到参数的解决方案,场景很简单,就是一个正常 axios post 请求,本文给大家分享问题原因分析及解决方案需要的朋友可以参考下
    2022-12-12
  • vue实现计算器封装

    vue实现计算器封装

    这篇文章主要为大家详细介绍了vue实现计算器的封装,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-04-04

最新评论