vue elementui 表格搜索组件封装

1.背景:

介绍:

vue结合element-ui的后台管理系统,会有很多的数据表格,结合数据表格的会有很多搜索选项。我们的搜索栏区域每一个数据表格搜索条件都不一样,并且在多人开发的情况下样式也不相同,布局样式还不能统一。

考虑到这一个问题,我们来封装一个搜索组件,统一配置,提升开发效率,并且减少一定量的代码量。

效果展示
在这里插入图片描述


2.问题分析

项目使用的是elementui框架,搜索栏这种表单提交,首先要使用el-form组件来封装,而复杂点就是表单项可能有很多种,例如input输入框、select选择框、日期时间选择框、日期时间范围选择框、cascader级联选择框等,每一项的字段名prop、名称label、绑定的属性方法都不尽相同。所以不能通过普通的绑定个别属性的方式来处理,而slot插槽的方式也无法简化,最终决定通过传递一个配置项数组的形式来解析生成相应的结构。


3.组件实现:

目前实现的方式由两部分组成,一部分是form表单组件,接受父组件传递的配置项数组,一部分是封装一些常用的表单项组件,通过v-if来控制,form表单组件里引入该表单项组件,循环遍历,根据传递的表单项类型来匹配显示具体的表单项。


示例代码1

 <el-form
      class="search-block"
      ref="searchFormRef"
      :model="formModel"
      :inline="props.inline"
    >
      <el-row>
        <el-form-item
          v-for="(item, key) in props.searchForm"
          :key="key"
          :label="item.label"
          :prop="key"
          :class="item.class"
        >
          <template
            v-if="item.component === 'el-date-picker' && item.customContent"
          >
            <el-date-picker
              v-bind="item.attrs"
              v-model="formModel[key]"
              :style="item.style || 'width:258px'"
              clearable
              :editable="false"
              :type="item.type || ''"
              :prefix-icon="item.customPrefix ? customPrefix : ''"
            >
            </el-date-picker>
          </template>
        </el-form-item>
      </el-row>
    </el-form>

示例代码2

<el-form
      class="search-block"
      ref="searchFormRef"
      :model="formModel"
      :inline="props.inline"
    >
      <el-row>
          <component
            :is="item.component"
            v-bind="item.attrs"
            v-on="item.event"
            v-model="formModel[key]"
            :id="item.id"
            clearable
            v-if="!item.customContent"
            :style="item.style || 'width:158px'"
            :prefix-icon="item.customPrefix ? customPrefix : ''"
          >
            <template #default v-if="item.component === 'el-select'">
              <el-option
                v-for="option in item.options"
                :key="option.key"
                :value="option.key"
                :label="option.value"
              >
              </el-option>
            </template>
          </component>
        </el-form-item>
      </el-row>
    </el-form>

4.参数配置:

4.1组件内参数示例:

主要配置接收的数据

<script setup>
const props = defineProps({
  title: { type: String, default: '搜索' },
  searchForm: { type: Object }, // 传入的数据
  inline: {
    type: Boolean,
    default: true
  },
  searchBtnShow: { // 是否显示【搜索】【清空】按钮
    type: Boolean,
    default: true
  },
  emitSearch: [Object, String] // 解决跳转页码后选择器内容为空
})
</script>

4.2组件外传入参数配置示例

// 搜索栏数据
const searchForm = reactive({
  projectName: {
    label: '项目名称',
    component: 'el-input',
    attrs: {
    },
    options: [],
    style: {
    },
    event: {}
  },
  indicatorId: {
    label: '关联病理指标',
    component: 'el-select',
    attrs: {
    },
    options: [],
    style: {
    },
    event: {}
  },
  beginTime: {
    label: '创建时间',
    component: 'el-date-picker',
    attrs: {
      rangeSeparator: '至',
      valueFormat: 'YYYY-MM-DD'
    },
    customPrefix: true,
    customContent: true,
    id: 'start-time',
    type: 'daterange',
    event: {},
    child: {
    }
  }
})

5.使用示例

  • 组件引入
<template>
 <search :searchForm="searchForm" title="" />
</template>
<script setup>
 import search from '@/components/search'
 // 搜索栏数据
const searchForm = reactive({
  projectName: {
    label: '项目名称',
    component: 'el-input',
    attrs: {
    },
    options: [],
    style: {
    },
    event: {}
  },
  indicatorId: {
    label: '关联病理指标',
    component: 'el-select',
    attrs: {
    },
    options: [],
    style: {
    },
    event: {}
  },
  beginTime: {
    label: '创建时间',
    component: 'el-date-picker',
    attrs: {
      rangeSeparator: '至',
      valueFormat: 'YYYY-MM-DD'
    },
    customPrefix: true,
    customContent: true,
    id: 'start-time',
    type: 'daterange',
    event: {},
    child: {
    }
  }
})
</script>

6.完成代码

1.search.vue

