基于elementui二次封装搜索组件(动态组件)

javascript 复制代码
<template>
  <div :class="{'gray-background': background}" class="searchArea">
    <el-form
        v-if="fieldColumns.length > 0"
        ref="formRef"
        :inline="inline"
        :model="formData"
        class="elForm"
        v-bind="formOpt"
    >
      <template v-for="item in fieldColumns">
        <component
            :is="'el-form-item'"
            v-if="!item.slot"
            :label="item.label"
            :prop="item.name"
            v-bind="item.formItemOpt"
        >
          <component
              :is="`el-${item.type}`"
              v-model="formData[item.name]"
              :collapse-tags="item.collapseTags"
              :disabled="item.disabled || false"
              :options="item.options|| ''"
              :placeholder="item.placeholder"
              :popper-append-to-body="true"
              :props="item.props"
              :style="{ width: item.width || '240px' }"
              v-bind="item.opt"
              @change="handleChange($event,item)"
          >
            <img v-if="item.type === 'input' && item.search" slot="suffix" src="@/assets/search.png"
                 @click="handleChange"/>
            <template v-if="item.type === 'select'">
              <el-option
                  v-for="val in item.options"
                  :key="val.value"
                  :label="val.label"
                  :value="val.value"
              ></el-option>
            </template>
          </component>
          <slot :name="item.slotName"></slot>
        </component>
        <slot v-else :name="item.slot" class="tool"></slot>
      </template>
      <span v-if="isReset" class="table_action_font" @click="handleReset">重置</span>
    </el-form>
    <div v-if="isDesc" class="desc">
      <slot name="desc"></slot>
    </div>
  </div>
</template>

<script>
export default {
  name: 'SearchArea',
  /**
   * complete: 有些场景中,需要在弹窗中使用SearchArea,需要调用submitFormData,但弹窗中的插槽挂载晚于弹窗,
   * 所以弹窗中的mounted获取不到SearchArea的ref,这里在SearchArea的mounted就绪后触发complete事件,使用者可以监听这个事件来完成一些操作
   */
  emits: ['handleQuery', 'complete', 'reset'],
  props: {
    isReset: {//是否显示  重置
      type: Boolean,
      default: false,
    },
    formOpt: {
      type: Object,
      default: () => {
      },
    },
    fieldColumns: {
      type: Array,
      default: () => [],
    },
    // 是否有文本内容
    isDesc: {
      type: Boolean,
      default: false,
    },
    // 传来的表单数据
    formDataProp: {
      type: Object,
      default: () => ({}),
    },
    inline: {
      type: Boolean,
      default: true,
    },
    /// 是否需要灰色背景
    background: {
      type: Boolean,
      default: true,
    }
  },
  data() {
    return {
      formData: {},
    };
  },
  mounted() {
    if (this.formDataProp) {
      this.formData = this.formDataProp;
    }
    this.$emit('complete');
  },
  methods: {
    handleChange(v, item) {
      this.$emit('handleQuery', v, this.formData, item);
    },
    // 把表单数据给到父组件
    submitFormData() {
      return this.formData;
    },
    // 重置
    handleReset() {
      this.$refs.formRef.resetFields();
      this.$emit("reset", {});
    },
  },
};
</script>

