当前位置: 首页 > news >正文

vxe-grid 全局自定义filter过滤器,支持字典过滤

一、vxe-table的全局筛选器filters的实现

官网例子:https://vxetable.cn/#/table/renderer/filter
进入之后:我们可以参照例子自行实现,也可以下载它的源码,进行调整

在这里插入图片描述
下载好后并解压,用vscode将解压后的文件打开。全局检索FilterInput,你工作中用的vxe-table多少版本的那就进多少版本的目录
在这里插入图片描述

点击进入,按照这个路劲找到对应文件夹
在这里插入图片描述
将filter相关的vue,复制到自己的项目中components文件夹下
在这里插入图片描述
将filter.tsx 到你的项目中去,常用的FilterInput和FilterContent组件,将其他的FilterExtend 和FilterComplex 相关的可以先注释掉。
在这里插入图片描述

打开filter.ts
在这里插入图片描述
这样就可以使用了,使用方式,按照官网的例子放到columns里即可,filters的结构不允许改变,他与filterRendes的组件是一一对应的
在这里插入图片描述
这里提供v4的相关源码代码:
FilterInput.vue

<template><div class="my-filter-input"><vxe-input type="text" v-model="demo1.option.data" placeholder="支持回车筛选" @keyup="keyupEvent" @input="changeOptionEvent"></vxe-input></div>
</template><script lang="ts">
import { defineComponent, PropType, reactive } from 'vue'
import { VxeInputEvents, VxeGlobalRendererHandles } from 'vxe-table'export default defineComponent({name: 'FilterInput',props: {params: Object as PropType<VxeGlobalRendererHandles.RenderFilterParams>},setup (props) {const demo1 = reactive({option: null as any})const load = () => {const { params } = propsif (params) {const { column } = paramsconst option = column.filters[0]demo1.option = option}}const changeOptionEvent = () => {const { params } = propsconst { option } = demo1if (params && option) {const { $panel } = paramsconst checked = !!option.data$panel.changeOption(null, checked, option)}}const keyupEvent: VxeInputEvents.Keyup = ({ $event }) => {const { params } = propsif (params) {const { $panel } = paramsif ($event.keyCode === 13) {$panel.confirmFilter($event)}}}load()return {demo1,changeOptionEvent,keyupEvent}}
})
</script><style scoped>
.my-filter-input {padding: 10px;
}
</style>

FilterContent.vue

<template><div class="my-filter-content"><div class="my-fc-search"><div class="my-fc-search-top"><vxe-input v-model="demo1.option.data.sVal" placeholder="搜索"></vxe-input></div><div class="my-fc-search-content"><template v-if="demo1.valList.length"><ul class="my-fc-search-list my-fc-search-list-head"><li class="my-fc-search-item"><vxe-checkbox v-model="demo1.isAll" @change="changeAllEvent">全选</vxe-checkbox></li></ul><ul class="my-fc-search-list my-fc-search-list-body"><li class="my-fc-search-item" v-for="(item, sIndex) in demo1.valList" :key="sIndex"><vxe-checkbox v-model="item.checked">{{ item.value }}</vxe-checkbox></li></ul></template><template v-else><div class="my-fc-search-empty">无匹配项</div></template></div></div><div class="my-fc-footer"><vxe-button status="primary" @click="confirmFilterEvent">确认</vxe-button><vxe-button @click="resetFilterEvent">重置</vxe-button></div></div>
</template><script lang="ts">
import { defineComponent, PropType, reactive } from 'vue'
import { VxeGlobalRendererHandles } from 'vxe-table'
import XEUtils from 'xe-utils'export default defineComponent({name: 'FilterContent',props: {params: Object as PropType<VxeGlobalRendererHandles.RenderFilterParams>},setup (props) {interface ColValItem {checked: boolean;value: string;}const demo1 = reactive({isAll: false,option: null as any,colValList: [] as ColValItem[],valList: [] as ColValItem[]})const load = () => {const { params } = propsif (params) {const { $table, column } = paramsconst { fullData } = $table.getTableData()const option = column.filters[0]const { vals } = option.dataconst colValList = Object.keys(XEUtils.groupBy(fullData, column.field)).map((val) => {return {checked: vals.includes(val),value: val} as ColValItem})demo1.option = optiondemo1.colValList = colValListdemo1.valList = colValList}}const searchEvent = () => {const { option, colValList } = demo1if (option) {demo1.valList = option.data.sVal ? colValList.filter((item) => item.value.indexOf(option.data.sVal) > -1) : colValList}}const changeAllEvent = () => {const { isAll } = demo1demo1.valList.forEach((item) => {item.checked = isAll})}const confirmFilterEvent = () => {const { params } = propsconst { option, valList } = demo1if (params && option) {const { data } = optionconst { $panel } = paramsdata.vals = valList.filter((item) => item.checked).map((item) => item.value)$panel.changeOption(null, true, option)$panel.confirmFilter()}}const resetFilterEvent = () => {const { params } = propsif (params) {const { $panel } = params$panel.resetFilter()}}load()return {demo1,searchEvent,changeAllEvent,confirmFilterEvent,resetFilterEvent}}
})
</script><style>
.my-filter-content {padding: 10px;user-select: none;
}
.my-filter-content .my-fc-search .my-fc-search-top {position: relative;padding: 5px 0;
}
.my-filter-content .my-fc-search .my-fc-search-top > input {border: 1px solid #ABABAB;padding: 0 20px 0 2px;width: 200px;height: 22px;line-height: 22px;
}
.my-filter-content .my-fc-search .my-fc-search-content {padding: 2px 10px;
}
.my-filter-content .my-fc-search-empty {text-align: center;padding: 20px 0;
}
.my-filter-content .my-fc-search-list {margin: 0;padding: 0;list-style: none;
}
.my-filter-content .my-fc-search-list-body {overflow: auto;height: 120px;
}
.my-filter-content .my-fc-search-list .my-fc-search-item {padding: 2px 0;display: block;
}
.my-filter-content .my-fc-footer {text-align: right;padding-top: 10px;
}
.my-filter-content .my-fc-footer button {padding: 0 15px;margin-left: 15px;
}
</style>

