Demo:基于elementplus的弹窗嵌套表单进行二次封装

基于elementplus的弹窗嵌套表单进行二次封装

所见即所得:简单封装方便工作
Demo:基于elementplus的弹窗嵌套表单进行二次封装_第1张图片
Demo:基于elementplus的弹窗嵌套表单进行二次封装_第2张图片

ProForm.vue代码:

<!--
 * @Author: 忆往昔
 * @LastEditTime: 2024-01-6 14:36:00
 * @email: 15871856064@163.com
-->
<template>
  <div class="penk-form-container">
    <el-dialog
      v-model="visible1"
      :fullscreen="props.fullscreen"
      :draggable="props.draggable"
      :title="props.title"
      :width="props.width || '50%'"
    >
      <el-form
        ref="ruleFormRef"
        label-width="120px"
        size="large"
        :model="form"
        :rules="props.formConfig.rules"
      >
        <template v-for="item in props.formConfig.formItemConfig" :key="item.prop">
          <el-form-item
            :label="item.label + ':'"
            :style="{ display: item.hidden == true ? 'none' : '' }"
            :prop="item.prop"
          >
            <!-- 输入框 -->
            <el-input
              v-if="item.type == 'input'"
              v-model="form[item.prop]"
              :placeholder="item.placeholder || ''"
              :clearable="item.clearable"
              :disabled="item.disabled"
              :type="item.inputType"
              :row="item.row"
              :style="{ width: item.width + 'px' }"
            />

            <!-- 下拉框 -->
            <el-select
              v-else-if="item.type == 'select'"
              v-model="form[item.prop]"
              :placeholder="item.placeholder"
              :clearable="item.clearable"
              :disabled="item.disabled"
              :style="{ width: item.width + 'px' }"
            >
              <el-option
                v-for="option in item.data"
                :key="option.value"
                :label="option.label"
                :value="option.value"
                :disabled="option.disabled"
              />
            </el-select>

            <!-- 多选框 -->
            <el-checkbox-group
              v-else-if="item.type == 'checkbox'"
              v-model="form[item.prop]"
              :placeholder="item.placeholder"
              :clearable="item.clearable"
              :disabled="item.disabled"
              :style="{ width: item.width + 'px' }"
            >
              <el-checkbox
                v-for="option in item.data"
                :key="option.value"
                :label="option.value"
                :disabled="option.disabled"
                >{{ option.label }}</el-checkbox
              >
            </el-checkbox-group>

            <!-- 单选框 -->
            <el-radio-group
              v-else-if="item.type == 'radio'"
              v-model="form[item.prop]"
              :placeholder="item.placeholder"
              :clearable="item.clearable"
              :disabled="item.disabled"
              :style="{ width: item.width + 'px' }"
            >
              <el-radio
                :label="option.value"
                size="large"
                v-for="option in item.data"
                :key="option.label"
                >{{ option.label }}</el-radio
              >
            </el-radio-group>
          </el-form-item>
        </template>
      </el-form>
      <template #footer>
        <span class="dialog-footer">
          <el-button @click="visible1 = false">取消</el-button>
          <el-button type="primary" @click="confirm(ruleFormRef)"> 确定 </el-button>
        </span>
      </template>
    </el-dialog>
  </div>
</template>

<script setup>
import { ref, reactive, watch, defineEmits, onMounted } from 'vue'
import { ElMessage } from 'element-plus'

let form = reactive({})
const visible1 = ref(true)
const ruleFormRef = ref()

const props = defineProps({
  formData: {
    type: Object,
    default: () => {}
  },
  formConfig: {
    type: Object,
    default: () => {}
  },
  visible: {
    type: Boolean,
    default: false
  },
  width: {
    type: String,
    default: '520px'
  },
  title: {
    type: String,
    default: '新增'
  },
  fullscreen: {
    type: Boolean,
    default: false
  },
  draggable: {
    type: Boolean,
    default: false
  },
  'append-to-body': {
    type: Boolean,
    default: false
  },
  'close-on-click-modal': {
    type: Boolean,
    default: false
  }
})

// 生成事件对象,数组中就是对象名
const emit = defineEmits(['update:visible', 'confirm'])

// 监听父组件的visible,用来简介控制el-dialog的弹框开关,一般是用于开
watch(
  () => props.visible,
  (n, o) => {
    visible1.value = n
  }
)
// 监听el-dialog显示状态,再通过@update:visible 通知父组件,一般是用于关
watch(visible1, (n, o) => {
  emit('update:visible', n)
})

// 每次触发,就证明父组件点了修改或者添加的按钮,传递了一个新的formData
// 需要重新给form 赋值,并且,对该表单项进行重置
watch(
  () => props.formData,
  (n, o) => {
    resetForm(ruleFormRef.value)
    form = reactive(n)
  }
)

