上篇文件介绍了基本的colspan
和rowspan
,这篇贴上一个学习代码,供以后修改。
效果如下:(这个demo v-if 和 v-for 混用了,这个不好)
<template>
<div class="rbac-table">
<div class="table-wrapper">
<div class="tabel-container">
<table>
<tbody>
<tr v-for="(item, index) in classTableData" :key="index">
<td v-for="(node, nodeIndex) in item" :key="nodeIndex" :colspan="node.colspan" :rowspan="node.rowspan" v-if="node.colspan !== 0 && node.rowspan !== 0">
<div v-if="node.data.type !== 'function'">
{{ node.data.name }}
<div>{{ node.colspan }}-{{ node.rowspan }}</div>
</div>
<div v-else>
<function-check :value="node" />
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</template>
<script>
import FunctionCheck from './components/FunctionCheck.vue'
const shortid = require('shortid')
// 深度遍历, 使用递归
const getNodeTable = data => {
let deep = 0
const resultArr = []
data.forEach(item => {
const itemArr = []
const map = (node, level, parent) => {
if (level > deep) {
deep = level
}
if (!node.id) {
node.id = shortid.generate()
}
if (parent == null) {
resultArr.push({
key: node.id,
arr: [
{
key: node.id,
_id: node._id,
// 第几层级
level: level,
// 名称
name: node.name,
function: node.function,
},
],
})
}
if (node.children) {
const parentIndex = resultArr.findIndex(x => {
return x.key == node.id
})
// 截取前面公用部分
const commonArr = resultArr[parentIndex].arr.slice(0, level)
const replaceArr = []
node.children.forEach((child, index) => {
child.id = shortid.generate()
replaceArr.push({
key: child.id,
arr: commonArr.concat({ level: level + 1, name: child.name, function: child.function, _id: child._id, key: child.id }),
})
})
resultArr.splice(parentIndex, 1, ...replaceArr)
node.children.forEach(child => {
map(child, level + 1, node)
})
}
}
map(item, 1, null)
})
return {
data: resultArr,
deep: deep,
}
}
const tableData = [
{
name: '订单管理',
type: 'menu',
_id: '1',
children: [
{
name: '销售订单',
_id: '2',
type: 'menu_function',
function: [
{
name: '全选',
},
{
name: '订单查看',
_id: '21',
},
{
name: '订单添加',
_id: '22',
},
{
name: '订单修改',
_id: '23',
},
{
name: '订单删除',
_id: '24',
},
{
name: '订单打印',
_id: '25',
},
{
name: '订单下载',
_id: '26',
},
{
name: '一键完成',
_id: '27',
},
{
name: '打印送货单',
_id: '28',
},
],
},
{
name: '采购订单',
type: 'menu_function',
_id: '3',
function: [
{
name: '全选',
},
{
name: '订单查看',
_id: '31',
},
{
name: '订单添加',
_id: '32',
},
{
name: '订单修改',
_id: '33',
},
{
name: '订单删除',
_id: '34',
},
{
name: '订单打印',
_id: '35',
},
{
name: '订单下载',
_id: '36',
},
{
name: '一键完成',
_id: '37',
},
{
name: '打印送货单',
_id: '38',
},
],
},
],
},
{
name: '销售订单',
_id: '5',
type: 'menu_function',
function: [
{
name: '全选',
},
{
name: '订单查看',
_id: '51',
},
{
name: '订单添加',
_id: '52',
},
{
name: '订单修改',
_id: '53',
},
{
name: '订单删除',
_id: '54',
},
{
name: '订单打印',
_id: '55',
},
{
name: '订单下载',
_id: '56',
},
{
name: '一键完成',
_id: '57',
},
{
name: '打印送货单',
_id: '58',
},
],
},
]
export default {
components: {
FunctionCheck,
},
data() {
return {
data: [],
columns: [],
classTableData: [],
}
},
mounted() {
const { data, deep } = getNodeTable(tableData)
const rowLength = data.length
const colLength = deep + 1
const bdata = new Array(rowLength)
for (let i = 0; i < colLength; i++) {
bdata[i] = new Array(colLength)
}
for (let i = 0; i < rowLength; i++) {
const row = data[i].arr
for (let j = colLength - 1; j > -1; j--) {
if (!row[j] && row[j - 1]) {
row[j] = JSON.parse(JSON.stringify(row[j - 1]))
row[j].type = 'function'
console.log('row[j]', row[j])
}
bdata[i][j] = {
data: row[j],
rowspan: 1,
colspan: 1,
}
}
}
let matchArr = []
let matchArrPos = []
// 最左侧为基准
let matchLeftArr = []
let matchLeftPos = []
for (let i = 0; i < rowLength; i++) {
matchLeftArr.push(bdata[i][0])
matchLeftPos.push({ x: i, y: 0 })
}
for (let i = 0; i < rowLength; i++) {
if (i == 0) {
matchArr = JSON.parse(JSON.stringify(bdata[i]))
}
for (let j = 0; j < colLength; j++) {
// row 处理 begin
if (i == 0) {
matchArrPos.push({ x: i, y: j })
} else {
if (bdata[i][j].data && bdata[i][j].data.key == matchArr[j].data.key) {
const { x, y } = matchArrPos[j]
bdata[x][y].rowspan = bdata[x][y].rowspan + 1
bdata[i][j].rowspan = 0
} else {
matchArr[j] = bdata[i][j]
matchArrPos[j] = { x: i, y: j }
}
}
// row 处理 end
// col 处理 begin
if (j > 0) {
if (bdata[i][j].data == undefined) {
const { x, y } = matchLeftPos[i]
bdata[x][y].colspan = bdata[x][y].colspan + 1
bdata[i][j].colspan = 0
} else {
matchLeftArr[i] = bdata[i][j]
matchLeftPos[i] = { x: i, y: j }
}
}
}
// col 处理 end
}
this.classTableData = bdata
},
}
</script>
<style lang="less" scoped>
.rbac-table {
background: white;
.table-wrapper {
width: 100%;
height: 100%;
overflow: auto;
}
.tabel-container {
margin: 7px;
table {
table-layout: fixed;
width: 100%;
tbody {
background-color: white;
td {
color: #677998;
}
}
th,
td {
width: 60px;
padding: 12px 2px;
font-size: 12px;
text-align: center;
border: 1px solid #d9d9d9;
position: relative;
}
tr td:first-child {
color: #333;
.period {
font-size: 8px;
}
}
}
}
}
</style>
组件FunctionCheck
<template>
<div class="function-check">
<div class="check-item" v-for="(item, index) in value.data.function" :key="index">
<a-checkbox @change="onChange">{{ item.name }}</a-checkbox>
</div>
</div>
</template>
<script>
export default {
props: {
value: {
type: Object,
default: () => {
return {}
},
},
},
}
</script>
<style lang="less" scoped>
.function-check {
width: 100%;
height: 100%;
padding-left: 10px;
display: flex;
flex-wrap: wrap;
.check-item {
width: 120px;
margin-top: 2px;
margin-bottom: 2px;
text-align: left;
}
}
</style>