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 插槽简介及使用示例
Nov 19 Vue.js
vuex页面刷新导致数据丢失的解决方案
Dec 10 Vue.js
Vue实现指令式动态追加小球动画组件的步骤
Dec 18 Vue.js
深入了解Vue动态组件和异步组件
Jan 26 Vue.js
Vue常用API、高级API的相关总结
Feb 02 Vue.js
如何在 Vue 中使用 JSX
Feb 14 Vue.js
vue+springboot实现登录验证码
May 27 Vue.js
Vue + iView实现Excel上传功能的完整代码
Jun 22 Vue.js
Vue组件更新数据v-model不生效的解决
Apr 02 Vue.js
vue2的 router在使用过程中遇到的一些问题
Apr 13 Vue.js
解决vue自定义组件@click点击失效问题
Apr 30 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
php自动注册登录验证机制实现代码
2011/12/20 PHP
PHP使用PhpSpreadsheet操作Excel实例详解
2020/03/26 PHP
跟随鼠标旋转的文字
2006/11/30 Javascript
原生JS操作网页给p元素添加onclick事件及表格隔行变色
2013/12/01 Javascript
JS 获取浏览器和屏幕宽高等信息代码
2014/03/31 Javascript
node.js中的buffer.toString方法使用说明
2014/12/14 Javascript
值得学习的bootstrap fileinput文件上传工具
2016/11/08 Javascript
js以分隔符分隔数组中的元素并转换为字符串的方法
2016/11/16 Javascript
JS实现浏览器打印、打印预览示例
2017/02/28 Javascript
vue子父组件通信的实现代码
2017/07/09 Javascript
Vue官网todoMVC示例代码
2018/01/29 Javascript
JavaScript 空间坐标的使用
2020/08/19 Javascript
python使用reportlab画图示例(含中文汉字)
2013/12/03 Python
python编写微信远程控制电脑的程序
2018/01/05 Python
基于Python实现的微信好友数据分析
2018/02/26 Python
TensorFlow变量管理详解
2018/03/10 Python
浅谈pandas中Dataframe的查询方法([], loc, iloc, at, iat, ix)
2018/04/10 Python
PyTorch学习笔记之回归实战
2018/05/28 Python
python消除序列的重复值并保持顺序不变的实例
2018/11/08 Python
Python3字符串encode与decode的讲解
2019/04/02 Python
Python何时应该使用Lambda函数
2019/07/02 Python
Python操作Jira库常用方法解析
2020/04/10 Python
python 实现两个线程交替执行
2020/05/02 Python
Ubuntu配置Pytorch on Graph (PoG)环境过程图解
2020/11/19 Python
TensorFlow低版本代码自动升级为1.0版本
2021/02/20 Python
美国排名第一的在线葡萄酒商店:Wine.com
2016/09/07 全球购物
荷兰时尚精品店:Labels Fashion
2020/03/22 全球购物
Ray-Ban雷朋奥地利官网:全球领先的太阳眼镜品牌
2020/10/12 全球购物
初中英语课后反思
2014/04/25 职场文书
关于学习的演讲稿
2014/05/10 职场文书
乡镇安全生产目标责任书
2014/07/23 职场文书
税务干部个人整改措施思想汇报
2014/10/10 职场文书
三八妇女节新闻稿
2015/07/17 职场文书
就业指导讲座心得体会
2016/01/15 职场文书
Windows安装Anaconda3的方法及使用过程详解
2021/06/11 Python
Java对文件的读写操作方法
2022/04/29 Java/Android