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 elementUI 使用el-select 时 change事件的触发问题
Nov 17 Vue.js
Vue +WebSocket + WaveSurferJS 实现H5聊天对话交互的实例
Nov 18 Vue.js
vue 动态生成拓扑图的示例
Jan 03 Vue.js
如何使用RoughViz可视化Vue.js中的草绘图表
Jan 30 Vue.js
vue 根据选择的月份动态展示日期对应的星期几
Feb 06 Vue.js
Vue.js 带下拉选项的输入框(Textbox with Dropdown)组件
Apr 17 Vue.js
vue中利用mqtt服务端实现即时通讯的步骤记录
Jul 01 Vue.js
idea编译器vue缩进报错问题场景分析
Jul 04 Vue.js
vue的项目如何打包上线
Apr 13 Vue.js
vue动态绑定style样式
Apr 20 Vue.js
vue postcss-px2rem 自适应布局
May 15 Vue.js
ant design vue的form表单取值方法
Jun 01 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 程式大小
2006/12/06 PHP
php中的观察者模式
2010/03/24 PHP
SWFUpload与CI不能正确上传识别文件MIME类型解决方法分享
2011/04/18 PHP
php的laravel框架快速集成微信登录的方法
2016/12/12 PHP
老生常谈PHP面向对象之标识映射
2017/06/21 PHP
PHP实现微信商户支付企业付款到零钱功能
2018/09/30 PHP
PHP简单验证码功能机制实例详解
2019/03/27 PHP
js 调整select 位置的函数
2008/02/21 Javascript
背景图跟随鼠标移动的Mootools插件实现代码
2011/12/12 Javascript
JS的replace方法详细介绍
2012/11/09 Javascript
返回页面顶部top按钮通过锚点实现(自写)
2013/08/30 Javascript
阿里巴巴技术文章分享 Javascript继承机制的实现
2016/01/14 Javascript
jQuery实现联动下拉列表查询框
2017/01/04 Javascript
JavaScript实现body内任意节点的自定义属性功能示例
2017/09/18 Javascript
详解如何使用router-link对象方式传递参数?
2019/05/02 Javascript
vue 解决数组赋值无法渲染在页面的问题
2019/10/28 Javascript
详解jQuery中的prop()使用方法
2020/01/05 jQuery
Vue Render函数原理及代码实例解析
2020/07/30 Javascript
JavaScript编码小技巧分享
2020/09/17 Javascript
JavaScript实现刮刮乐效果
2020/11/01 Javascript
JavaScript Dom实现轮播图原理和实例
2021/02/19 Javascript
[02:41]DOTA2英雄基础教程 冥魂大帝
2014/01/16 DOTA
python调用windows api锁定计算机示例
2014/04/17 Python
详解Python2.x中对Unicode编码的使用
2015/04/03 Python
Python Socket编程详细介绍
2017/03/23 Python
python学生管理系统代码实现
2020/04/05 Python
PYTHON绘制雷达图代码实例
2019/10/15 Python
浅析Python 中的 WSGI 接口和 WSGI 服务的运行
2020/12/09 Python
详解CSS3中@media的实际使用
2015/08/04 HTML / CSS
业务部门经理岗位职责
2014/02/23 职场文书
艺术节开幕词
2015/01/28 职场文书
收银员岗位职责
2015/02/03 职场文书
2015年业务工作总结范文
2015/04/10 职场文书
党员干部廉洁自律承诺书
2015/04/28 职场文书
刑事案件上诉状
2015/05/23 职场文书
安全生产隐患排查制度
2015/08/05 职场文书