FilterExtend.vue

<template><div class="my-filter-excel"><div class="my-fe-top"><ul class="my-fe-menu-group"><li class="my-fe-menu-link"><span>升序</span></li><li class="my-fe-menu-link"><span>倒序</span></li></ul><ul class="my-fe-menu-group"><li class="my-fe-menu-link" @click="resetFilterEvent"><span>清除筛选</span></li><li class="my-fe-menu-link"><i class="vxe-icon-question-circle-fill my-fe-menu-link-left-icon"></i><span>筛选条件</span><i class="vxe-icon-question-circle-fill my-fe-menu-link-right-icon"></i><div class="my-fe-menu-child-list"><ul class="my-fe-child-menu-group-list" v-for="(cList, gIndex) in demo1.caseGroups" :key="gIndex"><li v-for="(cItem, cIndex) in cList" :key="cIndex" class="my-fe-child-menu-item" @click="childMenuClickEvent(cItem)"><span>{{ cItem.label }}</span></li></ul></div></li></ul></div><div class="my-fe-search"><div class="my-fe-search-top"><input v-model="demo1.option.data.sVal" placeholder="搜索"/><i class="vxe-icon-question-circle-fill my-fe-search-icon"></i></div><ul class="my-fe-search-list"><li class="my-fe-search-item" @click="sAllEvent"><i class="vxe-icon-question-circle-fill my-fe-search-item-icon"></i><span>(全选)</span></li><li class="my-fe-search-item" v-for="(val, sIndex) in searchList" :key="sIndex" @click="sItemEvent(val)"><i :class="[demo1.option.data.vals.indexOf(val) === -1 ? 'vxe-icon-question-circle-fill my-fe-search-item-icon' : 'vxe-icon-question-circle-fill my-fe-search-item-icon']"></i><span>{{ val }}</span></li></ul></div><div class="my-fe-footer"><vxe-button status="primary" @click="confirmFilterEvent">确认</vxe-button><vxe-button @click="resetFilterEvent">重置</vxe-button></div></div>
</template><script lang="ts">
import { defineComponent, PropType, reactive, computed } from 'vue'
import { VXETable, VxeGlobalRendererHandles } from 'vxe-table'
import XEUtils from 'xe-utils'export default defineComponent({name: 'FilterExtend',props: {params: Object as PropType<VxeGlobalRendererHandles.RenderFilterParams>},setup (props) {interface CaseItem {label: string;value: string;}const demo1 = reactive({option: null as any,colValList: [] as string[],caseGroups: [[{ value: 'equal', label: '等于' },{ value: 'ne', label: '不等于' }],[{ value: 'greater', label: '大于' },{ value: 'ge', label: '大于或等于' },{ value: 'less', label: '小于' },{ value: 'le', label: '小于或等于' }]] as CaseItem[][]})const searchList = computed(() => {const { option, colValList } = demo1if (option) {return option.data.sVal ? colValList.filter(val => val.indexOf(option.data.sVal) > -1) : colValList}return []})const load = () => {const { params } = propsif (params) {const { $table, column } = paramsconst { fullData } = $table.getTableData()const option = column.filters[0]const colValList = Object.keys(XEUtils.groupBy(fullData, column.field))demo1.option = optiondemo1.colValList = colValList}}const sAllEvent = () => {const { option } = demo1if (option) {const { data } = optionif (data.vals.length > 0) {data.vals = []} else {data.vals = demo1.colValList}}}const sItemEvent = (val: string) => {const { option } = demo1if (option) {const { data } = optionconst vIndex = data.vals.indexOf(val)if (vIndex === -1) {data.vals.push(val)} else {data.vals.splice(vIndex, 1)}}}const confirmFilterEvent = () => {const { params } = propsconst { option } = demo1if (params && option) {const { data } = optionconst { $panel } = paramsdata.f1 = ''data.f2 = ''$panel.changeOption(null, true, option)$panel.confirmFilter()}}const resetFilterEvent = () => {const { params } = propsif (params) {const { $panel } = params$panel.resetFilter()}}const childMenuClickEvent = (cItem: CaseItem) => {VXETable.modal.alert({ content: cItem.label })}load()return {demo1,searchList,sAllEvent,sItemEvent,confirmFilterEvent,resetFilterEvent,childMenuClickEvent}}
})
</script><style>
.my-filter-excel {user-select: none;
}
.my-filter-excel .my-fe-top .my-fe-menu-group {position: relative;margin: 0;padding: 0;
}
.my-filter-excel .my-fe-top .my-fe-menu-group:after {content: "";position: absolute;width: 190px;right: 0;bottom: 0;border-bottom: 1px solid #E2E4E7;
}
.my-filter-excel .my-fe-top .my-fe-menu-group .my-fe-menu-link {position: relative;padding: 4px 20px 4px 30px;cursor: pointer;
}
.my-filter-excel .my-fe-top .my-fe-menu-group .my-fe-menu-link:hover {background-color: #C5C5C5;
}
.my-filter-excel .my-fe-top .my-fe-menu-group .my-fe-menu-link-left-icon {position: absolute;left: 10px;top: 6px;
}
.my-filter-excel .my-fe-top .my-fe-menu-group .my-fe-menu-link-right-icon {position: absolute;right: 10px;top: 6px;
}
.my-filter-excel .my-fe-top .my-fe-menu-group .my-fe-menu-link:hover .my-fe-menu-child-list {display: block;
}
.my-filter-excel .my-fe-top .my-fe-menu-group .my-fe-menu-link .my-fe-menu-child-list {display: none;position: absolute;top: 0;right: -120px;width: 120px;background-color: #fff;border: 1px solid #DADCE0;box-shadow: 3px 3px 4px -2px rgba(0, 0, 0, 0.6);
}
.my-filter-excel .my-fe-top .my-fe-menu-group .my-fe-menu-link .my-fe-child-menu-group-list {position: relative;padding: 0;
}
.my-filter-excel .my-fe-top .my-fe-menu-group .my-fe-menu-link .my-fe-child-menu-group-list:after {content: "";position: absolute;width: 90px;right: 0;bottom: 0;border-bottom: 1px solid #E2E4E7;
}
.my-filter-excel .my-fe-top .my-fe-menu-group .my-fe-menu-link .my-fe-child-menu-group-list > .my-fe-child-menu-item {position: relative;padding: 4px 20px 4px 30px;overflow: hidden;text-overflow: ellipsis;white-space: nowrap;
}
.my-filter-excel .my-fe-top .my-fe-menu-group .my-fe-menu-link .my-fe-child-menu-group-list > .my-fe-child-menu-item:hover {background-color: #C5C5C5;
}
.my-filter-excel .my-fe-search {padding: 0 10px 0 30px;
}
.my-filter-excel .my-fe-search .my-fe-search-top {position: relative;padding: 5px 0;
}
.my-filter-excel .my-fe-search .my-fe-search-top > input {border: 1px solid #ABABAB;padding: 0 20px 0 2px;width: 200px;height: 22px;line-height: 22px;
}
.my-filter-excel .my-fe-search .my-fe-search-top > .my-fe-search-icon {position: absolute;right: 5px;top: 10px;
}
.my-filter-excel .my-fe-search .my-fe-search-list {margin: 0;border: 1px solid #E2E4E7;padding: 2px 10px;overflow: auto;height: 140px;
}
.my-filter-excel .my-fe-search .my-fe-search-list .my-fe-search-item {cursor: pointer;padding: 2px 0;
}
.my-filter-excel .my-fe-search .my-fe-search-list .my-fe-search-item .my-fe-search-item-icon {width: 16px;
}
.my-filter-excel .my-fe-footer {text-align: right;padding: 10px 10px 10px 0;
}
.my-fe-popup .my-fe-popup-filter {padding-left: 30px;
}
.my-fe-popup .my-fe-popup-filter > .my-fe-popup-filter-select {width: 120px;
}
.my-fe-popup .my-fe-popup-filter > .my-fe-popup-filter-input {margin-left: 15px;width: 380px;
}
.my-fe-popup .my-fe-popup-describe {padding: 20px 0 10px 0;
}
.my-fe-popup .my-fe-popup-concat {padding-left: 50px;
}
.my-fe-popup .my-fe-popup-footer {text-align: right;
}
</style>

