Vue+Element实现服务调用el-dialog弹窗

2021-07-30 15:05:00 0 103

在使用Vue + Element 实现需求时常会遇到单个Vue文件内出现多个弹窗需求,一般会这样写

<!--*.vue-->
<template>
  <el-dialog :visible="visible1">弹框1</el-dialog>
  <el-dialog :visible="visible2">弹框2</el-dialog>
</template>

<script>
export default {
  return {
    visible1: false,
    visible2: false
  }
}
</script>

这样的写法在文件内容多的时候容易出现模板臃肿的问题,而且需要外部管理弹窗组件的开关状态visible

可以如何改进

借鉴了NgZoro的Modal组件的Service用法

可以考虑将el-dialog封装成Service来使用

<!--*.vue-->
<script>
// 笔者习惯将src设置alias为@
import DialogService from '@/service/dialog'
showDialog() {
  DialogService({ /* 弹框内需要用的data */})
}
</script>

如何实现

  • 首先需要定义DialogService的入口,内部通过Vue.extendI对组件模板进行继承

// src/service/dialog/index.js
import Vue from 'vue'

import dialogTemplate from './dialogTemplate.vue'
const DialogConstructor = Vue.extend(dialogTemplate)

import { isPlainObject } from 'lodash'

export default options => {
  let instance
  return function() {
    // 单例模式,惰性返回弹窗实例
    if (instance) {
      instance.visible = true
      return instance
    }

    instance = new DialogConstructor({
      data: isPlainObject(options) ? { ...options } : {}
    })

    instance.$mount()
    document.body.appendChild(instance.$el)
    instance.visible = true

    // 暴露实例方便后续的Ref操作
    return instance
  }
}
  • 接下来是dialogTemplate的实现,可根据实际业务进行调整,以下代码仅作为参考

<!--src/service/dialog/dialogTemplate.vue-->
<template>
  <el-dialog :title="title" :visible.sync="visible">
    <el-table :height="300" :data="tblData">
      <el-table-column
        props="prop1"
        label="col1"
        align="center"
      ></el-table-column>
      <el-table-column
        props="prop2"
        label="col2"
        align="center"
      ></el-table-column>
      <el-table-column
        Props="prop3"
        label="col3"
        align="center"
      ></el-table-column>
    </el-table>

    <div slot="footer" class="dialog-footer">
      <el-button v-show="submitVisible" size="small" @click="handleCancel">
        {{ cancelText }}
      </el-button>
      <el-button
        v-show="cancelVisible"
        size="small"
        type="primary"
        @click="handleSubmit"
      >
        {{ submitText }}
      </el-button>
    </div>
  </el-dialog>
</template>

<script>
import { isFunction } from 'lodash'

export default {
  data() {
    return {
      visible: false,
      title: '',
      labelWidth: '100px',
      content: null,

      tblData: [],

      /* footer */
      submitVisible: true,
      submitText: '确定',
      onSubmit: null,
      cancelVisible: true,
      cancelText: '取消',
      onCancel: null
    }
  },

  methods: {
    handleSubmit() {
      if (isFunction(this.onSubmit)) {
        this.onSubmit({ done: this._done })
      }
    },
    handleCancel() {
      if (isFunction(this.onCancel)) {
        this.onCancel({
          done: this._done
        })
      }
    },
    _done() {
      this.visible = false
    },
    _destory() {
      this.$destroy()
    }
  }
}
</script>

业务代码中使用

  • 渲染一个带表格的弹窗

<!--*.vue-->
<template>
  <el-button @click="showDialog">召唤表格</el-button>
</template>
<script>
import DialogService from '@/service/dialog'
export default {
  data() {
    return {
      dialogInstance: null
    }
  }
  methods: {
    showDialog() {
      this.dialogInstance = dialogService({
        title: '带表格的Dialog',
        onCancel: ({ done }) => done()
      })
    }
  }
}
</script>


随缘而来,乘风而去,山高海阔,自有我风采!
所属分类: Vue.js

发表留言