<style lang="scss" scoped>
.searchArea {
  &.gray-background {
    background: #F7F8FA;
    padding: 16px;
    border-radius: 6px;
    border: 1px solid #DCDEE0;
    margin: 16px 24px;
  }

  .tool {
    width: fit-content;
    margin-left: auto;
  }

  ::v-deep .el-form {
    display: flex;
    justify-content: flex-start;
    flex-wrap: wrap;
    align-items: center;
    gap: 16px;

    .el-form-item {
      display: flex;
      align-items: center;
      margin: 0 0 0 0;

      .el-form-item__label {
        line-height: 32px;
        padding-right: 8px;
        font-size: 14px;
        font-weight: 400;
        color: #333333;
      }

      .el-form-item__content {
        display: flex;
        align-items: center;
        line-height: 32px;

        .el-cascader {
          .el-input {
            input {
              height: 32px !important;
            }
          }

          .el-cascader__tags {
            flex-wrap: nowrap;
            overflow: hidden;

            .el-tag {
              max-width: 70% !important;
            }
          }
        }
      }

      .el-input {
        width: 100%;

        .el-input__inner {
          width: 100%;
          height: 32px;
          line-height: 32px;
          border-radius: 2px;
          padding: 0 30px 0 14px;
        }
      }

      .el-input__suffix {
        display: flex;
        align-items: center;
        right: 10px;

        &-inner {
          display: flex;
          align-items: center;
          gap: 4px;
        }

      }
    }
  }

  ::v-deep .el-button {
    height: 32px;
    padding: 0 12px;
    line-height: 32px;
    border-radius: 2px;
    min-width: 74px;
  }

  .desc {
    margin-bottom: 16px;
  }
}

</style>

使用:

javascript 复制代码
<SearchArea ref="searchAreaRef" :field-columns="onOrOffSettingQueryOptions" :form-data-prop="formData"
                :isReset="true"
                @handleQuery="handleQuery" @reset="reset">
    </SearchArea>
javascript 复制代码
//数据
onOrOffSettingQueryOptions = [
    {
        label: "校区",
        name: "campusCode",
        type: "select",
        options: [],
        opt: {
            clearable: true,
        },
        placeholder: '全部',
        width: '120px'
    }, {
        label: "楼栋教室",
        name: "roomIds",
        type: "cascader",
        options: [],
        collapseTags: true,
        disabled: true,
        props: {
            multiple: true,
            value: 'id',
            label: 'name'
        },
        placeholder: '全部',
        opt: {
            clearable: true,
            filterable: true,
            debounce: 500,
        },
    }, {
        label: "是否定时开关机",
        name: "timedPower",
        type: "select",
        options: [
            {value: 1, label: '是'},
            {value: 0, label: '否'}
        ],
        opt: {
            clearable: true,
        },
        placeholder: '全部',
        width: '120px'
    }, {
        label: "模式",
        name: "type",
        type: "select",
        options: [
            {value: 1, label: '每天'},
            {value: 2, label: '每周'},
            {value: 3, label: '仅一次'}
        ],
        opt: {
            clearable: true,
        },
        placeholder: '全部',
        width: '120px'
    }, {
        label: "",
        name: "param",
        type: "input",
        search: true,
        opt: {
            clearable: true,
        },
        placeholder: '支持查询教室名称',
        width: '240px',
    }, {
        slot: "reset",
    }
],
formData: {//字段需与name对应
        campusCode: '',
        roomIds: [],
        timedPower: '',
        type: '',
        param: ''
      },
相关推荐
成都被卷死的程序员22 分钟前
响应式网页设计--html
前端·html
mon_star°41 分钟前
将答题成绩排行榜数据通过前端生成excel的方式实现导出下载功能
前端·excel
Zrf21913184551 小时前
前端笔试中oj算法题的解法模版
前端·readline·oj算法
文军的烹饪实验室2 小时前
ValueError: Circular reference detected
开发语言·前端·javascript
Martin -Tang3 小时前
vite和webpack的区别
前端·webpack·node.js·vite
迷途小码农零零发3 小时前
解锁微前端的优秀库
前端
王解4 小时前
webpack loader全解析,从入门到精通(10)
前端·webpack·node.js
我不当帕鲁谁当帕鲁4 小时前
arcgis for js实现FeatureLayer图层弹窗展示所有field字段
前端·javascript·arcgis
那一抹阳光多灿烂4 小时前
工程化实战内功修炼测试题
前端·javascript
放逐者-保持本心,方可放逐5 小时前
微信小程序=》基础=》常见问题=》性能总结
前端·微信小程序·小程序·前端框架