近日,我接到一个产品需求,一个基于Material开发的后台系统,前期还好,但是越使用越发现坑多,很多功能都不支持,比如今天我遇到的这样一个需求:
一个可以打开的二级表格,同时一级表格的复选框可以控制当前二级表格的全选与非全选,当然,当下面的所有勾选框全部选中之后,上面的以及表格复选框也要保持选中状态。这个功能在Material内是不提供的,没办法,手写吧。
首先咱们实现二级表格的打开功能,实现原理很简单,随意一级还是二级表格,其实都是表格罢了,那么我们控制表格的数组不就行了嘛,比如一级表格有2个,打开当前表格之后,当前表格下面有四个子表格,咱们把表格数组相加就成了,同时控制一级二级表格的样式,话不多说,直接上代码(复选框的全选与费全选我也一并贴上来了,请注意看注释,代码中使用了Font Awesome, i标签为字体图标):
<template> <div> <md-table v-model="people" md-card> <md-table-row slot="md-table-row" slot-scope="{ item }"> <md-table-cell md-label="" md-sort-by="select" style="width: 10px"> <md-checkbox v-model="fatherArray" :disabled="remberFatherArr.indexOf(item.index) == -1 && item.index.indexOf('-') == -1" :class="{'change_checkbox_color':item.index.indexOf('-') > -1}" @change="showArray(item)" :value="item.index"></md-checkbox> </md-table-cell> <md-table-cell md-label="角色 / 成员" md-sort-by="name"> <i class="fa fa-caret-down fa-lg filter_icon lmr cur" :class="{'fa-caret-down':remberFatherArr.indexOf(item.index) == -1, 'fa-caret-up':remberFatherArr.indexOf(item.index) > -1}" @click="addArray(item)" v-show="item.index.indexOf('-') == -1"></i> <i class="fa fa-user fa-lg filter_icon ml lmr cur icon_pos" v-show="item.index.indexOf('-') > -1"></i> {{ item.name }} </md-table-cell> <md-table-cell md-label="名称" md-sort-by="email">{{ item.email }}</md-table-cell> <md-table-cell md-label="" md-sort-by=""> <i class="fa fa-pencil fa-lg filter_icon lmr cur" v-show="item.index.indexOf('-') > -1"></i> <i class="fa fa-trash fa-lg filter_icon lmr cur" v-show="item.index.indexOf('-') > -1"></i> </md-table-cell> </md-table-row> </md-table> </div> </template> <script> export default { data() { return { fatherArray: [], remberFatherArr: [], people: [ { index: "0", name: 'App Engine 查看者(4)', }, { index: "1", name: 'App Engine 查看者(4)', }, ], people_son: [ { name: 'Odette Demageard', email: '[email protected]', }, { name: 'Lonnie Izkovitz', email: '[email protected]', }, { name: 'Thatcher Stave', email: '[email protected]', }, { name: 'Clarinda Marieton', email: '[email protected]', } ], people_son2: [ { name: 'Odette Demageard', email: '[email protected]', }, { name: 'Lonnie Izkovitz', email: '[email protected]', }, { name: 'Thatcher Stave', email: '[email protected]', }, { name: 'Clarinda Marieton', email: '[email protected]', } ], } }, created() { }, methods: { showArray(item) { // 所有复选框的全选非全选的逻辑,因当前业务需求,插件也不提供,故逻辑手写 // 暂时无需考虑性能问题,遍历次数不多,百次以下,前端响应几乎无影响 let that = this; if (item.index.indexOf("-") == -1) { if (that.fatherArray.indexOf(item.index) > -1) { // 全选 that.people.forEach(function (val, ind) { (val.index.indexOf(item.index + "-") > -1 && that.fatherArray.indexOf(val.index) == -1) ? that.fatherArray.push(val.index) : ""; }) } else { // 取消全选 for (var i = that.fatherArray.length - 1; i >= 0; i--) { that.fatherArray[i].indexOf(item.index + "-") > -1 ? that.fatherArray.splice(i, 1) : "" } } } else { // 其余非全选框的点击筛选逻辑 逻辑较为复杂 阅读请仔细 // 实现原理:遍历原数组和选中数组,判断选中值的类型个数是否相等,相等则全选框选中,否则全选框选中状态消失 // 注意在全选框选中状态取消的时候加了一层节流判断(that.fatherArray.indexOf(item.index.substring(0, item.index.indexOf('-'))) > -1) let fatherIndex = 0; let allInIndex = 0; that.fatherArray.forEach(function (value, index) { value.indexOf(item.index.substring(0, item.index.indexOf('-') + 1)) > -1 ? fatherIndex++ : ""; }) that.people.forEach(function (value, index) { value.index.indexOf(item.index.substring(0, item.index.indexOf('-') + 1)) > -1 ? allInIndex++ : ""; }); fatherIndex == allInIndex ? that.fatherArray.push(item.index.substring(0, item.index.indexOf('-'))) : ((that.fatherArray.indexOf(item.index.substring(0, item.index.indexOf('-'))) > -1) ? that.fatherArray.splice(that.fatherArray.indexOf(item.index.substring(0, item.index.indexOf('-'))), 1) : "") } }, addArray(item) { // 注意index的排序问题"0-1","1-1","2-1" // 框架不提供该功能,此方法为手写逻辑 let that = this; let arrIndex = -1; for (var i = 0; i < that.people.length; i++) { if (item.index == that.people[i].index) { arrIndex = i; break } } // 判断是否是二次点击,如果是,删除,如果不是,添加 if (that.remberFatherArr.indexOf(item.index) > -1) { for (var i = that.people.length - 1; i >= 0; i--) { that.people[i].index.indexOf(item.index + "-") > -1 ? that.people.splice(i, 1) : "" } that.remberFatherArr.splice(that.remberFatherArr.indexOf(item.index), 1) return } that.remberFatherArr.push(item.index); //注意这里以下的代码为你从后台取的二级表格数据数组,现在是我写的假数据people_son和people_son2 //这里有一个问题需要注意,假数据数组不可重复使用,当然,当你从后台取值的时候就不用考虑了, //因为后端返回给你的数据肯定每次是新的(相同也无所谓) if (item.index == "0") { that.people_son.forEach(function (value, index) { arrIndex++ that.people.splice(arrIndex, 0, value) that.people[arrIndex]['index'] = item.index + "-" + index }) } else { that.people_son2.forEach(function (value, index) { arrIndex++ that.people.splice(arrIndex, 0, value) that.people[arrIndex]['index'] = item.index + "-" + index }) } console.log(that.people); }, } } </script> <style lang="scss" scoped> .md-checkbox { margin: 0; } </style>
实现效果如下(颜色不同是因为我有重置Material的默认样式,你也可以自定义一下):
嗯,就酱,大功告成,如果有什么问题欢迎给我留言,一定要看代码中的注释哦!
Material的坑还有很多很多很多。。。补坑之路尚很漫长,共勉。希望这篇文档能给您带来帮助,感谢阅读。