【设计模式篇】策略模式(通过案例讲解分析)

232 阅读1分钟

技术选型

  • vue2
  • element ui => el-dialog

实现功能

封装一个导入与下载模板的dialog公共组件

image.png

策略使用目的

通过每一次引用创建一个相关配置文件进行配置管理,达到结构统一管理,拆分不同模块管理。 解决如下代码问题:

  1. 在封装的组件中每一次引用都加入几行相关配置的代码导致页面代码越来越臃肿
  2. 每一次使用时都从父组件中传入过多相关配置资料

文件结构

image.png

组件的引用

<ImportDialog ref="import" :from="'ThirdPartyToolsManagementAccount'" @childFilter="handleFilter()" />
import ImportDialog from '@/components/ImportDialog'
export default {
    components: {  ImportDialog },
}

ref 注册组件引用信息

from 指定引用来源

childFilter 回调导入成功刷新页面

组件绘制与相关功能文件(index.vue)

关键代码

const data = strategy(newV) // 根据父组件传入来源调用不同策略配置

<template>
  <el-dialog
    class="import-dialog"
    :visible.sync="importVisible"
    :title="title"
    width="350px"
    :close-on-click-modal="false"
    :close-on-press-escape="false"
    :before-close="handleImportClose"
  >
    <el-form>
      <el-form-item label="导入文件">
        <el-upload
          ref="upload"
          :action="uploadUrl"
          :headers="myHeaders"
          :auto-upload="false"
          :limit="1"
          :before-upload="handleBeforeUpload"
          :on-exceed="handleExceed"
          :on-error="handleError"
          :on-success="handleSuccess"
        >
          <el-button
            size="small"
            type="primary"
            plain
            icon="el-icon-download"
          >选择文件</el-button>
          <div slot="tip" class="upload-tip">注意:仅支持 xlsx文件</div>
        </el-upload>
      </el-form-item>
      <el-form-item label="点击下载">
        <el-button type="text" class="download-button" @click="handleDownloadTemplate">模板</el-button>
      </el-form-item>
    </el-form>
    <span slot="footer" class="dialog-footer">
      <el-button @click="handleImportClose">取 消</el-button>
      <el-button v-loading="importLoading" type="primary" @click="handleImportConfirmed">确 定</el-button>
    </span>
  </el-dialog>
</template>

<script>
import { downloadByATag } from '@/utils'
import { getToken } from '@/utils/auth'
import strategy from './strategy'
export default {
  name: 'ImportDialog',
  props: {
    // 配置类型
    from: {
      type: String,
      default: ''
    }
  },
  data() {
    return {
      myHeaders: { Authorization: `Bearer ${getToken()}` },
      importVisible: false,
      importLoading: false,
      title: '', // dialog标题
      uploadUrl: '', // 上传url
      tempRequest: null // 模板url
    }
  },
  watch: {
    from: {
      handler(newV) {
        if (newV) {
          const data = strategy(newV) // 根据父组件传入来源调用不同策略配置
          this.title = data.title
          this.uploadUrl = data.uploadUrl
          this.tempRequest = data.tempRequest
        }
      },
      immediate: true
    }
  },
  methods: {
    // 导入弹窗展示
    show() {
      this.importVisible = true
    },
    // 导入窗口关闭
    handleImportClose() {
      this.importVisible = false
      this.$refs.upload.clearFiles()
    },
    // 导入确认
    handleImportConfirmed() {
      if (this.$refs.upload.$refs['upload-inner'].fileList.length === 0) {
        this.$message.error('请导入文件')
        return
      }
      this.uploadLoading = true
      this.$refs.upload.submit()
    },
    // 上传之前
    handleBeforeUpload(file) {
      const FileExt = file.name.replace(/.+\./, '')
      if (['xlsx'].indexOf(FileExt.toLowerCase()) === -1) {
        this.$message.error('文件格式有误,请重新上传')
        return false
      }
      if (file.size > 1024 * 1024 * 10) {
        this.$message.error('文件不能超过10MB')
        return false
      }
    },
    // 上传限制条件
    handleExceed(files, fileList) {
      this.$message.warning(`当前限制选择 1 个文件,本次选择了 ${files.length} 个文件,共选择了 ${files.length + fileList.length} 个文件`)
    },
    // 上传成功
    handleSuccess({ code, msg, data }, file, fileList) {
      if (code === 1) {
        this.handleImportClose()
        this.$emit('childFilter')
        if (!Array.isArray(data)) {
          downloadByATag(data.url, data.name)
          this.$message.error(data.msg)
        } else {
          this.$message.success('上传成功')
        }
      } else {
        this.$message.error('上传失败')
      }
      this.importLoading = false
    },
    // 上传错误
    handleError() {
      this.$message.error('上传失败')
    },
    // 下载模板
    handleDownloadTemplate() {
      this.tempRequest().then(res => {
        if (res?.code === 1) {
          this.$message.success(res.msg)
        } else {
          this.$message.error(res.msg)
        }
      })
    }
  }
}
</script>

<style scoped>
.upload-tip{
  color: red;
}
.download-button {
  padding: 0 !important;
  font-size: 14px !important;
}
.import-dialog .el-form-item {
  margin-bottom: 0px;
}
</style>

策略入口文件(strategy.js)

根据不同的来源实例化不同的策略配置信息

import ThirdPartyToolsManagementBasic from './options/ThirdPartyToolsManagementBasic'
import ThirdPartyToolsManagementAccount from './options/ThirdPartyToolsManagementAccount'
/**
 * 返回导入文件配置信息
 * @param {String} from 配置来源
 * @returns Object
 */
function strategy(from) {
  let result = {}
  switch (from) {
    case 'ThirdPartyToolsManagementBasic':
      result = new ThirdPartyToolsManagementBasic()
      break
    case 'ThirdPartyToolsManagementAccount':
      result = new ThirdPartyToolsManagementAccount()
      break
  }
  return result
}
export default strategy

策略配置文件(ThirdPartyToolsManagementAccount.js)

import { accountDataModelApi } from '@/api/accountInfo'
/**
 * 账号 - 账号信息 - 第三方支付工具 - 账号及店铺资料
 */
class ThirdPartyToolsManagementAccount {
  constructor() {
    this.title = '批量导入账号店铺资料'
    this.uploadUrl = '/api/v1/admin/account/third-party-tool/account-shop-import'
    this.tempRequest = accountDataModelApi
  }
}

export default ThirdPartyToolsManagementAccount