发现问题
近日,我接到一个产品需求,一个基于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: 'odemageard1@spotify.com',
},
{
name: 'Lonnie Izkovitz',
email: 'lizkovitz3@youtu.be',
},
{
name: 'Thatcher Stave',
email: 'tstave4@reference.com',
},
{
name: 'Clarinda Marieton',
email: 'cmarietonh@theatlantic.com',
}
],
people_son2: [
{
name: 'Odette Demageard',
email: 'odemageard1@spotify.com',
},
{
name: 'Lonnie Izkovitz',
email: 'lizkovitz3@youtu.be',
},
{
name: 'Thatcher Stave',
email: 'tstave4@reference.com',
},
{
name: 'Clarinda Marieton',
email: 'cmarietonh@theatlantic.com',
}
],
}
},
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的坑还有很多很多很多。。。补坑之路尚很漫长,共勉。希望这篇文档能给您带来帮助,感谢阅读。