vue项目收缩搜索表单

需求背景

如果列表的查询字段很多,整个页面全部显示的搜索条件,无疑体验很不好。一般默认只显示几个查询条件,通过点击按钮再显示全部查询条件。

收起状态:显示固定的几个筛选条件(默认筛选条件可自定义),按钮文案——展开。点击按钮切换到“展开状态”;

展开状态:显示全部筛选条件,按钮文案——收缩。点击按钮切换到“收起状态”。

 

技术栈

vue项目使用element-ui框架

 

代码实现

html部分

<!-- 收缩搜索表单组件 -->
<template>
  <div class="index-search-wrap">
    <el-form :model="value"
      ref="formInline"
      label-width="100px"
      label-position="right"
      class="form-inline-resevation"
      @submit.native.prevent>

      <el-row :gutter="32">
        <el-col v-for="(item, index) in showConfig"
          :key="index"
          :span="span">
          <el-form-item v-if="!item.hidden"
            :prop="item.key"
            :label="item.label || item.key">
            <template v-if="item.type==='select'">
              <DicElSelect v-if="item.dic"
                v-model="value[item.key]"
                :type="item.key" />
              <el-select v-else
                v-model="value[item.key]"
                :placeholder="item.placeholder || '请选择'">
                <el-option v-for="(item, index) in options[item.optKey]"
                  :key="index"
                  :label="item.lable"
                  :value="item.code" />
              </el-select>
            </template>

            <template v-else-if="item.type==='picker'">
              <el-date-picker v-model="value[item.key]"
                :type="item.pickerType"
                range-separator="至"
                start-placeholder="开始日期"
                end-placeholder="结束日期" />
            </template>

            <template v-else-if="item.type==='cascader'">
              <el-cascader ref="cascaderRef"
                :options="optionsNew[item.optKey]"
                :props="item.cascaderProps||{expandTrigger:'hover'}"
                :show-all-levels="item.showAllLevels"
                :style="{width:'100%'}"
                :placeholder="item.placeholder || '请选择'"
                popper-class="cascader-pop"
                collapse-tags
                clearable
                @change="onCascaderChange($event, item.key,item.optKey)">
                <template slot-scope="{ node, data }">
                  <span class="select-item"
                    @click="handleCascaderSelect">{{data.label}}</span>
                </template>
              </el-cascader>
            </template>

            <template v-else>
              <el-input v-model.trim="value[item.key]"
                :placeholder="item.placeholder|| '请输入'" />
            </template>
          </el-form-item>
        </el-col>

        <el-col :span="span"
          :offset="operationOffset"
          class="button-col">
          <slot />
        </el-col>
      </el-row>
    </el-form>
  </div>
</template>

组件支持select、datePicker日期选择器、cascader级联选择器、input输入

 

逻辑部分


<script>
import DicElSelect from '@/components/DicElSelect';
import { fetchDicList } from '@/api/api';
import { cloneDeep, sortBy } from 'lodash';
export default {
  name: 'CollapseSearchForm',

  components: { DicElSelect },

  props: {
    config: {
      type: Array,
      default: () => [],
    },
    options: {
      type: Object,
      default: () => ({}),
    },
    value: {
      type: Object,
      default: () => ({}),
    },
    span: {
      type: Number,
      default: 8,
    },
    isCollapse: Boolean,
    /**
     * default show files by order
     * eg: [key1, key2]
     */
    defaultShow: {
      type: Array,
      default: () => [],
    },
    // 一行展示files的数量
    rowNum: {
      type: [Number, String],
      default: 3,
    },
  },

  data() {
    return {
      optionsNew: {},
    };
  },

  computed: {
    defaultNum() {
      let len = this.defaultShow.length || 0;
      len < 3 && (len = 3);
      return len;
    },
    showConfig({ config, defaultShow = [], defaultNum, isCollapse }) {
      const hasdefaultShow = !!defaultShow.length;
      let show = [];
      if (hasdefaultShow) {
        show = defaultShow
          .reduce((pre, item) => {
            pre.push(config.find((x) => item === x.key));
            return pre;
          }, [])
          .slice(0, defaultNum);
      } else {
        show = config.slice(0, defaultNum);
      }
      return isCollapse ? show : config;
    },
    operationOffset() {
      const rowNum = this.rowNum;
      const showNum = this.showConfig.length;
      let space = showNum % rowNum;
      let offset = (rowNum - space - 1) * this.span;
      return offset;
    },
  },

  watch: {
    options: {
      immediate: true,
      deep: true,
      handler(val) {
        this.optionsNew = val;
      },
    },
  },

  mounted() {},

  methods: {
    /**
     * @param {Array} val 选中项的Item
     * @param {String} key file key
     * @param {Boolean} cut last-取最后一级的值;all-取所有级的值
     */
    onCascaderChange(val, key, optKey) {
      let option = cloneDeep(this.options[optKey]);
      let formData = cloneDeep(this.value);

      if (val.length) {
        const selectedOnLevel = val[0][0];
        option.forEach((h) => {
          if (h.value !== selectedOnLevel) h.disabled = true;
        });
      } else {
        option.forEach((h) => {
          h.disabled = false;
        });
      }
      this.optionsNew[optKey] = option;

      let tmp = [];
      if (val && Array.isArray(val) && val.length)
        tmp = val.map((x) => (x.length === 3 ? x[2] : x.slice(-1)[0]));

      formData[key] = tmp;
      this.$emit('input', formData);
    },
    handleCascaderSelect(e) {
      let parentPreviousElement = e.target.parentElement.previousElementSibling;
      let inputRadio = parentPreviousElement.children[0].children[1];
      inputRadio.click();
    },
    clearSupervisionDepartment() {
      const cascaders = this.$refs.cascaderRef || [];
      cascaders.forEach((x) => {
        x.handleClear();
      });
    },
  },
  beforeDestroy() {},
};
</script>

从浏览器方面来讲,这种实现方式还是有待完善的。因为每次切换收起/展开状态,都会引发页面的重排。

 

样式部分

显示样式代码
 <style lang="scss" scoped>
@import '~scss_vars';
.index-search-wrap {
  margin-bottom: 16px;
  @include backandPadding(0);

  .button-col {
    text-align: right;
    padding-bottom: 16px;
  }
}
</style> 

<style lang="scss">
.cascader-pop {
  .el-cascader-menu__wrap {
    height: 310px;
  }
  .el-scrollbar__bar.is-vertical {
    opacity: 1;
    width: 8px;
  }
}
</style>

 

结言:如果有好的思路,欢迎指出😀

posted @ 2022-08-19 09:31  丿流水  阅读(833)  评论(0)    收藏  举报