vxe-grid筛选渲染
index.vue
// index.vue <template> <div style="height: 400px"> <vxe-grid ref="xGrid" v-bind="gridOptions"></vxe-grid> </div> </template> <script> import './vxedeom/vxeTable' export default { data () { return { gridOptions: { highlightHoverRow: true, autoResize: true, height: 'auto', border: true, loading: false, editConfig: { trigger: 'dblclick', mode: 'cell', showStatus: true, showIcon: false, activeMethod: this.activeCellMethod }, mouseConfig: { selected: true, area: true, extension: true }, columns: [ { type: 'seq' }, { field: 'name', title: 'Name', filters: [{ data: [] }], filterRender: { name: 'FilterInput' } }, { field: 'role', title: 'Role', editRender: { name: 'RoleCell', events: { click: this.getCellData } }, filters: [{ data: { vals: [], sVal: '' } }], filterRender: { name: 'FilterContent' } }, { field: 'sex', title: 'Sex' }, { field: 'age', title: '年龄', filters: [{ data: { type: 'lt', name: '' } }], filterRender: { name: 'FilterComplex' } } ], data: [] } } }, mounted () { this.getData().then((data) => { this.gridOptions.data = data }) }, methods: { activeCellMethod () { return true }, getCellData (params) { console.log(params) }, getData () { return new Promise((resolve) => { const list = [ { name: 'Test1', role: '前端', sex: '男', age: 13 }, { name: 'Test2', role: '后端', sex: '男', age: 11 }, { name: 'Test3', role: '测试', sex: '男', age: 15 }, { name: 'Test4', role: '设计师', sex: '女', age: 12 }, { name: 'Test5', role: '前端', sex: '男', age: 13 }, { name: 'Test6', role: '前端', sex: '男', age: 16 }, { name: 'Test7', role: '前端', sex: '男', age: 22 } ] resolve(list) }) } } } </script>
vxeTable.js
// vxeTable.js import XEUtils from 'xe-utils' import VXETable from 'vxe-table' import FilterInput from './FilterInput' import FilterContent from './FilterContent' import FilterComplex from './FilterComplex' // table.js 定义组件 VXETable.renderer.add('FilterContent', { // 不显示底部按钮,使用自定义的按钮 isFooter: false, // 筛选模板 renderFilter (h, renderOpts, params) { return [ <FilterContent params={ params }></FilterContent> ] }, // 重置数据方法 filterResetMethod ({ options }) { options.forEach(option => { option.data = { vals: [], sVal: '' } }) }, // 筛选数据方法 filterMethod ({ option, row, column }) { const { vals } = option.data console.log(vals) // eslint-disable-next-line no-undef let cellValue = XEUtils.get(row, column.property) if (column.property === 'customerItemCode') { cellValue = cellValue.customerItemCode || cellValue } return vals.includes(cellValue) } }) // 条件过滤 VXETable.renderer.add('FilterComplex', { // 不显示底部按钮,使用自定义的按钮 isFooter: false, // 筛选模板 renderFilter (h, renderOpts, params) { const { events } = renderOpts return [ <FilterComplex params={ params } events={events}></FilterComplex> ] }, // 重置数据方法 filterResetMethod ({ options }) { // console.log(options) options.forEach(option => { option.data = { type: 'lt', name: '' } }) }, // 筛选数据方法 filterMethod ({ option, row, column }) { // console.log(option, row, column) const cellValue = parseFloat(XEUtils.get(row, column.property)) // console.log(cellValue) const { name, type } = option.data if (!name) { return true } if (type === 'lt') { return cellValue < parseInt(name) } else if (type === 'eq') { return cellValue === parseInt(name) } else if (type === 'gt') { return cellValue > parseInt(name) } return false } }) VXETable.renderer.add('FilterInput', { // 筛选模板 renderFilter (h, renderOpts, params) { // console.log(params) return [ <FilterInput params={ params }></FilterInput> ] }, // 筛选方法 filterMethod ({ option, row, column }) { const { data } = option const cellValue = row[column.property] if (cellValue) { return cellValue.indexOf(data) > -1 } return false } })
接下来是组件模板
FilterInput.vue
// FilterInput.vue <template> <div class="my-filter-input" style="text-align: right"> <vxe-input type="text" v-model="option.data" placeholder="支持回车筛选" @keyup="keyupEvent" @input="changeOptionEvent"></vxe-input> </div> </template> <script> export default { name: 'FilterInput', props: { params: Object, }, data () { return { column: null, option: null } }, created () { this.load() }, methods: { load () { const { column } = this.params const option = column.filters[0] this.column = column this.option = option }, changeOptionEvent () { // console.log('输入') const { params, option } = this const { $panel } = params const checked = !!option.data $panel.changeOption(null, checked, option) }, keyupEvent ({ $event }) { const { params } = this const { $panel } = params if ($event.keyCode === 13) { $panel.confirmFilter() } } } } </script> <style scoped> .my-filter-input { padding: 10px; } </style>
FilterComplex.vue
// FilterComplex.vue <template> <div class="my-filter-complex"> <div class="my-fc-type"> <vxe-radio v-model="option.data.type" name="fType" label="lt">小于</vxe-radio> <vxe-radio v-model="option.data.type" name="fType" label="eq">等于</vxe-radio> <vxe-radio v-model="option.data.type" name="fType" label="gt">大于</vxe-radio> </div> <div class="my-fc-name"> <vxe-input v-model="option.data.name" type="text" placeholder="请输入数量" @input="changeOptionEvent()"></vxe-input> </div> <div class="my-fc-footer" style="text-align: right"> <vxe-button :disabled="!option.data.name" type="text" @click="confirmEvent">筛选</vxe-button> <vxe-button style="margin-left: 0" type="text" @click="resetEvent">重置</vxe-button> </div> </div> </template> <script> // import XEUtils from 'xe-utils' export default { name: 'FilterComplex', props: { params: Object, events: Object }, data () { return { size: 'mini', // 被所有子组件继承 size column: null, option: null } }, created () { this.load() }, methods: { load () { const { column } = this.params console.log(this.params) const option = column.filters[0] this.column = column this.option = option }, changeOptionEvent () { console.log('输入') const { params, option } = this const { $panel } = params const checked = !!option.data.name $panel.changeOption(null, checked, option) }, confirmEvent () { console.log(this.params) const { $panel, column } = this.params console.log(column) $panel.confirmFilter() }, resetEvent () { // eslint-disable-next-line no-unused-vars const { $panel } = this.params $panel.resetFilter() } } } </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>
FilterContent.vue
// FilterContent.vue <template> <div class="my-filter-content"> <div class="my-fc-search"> <div class="my-fc-search-top"> <vxe-input v-model="option.data.sVal" placeholder="搜索" @input="searchEvent" suffix-icon="fa fa-search"></vxe-input> </div> <div class="my-fc-search-content"> <template v-if="valList.length"> <ul class="my-fc-search-list my-fc-search-list-head"> <li class="my-fc-search-item"> <vxe-checkbox v-model="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 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" style="text-align: right"> <vxe-button type="text" @click="confirmFilterEvent">筛选</vxe-button> <vxe-button style="margin-left: 0" type="text" @click="resetFilterEvent">重置</vxe-button> </div> </div> </template> <script> import XEUtils from 'xe-utils' export default { name: 'FilterContent', props: { params: Object }, data () { return { size: 'mini', isAll: false, option: null, colValList: [], valList: [] } }, created () { this.load() }, methods: { load () { const { $table, column } = this.params const { fullData } = $table.getTableData() const option = column.filters[0] const { vals } = option.data let colValList = Object.keys(XEUtils.groupBy(fullData, column.property)).map(val => { return { checked: vals.includes(val), value: val } }) const columnsArr = [] console.log(XEUtils.groupBy(fullData, column.property)) if (column.property === 'customerItemCode') { fullData.forEach(item => { // console.log(item['customerItemCode']['customerItemCode']) const toValue = item.customerItemCode.customerItemCode if (toValue) { columnsArr.push({ checked: vals.includes(toValue), value: toValue }) } }) if (columnsArr && columnsArr.length) { colValList = columnsArr } } console.log(colValList) this.option = option this.colValList = colValList this.valList = colValList }, searchEvent () { const { option, colValList } = this this.valList = option.data.sVal ? colValList.filter(item => item.value.indexOf(option.data.sVal) > -1) : colValList }, changeAllEvent () { const { isAll } = this this.valList.forEach(item => { item.checked = isAll }) }, confirmFilterEvent (evnt) { const { params, option, valList } = this const { data } = option const { $panel } = params data.vals = valList.filter(item => item.checked).map(item => item.value) console.log(this.events) $panel.changeOption(evnt, true, option) $panel.confirmFilter() }, resetFilterEvent () { const { $panel } = this.params $panel.resetFilter() } } } </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; */ } .my-fc-search-content ul { text-align: left; } </style>
参考链接 https://blog.csdn.net/weixin_45939191/article/details/122214060
浙公网安备 33010602011771号