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

vxe-grid 全局自定义filter过滤器,支持字典过滤官网例子 https vxetable cn table renderer filter 进入之后 我们可以参照例子自行实现 也可以下载它的源码 进行调整下载好后并解压 用 vscode 将解压后的文件打开

大家好,欢迎来到IT知识分享网。

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

在这里插入图片描述

下载好后并解压,用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, watch } 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] demo1.option = option } } const changeOptionEvent = () => { 
      const { 
      params } = props const { 
      option } = demo1 if (params && option) { 
      const { 
      $panel } = params const checked = !!option.data $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() watch(()-> props.params, ()=>{ 
      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,watch } 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 } = props if (params) { 
    const { 
    $table, column } = params const { 
    fullData } = $table.getTableData() const option = column.filters[0] const { 
    vals } = option.data const colValList = Object.keys(XEUtils.groupBy(fullData, column.field)).map((val) => { 
    return { 
    checked: vals.includes(val), value: 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() watch(()-> props.params, ()=>{ 
    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,watch } 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 } = demo1 if (option) { 
      return option.data.sVal ? colValList.filter(val => val.indexOf(option.data.sVal) > -1) : colValList } return [] }) const load = () => { 
      const { 
      params } = props if (params) { 
      const { 
      $table, column } = params const { 
      fullData } = $table.getTableData() const option = column.filters[0] const colValList = Object.keys(XEUtils.groupBy(fullData, column.field)) demo1.option = option demo1.colValList = colValList } } const sAllEvent = () => { 
      const { 
      option } = demo1 if (option) { 
      const { 
      data } = option if (data.vals.length > 0) { 
      data.vals = [] } else { 
      data.vals = demo1.colValList } } } const sItemEvent = (val: string) => { 
      const { 
      option } = demo1 if (option) { 
      const { 
      data } = option const vIndex = data.vals.indexOf(val) if (vIndex === -1) { 
      data.vals.push(val) } else { 
      data.vals.splice(vIndex, 1) } } } const confirmFilterEvent = () => { 
      const { 
      params } = props const { 
      option } = demo1 if (params && option) { 
      const { 
      data } = option const { 
      $panel } = params data.f1 = '' data.f2 = '' $panel.changeOption(null, true, option) $panel.confirmFilter() } } const resetFilterEvent = () => { 
      const { 
      params } = props if (params) { 
      const { 
      $panel } = params $panel.resetFilter() } } const childMenuClickEvent = (cItem: CaseItem) => { 
      VXETable.modal.alert({ 
      content: cItem.label }) } load() watch(()-> props.params, ()=>{ 
      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, watch } 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 } = props if (params) { 
    const { 
    column } = params const option = column.filters[0] demo1.option = option } } const changeOptionEvent = () => { 
    const { 
    params } = props const { 
    option } = demo1 if (params && option) { 
    const { 
    $panel } = params const checked = !!option.data.name $panel.changeOption(null, checked, option) } } const confirmEvent = () => { 
    const { 
    params } = props if (params) { 
    const { 
    $panel } = params $panel.confirmFilter() } } const resetEvent = () => { 
    const { 
    params } = props if (params) { 
    const { 
    $panel } = params $panel.resetFilter() } } load() watch(()-> props.params, ()=>{ 
    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 } = params options.forEach((option) => { 
    option.data = '' }) }, // 重置筛选复原方法(当未点击确认时,该选项将被恢复为默认值) filterRecoverMethod ({ 
    option }) { 
    option.data = '' }, // 筛选方法 filterMethod (params) { 
    const { 
    option, row, column } = params const { 
    data } = option const 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 } = 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: [], sVal: '' } }) }, // 筛选数据方法 filterMethod (params) { 
    const { 
    option, row, column } = params const { 
    vals } = option.data const 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 } = 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 } }) 

二、自行优化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-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 v-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,watch } 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(); watch(()-> props.params, ()=>{ 
      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-input v-model="demo1.option.data.sVal" type="text" placeholder="支持回车筛选" @keyup="keyupEvent" @input="changeOptionEvent" ></vxe-input> </div> </template> <script lang="ts"> import { 
      defineComponent, PropType, reactive,watch } 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(); watch(()-> props.params, ()=>{ 
      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 // } // }) 

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/148358.html

(0)
上一篇 2025-03-31 19:10
下一篇 2025-03-31 19:15

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信