一、封装原因

因为我在开发中不想使用 el-dialog 直接写页面,我想向下面这样使用组件,这样包括弹框头部、内容、底部都可以以组件形式传入插件实现分离控制

DialogBox({
   title: item.name == 'qq' ? 'QQ名片' : '微信名片',
   dom: QqCode,
   option: {
     type: item.name
   }
})

二、具体代码如下

主内容文件----index.vue
<template>
  <el-dialog
    class="dialog-plus"
    modal-class="dialog-plus-modal"
    :modal="props.modal"
    :close-on-click-modal="props.closeOnClickModal"
    align-center
    v-model="visible"
    :width="props.width"
    :show-close="false"
    @close="dealClose"
    @closed="dealClosed"
  >
    <div class="dialog-content">
      <component
        :is="props.dom"
        v-bind="props.option"
        v-on="{
          ...props.events,
          close: closeDialog
        }"
      />
    </div>
    <template #header>
      <div class="dialog-header">
        <div class="dialog-title">
          <component
            v-if="headerDom"
            :is="props.headerDom"
            v-bind="props.headerOption"
            v-on="{
              ...props.headerEvents,
              close: closeDialog
            }"
          />
          <template v-else>{{ props.title }}</template>
        </div>
        <i-ep-close class="dialog-close" @click="closeDialog" />
      </div>
    </template>
    <template #footer v-if="showFooter">
      <component
        v-if="footerDom"
        :is="props.footerDom"
        v-bind="props.footerOption"
        v-on="{
          ...props.footerEvents,
          close: closeDialog
        }"
      />
      <div v-else class="dialog-footer">
        <el-button @click="closeDialog">取消</el-button>
        <el-button type="primary" @click="dealConfirm"> 确认 </el-button>
      </div>
    </template>
  </el-dialog>
</template>

<script setup>
defineOptions({
  name: 'DialogPlus'
})
const props = defineProps({
  title: {
    type: String,
    default: '标题'
  },
  width: {
    type: [Number, String],
    default: 500
  },
  modal: {
    type: Boolean,
    default: true
  },
  closeOnClickModal: {
    type: Boolean,
    default: true
  },
  dom: {
    type: Object,
    default: null
  },
  option: {
    type: Object,
    default: () => ({})
  },
  events: {
    type: Object,
    default: () => ({})
  },
  headerDom: {
    type: Object,
    default: null
  },
  headerOption: {
    type: Object,
    default: () => ({})
  },
  headerEvents: {
    type: Object,
    default: () => ({})
  },
  showFooter: {
    type: Boolean,
    default: false
  },
  footerDom: {
    type: Object,
    default: null
  },
  footerOption: {
    type: Object,
    default: () => ({})
  },
  footerEvents: {
    type: Object,
    default: () => ({})
  },
  immediately: {
    type: Boolean,
    default: true
  },
  close: {
    type: Function,
    default: null
  },
  closed: {
    type: Function,
    default: null
  },
  confirm: {
    type: Function,
    default: null
  }
})
const visible = ref(false)

onMounted(() => {
  visible.value = true
})

const closeDialog = () => {
  visible.value = false
}

const dealClose = () => {
  props.close && props.close()
}

const dealClosed = () => {
  props.closed && props.closed()
}

const dealConfirm = () => {
  if (!props.confirm) return
  if (props.immediately) {
    visible.value = false
    props.confirm()
  } else {
    props.confirm(() => {
      visible.value = false
    })
  }
}
</script>