<template>
  <div class="search-module">
    <div class="title-heading" v-if="props.title">
      <span>{{ props.title }}</span>
    </div>
    <!-- 搜索 -->
    <el-form
      class="search-block"
      ref="searchFormRef"
      :model="formModel"
      :inline="props.inline"
    >
      <el-row>
        <el-form-item
          v-for="(item, key) in props.searchForm"
          :key="key"
          :label="item.label"
          :prop="key"
          :class="item.class"
        >
          <template
            v-if="item.component === 'el-date-picker' && item.customContent"
          >
            <el-date-picker
              v-bind="item.attrs"
              v-model="formModel[key]"
              :style="item.style || 'width:258px'"
              clearable
              :editable="false"
              :type="item.type || ''"
              :prefix-icon="item.customPrefix ? customPrefix : ''"
            >
            </el-date-picker>
          </template>
          <component
            :is="item.component"
            v-bind="item.attrs"
            v-on="item.event"
            v-model="formModel[key]"
            :id="item.id"
            clearable
            v-if="!item.customContent"
            :style="item.style || 'width:158px'"
            :prefix-icon="item.customPrefix ? customPrefix : ''"
          >
            <template #default v-if="item.component === 'el-select'">
              <el-option
                v-for="option in item.options"
                :key="option.key"
                :value="option.key"
                :label="option.value"
              >
              </el-option>
            </template>
          </component>
        </el-form-item>
        <div class="search-btn" v-if="searchBtnShow">
          <el-button type="primary" class="btn-default-blue" @click="searchSubmit('searchFormRef')"
            >搜索</el-button
          >
          <el-button type="primary" class="btn-default-blue" @click="resetSubmit('searchFormRef')"
            >清空</el-button
          >
        </div>
      </el-row>
    </el-form>
  </div>
</template>

<script setup>
const props = defineProps({
  title: { type: String, default: '搜索' },
  searchForm: { type: Object },
  inline: {
    type: Boolean,
    default: true
  },
  searchBtnShow: { // 是否显示【搜索】【清空】按钮
    type: Boolean,
    default: true
  },
  emitSearch: [Object, String] // 解决跳转页码后选择器内容为空
})
const formModel = ref({})
onBeforeMount(() => {
  const keys = Object.keys(props.searchForm)
  const obj = {}
  keys.forEach(key => {
    obj[key] = props.searchForm[key].defaultValue || ''
  })
  formModel.value = Object.assign({}, formModel.value, obj)
})
const searchFormRef = ref(null)
const emit = defineEmits(['refreshData', 'update:emitSearch'])

// 日期自定义样式
const customPrefix = shallowRef({
  render () {
    return h('p', { class: 'icon-rili-01 font_family icon-size' })
  }
})

const searchSubmit = () => {
  formModel.value.params = {}
  if (formModel.value?.beginTime) {
    const date = {
      beginTime: formModel.value.beginTime[0],
      endTime: formModel.value.beginTime[1]
    }
    formModel.value.params['beginTime'] = date.beginTime
    formModel.value.params['endTime'] = date.endTime
  } else if (!formModel.value.beginTime) {
    formModel.value.params['beginTime'] = ''
    formModel.value.params['endTime'] = ''
  }
  let assignForm = {...formModel.value}
  delete assignForm.beginTime
  emit('update:emitSearch', assignForm)
  emit('refreshData', assignForm, true)
  /* emit('update:emitSearch', Object.assign({}, formModel.value))
  emit('refreshData', Object.assign({}, formModel.value)) */
}
const resetSubmit = () => {
  searchFormRef.value.clearValidate()
  searchFormRef.value.resetFields()
  emit('update:emitSearch', null)
  emit('refreshData', null)
}

defineExpose({
  resetSubmit
})
</script>

<style lang="scss" scoped>
.search-module {
  display: flex;
  // height: 90px;
  // padding: 0 20px;
  flex-direction: column;
  // border-bottom: 1px solid #ccc;
  .title-heading {
    font-size: 20px;
    color: #333333;
    font-weight: 500;
    height: 50%;
    line-height: 3.5;
    // ::before {
    vertical-align: middle;
    // }
  }
  :deep(.el-form-item) {
    margin-bottom: unset;
    margin-right: 40px;
    height: 55px;
    .el-range-separator {
      line-height: 1.5;
    }
  }
  .date-del-margin {
    margin-right: 0px;
  }
  :deep(.el-form-item__label) {
    line-height: 55px;
  }
  /* .date-dash {
    :deep(.el-form-item__label) {
      padding: 0 4px;
    }
  } */
  .search-block {
    display: flex;
    margin: auto 0;
    > div {
      margin-right: 40px;
      /* display: inherit;
      align-items: baseline; */
    }
    :deep(.el-input__inner) {
      height: 30px;
    }
    .search-time {
      :deep(.el-input) {
        width: 158px;
      }
    }
    :deep(.el-input__prefix) {
      right: 5px;
      // left: unset;
    }
    .search-btn {
      // height: 100%;
      line-height: 55px;
      button {
        min-height: unset;
        height: 26px;
        min-width: 62px;
        padding: 0px;
      }
    }
  }
}
</style>

2.index.vue

<template>
 <search :searchForm="searchForm" title="" />
</template>
<script setup>
 import search from '@/components/search'
 // 搜索栏数据
const searchForm = reactive({
  projectName: {
    label: '项目名称',
    component: 'el-input',
    attrs: {
    },
    options: [],
    style: {
    },
    event: {}
  },
  indicatorId: {
    label: '关联病理指标',
    component: 'el-select',
    attrs: {
    },
    options: [],
    style: {
    },
    event: {}
  },
  beginTime: {
    label: '创建时间',
    component: 'el-date-picker',
    attrs: {
      rangeSeparator: '至',
      valueFormat: 'YYYY-MM-DD'
    },
    customPrefix: true,
    customContent: true,
    id: 'start-time',
    type: 'daterange',
    event: {},
    child: {
    }
  }
})
</script>

总结

vue结合elemen-ui的搜索组件封装就写完了,希望小伙伴们喜欢!!!

  • 1
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值