阅读 483

vue+element-ui的列表查询条件/筛选条件组件二次封装(Vue项目)

一、需求

对于后台管理系统项目必不可少的就是 “增删改查”;而 "查",就会根据表格的列数来显示多少个查询/筛选条件;为了方便因此封装了查询条件(筛选条件)组件

二、组件功能

1、自动排列布局,每行显示4列(即4个条件) 2、内置“查询”和“重置”操作,并且按钮始终居于查询条件的最右侧 3、特定查询条件(如日期范围),可以配置占2列(span属性) 4、自动填入placeholder(日期范围除外) 5、默认输入框清空功能及下拉选择可以搜索选择功能 复制代码

三、效果图

在这里插入图片描述

四、参数配置

1、代码示例

<t-query-condition :opts="opts" @submit="conditionEnter" :loading="loading" /> <!-- opts:配置项      @submit:点击查询按钮 返回最终数据      loading:查询按钮loading --> 复制代码

1、配置参数(Attributes)

参数说明类型默认值
opts接收筛选器组件配置formOpt{}
loading查询按钮 loading 状态,请求数据时需要体现Booleanfalse
reset是否显示“重置”按钮Booleantrue
boolEnter是否敲回车查询Booleantrue
labelWidthlabelWidth 宽度String'100px'

2、formOpt Attributes

参数说明类型默认值
label表单字段说明标题string
comp组件名称,可直接指定全局注册的组件,也可引入'elmentUI'如:Button 或者'el-button'string,component
span控件占用的列宽,默认占用 1 列,最多 4 列 (独占一行)number1
changeEvent默认事件为@input,可通过该属性指定其他事件(下拉选择和日期范围需要指定“change 事件”)string'input'
bind渲染时组件会调用 v-bind 指定设置该配置更新元素的属性(继承第三方组件属性)object
event配置组件事件,与写组件时@change 等同理object
child子组件列表,类似 select 组件存在 options 子组件的则需要用到Array
defaultVal默认值-

3. 事件(events)

事件名说明回调参数
change筛选器数据发生变化时触发Function(form: {[propName: dataIndex]: any})
submit点击筛选器查询按钮时触发Function(form: {[propName: dataIndex]: any})
reset点击筛选器重置按钮时触发Function(form: {[propName: dataIndex]: any})

五、具体代码

1、HTML

<template>   <el-form     :label-width="labelWidth"     :form="form"     size="small"     class="t-query-condition"     :style="{'grid-template-areas': gridAreas, 'grid-template-columns': `repeat(${colLength}, minmax(220px, ${100 / colLength}%))`}"   >     <el-form-item v-for="(opt, i) in cOpts" :key="i" :label="opt.label" :style="{gridArea: i}">       <OptComponent v-bind="opt" :opt="opt" :value="form[opt.dataIndex]" @change="change" />     </el-form-item>     <el-form-item       v-if="Object.keys(cOpts).length > 0"       label-width="0"       style="grid-area: submit_btn"       :class="{'flex_end': cellLength % colLength === 0}"     >       <el-button         type="primary"         size="small"         class="btn_check"         @click="checkHandle"         :loading="loading"       >查询</el-button>       <el-button v-if="reset" class="btn_reset" size="small" @click="resetHandle">重置</el-button>     </el-form-item>   </el-form> </template> 复制代码

2、js

