• element-ui组件库table组件优化封装/element-ui组件库form组件优化封装


    一个后端管理系统,有大量的表格,表单,所以基于element ui的el-table,el-form里面的表单元素进行二次封装是很有必要的,也可以保证每个页面的统一
    接下来的两个组件由我和另外两个同事在使用中不断优化,目前比较稳定
    1.目录

    2.案例

    下面两个文件,是我如何使用组件完成基本的table页面

    common-table.vue组件

    <template>
      <div style="padding:30px">
        <!-- 3将组件写入到页面 -->
         <!-- 7如果由额外的参数也可以用extraFormData传入 -->
        <commonTable 
          border
          :column="versionManageColumn"
          :pagination="versionManagePagi" 
          :data-url="verifyManageUrl"
          :filter-btn="filterBtn"
          :extra-form-data="extraFormData" 
        >
          <template #operate>
             <el-button type="info">查看信息</el-button>
          </template>
          <template #packageName="{ scope }">
            <div style="color:red">{{scope.row.packageName}}(嘿嘿嘿,我要变红)</div>
          </template>
        </commonTable>
      </div>
    </template>
    <script>
    // 4传入参数到组件里面,column必传,data-url必传,pagination必传,如果不需要分页,传versionManagePagi: {hide: true}
    // 凡是定义的常量,都可以重新写一个js,引入进来使用,不然页面会很多常量,例如这里的versionManageColumn
    import { versionManageColumn, filterBtn } from './commonTableOption'
    // 1引入commonTable组件
    import commonTable from '@/components/CommonTable'
    export default {
      components: {
        commonTable, // 2注入组件
      },
      data() {
        return {
          versionManagePagi: { 
            pageSize: 20,
            currentPage: 1,
            total: 0,
          },
          versionManageColumn,
          verifyManageUrl: 'http://47.110.148.106:3030/mock/11/version/manage',
          filterBtn,
          extraFormData: {
            name: '花花',
          }
        }
      }
    }
    </script>
    

    commonTableOption.js主要是定义常量

    export const versionManageColumn = [
      {
        prop: 'versionName',
        label: '版本名称',
        filterOption: {
          type: 'input',
          label: '版本名称',
          prop: 'versionName',
          placeholder: '请输入',
          formChildWidth: '250px',
        },
      },
      {
        prop: 'packageName',
        label: '包名称',
      },
      {
        prop: 'versionDesc',
        label: '版本说明',
      },
      // 5比较强大的地方在于能够直接配置进行去搜索
      {
        prop: 'isForceUpdate',
        label: '是否强制更新',
        filterOption: {
          type: 'select',
          label: '是否强制更新',
          prop: 'isForceUpdate',
          placeholder: '请选择',
          disabled: false,
          multiple: false,
          filterable: true,
          clearable: false,
          selectData: [
            { label: '是', value: 0 }, { label: '否', value: 1 },
          ],
          formChildWidth: '250px',
        },
      },
      {
        prop: 'installEquipmentNum',
        label: '安装设备数',
      },
      {
        prop: 'proportion',
        label: '占比',
      },
      {
        prop: 'versionPublishTime',
        label: '版本发布时间',
      },
      {
        prop: 'operate',
        label: '操作',
      },
    ]
    // 6按钮操作也可以进行配置
    export const filterBtn = { type: 'button', children:
      [
        { type: 'search' },
        { type: 'reset' },
        {
          type: 'export',
          apiUrl: 'xxx',
          isLimit: true,
          fileName: '咕咕咕',
        },
      ],
    }
    

    3.组件代码 (结合目录哦)
    文件1 CommonTable/index.vue

    <template>
      <div>
        <el-form
          ref="form"
          class="form-flex"
          :label-width="formLabelWidth"
          :disabled="formDisabled"
          :model="formData"
          :rules="formRules"
          :inline="inline"
        >
          <el-form-item
            v-for="(formItem, itemIndex) in formFields"
            v-show="!formItem.hidden"
            :key="itemIndex"
            :prop="formItem.prop"
            :label-width="formItem.type === 'button' ? '0px': formItem.labelWidth"
            :label="formItem.label"
            :class="formItem.class"
          >
            <div
              v-if="formItem.type === 'extraMention'"
              :class="formItem.class"
            >{{ formItem.prop }}</div>
            <!-- 输入框或者textarea-->
            <el-input
              v-if="formItem.type === 'input'"
              v-model="formData[formItem.prop]"
              :placeholder="formItem.placeholder"
              :disabled="formItem.disabled"
              :clearable="formItem.clearable"
              :style="{ formItem.formChildWidth}"
              :maxlength="formItem.maxlength"
            />
            <el-input
              v-if="formItem.type === 'textarea'"
              v-model="formData[formItem.prop]"
              :placeholder="formItem.placeholder"
              type="textarea"
              :disabled="formItem.disabled"
              :style="{ formItem.formChildWidth}"
              :clearable="formItem.clearable"
              :maxlength="formItem.maxlength"
              :autosize="formItem.autoSize"
              :rows="formItem.rows || 2"
            />
            <el-input
              v-if="formItem.type === 'number'"
              v-model.number="formData[formItem.prop]"
              :placeholder="formItem.placeholder"
              type="number"
              :disabled="formItem.disabled"
              :style="{ formItem.formChildWidth}"
              :clearable="formItem.clearable"
              :min="formItem.min"
              :max="formItem.max"
            />
            <!-- 下拉框 -->
            <el-select
              v-if="formItem.type === 'select'"
              v-model="formData[formItem.prop]"
              :placeholder="formItem.placeholder"
              :disabled="formItem.disabled"
              :style="{ formItem.formChildWidth}"
              :multiple="formItem.multiple"
              :filterable="formItem.filterable"
              :clearable="formItem.clearable"
              @change="val => selectChange(val, formItem.prop)"
            >
              <el-option
                v-for="(selectItem, index) in formItem.selectData"
                :key="index"
                :label="selectItem.label"
                :value="selectItem.value"
              />
            </el-select>
            <!-- 时间控件 -->
            <el-date-picker
              v-if="formItem.type === 'datePicker'"
              v-model="formData[formItem.prop]"
              :type="formItem.dateType"
              :value-format="formItem.valueFormat || 'yyyy-MM-dd HH:mm:ss'"
              :format="formItem.format || 'yyyy-MM-dd HH:mm:ss'"
              :placeholder="formItem.placeholder"
              :disabled="formItem.disabled"
              :style="{ formItem.formChildWidth}"
              range-separator="至"
              :start-placeholder="formItem.placeholderStart"
              :end-placeholder="formItem.placeholderEnd"
              :class="formItem.class"
              :picker-options="formItem.pickerOptions"
            />
            <el-time-picker
              v-if="formItem.type === 'timePicker'"
              v-model="formData[formItem.prop]"
              value-format="HH:mm:ss"
              :placeholder="formItem.placeholder"
              :disabled="formItem.disabled"
              :style="{ formItem.formChildWidth}"
            />
            <el-date-picker
              v-if="formItem.type === 'dateTimePiker'"
              v-model="formData[formItem.prop]"
              :value-format="formItem.valueFormat || 'yyyy-MM-dd HH:mm:ss'"
              :format="formItem.format || 'yyyy-MM-dd HH:mm:ss'"
              type="datetime"
              :disabled="formItem.disabled"
              :placeholder="formItem.placeholder"
              :style="{ formItem.formChildWidth}"
            />
            <div v-if="formItem.type === 'dateZones'">
              <div v-for="(dateItem, dateIndex) in formItem.children" :key="dateIndex" class="date-zone">
                <el-form-item :prop="dateItem.prop">
                  <el-date-picker
                    v-if="dateItem.type === 'dataPicker'"
                    v-model="formData[dateItem.prop]"
                    value-format="yyyy-MM-dd"
                    type="date"
                    :placeholder="dateItem.placeholder"
                    :disabled="dateItem.disabled"
                    :style="{ dateItem.formChildWidth}"
                  />
                </el-form-item> <span v-if="dateIndex===0 && inline">至</span>
              </div>
            </div>
            <!-- switch切换 -->
            <el-switch
              v-if="formItem.type === 'switch'"
              v-model="formData[formItem.prop]"
              :disabled="formItem.disabled"
              :style="{ formItem.formChildWidth}"
              @change="val => switchChange(val, formItem.prop)"
            />
            <!-- checkbox -->
            <el-checkbox-group
              v-if="formItem.type === 'checkbox'"
              v-model="formData[formItem.prop]"
              :disabled="formItem.disabled"
              :style="{ formItem.formChildWidth}"
              @change="val => checkChange(val, formItem.prop)"
            >
              <el-checkbox
                v-for="(selectItem, index) in formItem.checkData"
                :key="index"
                :label="selectItem"
                name="type"
              />
            </el-checkbox-group>
            <!-- radio -->
            <el-radio-group
              v-if="formItem.type === 'radio'"
              v-model="formData[formItem.prop]"
              :disabled="formItem.disabled || false"
              :fill="formItem.fill || '#409EFF'"
              :text-color="formItem.textColor || '#ffffff'"
              :style="{ formItem.formChildWidth}"
              @change="val => checkChange(val, formItem.prop)"
            >
              <el-radio
                v-for="(radioItem, index) in formItem.radioData"
                :key="index"
                :label="radioItem.label"
                :disabled="radioItem.disabled || false"
                :border="radioItem.border || false"
                :size="radioItem.size"
                :name="radioItem.primevalName || ''"
              >{{ radioItem.name || radioItem.label }}</el-radio>
            </el-radio-group>
            <!-- 普通标签 -->
            <div v-if="formItem.type === 'normalTag'" class="tag-fields">
    
              <el-tag
                v-for="(tagItem) in formItem.tagData"
                :key="tagItem.id"
                :closable="tagItem.closable || formItem.closable"
                :disable-transitions="tagItem.transitions"
                :size="tagItem.size"
                :effect="tagItem.effect"
                :type="tagItem.type"
                @close="tagClose(tagItem.id,formItem.tagData)"
              >{{ tagItem.name }}
              </el-tag>
              <el-tag v-if="!!(Object.keys(formItem.addTagBtnOption).length)" :size="formItem.addTagBtnOption.size" class="add-tag-btn" @click="addTag(formItem.tagData)">{{ formItem.addTagBtnOption.name }}</el-tag>
            </div>
            <!-- 图片标签 -->
            <div v-if="formItem.type === 'imageTag'" class="image-tag-fields-box">
              <div v-for="tagItem in formItem.tagData" :key="tagItem.id" class="img-item-wrap">
                <i v-if="!formItem.noDeleteIcon" class="el-icon-error delete-icon" @click="imageTagClose(tagItem.id,formItem.tagData)" />
                <div class="img-item" @click="uploadPreview(tagItem)"><img :src="tagItem.url" alt="暂无图片"></div>
                <span>{{ tagItem.name }}</span>
              </div>
              <div class="img-item-wrap add-item" @click="addImgTag(formItem.tagData)">
                <div class="img-item"> <span><i class="el-icon-plus add-btn" /></span></div>
              </div>
            </div>
            <!-- 自定义表单域 -->
            <div v-if="formItem.type === 'customSlot'" class="custom-slot-fields">
              <slot :name="`${formItem.prop}Slot`" />
            </div>
            <!--  upload 上传  -->
            <el-upload
              v-if="formItem.type === 'upload'"
              :ref="'uploadref'"
              :action="formItem.action"
              :headers="formItem.header"
              :multiple="formItem.multiple"
              :data="formItem.data"
              :name="formItem.name || 'file'"
              :with-credentials="formItem.withCredentials || false"
              :show-file-list="formItem.showFileList || true"
              :drag="formItem.drag || false"
              :accept="formItem.accept"
              :on-preview="formItem.onPreview || uploadPreview"
              :on-remove="formItem.onRemove"
              :on-success="formItem.onSuccess"
              :on-error="formItem.onError"
              :on-progress="formItem.onProgress"
              :on-change="formItem.onChange"
              :before-upload="formItem.beforeUplaod"
              :before-remove="formItem.beforeRemove"
              :list-type="formItem.listType || 'picture-card'"
              :auto-upload="formItem.autoUpload || true"
              :file-list="formData[formItem.prop] || []"
              :http-request="formItem.httpRequest"
              :disabled="formItem.disabled || false"
              :limit="formItem.limit"
              :on-exceed="formItem.onExceed"
            >
              <i class="el-icon-plus" />
              <!-- upload 插槽 -->
              <template #trigger>
                <slot :name="`${formItem.prop}Trigger`" />
              </template>
              <template #tip>
                <slot :name="`${formItem.prop}Tip`" />
              </template>
            </el-upload>
            <!-- 按钮 -->
            <div v-if="formItem.type === 'button'" class="button-flex">
              <div v-for="(buttonItem, buttonIndex) in formItem.children" :key="buttonIndex" class="button-child-flex">
                <button-comp
                  :button-item="buttonItem"
                  v-on="{
                    reset, confirm, cancel, search, exportFile
                  }"
                />
              </div>
            </div>
          </el-form-item>
        </el-form>
    
        <!-- 图片预览弹窗 -->
        <el-dialog :visible.sync="uploadDialogVisible" top="7vh" :append-to-body="true">
          <img width="100%" :src="dialogImageUrl" alt="">
        </el-dialog>
      </div>
    </template>
    
    <script>
    import buttonComp from './buttonComp'
    export default {
      components: {
        buttonComp,
      },
      props: {
        formLabelWidth: { // 表单label宽度
          type: String,
          default: '200px',
        },
        formData: { // 表单数据
          type: Object,
          default: null,
        },
        formDisabled: { // 是否禁用表单
          type: Boolean,
          default: false,
        },
        formRules: { // 表单验证规则
          type: Object,
          default: null,
        },
        // 设置json数据
        formFields: { // 表单项配置信息
          type: Array,
          default: () => [],
        },
        inline: { // 表单横向竖向控制
          type: Boolean,
          default: false,
        },
      },
      data() {
        return {
          dialogImageUrl: '',
          uploadDialogVisible: false,
        }
      },
      methods: {
        reset() {
          this.$refs['form'].resetFields()
          this.$emit('reset')
        },
        exportFile(buttonItem) {
          this.$emit('exportFile', buttonItem)
        },
        cancel() {
          this.$emit('cancel')
        },
        confirm() {
          this.$refs['form'].validate((valid) => {
            if (valid) {
              // 传事件到父亲组件
              this.$emit('confirm')
            } else {
              return false
            }
          })
        },
        // 下拉
        selectChange(val, prop) {
          this.$emit(`select${prop}`, val)
        },
        // switch切换
        switchChange(val, prop) {
          this.$emit(`switch${prop}`, val)
        },
        // 选中
        checkChange(val, prop) {
          this.$emit(`check${prop}`, val)
        },
        // 标签关闭事件
        tagClose(id, tagData) {
          const curIndex = tagData.findIndex((tagItem, index) => tagItem.id === id)
          tagData.splice(curIndex, 1)
          this.$emit('tagClose', id)
        },
        // 图片标签关闭事件
        imageTagClose(id, tagData) {
          const curIndex = tagData.findIndex((tagItem, index) => tagItem.id === id)
          tagData.splice(curIndex, 1)
          this.$emit('imgTagClose', id)
        },
        addTag(tagData) {
          this.$emit('addTagBtn', tagData)
        },
        addImgTag(tagData) {
          this.$emit('addImgTagBtn', tagData)
        },
        // 查询
        search() {
          this.$emit('search')
        },
        // 上传图片预览
        uploadPreview(file) {
          this.dialogImageUrl = file.url
          this.uploadDialogVisible = true
        },
      },
    }
    </script>
    <style lang="scss" scoped>
      .button-flex {
        display: flex;
        flex-wrap: wrap;
        text-align: center;
      }
      .button-child-flex {
        flex: 1;
        margin-right: 10px;
      }
      .date-zone {
        margin-bottom: 20px;
      }
      .tag-fields{
        display: flex;
        flex-wrap: wrap;
        /deep/.el-tag{
          margin: 0 10px 10px 0;
          &.add-tag-btn{
            color: #606266;
            background: #ffffff;
            border-color: #DCDFE6;
          }
          &.add-tag-btn:hover {
            color: #409EFF;
            border-color: #c6e2ff;
            background-color: #ecf5ff;
            cursor:pointer;
          }
        }
      }
    </style>
    
    

    文件2 CommonTable/pagination.vue

    <template>
      <div>
        <el-pagination
          background
          layout="total, sizes, prev, pager, next, jumper"
          :total="pagination.total"
          :page-size="pagination.size"
          :current-page="pagination.page"
          :page-sizes="pagination.sizeZones"
          @current-change="handleCurrentChange"
          @size-change="handleSizeChange"
        />
      </div>
    </template>
    
    <script>
    export default {
      props: {
        pagination: {
          type: Object,
          default: null
        }
      },
      data() {
        return {
        }
      },
      methods: {
        handleCurrentChange() {
        },
        handleSizeChange() {
        }
      }
    }
    </script>
    
    

    文件3 CommonTable/components/buttonComp.vue

    <template>
      <el-button
        :size="buttonItem.size || 'medium'"
        :type="buttonItem.btnType"
        :plain="buttonItem.plain || false"
        :round="buttonItem.round || false"
        :circle="buttonItem.circle || false"
        :loading="buttonItem.loading || false"
        :disabled="buttonItem.disabled || false"
        :icon="buttonItem.icon"
        @click="btnClick"
      >
        {{ buttonItem.btnText }}
      </el-button>
    </template>
    
    <script>
    export default {
      name: 'ButtonComp',
      props: {
        buttonItem: {
          type: Object,
          required: true,
        },
      },
      methods: {
        btnClick() {
          this.$emit('clickFunc')
        },
      },
    }
    </script>
    

    文件4 CommonTable/components/tbPagination.vue

    <template>
      <div :class="`${pagination.className || ''} defaultPagination`">
        <div class="tip-box">
          <span>本页个数:{{ pagination.currentTotal }}</span>
          <span>总数:{{ pagination.total }}</span>
        </div>
        <!--  分页器前插槽  -->
        <slot name="beforePagination" />
    
        <el-pagination
          v-if="pagination.isShow || true"
          :small="pagination.small || false"
          :background="pagination.background || true"
          :page-size="pagination.pageSize || 20"
          :total="pagination.total"
          :page-count="pagination.pageCount"
          :pager-count="pagination.pagerCount || 7"
          :current-page="pagination.currentPage || 1"
          :layout="pagination.layout || 'sizes, prev, pager, next'"
          :page-sizes="pagination.pageSizes || [5, 10, 20, 30, 40, 50, 100]"
          :popper-class="pagination.popperClass"
          :prev-text="pagination.prevText"
          :next-text="pagination.nextText"
          :disabled="pagination.disabled || false"
          :hide-on-single-page="pagination.hideOnSinglePage || false"
          @size-change="val => $emit('size-change', val)"
          @current-change="val => $emit('page-change', val)"
        />
    
        <!--  分页器后插槽  -->
        <slot name="afterPagination" />
      </div>
    </template>
    
    <script>
    export default {
      name: 'TbPagination',
      props: {
        pagination: { // 分页配置数据
          type: Object,
          required: true,
        },
      },
      methods: {
      },
    }
    </script>
    
    <style lang="scss" scoped>
      .defaultPagination{
        margin: 20px;
        display: flex;
        justify-content: space-between;
        align-items: center;
        .tip-box{
          span{
            padding-right: 20px;
            font-size: 14px;
            color: #606266;
          }
        }
      }
    </style>
    
    

    以上是封装table的代码,下面是分装form
    文件1
    CommomForm/index.vue

    <template>
      <div>
        <el-form
          ref="form"
          class="form-flex"
          :label-width="formLabelWidth"
          :disabled="formDisabled"
          :model="formData"
          :rules="formRules"
          :inline="inline"
        >
          <el-form-item
            v-for="(formItem, itemIndex) in formFields"
            v-show="!formItem.hidden"
            :key="itemIndex"
            :prop="formItem.prop"
            :label-width="formItem.type === 'button' ? '0px': formItem.labelWidth"
            :label="formItem.label"
            :class="formItem.class"
          >
            <div
              v-if="formItem.type === 'extraMention'"
              :class="formItem.class"
            >{{ formItem.prop }}</div>
            <!-- 输入框或者textarea-->
            <el-input
              v-if="formItem.type === 'input'"
              v-model="formData[formItem.prop]"
              :placeholder="formItem.placeholder"
              :disabled="formItem.disabled"
              :clearable="formItem.clearable"
              :style="{ formItem.formChildWidth}"
              :maxlength="formItem.maxlength"
            />
            <el-input
              v-if="formItem.type === 'textarea'"
              v-model="formData[formItem.prop]"
              :placeholder="formItem.placeholder"
              type="textarea"
              :disabled="formItem.disabled"
              :style="{ formItem.formChildWidth}"
              :clearable="formItem.clearable"
              :maxlength="formItem.maxlength"
              :autosize="formItem.autoSize"
              :rows="formItem.rows || 2"
            />
            <el-input
              v-if="formItem.type === 'number'"
              v-model.number="formData[formItem.prop]"
              :placeholder="formItem.placeholder"
              type="number"
              :disabled="formItem.disabled"
              :style="{ formItem.formChildWidth}"
              :clearable="formItem.clearable"
              :min="formItem.min"
              :max="formItem.max"
            />
            <!-- 下拉框 -->
            <el-select
              v-if="formItem.type === 'select'"
              v-model="formData[formItem.prop]"
              :placeholder="formItem.placeholder"
              :disabled="formItem.disabled"
              :style="{ formItem.formChildWidth}"
              :multiple="formItem.multiple"
              :filterable="formItem.filterable"
              :clearable="formItem.clearable"
              @change="val => selectChange(val, formItem.prop)"
            >
              <el-option
                v-for="(selectItem, index) in formItem.selectData"
                :key="index"
                :label="selectItem.label"
                :value="selectItem.value"
              />
            </el-select>
            <!-- 时间控件 -->
            <el-date-picker
              v-if="formItem.type === 'datePicker'"
              v-model="formData[formItem.prop]"
              :type="formItem.dateType"
              :value-format="formItem.valueFormat || 'yyyy-MM-dd HH:mm:ss'"
              :format="formItem.format || 'yyyy-MM-dd HH:mm:ss'"
              :placeholder="formItem.placeholder"
              :disabled="formItem.disabled"
              :style="{ formItem.formChildWidth}"
              range-separator="至"
              :start-placeholder="formItem.placeholderStart"
              :end-placeholder="formItem.placeholderEnd"
              :class="formItem.class"
              :picker-options="formItem.pickerOptions"
            />
            <el-time-picker
              v-if="formItem.type === 'timePicker'"
              v-model="formData[formItem.prop]"
              value-format="HH:mm:ss"
              :placeholder="formItem.placeholder"
              :disabled="formItem.disabled"
              :style="{ formItem.formChildWidth}"
            />
            <el-date-picker
              v-if="formItem.type === 'dateTimePiker'"
              v-model="formData[formItem.prop]"
              :value-format="formItem.valueFormat || 'yyyy-MM-dd HH:mm:ss'"
              :format="formItem.format || 'yyyy-MM-dd HH:mm:ss'"
              type="datetime"
              :disabled="formItem.disabled"
              :placeholder="formItem.placeholder"
              :style="{ formItem.formChildWidth}"
            />
            <div v-if="formItem.type === 'dateZones'">
              <div v-for="(dateItem, dateIndex) in formItem.children" :key="dateIndex" class="date-zone">
                <el-form-item :prop="dateItem.prop">
                  <el-date-picker
                    v-if="dateItem.type === 'dataPicker'"
                    v-model="formData[dateItem.prop]"
                    value-format="yyyy-MM-dd"
                    type="date"
                    :placeholder="dateItem.placeholder"
                    :disabled="dateItem.disabled"
                    :style="{ dateItem.formChildWidth}"
                  />
                </el-form-item> <span v-if="dateIndex===0 && inline">至</span>
              </div>
            </div>
            <!-- switch切换 -->
            <el-switch
              v-if="formItem.type === 'switch'"
              v-model="formData[formItem.prop]"
              :disabled="formItem.disabled"
              :style="{ formItem.formChildWidth}"
              @change="val => switchChange(val, formItem.prop)"
            />
            <!-- checkbox -->
            <el-checkbox-group
              v-if="formItem.type === 'checkbox'"
              v-model="formData[formItem.prop]"
              :disabled="formItem.disabled"
              :style="{ formItem.formChildWidth}"
              @change="val => checkChange(val, formItem.prop)"
            >
              <el-checkbox
                v-for="(selectItem, index) in formItem.checkData"
                :key="index"
                :label="selectItem"
                name="type"
              />
            </el-checkbox-group>
            <!-- radio -->
            <el-radio-group
              v-if="formItem.type === 'radio'"
              v-model="formData[formItem.prop]"
              :disabled="formItem.disabled || false"
              :fill="formItem.fill || '#409EFF'"
              :text-color="formItem.textColor || '#ffffff'"
              :style="{ formItem.formChildWidth}"
              @change="val => checkChange(val, formItem.prop)"
            >
              <el-radio
                v-for="(radioItem, index) in formItem.radioData"
                :key="index"
                :label="radioItem.label"
                :disabled="radioItem.disabled || false"
                :border="radioItem.border || false"
                :size="radioItem.size"
                :name="radioItem.primevalName || ''"
              >{{ radioItem.name || radioItem.label }}</el-radio>
            </el-radio-group>
            <!-- 普通标签 -->
            <div v-if="formItem.type === 'normalTag'" class="tag-fields">
    
              <el-tag
                v-for="(tagItem) in formItem.tagData"
                :key="tagItem.id"
                :closable="tagItem.closable || formItem.closable"
                :disable-transitions="tagItem.transitions"
                :size="tagItem.size"
                :effect="tagItem.effect"
                :type="tagItem.type"
                @close="tagClose(tagItem.id,formItem.tagData)"
              >{{ tagItem.name }}
              </el-tag>
              <el-tag v-if="!!(Object.keys(formItem.addTagBtnOption).length)" :size="formItem.addTagBtnOption.size" class="add-tag-btn" @click="addTag(formItem.tagData)">{{ formItem.addTagBtnOption.name }}</el-tag>
            </div>
            <!-- 图片标签 -->
            <div v-if="formItem.type === 'imageTag'" class="image-tag-fields-box">
              <div v-for="tagItem in formItem.tagData" :key="tagItem.id" class="img-item-wrap">
                <i v-if="!formItem.noDeleteIcon" class="el-icon-error delete-icon" @click="imageTagClose(tagItem.id,formItem.tagData)" />
                <div class="img-item" @click="uploadPreview(tagItem)"><img :src="tagItem.url" alt="暂无图片"></div>
                <span>{{ tagItem.name }}</span>
              </div>
              <div class="img-item-wrap add-item" @click="addImgTag(formItem.tagData)">
                <div class="img-item"> <span><i class="el-icon-plus add-btn" /></span></div>
              </div>
            </div>
            <!-- 自定义表单域 -->
            <div v-if="formItem.type === 'customSlot'" class="custom-slot-fields">
              <slot :name="`${formItem.prop}Slot`" />
            </div>
            <!--  upload 上传  -->
            <el-upload
              v-if="formItem.type === 'upload'"
              :ref="'uploadref'"
              :action="formItem.action"
              :headers="formItem.header"
              :multiple="formItem.multiple"
              :data="formItem.data"
              :name="formItem.name || 'file'"
              :with-credentials="formItem.withCredentials || false"
              :show-file-list="formItem.showFileList || true"
              :drag="formItem.drag || false"
              :accept="formItem.accept"
              :on-preview="formItem.onPreview || uploadPreview"
              :on-remove="formItem.onRemove"
              :on-success="formItem.onSuccess"
              :on-error="formItem.onError"
              :on-progress="formItem.onProgress"
              :on-change="formItem.onChange"
              :before-upload="formItem.beforeUplaod"
              :before-remove="formItem.beforeRemove"
              :list-type="formItem.listType || 'picture-card'"
              :auto-upload="formItem.autoUpload || true"
              :file-list="formData[formItem.prop] || []"
              :http-request="formItem.httpRequest"
              :disabled="formItem.disabled || false"
              :limit="formItem.limit"
              :on-exceed="formItem.onExceed"
            >
              <i class="el-icon-plus" />
              <!-- upload 插槽 -->
              <template #trigger>
                <slot :name="`${formItem.prop}Trigger`" />
              </template>
              <template #tip>
                <slot :name="`${formItem.prop}Tip`" />
              </template>
            </el-upload>
            <!-- 按钮 -->
            <div v-if="formItem.type === 'button'" class="button-flex">
              <div v-for="(buttonItem, buttonIndex) in formItem.children" :key="buttonIndex" class="button-child-flex">
                <button-comp
                  :button-item="buttonItem"
                  v-on="{
                    reset, confirm, cancel, search, exportFile
                  }"
                />
              </div>
            </div>
          </el-form-item>
        </el-form>
    
        <!-- 图片预览弹窗 -->
        <el-dialog :visible.sync="uploadDialogVisible" top="7vh" :append-to-body="true">
          <img width="100%" :src="dialogImageUrl" alt="">
        </el-dialog>
      </div>
    </template>
    
    <script>
    import buttonComp from './buttonComp'
    export default {
      components: {
        buttonComp,
      },
      props: {
        formLabelWidth: { // 表单label宽度
          type: String,
          default: '200px',
        },
        formData: { // 表单数据
          type: Object,
          default: null,
        },
        formDisabled: { // 是否禁用表单
          type: Boolean,
          default: false,
        },
        formRules: { // 表单验证规则
          type: Object,
          default: null,
        },
        // 设置json数据
        formFields: { // 表单项配置信息
          type: Array,
          default: () => [],
        },
        inline: { // 表单横向竖向控制
          type: Boolean,
          default: false,
        },
      },
      data() {
        return {
          dialogImageUrl: '',
          uploadDialogVisible: false,
        }
      },
      methods: {
        reset() {
          this.$refs['form'].resetFields()
          this.$emit('reset')
        },
        exportFile(buttonItem) {
          this.$emit('exportFile', buttonItem)
        },
        cancel() {
          this.$emit('cancel')
        },
        confirm() {
          this.$refs['form'].validate((valid) => {
            if (valid) {
              // 传事件到父亲组件
              this.$emit('confirm')
            } else {
              return false
            }
          })
        },
        // 下拉
        selectChange(val, prop) {
          this.$emit(`select${prop}`, val)
        },
        // switch切换
        switchChange(val, prop) {
          this.$emit(`switch${prop}`, val)
        },
        // 选中
        checkChange(val, prop) {
          this.$emit(`check${prop}`, val)
        },
        // 标签关闭事件
        tagClose(id, tagData) {
          const curIndex = tagData.findIndex((tagItem, index) => tagItem.id === id)
          tagData.splice(curIndex, 1)
          this.$emit('tagClose', id)
        },
        // 图片标签关闭事件
        imageTagClose(id, tagData) {
          const curIndex = tagData.findIndex((tagItem, index) => tagItem.id === id)
          tagData.splice(curIndex, 1)
          this.$emit('imgTagClose', id)
        },
        addTag(tagData) {
          this.$emit('addTagBtn', tagData)
        },
        addImgTag(tagData) {
          this.$emit('addImgTagBtn', tagData)
        },
        // 查询
        search() {
          this.$emit('search')
        },
        // 上传图片预览
        uploadPreview(file) {
          this.dialogImageUrl = file.url
          this.uploadDialogVisible = true
        },
      },
    }
    </script>
    <style lang="scss" scoped>
      .button-flex {
        display: flex;
        flex-wrap: wrap;
        text-align: center;
      }
      .button-child-flex {
        flex: 1;
        margin-right: 10px;
      }
      .date-zone {
        margin-bottom: 20px;
      }
      .tag-fields{
        display: flex;
        flex-wrap: wrap;
        /deep/.el-tag{
          margin: 0 10px 10px 0;
          &.add-tag-btn{
            color: #606266;
            background: #ffffff;
            border-color: #DCDFE6;
          }
          &.add-tag-btn:hover {
            color: #409EFF;
            border-color: #c6e2ff;
            background-color: #ecf5ff;
            cursor:pointer;
          }
        }
      }
    </style>
    

    文件2 CommomForm/buttonComp.vue

    <template>
      <el-button
        v-if="haveBtn(buttonItem.type)"
        v-show="!buttonItem.hidden"
        :size="buttonItem.size || 'medium'"
        :type="buttonItem.btnType || itemOption.type"
        :plain="buttonItem.plain || false"
        :round="buttonItem.round || false"
        :circle="buttonItem.circle || false"
        :loading="buttonItem.loading || false"
        :disabled="buttonItem.disabled || false"
        :icon="buttonItem.icon || itemOption.icon"
        @click="btnClick"
      >
        {{ buttonItem.btnText || itemOption.text }}
      </el-button>
    </template>
    
    <script>
    export default {
      name: 'ButtonComp',
      props: {
        buttonItem: {
          type: Object,
          required: true,
        },
      },
      data() {
        return {
          defaultOption: { // 按钮默认配置
            reset: {
              icon: 'el-icon-refresh-left', type: 'warning', text: '重 置', emit: 'reset',
            },
            confirm: {
              icon: 'el-icon-circle-check', type: 'primary', text: '确 定', emit: 'confirm',
            },
            cancel: {
              icon: 'el-icon-circle-close', type: '', text: '取 消', emit: 'cancel',
            },
            search: {
              icon: 'el-icon-search', type: 'primary', text: '查 询', emit: 'search',
            },
            export: {
              icon: 'el-icon-folder-opened', type: 'info', text: '导 出', emit: 'exportFile',
            },
          },
        }
      },
      computed: {
        itemOption() {
          return this.defaultOption[this.buttonItem.type]
        },
      },
      methods: {
        haveBtn(type) {
          return this.defaultOption.hasOwnProperty(type)
        },
        btnClick() {
          this.$emit(this.itemOption.emit, this.buttonItem)
        },
      },
    }
    </script>
    
    

    api/commonTable.js

    import request from '@/utils/request'
    import qs from 'qs'
    
    export function apiRequest(url, params, method) {
      return request({
        url: url,
        method: method || 'get',
        params,
      })
    }
    
    export function apiQsRequest(url, params, method) {
      console.log(params, 7878);
      return request({
        url: url,
        method: method || 'get',
        params: {
          query: params,
        },
      })
    }
    
    export function exportFile(url, params) {
      return request({
        responseType: 'blob',
        headers: {
          'Content-Type': 'application/json',
        },
        timeout: 1000 * 60,
        url: url,
        method: 'get',
        params: {
          query: qs.stringify(params),
        },
      })
    }
    

    记得npm install qs --save哦,因为传过去可能是数组,所以直接qs过去拉~
    任何不会用,在下面留言吧~ 467015242,我的微信,备注: table组件使用,这样我就来看看你留言了什么,一般不会通过

  • 相关阅读:
    LeetCode 45. Jump Game II
    LeetCode 55. Jump Game
    LeetCode 134. Gas Station
    LeetCode 406. Queue Reconstruction by Height
    LeetCode 860. Lemonade Change
    LeetCode 1005. Maximize Sum Of Array After K Negations
    LeetCode 37. Sudoku Solver
    LeetCode 376. Wiggle Subsequence
    LeetCode 135. Candy
    LeetCode 455. Assign Cookies
  • 原文地址:https://www.cnblogs.com/antyhouse/p/13448558.html
Copyright © 2020-2023  润新知