Dialog封装使用

该文章介绍了一个Vue扩展的Dialog组件,用于创建可复用的弹框。组件支持动态挂载、内容定制、事件绑定以及异步操作。通过安装和配置,可以在项目中实现灵活的对话框管理,包括控制上一次弹窗是否保留、自定义标题、内容和脚部组件等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

import Vue from 'vue'
import store from '../../store'
import Dialog from '@/views/components/dialog'
let instance
let isExist
const DialogBox = Vue.extend(Dialog)
Dialog.install = (data) => {
  if (!data.dom) {
    console.log('内容缺失')
    return false
  }
  if (data.coexist) { // 尚持弹框是否保留
    isExist = new DialogBox({
      data,
      store
    }).$mount()
    document.body.appendChild(isExist.$el)
    // 挂载至页面(#app)
    Vue.nextTick(() => {
      isExist.visible = true
      // show 和弹窗组件里的show对应,用于控制显隐
    })
  } else {
    if (isExist) {
      isExist.visible = false
      document.body.removeChild(isExist.$el)
      isExist = null
    }
    if (instance) {
      instance.visible = false
      document.body.removeChild(instance.$el)
      instance = null
    } // 移除已有弹窗,确保只有一个弹窗显示
    instance = new DialogBox({
      data,
      store
    }).$mount()
    document.body.appendChild(instance.$el)
    // 挂载至页面(#mes

    Vue.nextTick(() => {
      instance.visible = true
      // visible 和弹窗组件里的show对应,用于控制显隐
    })
  }
}
/**
 * 简单的使用方式
 * this.$dialogPopup({
      title: '测试', // 标题的内容
      dom: Test, // 组件是自己创建的
      width: '800px', // 弹框的宽度
      coexist: false, // 控制上一次弹窗是否保留,默认false
      option: {} 数据会传入自己的组件  通过props里定义option 组件里可以使用this.option 拿到
    })
  * 异步用法
    this.$dialogPopup({
      title: '测试',
      dom: Test,
      showFooter: true, // 展示脚部组件
      isSync: true, // 是否要异步关闭
      width: '800px',
      coexist: false, // 控制上一次弹窗是否保留,默认false
      option: data,
      ok: (success) => { // ok 回调的参数是一个函数 调用就可以在接口调用后关闭弹框
        setTimeout(() => {
          success()
        }, 5000)
      }
    })
  * 给内容绑定事件 让组件内的事件能推到组件调用里外头
    this.$dialogPopup({
      title: '测试',
      dom: Test,
      width: '800px',
      coexist: false, // 控制上一次弹窗是否保留,默认false
      option: data,
      events: 'content', // 给传递到组件的自定义内容组件绑定content 事件,组件内使用this.$emit('content', data)调用  多个请用数组
      content: (data) => { // 定义同名的函数对象其中可以拿到组件对外外传输的值
        // data 就是要传递的参数
      },
      clickContent: (data)=> {
        // 组件默认绑定了click事件 自定义内容组件内使用this.$emit('click', data)调用
      }
    })
  * 脚步自定义组件和异步情况下自定义组件的用法
    this.$dialogPopup({
      title: '测试',
      dom: Test,
      showFooter: true, // 展示脚部组件
      footerDom: TestFooter, // 自定义脚部组件
      footerEvents: 'footer', // 自定义脚部事件 多个请用数组
      footer: (data, success) => { // 需要定义同名的事件名称  success 是异步情况下第二个参数
        setTimeout(() => {
          success()
        }, 3000)
      },
      isSync: true, // 开启异步
      width: '800px',
      coexist: false, // 控制上一次弹窗是否保留,默认false
      option: data
    })
 */
export default Dialog

dialog

<template>
  <common
    ref="dialogInstance"
    :visible.sync="visible"
    :width="popupWidth"
    center
    :show-close="needClose"
    @close="closeDialog"
    @closed="closed"
    @open="openDialog"
  >
    <template #title>
      <span v-if="title" class="common-dialog-title">{{ title }}</span>
      <component
        :is="titleDom"
        v-if="titleDom"
        :option.sync="titleOption"
        v-on="dealTitleEvent"
      />
    </template>
    <component
      :is="dom"
      :option.sync="option"
      v-on="dealEvent"
    />
    <template v-if="showFooter" #footer>
      <component
        :is="footerDom"
        v-if="footerDom"
        :option.sync="footerOption"
        v-on="dealFooterEvent"
      />
      <div v-else class="common-dialog-bottom">
        <el-button @click="cancelDialog">{{ cancelText }}</el-button>
        <el-button type="primary" :loading="loading" @click="okDialog">{{ okText }}</el-button>
      </div>
    </template>
  </common>