<script> import OptComponent from './OptComponent' export default {   name: 'TQueryCondition',   components: {     OptComponent   },   props: {     // 配置项     opts: {       type: Object,       default: () => ({})     },     labelWidth: {       type: String,       default: '100px'     },     loading: {       type: Boolean,       default: false     },     reset: {       type: Boolean,       default: true     },     boolEnter: {       type: Boolean,       default: true     }   },   data () {     return {       form: Object.keys(this.opts).reduce((acc, field) => {         acc[field] = this.opts[field].defaultVal || null         return acc       }, {})     }   },   watch: {     opts: {       handler (opts) {         this.form = this.initForm(opts, true)       },       deep: true     }   },   computed: {     cOpts () {       return Object.keys(this.opts).reduce((acc, field) => {         let opt = {           ...this.opts[field]         }         opt.dataIndex = field         acc[field] = opt         return acc       }, {})     },     gridAreas () { // grid布局按钮位置       let template = "'. . . .'"       switch (this.colLength) {         case 3:           template = "'. . .'"           break         case 2:           template = "'. .'"           break       }       let areas = [template]       Object.keys(this.opts).forEach(key => { // 根据控件描述注定占用多少列及顺序         let span = 1         if (this.opts[key].span > 1 || this.opts[key].span <= 2) { // 最多占用2列           span = this.opts[key].span         }         // 计算剩余多少未占用的位置         let count = 0         let scrstr = areas[areas.length - 1]         while (scrstr.indexOf('.') !== -1) {           scrstr = scrstr.replace(/\./, '')           count++         }         // 若剩余位置不足以放下下一个控件         if (count < span) {           areas.push(template)         }         let i = 0         while (i < span) {           areas[areas.length - 1] = areas[areas.length - 1].replace(/\./, key)           i++         }       })       // 若控件正好占满一行时,补充多一列放置btn       if (areas[areas.length - 1].indexOf('.') === -1) {         areas.push(template)       }       if (this.cellLength % this.colLength === 0) { // 正好占满一行         areas[areas.length - 1] = areas[areas.length - 1].replace(/\.'$/, "submit_btn'")       } else {         areas[areas.length - 1] = areas[areas.length - 1].replace(/\./, 'submit_btn')       }       return (areas + '').replace(/,/g, '')     },     colLength () { // 行列数       const width = window.innerWidth       let colLength = 4       if (width > 768 && width < 1280) {         colLength = 3       } else if (width <= 768) {         colLength = 2       }       return colLength     },     // 占用单元格长度     span () {       let span = 1       Object.keys(this.opts).forEach(key => {         span = this.opts[key].span > 4 ? 4 : this.opts[key].span || 1       })       return span     },     cellLength () { // 占用单元格长度       let length = 0       Object.keys(this.opts).forEach(key => {         let span = this.opts[key].span > 4 ? 4 : this.opts[key].span || 1         length += span       })       return length     }   },   methods: {     initForm (opts, keepVal = false) {       return Object.keys(opts).reduce((acc, field) => {         if (keepVal && this.form) {           acc[field] = this.form[field]         } else if (opts[field].defaultVal) {           acc[field] = opts[field].defaultVal         } else {           acc[field] = null         }         return acc       }, {})     },     resetHandle () {       this.form = this.initForm(this.opts)       this.checkHandle()     },     change (v, dataIndex) {       this.form[dataIndex] = v       this.$emit('change', {         ...this.form       })     },     checkHandle () {       this.$emit('submit', this.form)     }   },   created () {     if (this.boolEnter) {       var lett = this       document.onkeydown = function (e) {         var key = window.event.keyCode         if (key === 13) {           lett.checkHandle()         }       }     }   } } </script> 复制代码

3、SCSS

<style> .t-query-condition.el-form {   position: relative;   display: grid;   gap: 2px 8px;   margin-bottom: -7px;   text-align: left;   .el-select,   .el-date-editor,   .ant-calendar-picker {     width: 100%;   }   .flex_end {     grid-area: submit_btn;     .el-form-item__content {       display: flex;       justify-content: flex-end;       align-items: center;     }   }   .el-form-item {     display: flex;     margin-bottom: 6px;     .el-form-item__label {       flex-shrink: 0;       min-width: 60px;       padding-left: 8px;     }     .el-form-item__content {       flex-grow: 1;       overflow: hidden;       margin-left: 0 !important;     }   }   .btn_check {     position: relative;     top: -1px;   }   .btn_reset {     position: relative;     top: -1px;     margin-left: 8px;   } } </style> 复制代码

4、OptComponent组件

<template>   <component     :is="comp"     v-bind="{clearable:true,filterable:true,...bind}"     :placeholder="getPlaceholder(opt)"     v-on="cEvent"     :value="value"   >     <OptComponent v-for="(cOpt, i) in child" :key="i" v-bind="cOpt" :value="cOpt.value" />   </component> </template> <script> export default {   name: 'OptComponent',   props: {     dataIndex: {       type: String,       default: ''     },     opt: {       type: Object,       default: () => ({})     },     bind: {       type: Object,       default: () => ({})     },     event: {       type: Object,       default: () => ({})     },     comp: {       type: [String, Object],       default: ''     },     child: {       type: Array,       default: () => ([])     },     value: {       type: [String, Number, Array, Date],       default: ''     },     changeEvent: {       type: String,       default: 'input'     }   },   computed: {     cEvent () {       let event = { ...this.event }       let changeEvent = {}       if (this.changeEvent) {         changeEvent[this.changeEvent] = (v) => {           event[this.changeEvent] && event[this.changeEvent](v, arguments)           this.$emit('change', v, this.dataIndex, arguments)         }       }       return { ...event, ...changeEvent }     }   },   methods: {     // 得到placeholder的显示     getPlaceholder (row) {       // console.log(111, row)       let placeholder       if (row.comp) {         if (row.comp.includes('input')) {           placeholder = '请输入' + row.label         } else if (row.comp.includes('select') || row.comp.includes('date')) {           placeholder = '请选择' + row.label         } else {           placeholder = row.label         }       }       return placeholder     }   } } </script>


作者:wocwin
链接:https://juejin.cn/post/7047771278542913572


文章分类
代码人生
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