<style lang="scss">
.dialog-plus {
  margin: auto !important;
  min-height: 500px;
  height: fit-content;
  background: #03151fca;
  border: 1px solid #2aa8ff;
  box-shadow: 0px 1px 8px 0px #2aa8ff, inset 0px 1px 5px 0px #2aa8ff;
  color: #fff;
  padding: 10px;
  .el-dialog__header {
    position: relative;
    box-sizing: border-box;
    padding: 0 10px;
    line-height: 50px;
    height: 50px;
    width: 100%;
    background: linear-gradient(
      45deg,
      rgb(2 103 153 / 82%) 0%,
      rgb(0 55 71 / 56%) 100%
    );
    border-radius: 2px;
    .dialog-header {
      width: 100%;
      height: 100%;
      position: relative;
      display: flex;
      flex-flow: row nowrap;
      justify-content: space-between;
      align-items: center;
      .dialog-title {
        font-size: 18px;
        text-align: left;
      }
      .dialog-close {
        font-size: 18px;
        cursor: pointer;
        transition: all 0.2s;
        &:hover {
          color: rgb(40, 205, 255);
        }
      }
    }
    .el-dialog__headerbtn {
      top: 50%;
      z-index: 10;
      transform: translateY(-50%);
      .el-dialog__close {
        color: #fff;
        font-size: 25px;
        transition: all 0.2s;
      }
      &:hover {
        .el-dialog__close {
          color: rgb(40, 205, 255);
        }
      }
    }
  }
  .el-dialog__body {
    height: 100%;
    padding: 0;
    color: #fff;
    .dialog-content {
      padding: 10px 0;
    }
  }
  .dialog-footer {
    display: flex;
    flex-flow: row nowrap;
    justify-content: center;
    align-items: center;
  }
}
</style>
实现函数式封装的方法文件 index.js
import { createApp } from 'vue'
import DialogPlus from './index.vue'
import { uniqueId } from 'lodash-es'

let instance = null
let instanceApp = null
let isExist = null
let isExistApp = null

const DialogBox = (data) => {
  if (!data.dom) {
    console.log('内容缺失')
    return false
  }
  if (data.coexist) {
    isExist = document.createElement('div')
    isExist.setAttribute('id', uniqueId('dialog-'))
    document.body.appendChild(isExist)
    isExistApp = createApp(DialogPlus, {
      ...data,
      closed: () => {
        isExistApp.unmount()
        isExist.remove()
        data.closed && data.closed()
      }
    })
    isExistApp.mount(isExist)
  } else {
    if (isExist) {
      isExistApp.unmount()
      isExist.remove()
    }
    if (instance) {
      instanceApp.unmount()
      instance.remove()
    } // 移除已有弹窗,确保只有一个弹窗显示
    instance = document.createElement('div')
    instance.setAttribute('id', uniqueId('dialog-'))
    document.body.appendChild(instance)
    instanceApp = createApp(DialogPlus, {
      ...data,
      closed: () => {
        instanceApp.unmount()
        instance.remove()
        data.closed && data.closed()
      }
    })
    instanceApp.mount(instance)
  }
}
export default DialogBox
使用方法
DialogBox({
    title: '123',
    dom: QqCode,
    option: {}
})

三、参数说明

参数 说明 备注

title

标题
 width 宽度
 modal 是否要蒙层

closeOnClickModal

点击蒙层关闭弹窗

dom

内容组件(VUE 组件)

option

传给内容组件的参数

events

绑定到内容组件的事件

headerDom

头部组件(VUE 组件) 不传默认显示 title

headerOption

传给头部组件的参数

headerEvents

绑定到头部组件的事件

showFooter

是否有底部

footerDom

底部组件(VUE 组件) 不传默认显示默认的底部组件

footerOption

传给底部组件的参数

footerEvents

绑定到底部组件的事件

immediately

默认底部组件点击确认按钮是否立即关闭弹窗

close

关闭弹窗参数

closed

彻底关闭弹窗参数

confirm

确认关闭弹窗参数

效果如下图

GitHub 加速计划 / eleme / element
15
3
下载
A Vue.js 2.0 UI Toolkit for Web
最近提交(Master分支:4 个月前 )
c345bb45 1 年前
a07f3a59 * Update transition.md * Update table.md * Update transition.md * Update table.md * Update transition.md * Update table.md * Update table.md * Update transition.md * Update popover.md 1 年前
Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