</template>
<script>
import Common from '@/views/components/dialog/common.vue'
export default {
  name: 'DialogAll',
  components: {
    Common
  },
  data() {
    return {
      visible: false,
      title: '',
      width: '550px',
      showClose: true,
      cancelText: '取消',
      okText: '确认',
      loading: false,
      showFooter: false,
      isSync: false,
      footerDom: null,
      titleDom: null,
      events: [],
      footerEvents: [],
      titleEvents: [],
      option: null,
      titleOption: null,
      footerOption: null,
      hasClosed: false
    }
  },
  computed: {
    popupWidth() {
      return this.width || '550px'
    },
    needClose() {
      return this.showClose || true
    },
    dealEvent() {
      let events = this.events
      const newEvent = {}
      if (Object.prototype.toString.call(events) === '[object String]') {
        events = [events]
      }
      events.forEach(item => {
        newEvent[item] = (data) => {
          this[item] && this[item](data, () => {
            this.visible = false
          })
        }
      })
      const eventObject = {
        'click': this.clickContent,
        ...newEvent
      }
      return eventObject
    },
    dealTitleEvent() {
      let events = this.titleEvents
      const newEvent = {}
      if (Object.prototype.toString.call(events) === '[object String]') {
        events = [events]
      }
      events.forEach(item => {
        newEvent[item] = (data) => {
          this[item] && this[item](data, () => {
            this.visible = false
          })
        }
      })
      const eventObject = {
        'close': this.closeDialog,
        ...newEvent
      }
      return eventObject
    },
    dealFooterEvent() {
      let footerEvents = this.footerEvents
      const newEvent = {}
      if (Object.prototype.toString.call(footerEvents) === '[object String]') {
        footerEvents = [footerEvents]
      }
      footerEvents.forEach(item => {
        newEvent[item] = (data) => {
          if (this[item]) {
            if (this.isSync) {
              this.loading = true
              this[item](data, () => {
                this.loading = true
                this.visible = false
              })
            } else {
              this.visible = false
              this[item](data)
            }
          }
        }
      })
      const eventObject = {
        'click': this.clickFooter,
        ...newEvent
      }
      return eventObject
    }
  },
  mounted() {
    this.hasClosed = false
  },
  methods: {
    closeDialog() {
      this.visible = false
      if (this.close) {
        this.close()
      }
    },
    clickContent() {
      if (this.clickContent) {
        this.clickContent()
      }
    },
    clickFooter() {
      if (this.clickFooter) {
        this.clickFooter()
      }
    },
    openDialog() {
      if (this.open) {
        this.open()
      }
    },
    cancelDialog() {
      // 取消
      this.visible = false
      if (this.cancel) {
        this.cancel()
      }
    },
    okDialog() {
      // 确认
      if (!this.isSync) {
        this.visible = false
      }
      if (this.ok) {
        if (this.isSync) {
          this.loading = true
          this.ok(() => {
            this.loading = true
            this.visible = false
          })
        } else {
          this.ok()
        }
      }
    },
    closed() {
      this.hasClosed = true
    }
  }
}
</script>
<style lang="scss">
.common-dialog {
  .el-dialog {
    min-height: 500px;
    background: #03151F;
    border: 1px solid #2AA8FF;
    box-shadow: 0px 1px 18px 0px #2AA8FF,inset 0px 1px 10px 0px #2AA8FF;
    color: #fff;
    padding: 10px;
    .el-dialog__header {
      position: relative;
      box-sizing: border-box;
      padding: 0 14px;
      line-height: 60px;
      height: 60px;
      width: 100%;
      background: url(../../../assets/images/alert-bg.png) no-repeat center bottom;
      background-size: calc(100% + 20px) calc(100% + 20px);
      display: flex;
      flex-flow: row nowrap;
      justify-content: space-between;
      align-items: center;
      &::before {
        width: 100%;
        content: "";
        height: 6px;
        position: absolute;
        left: -11px;
        top: -17px;
        background: url(../../../assets/images/alert-bg.png) no-repeat left top;
        background-size: auto, 8px;
      }
      .common-dialog-title {
        font-size: 16px;
        text-align: left;
        text-indent: 18px;
        position: relative;
        &::before {
          content: "";
          width: 4px;
          height: 14px;
          position: absolute;
          left: 0;
          top: 50%;
          transform: translateY(-50%);
          background: #fff;
        }
      }
      .el-dialog__headerbtn {
        top: 50%;
        transform: translateY(-50%);
        .el-dialog__close {
          color: #fff;
          transition: all 0.2s;
        }
        &:hover {
          .el-dialog__close {
            color: #2AA8FF;
          }
        }
      }
    }
    .el-dialog__body {
      height: 100%;
      padding: 0;
      color: #fff;
    }
  }
}
</style>

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值