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-router定义元信息meta操作
Dec 07 Vue.js
vue下拉刷新组件的开发及slot的使用详解
Dec 23 Vue.js
vue 使用class创建和清除水印的示例代码
Dec 25 Vue.js
浅谈Vue开发人员的7个最好的VSCode扩展
Jan 20 Vue.js
vue使用节流函数的踩坑实例指南
May 20 Vue.js
vue-cli4.5.x快速搭建项目
May 30 Vue.js
vue响应式原理与双向数据的深入解析
Jun 04 Vue.js
vue-router中hash模式与history模式的区别
Jun 23 Vue.js
idea编译器vue缩进报错问题场景分析
Jul 04 Vue.js
vue 数字翻牌器动态加载数据
Apr 20 Vue.js
vue修饰符.capture和.self的区别
Apr 22 Vue.js
vue 把二维或多维数组转一维数组
Apr 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
DC最新动画电影:《战争之子》为何内容偏激,毁了一个不错的漫画
2020/04/09 欧美动漫
php cookie 作用范围?不要在当前页面使用你的cookie
2009/03/24 PHP
php格式化时间戳显示友好的时间实现思路及代码
2014/10/23 PHP
php array_map使用自定义的函数处理数组中的每个值
2016/10/26 PHP
Yii2.0实现生成二维码功能实例
2017/10/24 PHP
Prototype Function对象 学习
2009/07/12 Javascript
javascript 遍历验证所有文本框的值
2009/08/27 Javascript
Jquery AutoComplete自动完成 的使用方法实例
2010/03/19 Javascript
jQuery Ajax提交表单查询获得数据实例代码
2012/09/19 Javascript
js confirm()方法的使用方法实例
2013/07/13 Javascript
jQuery动画出现连续触发、滞后反复执行的解决方法
2015/01/28 Javascript
js随机生成字母数字组合的字符串 随机动画数字
2015/09/02 Javascript
jQuery实现简单的图片查看器
2020/09/11 Javascript
原生JS实现DOM加载完成马上执行JS代码的方法
2018/09/07 Javascript
JavaScript判断浏览器运行环境的详细方法
2019/06/30 Javascript
[02:06]DOTA2肉山黑名单魔法终结者 敌法师中文配音鉴赏
2013/06/17 DOTA
python根据出生年份简单计算生肖的方法
2015/03/27 Python
Python实现获取操作系统版本信息方法
2015/04/08 Python
Python使用urllib2模块实现断点续传下载的方法
2015/06/17 Python
Python常见异常分类与处理方法
2017/06/04 Python
Python字典及字典基本操作方法详解
2018/01/30 Python
浅谈Python采集网页时正则表达式匹配换行符的问题
2018/12/20 Python
python3 字符串知识点学习笔记
2020/02/08 Python
django 扩展user用户字段inlines方式
2020/03/30 Python
详解Python openpyxl库的基本应用
2021/02/26 Python
HTML+CSS3 模仿Windows7 桌面效果
2010/06/17 HTML / CSS
公积金单位接收函
2014/01/11 职场文书
教师个人鉴定材料
2014/02/08 职场文书
书法比赛获奖感言
2014/02/10 职场文书
家长对孩子的评语
2014/04/18 职场文书
婚前保证书范文
2015/02/28 职场文书
素质教育学习心得体会
2016/01/19 职场文书
2016年八一建军节活动总结
2016/04/05 职场文书
快消品行业营销模式与盈利模式分享
2019/09/27 职场文书
Python爬虫之爬取最新更新的小说网站
2021/05/06 Python
Java 使用类型为Object的变量指向任意类型的对象
2022/04/13 Java/Android