這個算法非常有價值.50塊錢提供核心協助
我qq
840189859
我微信
18500591275
場景: 我們現在有一個樹狀結構的數據,如下圖:
大概的數據結構如下:
const tree = {
value: '根節點',
children: [
{
value: '學校',
children: [
{
value: '學生',
children: [
{
value: '年齡',
children: [
{
value: '身高'
}
]
}
]
}
......
]
}
]
}
現在我們要將這樣的數據轉為行數據, 並用vue將其渲染為table, 效果如下:
OK,下面我們一一進行解析。
第一步,遞歸樹狀結構,轉化為行數據
parseTreeToRow(node, data = [], row = []) { if (!node.children) { data.push(row); } else { for (let i = 0; i < node.children.length; i++) { const child = node.children[i]; const cell = { value: child.value }; this.parseTreeToRow(child, data, [...row, cell]); } } return data; }; //通過上面的遞歸函數,解析出來的行數據如下: const data = [ [{ value: '學校'}, { value: '學生' }, { value: '年齡' }, { value: '身高' }], [{ value: '成都一中'}, { value: '張三' }, { value: '17' }, { value: '170' }], [{ value: '成都二中'}, { value: '李四' }, { value: '17' }, { value: '174' }], [{ value: '成都二中'}, { value: '王五' }, { value: '18' }, { value: '168' }], [{ value: '成都二中'}, { value: '王五' }, { value: '19' }, { value: '177' }], ...... ];
第二步,添加rowspan信息
此時,很明顯渲染出來的table並沒有進行合並,如果對解析后的行數據二次解析亦可找到其rowspan,這里不做二次解析,我們回到上面的遞歸函數中,做如下處理:
parseTreeToRow(node, data = [], row = []) { if (!node.children) { data.push(row); } else { for (let i = 0; i < node.children.length; i++) { const child = node.children[i]; const cell = { value: child.value, rowspan: this.computeLeafCount(node) }; this.parseTreeToRow(child, data, [...row, cell]); } } return data; }; /** 1. 計算某個節點下葉子節點的數量 2. @param { Object } node 節點 3. @returns { Number } leafCount 葉子節點的數量 */ computeLeafCount(node) { if(!node.children){ node.rowspan = 1; return 1; } else { let leafCount = 0; for(let i = 0 ; i < node.children.length ; i++) { leafCount = leafCount + this.computeLeafCount(node.children[i]); } node.rowspan = leafCount; return leafCount; } } //解析出的數據如下: const data = [ [{ value: '學校', rowspan: 7 }, { value: '學生', rowspan: 1 }, { value: '年齡', rowspan: 1 }, { value: '身高', rowspan: 1 }], [{ value: '成都一中', rowspan: 7 }, { value: '張三', rowspan: 1 }, { value: '17', rowspan: 1 }, { value: '170', rowspan: 1 }], [{ value: '成都二中', rowspan: 7 }, { value: '李四', rowspan: 3 }, { value: '17', rowspan: 1 }, { value: '174', rowspan: 1 }], [{ value: '成都二中', rowspan: 7 }, { value: '王五', rowspan: 3 }, { value: '18', rowspan: 1 }, { value: '168', rowspan: 1 }], [{ value: '成都二中', rowspan: 7 }, { value: '王五', rowspan: 3 }, { value: '19', rowspan: 1 }, { value: '177', rowspan: 1 }], ...... ];
但是可以發現,我們需要的合並信息解析到了child中,且相同的單元格只有第一行的rowspan保留,其余要置為0,。
第三步,處理異常合並信息
回到遞歸函數中,
parseTreeToRow(node, data = [], row = []) { if (!node.children) { data.push(row); } else { for (let i = 0; i < node.children.length; i++) { const child = node.children[i]; const cell = { value: child.value }; /******************添加的代碼******************/ //深度克隆父親,因為后代共用了該引用數據 const extendRow = [ ...JSON.parse(JSON.stringify(row)), cell]; if (extendRow.length === 1) { //第一列 extendRow[0].rowspan = 1; } else if (extendRow.length > 1) { //將該行的最后一列的rowspan賦給上一列 //再將自身置為1(避免最后一列無值) extendRow[extendRow.length - 2].rowspan = i === 0 ? this.computeLeafCount(node) : 0; extendRow[extendRow.length - 1].rowspan = 1; } /******************添加的代碼******************/ this.parseTreeToRow(child, data, extendRow); } } return data; }; //解析后的數據結構如下: const data = [ [{ value: '學校', rowspan: 1 }, { value: '學生', rowspan: 1 }, { value: '年齡', rowspan: 1 }, { value: '身高', rowspan: 1 }], [{ value: '成都一中', rowspan: 1 }, { value: '張三', rowspan: 1 }, { value: '17', rowspan: 1 }, { value: '170', rowspan: 1 }], [{ value: '成都二中', rowspan: 1 }, { value: '李四', rowspan: 3 }, { value: '17', rowspan: 1 }, { value: '174', rowspan: 1 }], [{ value: '成都二中', rowspan: 1 }, { value: '王五', rowspan: 0 }, { value: '18', rowspan: 1 }, { value: '168', rowspan: 1 }], [{ value: '成都二中', rowspan: 1 }, { value: '王五', rowspan: 0 }, { value: '19', rowspan: 1 }, { value: '177', rowspan: 1 }], ...... ];
<table> <tr v-for="(row, i) in data" :key="i"> <td v-for="(cell, j) in row" v-if="cell.rowspan" :key="j" :rowspan="cell.rowspan" :colspan="cell.colspan"> <div class="cell">{{ cell.value }}</div> </td> </tr> </table>
大功告成!最后的效果如下: