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+vant实现购物车全选和反选功能
Nov 17 Vue.js
vue表单验证之禁止input输入框输入空格
Dec 03 Vue.js
Vue看了就会的8个小技巧
Jan 21 Vue.js
如何封装Vue Element的table表格组件
Feb 06 Vue.js
Vue实现todo应用的示例
Feb 20 Vue.js
vue 使用饿了么UI仿写teambition的筛选功能
Mar 01 Vue.js
vue基于Teleport实现Modal组件
May 31 Vue.js
Vue中插槽slot的使用方法与应用场景详析
Jun 08 Vue.js
Vue实现跑马灯样式文字横向滚动
Nov 23 Vue.js
vue使用echarts实现折线图
Mar 21 Vue.js
vue ref如何获取子组件属性值
Mar 31 Vue.js
Vue ECharts实现机舱座位选择展示功能
May 15 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 cookies中删除的一般赋值方法
2011/05/07 PHP
PHP 实现类似js中alert() 提示框
2015/03/18 PHP
php 实现进制相互转换
2016/04/07 PHP
浅谈laravel orm 中的一对多关系 hasMany
2019/10/21 PHP
基于jquery实现后台左侧菜单点击上下滑动显示
2013/04/11 Javascript
javascript中apply和call方法的作用及区别说明
2014/02/14 Javascript
js实现网页倒计时、网站已运行时间功能的代码3例
2014/04/14 Javascript
jQuery中noConflict()用法实例分析
2015/02/08 Javascript
JavaScript判断用户是否对表单进行了修改的方法
2015/03/18 Javascript
JavaScript中的getDay()方法使用详解
2015/06/09 Javascript
微信小程序 省市区选择器实例详解(附源码下载)
2017/01/05 Javascript
angular2+nodejs实现图片上传功能
2017/03/27 NodeJs
Angular.JS中的指令引用template与指令当做属性详解
2017/03/30 Javascript
ES6字符串模板,剩余参数,默认参数功能与用法示例
2017/04/06 Javascript
Vue.js仿Metronic高级表格(一)静态设计
2017/04/17 Javascript
关于vue.js发布后路径引用的问题解决
2017/08/15 Javascript
jQuery图片缩放插件smartZoom使用实例详解
2017/08/25 jQuery
Nginx 配置多站点vhost 的方法
2018/01/07 Javascript
解决nodejs的npm命令无反应的问题
2018/05/17 NodeJs
详解Python发送邮件实例
2016/01/10 Python
python登录并爬取淘宝信息代码示例
2017/12/09 Python
python unittest实现api自动化测试
2018/04/04 Python
对python遍历文件夹中的所有jpg文件的实例详解
2018/12/08 Python
Python3实现获取图片文字里中文的方法分析
2018/12/13 Python
10行Python代码计算汽车数量的实现方法
2019/10/23 Python
Python读取JSON数据操作实例解析
2020/05/18 Python
Django搭建项目实战与避坑细节详解
2020/12/06 Python
详解pandas中利用DataFrame对象的.loc[]、.iloc[]方法抽取数据
2020/12/13 Python
CSS3实战第一波 让我们尽情的圆角吧
2010/08/27 HTML / CSS
美国克罗格超市在线购物:Kroger
2019/06/21 全球购物
班级聚会策划书
2014/01/16 职场文书
纪念九一八爱国演讲稿600字
2014/09/14 职场文书
教师考核表个人总结
2015/02/12 职场文书
紫日观后感
2015/06/05 职场文书
详解python的内存分配机制
2021/05/10 Python
Vue全家桶入门基础教程
2021/05/14 Vue.js