FilterComplex.vue

<template><div class="my-filter-complex"><div class="my-fc-type"><vxe-radio v-model="demo1.option.data.type" name="fType" label="has">包含</vxe-radio><vxe-radio v-model="demo1.option.data.type" name="fType" label="eq">等于</vxe-radio></div><div class="my-fc-name"><vxe-input v-model="demo1.option.data.name" type="text" placeholder="请输入名称" @input="changeOptionEvent()"></vxe-input></div><div class="my-fc-footer"><vxe-button status="primary" @click="confirmEvent">确认</vxe-button><vxe-button @click="resetEvent">重置</vxe-button></div></div>
</template><script lang="ts">
import { defineComponent, PropType, reactive } from 'vue'
import { VxeGlobalRendererHandles } from 'vxe-table'export default defineComponent({name: 'FilterComplex',props: {params: Object as PropType<VxeGlobalRendererHandles.RenderFilterParams>},setup (props) {const demo1 = reactive({option: null as any})const load = () => {const { params } = propsif (params) {const { column } = paramsconst option = column.filters[0]demo1.option = option}}const changeOptionEvent = () => {const { params } = propsconst { option } = demo1if (params && option) {const { $panel } = paramsconst checked = !!option.data.name$panel.changeOption(null, checked, option)}}const confirmEvent = () => {const { params } = propsif (params) {const { $panel } = params$panel.confirmFilter()}}const resetEvent = () => {const { params } = propsif (params) {const { $panel } = params$panel.resetFilter()}}load()return {demo1,changeOptionEvent,confirmEvent,resetEvent}}
})
</script><style scoped>
.my-filter-complex {width: 260px;padding: 5px 15px 10px 15px;
}
.my-filter-complex .my-fc-type {padding: 8px 0;
}
.my-filter-complex .my-fc-footer {text-align: center;
}
</style>

