UNPKG

vue-data-tables

Version:

A simple, customizable and pageable table, based on vue2 and element-ui.

600 lines (537 loc) 16.1 kB
# 过滤 `vue-data-tables` 接受属性 `filters` 来现实对表格内容的过滤。传入 `filters` 的值是一个列表,其每一项称为一个`过滤项`,格式如下: ``` // 以类似typescript的定义格式描述 [ { // 一个过滤项 prop?: String | Array | Undefined; // 用于指定这个过滤项是针对哪个(些)列的 value: any; // 过滤值 filterFn?: (row, filter) => Boolean; // 过滤函数,`data-tables` 用此函数自定义过滤规则 [key: string]: any; // 如果需要,`data-tables-server` 可添加任意属性, // 用于定制数据更新的 http 请求。 }, ... ] ``` filterFn 的第一个参数 row 代表列数据,第二个参数 filter 则是本过滤项。 ## data-tables 的过滤原理 `data-tables` 根据 `filters` 传入的`过滤项`列表中的每一个`过滤项`生成一个 [Array.prototype.filter](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/filter) 的过滤函数,并逐项调用 [Array.prototype.filter](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/filter) 来过滤数据, 其逻辑如下: ![](../_media/filter.svg) * 如果 value 值是 `[]`, `undefined` 或 `""`, 则不做过滤。 * 如果 filterFn 不存在,那么根据 value 和 prop 的类型, `data-tables` 会构造不同的过滤函数,即图中的F1 ~ F4。 * prop 是 String, value 不是 Array (`F1`) * prop 是 String, value 是 Array (`F2`) * prop 是 Array 或 undefined, value 不是 Array (`F3`) * prop 是 Array 或 undefined, value 是 Array (`F4`) * 如果 filterFn 存在的话, 则用 filterFn 来过滤 > 从流程图中可以看出来,`prop 是 undefined` 可以看作是 `prop 是 Array` 的一种特殊情况。 ### prop 是 String, value 不是 Array (`F1`) 过滤函数 `F1` 逻辑为: ``` 在`参与比较的值`都 string 化 (简单的通过 toString 函数) 并忽略大小写的前提下, row 的 prop 属性值(row[prop]) 如果包含过滤值(value),则保留这项。 ``` 比如下例中,我们对属性 `name` 进行过滤,过滤值为 `us`。那么只有 name 只为 'USA' 的第一条数据会保留在表中。 ```html /*vue*/ <desc> 把input里的值改为 `us` 尝试下 </desc> <template> <div> <div style='margin-bottom: 10px'> <el-row> <el-col :span='6'> <el-input v-model='filters[0].value' placeholder='input "us" to try'></el-input> </el-col> </el-row> </div> <data-tables :data='data' :filters='filters'> <el-table-column v-for="title in titles" :prop="title.prop" :label="title.label" :key="title.prop" > </el-table-column> </data-tables> </div> </template> <script> export default { data() { return { data: [ { name: 'USA', rank: 1 }, { name: 'China', rank: 2 } ], titles: [{ prop: 'name', label: 'Name' }, { prop: 'rank', label: 'Rank' }], filters: [ { prop: 'name', value: '' } ] } } } </script> ``` ### prop 是 String, value 是 Array (`F2`) 过滤函数 `F2` 逻辑为: ``` 在`参与比较的值`都 string 化 (简单的通过 toString 函数) 并忽略大小写的前提下, row 的 prop 属性值(row[prop])如果包含多个过滤值(value)中的任意一个,则保留这项。 ``` 比如下例中,我们对属性 `name` 进行过滤,过滤值为 `us` 和 `china`时,两条数据都会被保留。 ```html /*vue*/ <desc> 选择 China 和 USA 来尝试下 </desc> <template> <div> <div style='margin-bottom: 10px'> <el-row> <el-col :span='6'> <el-checkbox-group v-model='filters[0].value'> <el-checkbox label='China'></el-checkbox> <el-checkbox label='USA'></el-checkbox> </el-checkbox-group> </el-col> </el-row> </div> <data-tables :data='data' :filters='filters'> <el-table-column v-for="title in titles" :prop="title.prop" :label="title.label" :key="title.prop" > </el-table-column> </data-tables> </div> </template> <script> export default { data() { return { data: [ { name: 'USA', rank: 1 }, { name: 'China', rank: 2 } ], titles: [{ prop: 'name', label: 'Name' }, { prop: 'rank', label: 'Rank' }], filters: [ { prop: 'name', value: [] } ] } } } </script> ``` ### prop 是 Array, value 不是 Array (`F3`) 过滤函数 `F3` 逻辑为: ``` 在`参与比较的值`都 string 化 (简单的通过 toString 函数) 并忽略大小写的前提下, row 的 多个 prop 属性值(row[prop])中有一个包含过滤值(value),则保留这项。 ``` 比如下例中,我们对属性 `name` 和 `rank` 进行过滤,过滤值为 `us` 或 `1`, 第一条数据会保留在表中。 ```html /*vue*/ <template> <div> <div style='margin-bottom: 10px'> <el-row> <el-col :span='10'> <el-input v-model='filters[0].value' placeholder='input "us" or "1" to try'></el-input> </el-col> </el-row> </div> <data-tables :data='data' :filters='filters'> <el-table-column v-for="title in titles" :prop="title.prop" :label="title.label" :key="title.prop" > </el-table-column> </data-tables> </div> </template> <script> export default { data() { return { data: [ { name: 'USA', rank: 1 }, { name: 'China', rank: 2 } ], titles: [{ prop: 'name', label: 'Name' }, { prop: 'rank', label: 'Rank' }], filters: [ { prop: ['name', 'rank'], value: '' } ] } } } </script> ``` ### prop 是 Array, value 是 Array (`F4`) > 这个场景似乎令人费解,所以不建议使用,如果没有特别需求,可以跳过这一节。 过滤函数 `F4` 逻辑为: ``` 在`参与比较的值`都 string 化 (简单的通过 toString 函数) 并忽略大小写的前提下, row 的多个 prop 属性值(row[prop])中有一个包含多个过滤值(value)中的任意一个,则保留这项。 ``` 比如下例中,我们又有2条数据, 我们对属性 `name` 和 `neighbor` 进行过滤,过滤值为 'China' 和 'Canada' 时,两条数据都会被保留。 ```html /*vue*/ <template> <div> <div style='margin-bottom: 10px'> <el-row> <el-col :span='12'> <el-checkbox-group v-model='filters[0].value'> <el-checkbox label='China'></el-checkbox> <el-checkbox label='USA'></el-checkbox> <el-checkbox label='Canada'></el-checkbox> <el-checkbox label='Russia'></el-checkbox> </el-checkbox-group> </el-col> </el-row> </div> <data-tables :data='data' :filters='filters'> <el-table-column v-for="title in titles" :prop="title.prop" :label="title.label" :key="title.prop" > </el-table-column> </data-tables> </div> </template> <script> export default { data() { return { data: [ { name: 'USA', neighbor: 'Canada' }, { name: 'China', neighbor: 'Russia' } ], titles: [{ prop: 'name', label: 'Name' }, { prop: 'neighbor', label: 'Neighbor' }], filters: [ { prop: ['name', 'neighbor'], value: [] } ] } } } </script> ``` ### prop 是 `undefined` 如上文提到的,`prop 是 undefined` 可以认为是 `prop 是 Array` 的一种特殊情况。 * 如果未设置 `data-tables` 的 `filterProps` 属性, 那么 `prop` 会被赋值为 data 队列里第一个元素的所有的属性。过滤逻辑按 `prop 为一个 Array` 来处理 比如下例中,我们没有设置过滤项的 prop 值,此时 prop 被自动认为是 `data[0]` 的所有属性,即: name 和 rank。 ```html /*vue*/ <template> <div> <div style='margin-bottom: 10px'> <el-row> <el-col :span='10'> <el-input v-model='filters[0].value' placeholder='input "us" or "1" to try'></el-input> </el-col> </el-row> </div> <data-tables :data='data' :filters='filters'> <el-table-column v-for="title in titles" :prop="title.prop" :label="title.label" :key="title.prop" > </el-table-column> </data-tables> </div> </template> <script> export default { data() { return { data: [ { name: 'USA', rank: 1 }, { name: 'China', rank: 2 } ], titles: [{ prop: 'name', label: 'Name' }, { prop: 'rank', label: 'Rank' }], filters: [ { value: '' } ] } } } </script> ``` * 有些情况下,我们需要灵活性,不想让 `data-tables` 自动为我们赋值,这时可以使用 `data-tables` 的 `filterProps` 属性来定义缺省的 prop 列表。 例如下例中,2条数据的 `members` 属性都为 `['USA', 'China']`, 如果我们不设置过滤项的 prop, 然后用 `us` 去过滤,会发现列表不会变化,因为 `members` 也被用于了过滤,所有的列都符合过滤条件。设置 `filterProps` 可以解决这个问题。 > 当然,我们可以通过为每一个过滤项配置 prop 属性来处理,但是如果有多个过滤项,`filterProps` 来做全局配置会更方便。 ```html /*vue*/ <desc> 去选,勾选的 filterProps,来体验区别。 </desc> <template> <div> <div> <el-checkbox v-model='setFilterProps'> filterProps</el-checkbox> </div> <div style='margin: 10px 0'> <el-row align='middle' type='flex' :gutter='20'> <el-col :span='10'> <el-input v-model='filters[0].value' placeholder='input "us" or "1" to try'></el-input> </el-col> <el-col :span='10'> <el-checkbox-group v-model='filters[1].value'> <el-checkbox label='China'></el-checkbox> <el-checkbox label='USA'></el-checkbox> </el-checkbox-group> </el-col> </el-row> </div> <data-tables :data='data' :filters='filters' :filter-props='setFilterProps ? ["name", "rank"] : undefined'> <el-table-column v-for="title in titles" :prop="title.prop" :label="title.label" :key="title.prop" > </el-table-column> </data-tables> </div> </template> <script> export default { data() { return { data: [ { name: 'USA', rank: 1, members: ['USA', 'China'] }, { name: 'China', rank: 2, members: ['USA', 'China'] } ], setFilterProps: true, titles: [{ prop: 'name', label: 'Name' }, { prop: 'rank', label: 'Rank' }, { prop: 'members', label: 'Members' }], filters: [ { value: '' }, { value: [] } ] } } } </script> ``` ### 使用 filterFn 在一些情况下,默认的比较方式不能满足过滤要求,此时可以使用 filterFn, 来自定义过滤函数。 比如下例中,data 里的日期格式是 Data String 化之后的值,展示的时候,我们将其转成了,方便阅读的 `yyyy-MM-dd` 格式。过滤的时候,用户肯定是期望也使用 `yyyy-MM-dd` 的格式来过滤。此时普通的字符串比较就解决不了问题了,我们需要 filterFn。 ```html /*vue*/ /*no-boot-code*/ <desc> 键入 2017-7-2 试一试 </desc> <template> <div> <el-input style='margin-bottom: 10px; width: 200px;' v-model='filters[0].value'></el-input> <data-tables :data='data' :filters='filters'> <el-table-column prop="flow_no" label="NO." sortable="custom"> </el-table-column> <el-table-column prop="content" label="Content." sortable="custom"> </el-table-column> <el-table-column prop="date" label="Date" sortable="custom"> <template slot-scope="scope"> <div>{{getDate(scope.row.date)}}</div> </template> </el-table-column> </data-tables> </div> </template> <script> Vue.use(DataTables) let data = [{ "content": "Water flood", "flow_no": "FW201601010001", "date": "Wed Jul 08 2017 09:18:41 GMT+0800 (CST)" }, { "content": "Lock broken", "flow_no": "FW201601010002", "date": "Wed Jul 02 2017 14:19:29 GMT+0800 (CST)" }, { "content": "Help to buy some drinks", "flow_no": "FW201601010003", "date": "Wed Jul 03 2017 19:08:54 GMT+0800 (CST)" }] let titles = [{ prop: "flow_no", label: "NO." }, { prop: "content", label: "Content" }, { prop: "flow_type", label: "Type" }] export default { data() { return { data, titles, filters: [ { value: '', filterFn: (row, filter) => { return Object.keys(row).some(prop => { if (prop === 'date') { return this.getDate(row.date).indexOf(filter.value) > -1 } else { return row[prop].toLowerCase().indexOf(filter.value.toLowerCase()) > -1 } }) } } ] } }, methods: { getDate(date) { let elDate = new Date(date) return elDate.getFullYear() + '-' + (elDate.getMonth() + 1) + '-' + elDate.getDate() } } } </script> ``` ## data-tables-server 的过滤 与 [data-tables-server 的排序](zh-cn/sort.md?id=data-tables-server-的排序) 一样, 本质上 `data-tables-server` 也不参与数据的过滤工作, 过滤也只发生在后台,`data-tables-server` 只是需要把过滤规则发给后台。 在过滤条件变化的时,`data-tables-server` 发射一个类型为 `filters` 的 `query-change` 事件,外层组件需要监听该事件,并把向服务器发送请求来获取数据。 `query-info` 事件发射的数据的 `filter` 字段的值就等于 `this.filters`, 除了 value 字段是必须外,可以在定义 `this.filters` 的时候添加任何需要的字段,为后台的过滤提供其需要的信息。 下例中,由于后台需要一个 `search_prop` 属性来标记过滤的属性,我们就在定义过滤项的时候添加了这个属性。 ```html /*vue*/ <template> <div> <div style='margin-bottom: 10px; width: 200px;'> <el-input v-model='filters[0].value'></el-input> </div> <data-tables-server :data='data' :total='total' :filters='filters' :pagination-props='{ pageSizes: [5, 10, 15] }' @query-change='loadData'> <el-table-column v-for="title in titles" :prop="title.prop" :label="title.label" :key="title.label"> </el-table-column> </data-tables-server> </div> </template> <script> export default { data() { return { data, titles, total: 0, filters: [ { value: '', 'search_prop': 'flow_no' // define search_prop for backend usage. } ] } }, methods: { async loadData(queryInfo) { queryInfo.type === 'filter' && this.$message(`search_prop: ${queryInfo.filters[0].search_prop}, value: ${queryInfo.filters[0].value}`) let { data, total } = await http(queryInfo) this.data = data this.total = total } } } </script> ```