需求描述
實(shí)現(xiàn)對(duì)數(shù)據(jù)庫(kù)表和表字段的勾選,數(shù)據(jù)庫(kù)表包含了表字段互站,后端一次性返回所有表的數(shù)據(jù)囤热。前端需要自行對(duì)表做翻頁(yè)處理。當(dāng)用戶勾選完需要的表和字段后穆役,再把勾選后的數(shù)據(jù)發(fā)送給后端禁漓。
需求拆分
- 前端翻頁(yè)功能
- 跨頁(yè)級(jí)聯(lián)勾選功能
實(shí)現(xiàn)效果
具體實(shí)現(xiàn)
前端翻頁(yè)功能
需要實(shí)現(xiàn)前端翻頁(yè)的部分是數(shù)據(jù)庫(kù)表,進(jìn)入頁(yè)面后孵睬,默認(rèn)自動(dòng)向后端獲取一次 搜索后的表數(shù)據(jù)searchTableList
播歼,獲取到之后,計(jì)算當(dāng)前頁(yè)顯示的表數(shù)據(jù)掰读,計(jì)算公式為 curTableList = searchTableList.slice((page - 1) * size, page * size)
秘狞,page
,size
保存在 url
參數(shù)中蹈集。如果用戶點(diǎn)擊翻頁(yè)烁试,則重新計(jì)算當(dāng)前頁(yè)顯示的表數(shù)據(jù)。如果用戶搜索表拢肆,則重置頁(yè)數(shù)為 1
后减响,獲取 searchTableList
,并重新計(jì)算當(dāng)前頁(yè)顯示的表數(shù)據(jù)郭怪。
流程圖
關(guān)鍵代碼
// 獲取當(dāng)前頁(yè)表數(shù)據(jù)
getCurTableList() {
// 不發(fā)請(qǐng)求支示,根據(jù) searchTableList 獲取數(shù)據(jù)。模擬翻頁(yè)
let page = Number(this.$route.query.page || 1);
let size = Number(this.$route.query.size || 10);
let total = this.searchTableList.length;
let maxPage = Math.ceil(total / size);
page = page > maxPage ? maxPage : page;
this.tablePageData = { page, size, total };
this.curTableList = this.searchTableList.slice((page - 1) * size, page * size);
},
跨頁(yè)級(jí)聯(lián)勾選功能
分析用戶可進(jìn)行的勾選操作的勾選框:
- 全部表勾選框鄙才,共有未選颂鸿、部分先和全選有三種狀態(tài),未選和部分選狀態(tài)點(diǎn)擊可勾選全部表攒庵,全選狀態(tài)點(diǎn)擊可取消勾選全部表嘴纺;
- 當(dāng)前頁(yè)表勾選框败晴,共有未選、部分選和全選有三種狀態(tài)栽渴,未選和部分選狀態(tài)點(diǎn)擊可勾選當(dāng)前頁(yè)全部表尖坤,全選狀態(tài)點(diǎn)擊可取消勾選當(dāng)前頁(yè)全部表;
- 單個(gè)表勾選框闲擦,共有未選糖驴、部分選和全選有三種狀態(tài),未選和部分選狀態(tài)點(diǎn)擊可勾選表中的全部字段佛致,全選狀態(tài)點(diǎn)擊可取消勾選表中的全部字段贮缕;
- 全部字段勾選框,共有未選俺榆、部分選和全選有三種狀態(tài)感昼,未選和部分選狀態(tài)點(diǎn)擊可勾選表中的全部字段,全選狀態(tài)點(diǎn)擊可取消勾選表中的全部字段罐脊;
- 單個(gè)字段勾選框定嗓,共有未選和已選有兩種狀態(tài),未選狀態(tài)點(diǎn)擊可勾選表中的該字段萍桌,已選狀態(tài)點(diǎn)擊可取消勾選表中的該字段宵溅;
全部表數(shù)據(jù) allTableList,該數(shù)據(jù)結(jié)構(gòu)如下:
// 全部表
allTableList: [
// 每個(gè)表
{
"tableName": "table-name", // 表名
// 表中的全部字段
"fieldList": [
// 每個(gè)字段
{
"fieldName": "field-name", // 字段名
},
],
},
]
根據(jù)上面的信息分析上炎,為了實(shí)現(xiàn)勾選狀態(tài)的聯(lián)動(dòng)恃逻,最好的辦法是把所有的已勾選項(xiàng)放在一個(gè)變量中保存,該變量保存了選中的表和字段藕施,然后通過(guò)計(jì)算方法確定每個(gè)勾選框的狀態(tài)寇损。該勾選狀態(tài)變量的結(jié)構(gòu)如下:
// 選中的表和字段
checkedTableAndField: {
// 選中的表名
"table-name": [
"field-name", // 表中選中的字段
],
}
有了 checkedTableAndField
變量,所有的勾選框狀態(tài)就都可以通過(guò)它來(lái)計(jì)算得到了裳食。下面列出所有勾選框狀態(tài)的計(jì)算方法:
- 全部表勾選框矛市,全選狀態(tài)=全部表狀態(tài)都全選,部分選狀態(tài)=本身非全選狀態(tài)且有任一表是部分選或全選狀態(tài)诲祸,未選狀態(tài)=本身非全選且本身非部分選浊吏。轉(zhuǎn)換為代碼如下:
// 全部表是否全選
isTableAllChecked() {
return this.allTableList.length && this.allTableList.every(tableObj => this.isPerTableAllChecked(tableObj));
},
// 全部表是否部分選
isTablePartChecked() {
return !this.isTableAllChecked && this.allTableList.some(tableObj => this.isPerTablePartChecked(tableObj) || this.isPerTableAllChecked(tableObj));
},
- 當(dāng)前頁(yè)表勾選框,全選狀態(tài)=當(dāng)前頁(yè)表狀態(tài)都全選救氯,部分選狀態(tài)=本身非全選狀態(tài)且有任一當(dāng)前頁(yè)表是部分選或全選狀態(tài)找田,未選狀態(tài)=本身非全選且本身非部分選。轉(zhuǎn)換為代碼如下:
// 當(dāng)前頁(yè)的表是否全選
isCurTableAllChecked() {
return this.curTableList.length && this.curTableList.every(tableObj => this.isPerTableAllChecked(tableObj));
},
// 當(dāng)前頁(yè)的表是否部分選
isCurTablePartChecked() {
return !this.isCurTableAllChecked && this.curTableList.some(tableObj => this.isPerTablePartChecked(tableObj) || this.isPerTableAllChecked(tableObj));
},
- 單個(gè)表勾選框径密,全選狀態(tài)=表中的全部字段狀態(tài)都勾選午阵,部分選狀態(tài)=本身非全選狀態(tài)且表中有任一字段勾選躺孝,未選狀態(tài)=本身非全選且本身非部分選享扔。轉(zhuǎn)換為代碼如下:
// 單個(gè)表是否全選
isPerTableAllChecked(tableObj) {
let checkedFieldArr = vm.checkedTableAndField[tableObj.tableName];
return checkedFieldArr && checkedFieldArr.length === tableObj.fieldList.length;
},
// 單個(gè)表是否部分選
isPerTablePartChecked(tableObj) {
let checkedFieldArr = vm.checkedTableAndField[tableObj.tableName];
return !vm.isPerTableAllChecked(tableObj) && checkedFieldArr && checkedFieldArr.length;
},
- 全部字段勾選框底桂,全選狀態(tài)=全部字段狀態(tài)都勾選,部分選狀態(tài)=本身非全選狀態(tài)且有任一字段勾選惧眠,未選狀態(tài)=本身非全選且本身非部分選籽懦。轉(zhuǎn)換為代碼如下:
// this.allFieldList 是當(dāng)前選中的表的所有字段,這里省略該變量部分代碼
// 當(dāng)前已選中的字段的標(biāo)識(shí)集合
curCheckedFieldArr() {
return this.checkedTableAndField[this.curTableName] || [];
},
// 全部字段是否全選
isFieldAllChecked() {
return this.allFieldList.length && this.allFieldList.length === this.curCheckedFieldArr.length;
},
// 全部字段是否部分選
isFieldPartChecked() {
return !this.isFieldAllChecked && this.curCheckedFieldArr.length;
}
- 單個(gè)字段勾選框氛魁,勾選狀態(tài)=本身是勾選暮顺,未選狀態(tài)=本身非勾選。轉(zhuǎn)換為代碼如下:
// 單個(gè)字段是否勾選
isFieldChecked(fieldName) {
return curCheckedFieldArr.includes(fieldName)
}
以上逐步分析了各個(gè)勾選框的狀態(tài)如何確定秀存,基本圍繞著 checkedTableAndField
變量進(jìn)行捶码,那么當(dāng)我們更新 checkedTableAndField
的數(shù)據(jù),所有的勾選框狀態(tài)都會(huì)隨著它更新了或链。這里貼出來(lái)更新 checkedTableAndField
數(shù)據(jù)的部分代碼(詳情參考具體項(xiàng)目實(shí)現(xiàn)):
// 點(diǎn)擊 選擇全部表
checkAllTable() {
let vm = this;
let checkedTableAndField = {};
if (!vm.isTableAllChecked) {
vm.allTableList.forEach(tableObj => {
checkedTableAndField[tableObj.tableName] = tableObj.fieldList.map(item => item.sensTypeMain.fieldName);
});
} else {
vm.allTableList.forEach(tableObj => {
checkedTableAndField[tableObj.tableName] = [];
});
}
vm.checkedTableAndField = checkedTableAndField;
},
// 點(diǎn)擊 選擇當(dāng)前頁(yè)的表
checkCurTable() {
let vm = this;
let checkedTableAndField = {};
if (!vm.isCurTableAllChecked) {
vm.curTableList.forEach(tableObj => {
checkedTableAndField[tableObj.tableName] = tableObj.fieldList.map(item => item.sensTypeMain.fieldName);
});
} else {
vm.curTableList.forEach(tableObj => {
checkedTableAndField[tableObj.tableName] = [];
});
}
vm.checkedTableAndField = checkedTableAndField;
},
// 點(diǎn)擊 選擇單個(gè)表
checkPerTable(tableObj) {
let vm = this;
let checkedFieldArr = !vm.isPerTableAllChecked(tableObj) ? tableObj.fieldList.map(item => item.sensTypeMain.fieldName) : [];
this.$set(this.checkedTableAndField, tableObj.tableName, checkedFieldArr);
},
// 點(diǎn)擊 選擇當(dāng)前顯示的全部字段
checkCurAllField() {
let vm = this;
let checkedFieldArr = !vm.isFieldAllChecked ? vm.allFieldList.map(item => item.sensTypeMain.fieldName) : [];
this.$set(this.checkedTableAndField, this.curTableName, checkedFieldArr);
},
// 點(diǎn)擊 選擇字段
checkField(fieldName) {
let checkedFieldArr = this.checkedTableAndField[this.curTableName];
if (checkedFieldArr) {
let position = checkedFieldArr.indexOf(fieldName);
position > -1 ? checkedFieldArr.splice(position, 1) : checkedFieldArr.push(fieldName);
} else {
checkedFieldArr = [fieldName];
}
this.$set(this.checkedTableAndField, this.curTableName, checkedFieldArr);
},
總結(jié)
以上就實(shí)現(xiàn)了純前端翻頁(yè)+跨頁(yè)級(jí)聯(lián)勾選效果惫恼。純前端翻頁(yè)是把先把搜索數(shù)據(jù)保存在本地變量中,然后通過(guò)數(shù)組的切片功能澳盐,根據(jù)當(dāng)前頁(yè)數(shù)和大小進(jìn)行切片祈纯,再把結(jié)果保存到當(dāng)前頁(yè)中〉鸢遥跨頁(yè)級(jí)聯(lián)選擇是先把所有數(shù)據(jù)保存在本地變量中腕窥,再分析如何確定各個(gè)勾選框狀態(tài),最后通過(guò)一個(gè)保存了已勾選的表和字段狀態(tài)的變量進(jìn)行狀態(tài)更新筛婉。這其中的重點(diǎn)便是理解如何構(gòu)建和維護(hù)這樣一個(gè)變量簇爆。
另外,純前端翻頁(yè)是目的是為了能夠完成跨頁(yè)級(jí)聯(lián)勾選功能爽撒,因?yàn)橹挥泻蠖朔祷亓怂械臄?shù)據(jù)給我們冕碟,我們才能計(jì)算出全部選擇勾選框的狀態(tài)。數(shù)據(jù)量過(guò)大的情況下匆浙,后端即使返回了所有數(shù)據(jù)給我們安寺,瀏覽器也無(wú)法進(jìn)行大量數(shù)據(jù)的保存和計(jì)算。這種情況下首尼,需要采取另外的方案挑庶。