Add a low cost column hide controller to your table page
Recently, I received a demand, the background is the user feedback that there are generally too many columns in the table. Different user groups focus on different columns, and they expect to customize and control which columns are displayed.
This requirement is not complicated and can be easily implemented with V-IF control. The scary thing is that there are hundreds of such pages, and each page may contain 20-40 different columns. It would be too elegant to control each column with a V-IF statement.
implementation
Core ideas
Because of the large amount of code, the best way to achieve the lowest cost implementation is to register a component with the same name in the entry file to override the original table component without modifying the original tags and attributes. The following code uses the Element library example
import CtrlTable from '@/components/CtrlTable'
Vue.component('el-table', CtrlTable)
Copy the code
Next to write CtrlTable this component, our core appeal is to modify the stock of code as little as possible, so here to first attR and event monitor pass down
CtrlTable.vue
import { Table } from 'element-ui'
export default {
name: 'CtrlTable'.components: {
'origin-table': Table
},
render (h) {
return h('origin-table', {
attrs: this.$attrs,
ref: 'table'.on: this.$listeners
}, this.$slots.default)
}
}
Copy the code
The above component imports the Table component from the Element-UI and returns it directly in the render function. This component is meant to be an intermediate component that accepts attrs and event listeners already written in the el-table tag in the old code. They are then passed to the real El-Table component. At this point, you can look at the pages that contain the El-Table in the page, and they appear in the browser normally. They look exactly the same as before, but in fact there is an extra layer in the middle.
Completion implementation
Add the control statement, which is actually quite simple. Just filter $slots.default and receive checked props for which column to display
CtrlTable.vue
import { Table } from 'element-ui'
export default {
name: 'CtrlTable'.components: {
'origin-table': Table
},
props: {
checked: {
type: [Array.undefined].default: undefined}},computed: {
columns () {
if (!this.checked) {
return this.$slots.default
}
return this.$slots.default.filter(item= > (
this.checked.includes(item.componentOptions && item.componentOptions.propsData.label) || ! (item.componentOptions && item.componentOptions.propsData.label) || (item.componentOptions && item.componentOptions.propsData.label ==='operation')
))
}
},
render (h) {
return h('origin-table', {
attrs: this.$attrs,
ref: 'table'.on: this.$listeners
}, this.columns)
}
}
Copy the code
Note that one little detail is that if you don’t have checked, it will render all of the $slots.default. The nice thing about this is that if you have pages that don’t need column control, you can still render all of the columns as long as you don’t pass checked.
Next is the implementation of the controller, drawn into a mixin, the logic is relatively simple, directly paste code
columnsCtrl.js
import Setting from '@/components/Setting'
const CONDITION_STORAGE_KEY = 'localstorage_key_demo'
export default {
components: {
Setting
},
data: () = > ({
tableCondition: [].tableChecked: []
}),
mounted () {
this.__initCondition()
},
methods: {
__initCondition () {
const {
table
} = this.$refs
if (table && table.$slots && table.$slots.default.length) {
this.tableCondition = table.$slots.default.map(item= > item.componentOptions && item.componentOptions.propsData.label).filter(item= >!!!!! item && item ! = ='operation')}this.__checkView(this.__getCache('table'))
},
__checkView (checked) {
const { table } = this.$refs
this.tableChecked = checked || table.$slots.default.map(item= > item.componentOptions && item.componentOptions.propsData.label).filter(item= >!!!!! item && item ! = ='operation')
},
__getCache () {
const { name } = this.$route
const cacheKey = `${name}`
const cache = JSON.parse(localStorage.getItem(CONDITION_STORAGE_KEY))
if (cache && cache[cacheKey]) {
return cache[cacheKey]
}
return null
},
handleSettingShow (cb) {
const cache = this.__getCache()
cb && cb(cache || [...this.tableCondition])
},
handleSettingSave ({ cb, checked }) {
const { name } = this.$route
const cacheKey = name
let cache = JSON.parse(localStorage.getItem(CONDITION_STORAGE_KEY))
if(! cache) { cache = {} } cache[cacheKey] = [...checked]localStorage.setItem(CONDITION_STORAGE_KEY, JSON.stringify(cache))
this.__checkView(checked)
cb && cb()
}
}
}
Copy the code
The controller component part of the code is relatively simple, omitted here
demo
The complete code
Copy the code