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 Elenent实现表格相同数据列合并
Nov 30 Vue.js
vue实现表格合并功能
Dec 01 Vue.js
vue 在服务器端直接修改请求的接口地址
Dec 19 Vue.js
vue实现树状表格效果
Dec 29 Vue.js
vue+elementui通用弹窗的实现(新增+编辑)
Jan 07 Vue.js
Vue 实现可视化拖拽页面编辑器
Feb 01 Vue.js
vue使用echarts画组织结构图
Feb 06 Vue.js
vue脚手架项目创建步骤详解
Mar 02 Vue.js
vue 数据双向绑定的实现方法
Mar 04 Vue.js
vue3.0 项目搭建和使用流程
Mar 04 Vue.js
一篇文章告诉你如何实现Vue前端分页和后端分页
Feb 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
php的数组与字符串的转换函数整理汇总
2013/07/18 PHP
php+mysql不用递归实现的无限级分类实例(非递归)
2014/07/08 PHP
Laravel多用户认证系统示例详解
2018/03/13 PHP
Ajax+PHP实现的模拟进度条功能示例
2019/02/11 PHP
JavaScript 继承详解(二)
2009/07/13 Javascript
基于jquery的滚动新闻列表
2010/06/19 Javascript
jquery attr方法获取input的checked属性问题
2014/05/26 Javascript
JS实现点击文字对应DIV层不停闪动效果的方法
2015/03/02 Javascript
谈谈JavaScript类型系统之Math
2016/01/06 Javascript
微信小程序-消息提示框实例
2016/11/24 Javascript
完美解决jQuery fancybox ie 无法显示关闭按钮的问题
2016/11/29 Javascript
js闭包用法实例详解
2016/12/13 Javascript
关于jQuery EasyUI 中刷新Tab选项卡后一个页面变形的解决方法
2017/03/02 Javascript
jQuery插件HighCharts实现2D柱状图、折线图的组合多轴图效果示例【附demo源码下载】
2017/03/09 Javascript
详解React Native网络请求fetch简单封装
2017/08/10 Javascript
利用yarn代替npm管理前端项目模块依赖的方法详解
2017/09/04 Javascript
npm全局模块卸载及默认安装目录修改方法
2018/05/15 Javascript
Node.js模拟发起http请求从异步转同步的5种用法
2018/09/26 Javascript
vue 项目打包时样式及背景图片路径找不到的解决方式
2019/11/12 Javascript
使用Mock.js生成前端测试数据
2020/12/13 Javascript
Python性能优化的20条建议
2014/10/25 Python
Python制作钉钉加密/解密工具
2016/12/07 Python
深入理解NumPy简明教程---数组3(组合)
2016/12/17 Python
Python中的并发处理之asyncio包使用的详解
2018/04/03 Python
python-itchat 统计微信群、好友数量,及原始消息数据的实例
2019/02/21 Python
在PyCharm中实现添加快捷模块
2020/02/12 Python
python 如何区分return和yield
2020/09/22 Python
HTML5实现动画效果的方式汇总
2016/02/29 HTML / CSS
罗兰·穆雷官网:Roland Mouret
2018/09/28 全球购物
简历自荐信
2013/12/02 职场文书
学生会竞选演讲稿
2014/04/24 职场文书
授权委托书协议书
2014/10/16 职场文书
2014年体检中心工作总结
2014/12/23 职场文书
驾驶员安全责任协议书
2016/03/22 职场文书
家电创业计划书
2019/08/05 职场文书
Mysql systemctl start mysqld报错的问题解决
2021/06/03 MySQL