filter.tsx

import { VXETable } from 'vxe-table'
import FilterInput from './components/FilterInput.vue'
import FilterContent from './components/FilterContent.vue'
import FilterComplex from './components/FilterComplex.vue'
import FilterExtend from './components/FilterExtend.vue'// 创建一个简单的输入框筛选
VXETable.renderer.add('FilterInput', {// 筛选模板renderFilter (renderOpts, params) {return <FilterInput params={ params }></FilterInput>},// 重置数据方法filterResetMethod (params) {const { options } = paramsoptions.forEach((option) => {option.data = ''})},// 重置筛选复原方法(当未点击确认时,该选项将被恢复为默认值)filterRecoverMethod ({ option }) {option.data = ''},// 筛选方法filterMethod (params) {const { option, row, column } = paramsconst { data } = optionconst cellValue = row[column.field]if (cellValue) {return cellValue.indexOf(data) > -1}return false}
})// 创建一个条件的渲染器
VXETable.renderer.add('FilterComplex', {// 不显示底部按钮,使用自定义的按钮showFilterFooter: false,// 筛选模板renderFilter (renderOpts, params) {return <FilterComplex params={ params }></FilterComplex>},// 重置数据方法filterResetMethod (params) {const { options } = paramsoptions.forEach((option) => {option.data = { type: 'has', name: '' }})},// 筛选数据方法filterMethod (params) {const { option, row, column } = paramsconst cellValue = row[column.field]const { name } = option.dataif (cellValue) {return cellValue.indexOf(name) > -1}return false}
})// 创建一个支持列内容的筛选
VXETable.renderer.add('FilterContent', {// 不显示底部按钮,使用自定义的按钮showFilterFooter: false,// 筛选模板renderFilter (renderOpts, params) {return <FilterContent params={ params }></FilterContent>},// 重置数据方法filterResetMethod (params) {const { options } = paramsoptions.forEach((option) => {option.data = { vals: [], sVal: '' }})},// 筛选数据方法filterMethod (params) {const { option, row, column } = paramsconst { vals } = option.dataconst cellValue = row[column.field]return vals.includes(cellValue)}
})// 创建一个复杂的筛选器
VXETable.renderer.add('FilterExtend', {// 不显示底部按钮,使用自定义的按钮showFilterFooter: false,// 筛选模板renderFilter (renderOpts, params) {return <FilterExtend params={ params }></FilterExtend>},// 重置数据方法filterResetMethod (params) {const { options } = paramsoptions.forEach((option) => {option.data = { vals: [], sVal: '', fMenu: '', f1Type: '', f1Val: '', fMode: 'and', f2Type: '', f2Val: '' }})},// 筛选数据方法filterMethod (params) {const { option, row, column } = paramsconst cellValue = row[column.field]const { vals, f1Type, f1Val } = option.dataif (cellValue) {if (f1Type) {return cellValue.indexOf(f1Val) > -1} else if (vals.length) {// 通过指定值筛选return vals.includes(cellValue)}}return false}
})

二、自行优化filters实现,支持字典的转换

通过上面的方式,已经实现了过滤器,但是多次使用,衍生出一个问题,就是如果我的列是个字典列,并且字典值的转换用的是columns内的solt,如FilterContent组件,它将会渲染的时字典的value列表,并非用户看到的中文列表,用户怎么知道你过滤器的看到的1,2,3和你的数据时对应的,或者时FilterInput 你输入的必须时字典code,不能是中文,否则将无法筛选出数据。

解决问题1: 在数据库查询数据时,根据该列关联字典表,将中文给转换过来,
解决问题2:前端查询数据后,在给表格赋值时将字典数据转换回来,这样有些麻烦,
解决问题3:优化筛选组件,使其支持字典的筛选。由于项目中只用到了FilterInput和FilterContent这里只提供这两个组件的优化。
1. 先说下在哪里做了调整
filtes的结构上做了些调整,data里都增加了字典的数据, filterContent 参数移除sval参数,同样在filterContent 组件内input筛选也将被移除,只保留多选列表进行筛选
在这里插入图片描述
FilterInput
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

“FilterContent.vue”,它与FilterInput不一样,需要面板打开时,就显示过滤列表
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2. 调整后的代码
FilterContent.vue

