一、封装原因

因为我在开发中不想使用 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
54.06 K
14.63 K
下载
A Vue.js 2.0 UI Toolkit for Web
最近提交(Master分支:3 个月前 )
c345bb45 7 个月前
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 7 个月前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