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 表单输入框不支持focus及blur事件的解决方案
Nov 17 Vue.js
浅析VUE防抖与节流
Nov 24 Vue.js
vue中利用three.js实现全景图的完整示例
Dec 07 Vue.js
vuex页面刷新导致数据丢失的解决方案
Dec 10 Vue.js
Vue 修改网站图标的方法
Dec 31 Vue.js
如何在Vue项目中添加接口监听遮罩
Jan 25 Vue.js
Vue单页面应用中实现Markdown渲染
Feb 14 Vue.js
vue实现无缝轮播效果(跑马灯)
May 14 Vue.js
Vue3中的Refs和Ref详情
Nov 11 Vue.js
Vue监视数据的原理详解
Feb 24 Vue.js
vue2的 router在使用过程中遇到的一些问题
Apr 13 Vue.js
vue @ ~ 相对路径 路径别名设置方式
Jun 05 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
《神奇女侠:血脉》神力女超人大战犯罪公司
2020/04/09 欧美动漫
php 使用GD库为页面增加水印示例代码
2014/03/24 PHP
php实现批量上传数据到数据库(.csv格式)的案例
2017/06/18 PHP
php unlink()函数使用教程
2018/07/12 PHP
php实现对文件压缩简单的方法
2019/09/29 PHP
PHP开发api接口安全验证操作实例详解
2020/03/26 PHP
原生js实现查找/添加/删除/指定元素的class
2013/04/12 Javascript
jQuery实现图片放大预览实现原理及代码
2013/09/12 Javascript
js的alert样式如何更改如背景颜色
2014/01/22 Javascript
Javascript字符串浏览器兼容问题分析
2014/12/01 Javascript
jQuery DOM删除节点操作指南
2015/03/03 Javascript
jQuery Validate插件实现表单验证
2016/08/19 Javascript
javascript实现简单的on事件绑定
2016/08/23 Javascript
老生常谈Javascript中的原型和this指针
2016/10/09 Javascript
React服务端渲染(总结)
2017/07/01 Javascript
原生js 封装get ,post, delete 请求的实例
2017/08/11 Javascript
详解Vue中一种简易路由传参办法
2017/09/15 Javascript
基于Require.js使用方法(总结)
2017/10/26 Javascript
angularjs实现分页和搜索功能
2018/01/03 Javascript
Koa2微信公众号开发之消息管理
2018/05/16 Javascript
微信小程序onLaunch异步,首页onLoad先执行?
2018/09/20 Javascript
Python的Django框架中模板碎片缓存简介
2015/07/24 Python
利用PyInstaller将python程序.py转为.exe的方法详解
2017/05/03 Python
PyQt5+Pycharm安装和配置图文教程详解
2020/03/24 Python
HTML5仿手机微信聊天界面
2016/03/18 HTML / CSS
仿酷狗html5手机音乐播放器主要部分代码
2013/05/15 HTML / CSS
美国高端婴童品牌:Hanna Andersson
2016/10/30 全球购物
匡威德国官网:Converse德国
2019/01/26 全球购物
英国高街奥特莱斯:Highstreet Outlet
2019/11/21 全球购物
机械工程学院大学生求职信
2014/05/25 职场文书
学校端午节活动总结
2015/02/11 职场文书
朋友聚会开场白
2015/06/01 职场文书
小学英语教学反思范文
2016/02/15 职场文书
遇事可以测出您的见识与格局
2019/09/16 职场文书
22句经典语录:送给优柔寡断和胡思乱想的朋友们
2019/12/13 职场文书
pytorch 如何使用float64训练
2021/05/24 Python