vue基于Teleport实现Modal组件


Posted in Vue.js onMay 31, 2021

1.认识Teleport

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

  • 没有Teleport

vue基于Teleport实现Modal组件

  • 有Teleport

vue基于Teleport实现Modal组件

下面就实战介绍一下如何用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.js 相关文章推荐
Vue3+elementui plus创建项目的方法
Dec 01 Vue.js
vue+elementUI动态增加表单项并添加验证的代码详解
Dec 17 Vue.js
Vue实现手机号、验证码登录(60s禁用倒计时)
Dec 19 Vue.js
Vue 简单实现前端权限控制的示例
Dec 25 Vue.js
vue实现登录功能
Dec 31 Vue.js
Vue项目打包部署到apache服务器的方法步骤
Feb 01 Vue.js
Vue常用API、高级API的相关总结
Feb 02 Vue.js
vue使用Google Recaptcha验证的实现示例
Aug 23 Vue.js
vue整合百度地图显示指定地点信息
Apr 06 Vue.js
Axios代理配置及封装响应拦截处理方式
Apr 07 Vue.js
vue配置型表格基于el-table拓展之table-plus组件
Apr 12 Vue.js
Vue Element plus使用方法梳理
Dec 24 Vue.js
Vue+Element UI实现概要小弹窗的全过程
vue-cli4.5.x快速搭建项目
Vue CLI中模式与环境变量的深入详解
springboot+VUE实现登录注册
May 27 #Vue.js
vue+springboot实现登录验证码
vue+spring boot实现校验码功能
May 27 #Vue.js
vue-cropper组件实现图片切割上传
May 27 #Vue.js
You might like
利用PHP生成静态HTML文档的原理
2012/10/29 PHP
经典PHP加密解密函数Authcode()修复版代码
2015/04/05 PHP
Laravel5.1框架注册中间件的三种场景详解
2019/07/09 PHP
Nginx+php配置文件及原理解析
2020/12/09 PHP
图片按比例缩放函数
2006/06/26 Javascript
Z-Blog中用到的js代码
2007/03/15 Javascript
js(jQuery)获取时间的方法及常用时间类搜集
2013/10/23 Javascript
JavaScript实现将xml转换成html table表格的方法
2015/04/17 Javascript
jquery获取节点名称
2015/04/26 Javascript
使用RequireJS优化JavaScript引用代码的方法
2015/07/01 Javascript
javascript省市级联功能实现方法实例详解
2015/10/20 Javascript
Easyui 之 Treegrid 笔记
2016/04/29 Javascript
jQuery Mobile 触摸事件实例
2016/06/04 Javascript
JavaScript实现使用Canvas绘制图形的基本教程
2016/10/27 Javascript
JS实现求5的阶乘示例
2019/01/21 Javascript
在Django的form中使用CSS进行设计的方法
2015/07/18 Python
python通过opencv实现批量剪切图片
2017/11/13 Python
python 实现将文件或文件夹用相对路径打包为 tar.gz 文件的方法
2019/06/10 Python
Tensorflow 自定义loss的情况下初始化部分变量方式
2020/01/06 Python
pytorch 常用函数 max ,eq说明
2020/06/28 Python
详解通过HTML5 Canvas实现图片的平移及旋转变化的方法
2016/03/22 HTML / CSS
雪花秀美国官方网站:韩国著名草本护肤化妆品品牌
2016/10/19 全球购物
英国休闲奢华的缩影:Crew Clothing
2019/05/05 全球购物
卫校毕业生自我鉴定
2013/10/31 职场文书
日语专业毕业生自荐信
2013/11/11 职场文书
小学生考试获奖感言
2014/01/30 职场文书
学习十八大报告感言
2014/02/04 职场文书
酒店管理失职检讨书
2014/09/16 职场文书
2014年村支部书记四风对照检查材料思想汇报
2014/10/02 职场文书
生日答谢词
2015/01/05 职场文书
拾金不昧表扬稿
2015/01/16 职场文书
店长岗位职责
2015/02/11 职场文书
2016优秀班主任个人先进事迹材料
2016/02/26 职场文书
详解Python小数据池和代码块缓存机制
2021/04/07 Python
MySQL系列之十 MySQL事务隔离实现并发控制
2021/07/02 MySQL
《月歌。》宣布制作10周年纪念剧场版《RABBITS KINGDOM THE MOVIE》
2022/04/02 日漫