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 相关文章推荐
Vue如何循环提取对象数组中的值
Nov 18 Vue.js
Vue Elenent实现表格相同数据列合并
Nov 30 Vue.js
Vue+element-ui添加自定义右键菜单的方法示例
Dec 08 Vue.js
vue调用微信JSDK 扫一扫,相册等需要注意的事项
Jan 03 Vue.js
vue watch监控对象的简单方法示例
Jan 07 Vue.js
vue自定义组件实现双向绑定
Jan 13 Vue.js
vue动态设置路由权限的主要思路
Jan 13 Vue.js
vue 中this.$set 动态绑定数据的案例讲解
Jan 29 Vue.js
vue-video-player 断点续播的实现
Feb 01 Vue.js
vue-cli中实现响应式布局的方法
Mar 02 Vue.js
使用vue-element-admin框架从后端动态获取菜单功能的实现
Apr 29 Vue.js
使用这 6个Vue加载动画库来减少我们网站的跳出率
May 18 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
不用数据库的多用户文件自由上传投票系统(1)
2006/10/09 PHP
php通过字符串调用函数示例
2014/03/02 PHP
PHP学习笔记(三):数据类型转换与常量介绍
2015/04/17 PHP
分享PHP计算两个日期相差天数的代码
2015/12/23 PHP
php 数组处理函数extract详解及实例代码
2016/11/23 PHP
php中分页及SqlHelper类用法实例
2017/01/12 PHP
PHP/HTML混写的四种方式总结
2017/02/27 PHP
php实现的双色球算法示例
2017/06/20 PHP
php中用unset销毁变量并释放内存
2020/05/10 PHP
JS时间选择器 兼容IE6,7,8,9
2012/06/26 Javascript
jQuery实现拖动调整表格单元格大小的代码实例
2015/01/13 Javascript
BootStrop前端框架入门教程详解
2016/12/25 Javascript
浅谈Angular2 ng-content 指令在组件中嵌入内容
2017/08/18 Javascript
js replace 全局替换的操作方法
2018/06/12 Javascript
基于Vue和Element-Ui搭建项目的方法
2019/09/06 Javascript
详解ES6 中的Object.assign()的用法实例代码
2021/01/11 Javascript
使用Python内置的模块与函数进行不同进制的数的转换
2016/03/12 Python
Python编程中实现迭代器的一些技巧小结
2016/06/21 Python
python 时间信息“2018-02-04 18:23:35“ 解析成字典形式的结果代码详解
2018/04/19 Python
python实现本地图片转存并重命名的示例代码
2018/10/27 Python
django如何实现视图重定向
2019/07/24 Python
python实现opencv+scoket网络实时图传
2020/03/20 Python
Python Socketserver实现FTP文件上传下载代码实例
2020/03/27 Python
Python应用实现处理excel数据过程解析
2020/06/19 Python
python+appium+yaml移动端自动化测试框架实现详解
2020/11/24 Python
NBA欧洲商店(英国):NBA Europe Store UK
2018/07/27 全球购物
Lulu Guinness露露·吉尼斯官网:红唇包
2019/02/03 全球购物
STP的判定过程
2012/10/01 面试题
优质的学校老师推荐信
2013/10/28 职场文书
什么是岗位职责
2013/11/12 职场文书
《最佳路径》教学反思
2014/04/13 职场文书
幼儿园师德师风学习材料
2014/05/29 职场文书
五一促销活动总结
2014/07/01 职场文书
2014年社区综治工作总结
2014/11/17 职场文书
mysql数据库入门第一步之创建表
2021/05/14 MySQL
MySQL系列之一 MariaDB-server安装
2021/07/02 MySQL