// 确定按钮触发
const confirm = async (formEl) => {
  if (!formEl) return
  await formEl.validate((valid, fields) => {
    if (valid) {
      emit('confirm', form)
    } else {
      console.log('error submit!', fields)
      ElMessage({
        showClose: true,
        message: '请完善表单信息!',
        type: 'error'
      })
    }
  })
}

// 重置表单
const resetForm = (formEl) => {
  if (!formEl) return
  formEl.resetFields()
}

onMounted(() => {
  console.log(props.formConfig);
  // 初始化 配置弹框是否可显示
  visible1.value = props.visible
  // 初始化 配置formData
  props.formConfig.formItemConfig.map((item) => {
    form[item.prop] = ''
  })
})
</script>

<style lang="scss" scoped>
.penk-form-container {
  .el-table-border {
    border: 1px #eee solid;
  }
  :deep(.el-dialog__body) {
    border-top: 1px solid #eee;
  }
}
</style>
组件使用示例:
<template>
  <MyTable
    :tableData="tableData"
    :columns="columns"
    :total="total"
    :currentPage="listQuery.pageNo"
    :pageSize="listQuery.pageSize"
    @changeTableData="changeTableData"
  >
    <!-- <template #check="{ slotProps }">
      <el-tag class="ml-2" :type="slotProps.check ? 'success' : 'danger'">
        {{ checkFilter(slotProps.check) }}
      </el-tag>
    </template> -->
    <template #operator="{ slotProps }">
      <el-button type="primary" @click="setData('edit', slotProps)">编辑</el-button>
      <el-button type="primary" @click="handleAddItem">新增</el-button>
      <el-button type="primary" @click="handleEditItem(slotProps)">修改</el-button>
      <el-button type="danger" @click="handleDel(slotProps)">删除</el-button>
    </template>
  </MyTable>
  <!-- 表单弹框 -->
  <ProForm
    :title="title"
    :formConfig="formConfig"
    :formData="formData"
    v-model:visible="visible"
    append-to-body
    @confirm="saveItem"
  />
</template>

<script setup>
import { ref, onMounted } from 'vue'
import MyTable from '@/components/MyTable/MyTable.vue'
import ProForm from '@/components/ProForm/ProForm.vue'

let listQuery = ref({
  pageNo: 1,
  pageSize: 10
})
const tableData = ref([
  { number: '001', numberplate: '京A12345', date: '2022-01-01', check: '正常', operator: '编辑' },
  { number: '002', numberplate: '京B67890', date: '2022-02-01', check: '正常', operator: '编辑' },
  { number: '003', numberplate: '京C24680', date: '2022-03-01', check: '故障', operator: '编辑' },
  { number: '004', numberplate: '京D13579', date: '2022-04-01', check: '正常', operator: '编辑' },
  { number: '005', numberplate: '京E97531', date: '2022-05-01', check: '正常', operator: '编辑' }
])
let total = ref(0)

/**
 * prop:数据项列名
 * label:列名展示名
 * fixed:固定列 true/right/left
 * width:列宽
 * show-overflow-tooltip
 * type:对应列的类型 selection / index / expand
 * sortable:true/false
 * selectable:Function
 * formatter:格式化内容 function(row, column, cellValue, index)
 **/
let columns = ref([
  { prop: 'number', label: '车牌自编号' },
  { prop: 'numberplate', label: '车牌号' },
  { prop: 'date', label: '出厂日期' },
  { prop: 'check', label: '车辆状态' },
  { prop: 'operator', label: '操作', fixed: 'right' }
])

onMounted(() => {})

const changeTableData = (pageNum, pageSize) => {
  listQuery.value.pageNo = pageNum
  listQuery.value.pageSize = pageSize
  getCarList()
}

const visible = ref(false) // 控制弹窗开关
const title = ref('') // 弹窗标题
const formData = ref({}) // 表单数据

// 表单配置项
const formConfig = {
  formItemConfig: [
    {
      label: '类型名',
      prop: 'typeName',
      type: 'input'
    },
    {
      label: '父级类型名',
      prop: 'parentId',
      type: 'select',
      data: []
    }
  ],
  rules: {
    typeName: [
      {
        required: true,
        message: '请输入类型名',
        trigger: 'blur'
      }
    ]
  }
}

// 添加数据按钮
const handleAddItem = () => {
  visible.value = true
  title.value = '新增'
  formData.value = {}
}

// 修改数据按钮
const handleEditItem = (row) => {
  visible.value = true
  title.value = '修改'
  formData.value = row
}

// 表单提交
const saveItem = (form) => {
  console.log('提交', form)
}
</script>

你可能感兴趣的:(vue.js,elementui,前端)