<template><div class="my-filter-content"><div class="my-fc-search"><div class="my-fc-search-top"><!-- <vxe-inputv-model="demo1.option.data.sVal"placeholder="搜索"></vxe-input> --></div><div class="my-fc-search-content"><template v-if="demo1.valList.length"><ul class="my-fc-search-list my-fc-search-list-head"><li class="my-fc-search-item"><vxe-checkbox v-model="demo1.isAll" @change="changeAllEvent">全选</vxe-checkbox></li></ul><ul class="my-fc-search-list my-fc-search-list-body"><liv-for="(item, sIndex) in demo1.valList":key="sIndex"class="my-fc-search-item"><vxe-checkbox v-model="item.checked">{{item.label}}</vxe-checkbox></li></ul></template><template v-else><div class="my-fc-search-empty">无匹配项</div></template></div></div><div class="my-fc-footer"><vxe-button status="primary" @click="confirmFilterEvent">确认</vxe-button><vxe-button @click="resetFilterEvent">重置</vxe-button></div></div>
</template><script lang="ts">import { defineComponent, PropType, reactive } from 'vue';import { VxeGlobalRendererHandles } from 'vxe-table';import XEUtils from 'xe-utils';export default defineComponent({name: 'FilterContent',props: {params: Object as PropType<VxeGlobalRendererHandles.RenderFilterParams>,},setup(props) {interface ColValItem {checked: boolean;value: string;label: string;}const demo1 = reactive({isAll: false,option: null as any,colValList: [] as ColValItem[],valList: [] as ColValItem[],});const load = () => {const { params } = props;if (params) {const { $table, column } = params;const { fullData } = $table.getTableData();const option: any = column.filters[0];const { vals } = option.data;/** 重置数据,解决bug:可能由于动态渲染columns,导致过滤面板勾选后点击确认按钮,过滤后无法更新表格数据,* 经过尝试,点击重置按钮,在进行过滤,可正常过滤,所以这里重置下data ;问题得以解决*/option.data = {vals: option.data.vals,// sVal: option.data.sVal,dict: option.data.dict ? option.data.dict : undefined,};if (option.data.dict && option.data.dict.length > 0) {const colValList = Object.keys(XEUtils.groupBy(fullData, column.field)).map((val) => {const value = option.data.dict.filter((item) => String(item.value) === String(val));let label = val;if (value.length > 0) {label = value[0].label;}return {checked: vals.includes(val),value: val,label,} as ColValItem;});demo1.option = option;demo1.colValList = colValList;demo1.valList = colValList;} else {const colValList = Object.keys(XEUtils.groupBy(fullData, column.field)).map((val) => {return {checked: vals.includes(val),value: val,label: val,} as ColValItem;});demo1.option = option;demo1.colValList = colValList;demo1.valList = colValList;}}};// const searchEvent = () => {//   const { option, colValList } = demo1;//   if (option) {//     demo1.valList = option.data.sVal//       ? colValList.filter(//           (item) => item.value.indexOf(option.data.sVal) > -1//         )//       : colValList;//   }// };const changeAllEvent = () => {const { isAll } = demo1;demo1.valList.forEach((item) => {item.checked = isAll;});};const confirmFilterEvent = () => {const { params } = props;const { option, valList } = demo1;if (params && option) {const { data } = option;const { $panel } = params;data.vals = valList.filter((item) => item.checked).map((item) => item.value);$panel.changeOption(null, true, option);$panel.confirmFilter();}};const resetFilterEvent = () => {const { params } = props;if (params) {const { $panel } = params;$panel.resetFilter();}};load();return {demo1,// searchEvent,changeAllEvent,confirmFilterEvent,resetFilterEvent,};},});
</script><style>.my-filter-content {padding: 10px;user-select: none;}.my-filter-content .my-fc-search .my-fc-search-top {position: relative;padding: 5px 0;}.my-filter-content .my-fc-search .my-fc-search-top > input {border: 1px solid #ababab;padding: 0 20px 0 2px;width: 200px;height: 22px;line-height: 22px;}.my-filter-content .my-fc-search .my-fc-search-content {padding: 2px 10px;}.my-filter-content .my-fc-search-empty {text-align: center;padding: 20px 0;}.my-filter-content .my-fc-search-list {margin: 0;padding: 0;list-style: none;}.my-filter-content .my-fc-search-list-body {overflow: auto;height: 120px;}.my-filter-content .my-fc-search-list .my-fc-search-item {padding: 2px 0;display: block;}.my-filter-content .my-fc-footer {text-align: right;padding-top: 10px;}.my-filter-content .my-fc-footer button {padding: 0 15px;margin-left: 15px;}
</style>

FilterInput.vue

<template><div class="my-filter-input"><vxe-inputv-model="demo1.option.data.sVal"type="text"placeholder="支持回车筛选"@keyup="keyupEvent"@input="changeOptionEvent"></vxe-input></div>
</template><script lang="ts">import { defineComponent, PropType, reactive } from 'vue';import { VxeInputEvents, VxeGlobalRendererHandles } from 'vxe-table';export default defineComponent({name: 'FilterInput',props: {params: Object as PropType<VxeGlobalRendererHandles.RenderFilterParams>,},setup(props) {const demo1 = reactive({option: null as any,});const load = () => {const { params } = props;if (params) {const { column } = params;const option = column.filters[0];option.data = {sVal: option.data.sVal,dict: option.data.dict ? option.data.dict : undefined,};demo1.option = option;}};const changeOptionEvent = () => {const { params } = props;const { option } = demo1;if (params && option) {const { $panel } = params;const checked = !!option.data.sVal;$panel.changeOption(null, checked, option);}};const keyupEvent: VxeInputEvents.Keyup = ({ $event }) => {const { params } = props;if (params) {const { $panel } = params;if ($event.keyCode === 13) {$panel.confirmFilter($event);}}};load();return {demo1,changeOptionEvent,keyupEvent,};},});
</script><style scoped>.my-filter-input {padding: 10px;}
</style>

filter.tsx

import { VXETable } from 'vxe-table';
import FilterInput from '@/components/Filter/FilterInput.vue';
import FilterContent from '@/components/Filter/FilterContent.vue';
// import FilterComplex from './components/FilterComplex.vue'
// import FilterExtend from './components/FilterExtend.vue'// 创建一个简单的输入框筛选
VXETable.renderer.add('FilterInput', {// 筛选模板renderFilter: (renderOpts, params) => {return [<FilterInput params={ params }></FilterInput>];},// 重置数据方法filterResetMethod (params) {const { options } = params;options.forEach((option) => {option.data = {sVal: '',dict: option.data.dict ? option.data.dict : undefined,};});},// 重置筛选复原方法(当未点击确认时,该选项将被恢复为默认值)filterRecoverMethod ({ option }) {option.data = {sVal: '',dict: option.data.dict ? option.data.dict : undefined,};},// 筛选方法filterMethod (params) {const { option, row, column } = params;const { data } = option;if(data.dict && data.dict.length > 0) {const cellValue = row[column.field];const dictItem = data.dict.filter((item)=>item.label.indexOf(data.sVal) > -1).map((item) => item.value);if(dictItem.length > 0){return dictItem.indexOf(cellValue) > -1;}} else {const cellValue = row[column.field];if (cellValue) {return cellValue.indexOf(data.sVal) > -1;}}return false;},
});// // 创建一个条件的渲染器
// VXETable.renderer.add('FilterComplex', {
//   // 不显示底部按钮,使用自定义的按钮
//   showFilterFooter: false,
//   // 筛选模板
//   renderFilter (renderOpts, params) {
//     return <FilterComplex params={ params }></FilterComplex>
//   },
//   // 重置数据方法
//   filterResetMethod (params) {
//     const { options } = params
//     options.forEach((option) => {
//       option.data = { type: 'has', name: '' }
//     })
//   },
//   // 筛选数据方法
//   filterMethod (params) {
//     const { option, row, column } = params
//     const cellValue = row[column.field]
//     const { name } = option.data
//     if (cellValue) {
//       return cellValue.indexOf(name) > -1
//     }
//     return false
//   }
// })// 创建一个支持列内容的筛选
VXETable.renderer.add('FilterContent', {// 不显示底部按钮,使用自定义的按钮showFilterFooter: false,// 筛选模板renderFilter (renderOpts, params) {return [<FilterContent params={ params }></FilterContent>];},// 重置数据方法filterResetMethod (params) {const { options } = params;options.forEach((option) => {option.data = { vals: [],dict: option.data.dict ? option.data.dict : undefined};});},// 筛选数据方法filterMethod (params) {const { option, row, column } = params;const { vals } = option.data;const cellValue = row[column.field];console.log(cellValue,vals.includes(cellValue))return vals.includes(cellValue);},
});// // 创建一个复杂的筛选器
// VXETable.renderer.add('FilterExtend', {
//   // 不显示底部按钮,使用自定义的按钮
//   showFilterFooter: false,
//   // 筛选模板
//   renderFilter (renderOpts, params) {
//     return <FilterExtend params={ params }></FilterExtend>
//   },
//   // 重置数据方法
//   filterResetMethod (params) {
//     const { options } = params
//     options.forEach((option) => {
//       option.data = { vals: [], sVal: '', fMenu: '', f1Type: '', f1Val: '', fMode: 'and', f2Type: '', f2Val: '' }
//     })
//   },
//   // 筛选数据方法
//   filterMethod (params) {
//     const { option, row, column } = params
//     const cellValue = row[column.field]
//     const { vals, f1Type, f1Val } = option.data
//     if (cellValue) {
//       if (f1Type) {
//         return cellValue.indexOf(f1Val) > -1
//       } else if (vals.length) {
//         // 通过指定值筛选
//         return vals.includes(cellValue)
//       }
//     }
//     return false
//   }
// })

相关文章:

vxe-grid 全局自定义filter过滤器,支持字典过滤

一、vxe-table的全局筛选器filters的实现 官网例子&#xff1a;https://vxetable.cn/#/table/renderer/filter 进入之后&#xff1a;我们可以参照例子自行实现&#xff0c;也可以下载它的源码&#xff0c;进行调整 下载好后并解压&#xff0c;用vscode将解压后的文件打开。全局…...

ECharts 环形图组件封装

一、ECharts引入1.安装echarts包npm install echarts --save2.引入echarts这里就演示全局引入了&#xff0c;挂载到vue全局&#xff0c;后面使用时&#xff0c;直接使用 $echartsimport * as echarts from echarts Vue.prototype.$echarts echarts二、写echarts组件这里演示环…...

c++ 怎么调用python 提供的函数接口

在 C 中调用 Python 函数有多种方法&#xff0c;以下是其中的两种常见方法&#xff1a;使用 Python/C APIPython 提供了 C/C API&#xff0c;可以通过该 API 在 C 中调用 Python 函数。使用这种方法&#xff0c;需要先将 Python 解释器嵌入到 C 代码中&#xff0c;然后可以通过…...

【动态规划】背包问题(01背包,完全背包)

Halo&#xff0c;这里是Ppeua。平时主要更新C语言&#xff0c;C&#xff0c;数据结构算法......感兴趣就关注我吧&#xff01;你定不会失望。 &#x1f308;个人主页&#xff1a;主页链接 &#x1f308;算法专栏&#xff1a;专栏链接 我会一直往里填充内容哒&#xff01; &…...

记录 UE5 完全重新构建 UE C++项目

不知道搞了什么&#xff0c;C项目的实时代码编译罢工了&#xff0c;搞了半天都修不好&#xff0c;只能又重建了 UE5 版本为 v5.1.1 删除以下文件夹 /Binaries /Intermediate /SavedBinaries 文件夹是编译后的模块 Intermediate 文件夹里是中间层的C代码&#xff0c;完全由ue…...

java版云HIS系统源码 微服务架构支持VUE

云his系统源码 一个好的HIS系统&#xff0c;要具有开放性&#xff0c;便于扩展升级&#xff0c;增加新的功能模块&#xff0c;支撑好医院的业务的拓展&#xff0c;而且可以反过来给医院赋能&#xff0c;最终向更多的患者提供更好地服务。 私信了解更多&#xff01; 本套基于…...

苹果内购支付检验错误码

21000 The request to the App Store didn’t use the HTTP POST request method. 对App Store的请求没有使用HTTP POST请求方法。 21001 The App Store no longer sends this status code. App Store不再发送此状态代码。 21002 The data in the receipt-data property…...

day27_css

今日内容 上课同步视频:CuteN饕餮的个人空间_哔哩哔哩_bilibili 同步笔记沐沐霸的博客_CSDN博客-Java2301 零、 复习昨日 一、CSS 零、 复习昨日 见代码 一 、引言 1.1CSS概念 ​ 层叠样式表(英文全称&#xff1a;Cascading Style Sheets)是一种用来表现HTML&#xff08;标准通…...

智慧赋能,聚力开源——第四届OpenI/O 启智开发者大会开源治理专场顺利举办!

为汇聚国内外知名开源组织共同探讨中国开源生态建设及开源治理相关议题&#xff0c;推进产学研用开源合作&#xff0c;2月24日下午&#xff0c;第四届OpenI/O启智开发者大会在深圳人才研修院智汇中心举办以“构建开源联合体&#xff0c;共建开源生态”为主题的开源治理专场分论…...

Java工程师应该如何成长?

近几年&#xff0c;不少开发者会抱怨“面试造火箭&#xff0c;天天拧螺丝”&#xff0c;每天进行重复业务开发&#xff0c;似乎能力被日常工作限制&#xff0c;无法突破提高。 极客时间《Java 核心技术 36 讲》专栏作者杨晓峰认为&#xff0c;如果处于新手阶段&#xff0c;全面…...

【数据分析师求职面试指南】必备编程技能整理之Hive SQL必备用法

文章目录熟悉Python懂R语言掌握SQL大数据基础数据库常用类型多表查询更多聚合函数distinctcase when窗口函数动态更新一行变多行调优内容整理自《拿下offer 数据分析师求职面试指南》—徐粼著 第四章编程技能考查其他内容&#xff1a;【数据分析师求职面试指南】必备基础知识整…...

Maven - Linux 服务器 Maven 环境安装与测试

目录 一.引言 二.安装流程 1.获取安装包 2.解压并安装 3.配置环境 4.mvn 验证 三.测试踩坑 1.Permission denied 2.Plugin or dependencies Error 一.引言 通道机上的 java 项目需要 mvn package 提示没有 mvn 命令&#xff0c;下面记录下安装 maven 的全过程。 二.安…...

5G模块可以注册到4G,不能注册到5G;SIM卡接到5G手机是可以注册到5G网络的?

5G网络覆盖范围较小或者信号质量不佳。在这种情况下&#xff0c;您可以尝试移动到不同的位置&#xff0c;以获得更好的信号质量和覆盖范围。 目前&#xff0c;5G网络已经在全球多个国家和地区推出&#xff0c;并且在不断扩大覆盖范围。以下是一些已经拥有5G覆盖的主要地区&…...

宝塔webhook自动化打包vue项目时,npm不生效问题

文章目录&#x1f4cb;前言&#x1f3af;查看webhook配置的代码&#x1f3af;测试代码&#xff0c;检查输出内容&#x1f3af;解决方法&#x1f4cb;前言 这篇文章主要是记录和解决在宝塔面板中&#xff0c;webhook自动化打包vue项目时&#xff0c;npm不生效问题。说来奇怪&am…...

嵌入式 Linux进程间通信之信号量

目录 一、信号量 1、信号量概述 2、什么是信号量 3、信号量的分类 4、进程获取共享资源要执行的操作 5、System V IPC 机制&#xff1a;信号量 5.1 semget函数 5.2 semop函数 5.3 semctl函数 一、信号量 1、信号量概述 信号量集&#xff1a;由若干个信号组成的集合&a…...

谷粒学院开发(一):基础准备

商业模式 常见商业模式 B2C模式&#xff1a; 两个角色&#xff1a; 管理员&#xff1a;增加&#xff0c;修改&#xff0c;删除普通用户&#xff1a;查询 商家到用户&#xff0c;自己制作大量自有版权的视频&#xff0c;放在自有平台上&#xff0c;让用户付费。 这是这个项目使…...

Photoshop如何安装ZXP扩展插件?

Photoshop如何安装ZXP扩展插件呢&#xff1f;有一些小伙伴不会安装&#xff0c;今天介绍两种安装ZXP扩展的方法&#xff0c;希望对能帮助到大家。方法一&#xff1a;手动安装方式1&#xff09;把下载好的.zxp扩展名改为.zip&#xff0c;然后解压。Windows系统&#xff1a;C:\Us…...

c++面试技巧-基础篇4

1.面试官&#xff1a;在使用继承时需要注意哪些问题&#xff1f; 应聘者&#xff1a;在使用继承时需要注意以下内容。 &#xff08;1&#xff09;父类的构造函数和析构函数是不会被继承的&#xff0c;需要重写派生类的构造函数和析构函数。 &#xff08;2&#xff09;派生类…...

openEuler用户软件仓(EUR)介绍

什么是 EUR EUR(openEuler User Repo)是openEuler社区针对开发者推出的个人软件包托管平台&#xff0c;目的在于为开发者提供一个易用的软件包分发平台。 链接&#xff1a;https://eur.openeuler.openatom.cn/ 为什么我们需要 EUR 在操作系统的世界&#xff0c;软件包是一等…...

MySQL的图形化界面开发工具DataGrip的下载安装

在日常的开发中&#xff0c;会借助于MySQL的图形化界面&#xff0c;来简化开发&#xff0c;提高开发效率。目前mysql主流的图形化界面工具&#xff0c;有Navicat、SQLyog、DataGrip等&#xff0c;最后一种DataGrip&#xff0c;这种图形化界面工具&#xff0c;功能更加强大&…...

Vue记事本应用实现教程

文章目录 1. 项目介绍2. 开发环境准备3. 设计应用界面4. 创建Vue实例和数据模型5. 实现记事本功能5.1 添加新记事项5.2 删除记事项5.3 清空所有记事 6. 添加样式7. 功能扩展&#xff1a;显示创建时间8. 功能扩展&#xff1a;记事项搜索9. 完整代码10. Vue知识点解析10.1 数据绑…...

C++实现分布式网络通信框架RPC(3)--rpc调用端

目录 一、前言 二、UserServiceRpc_Stub 三、 CallMethod方法的重写 头文件 实现 四、rpc调用端的调用 实现 五、 google::protobuf::RpcController *controller 头文件 实现 六、总结 一、前言 在前边的文章中&#xff0c;我们已经大致实现了rpc服务端的各项功能代…...

CTF show Web 红包题第六弹

提示 1.不是SQL注入 2.需要找关键源码 思路 进入页面发现是一个登录框&#xff0c;很难让人不联想到SQL注入&#xff0c;但提示都说了不是SQL注入&#xff0c;所以就不往这方面想了 ​ 先查看一下网页源码&#xff0c;发现一段JavaScript代码&#xff0c;有一个关键类ctfs…...

STM32标准库-DMA直接存储器存取

文章目录 一、DMA1.1简介1.2存储器映像1.3DMA框图1.4DMA基本结构1.5DMA请求1.6数据宽度与对齐1.7数据转运DMA1.8ADC扫描模式DMA 二、数据转运DMA2.1接线图2.2代码2.3相关API 一、DMA 1.1简介 DMA&#xff08;Direct Memory Access&#xff09;直接存储器存取 DMA可以提供外设…...

【android bluetooth 框架分析 04】【bt-framework 层详解 1】【BluetoothProperties介绍】

1. BluetoothProperties介绍 libsysprop/srcs/android/sysprop/BluetoothProperties.sysprop BluetoothProperties.sysprop 是 Android AOSP 中的一种 系统属性定义文件&#xff08;System Property Definition File&#xff09;&#xff0c;用于声明和管理 Bluetooth 模块相…...

3403. 从盒子中找出字典序最大的字符串 I

3403. 从盒子中找出字典序最大的字符串 I 题目链接&#xff1a;3403. 从盒子中找出字典序最大的字符串 I 代码如下&#xff1a; class Solution { public:string answerString(string word, int numFriends) {if (numFriends 1) {return word;}string res;for (int i 0;i &…...

Mobile ALOHA全身模仿学习

一、题目 Mobile ALOHA&#xff1a;通过低成本全身远程操作学习双手移动操作 传统模仿学习&#xff08;Imitation Learning&#xff09;缺点&#xff1a;聚焦与桌面操作&#xff0c;缺乏通用任务所需的移动性和灵活性 本论文优点&#xff1a;&#xff08;1&#xff09;在ALOHA…...

Fabric V2.5 通用溯源系统——增加图片上传与下载功能

fabric-trace项目在发布一年后,部署量已突破1000次,为支持更多场景,现新增支持图片信息上链,本文对图片上传、下载功能代码进行梳理,包含智能合约、后端、前端部分。 一、智能合约修改 为了增加图片信息上链溯源,需要对底层数据结构进行修改,在此对智能合约中的农产品数…...

Java + Spring Boot + Mybatis 实现批量插入

在 Java 中使用 Spring Boot 和 MyBatis 实现批量插入可以通过以下步骤完成。这里提供两种常用方法&#xff1a;使用 MyBatis 的 <foreach> 标签和批处理模式&#xff08;ExecutorType.BATCH&#xff09;。 方法一&#xff1a;使用 XML 的 <foreach> 标签&#xff…...

SQL慢可能是触发了ring buffer

简介 最近在进行 postgresql 性能排查的时候,发现 PG 在某一个时间并行执行的 SQL 变得特别慢。最后通过监控监观察到并行发起得时间 buffers_alloc 就急速上升,且低水位伴随在整个慢 SQL,一直是 buferIO 的等待事件,此时也没有其他会话的争抢。SQL 虽然不是高效 SQL ,但…...