preface
Popular UI libraries such as Element UI, Ant Design, and regular table interactions all have methods that support them. For example, multi-level table headers, radio, multi-selection, custom table headers, and so on, including cell merging in headings. But business scenarios are changing, and scaling based on dependent libraries is common.
Table tree cell line combination is a relatively comprehensive point, this article based on Vue3 + Element Plus with you to achieve the dismantlement of table tree cell combination.
Take a look at the completed Demo 😘.
The sliding window
Before implementing it, let’s talk about the idea of sliding Windows. Anyone who brushes LeetCode regularly should be familiar with it.
The sliding window idea is to think of a subarray (substring) as a sliding window, and then slide the window over the array (string). In the sliding process, an element goes out to the left, an element goes in to the right, and then you just calculate the value of the element in the current window.
Sliding window idea frame:
- Initialize left = right = 0 in array (string) using the left and right pointer technique in double pointer, call index closed interval [left,right] a window.
- Enlarge the window [left, right] by increasing the right pointer until the window meets the requirements.
- Stop adding right and add left to narrow the window until it no longer meets the requirements. Also, each time you add a left, you update the result of a round.
- Repeat 2 and 3 until right reaches the end of the array or string.
Let’s look at a problem 🤣 : the smallest subarray, perfect for the idea of sliding Windows.
Given an array containing n positive integers and a positive integer target.
Find the smallest contiguous subarray [numsl, numSL +1,…, numsr-1, numsr] that satisfies the sum and ≥ target, and return its length. If no subarray exists, return 0.
One more 🌰 :
Input: target = 7, nums = [2,3,1,2,4,3] output: 2 description: the subarray [4,3] is the smallest subarray in this condition.Copy the code
Solution:
var minSubArrayLen = function(target, nums) {
let length = nums.length
// Initializes the double pointer to form a closed interval window.
let i = 0
let j = 0
let sum = 0
let ans = Infinity
// Until j to the end
while(j < length) {
sum+=nums[j]
// Stop adding j and add I instead, and narrow the window until it does not meet the requirement
while(sum >= target) {
ans = Math.min(ans, j - i + 1)
sum -= nums[i]
i++
}
// Increment j until the requirement is met
j++
}
return ans === Infinity ? 0 : ans
};
Copy the code
implementation
Realize from simple to deep, first explain the table cell row merge, then explain the table tree cell merge, step by step may be easier to understand.
The cell row merge of the table
Combine rows based on the span-method provided by Element Plus.
Take a look at the cell row merge provided on the official website.
objectSpanMethod({ row, column, rowIndex, columnIndex }) {
if(columnIndex === 0) {
if(rowIndex % 2= = =0) {
return {
rowspan: 2.colspan: 1}}else {
return {
rowspan: 0.colspan: 0}}}}Copy the code
The example shows that the method is used to set the RowSPAN for each row of cells. The total number of downmerged cells is the value of RowSPAN, and the value of rowSPAN for the merged cell is 0.
Therefore, we need to calculate the rowSPAN value for each row of cells.
Write a table page and add a fake data.
<template>
<div class="cell-merge-container">
<div class="basic">
<div class="basic-header">Cell row merge of the base table (with merge Name as an example)</div>
<div class="basic-table">
<el-table
:data="basicTableData"
:span-method="basicObjectSpanMethod"
border
style="width: 100%; margin-top: 20px"
>
<el-table-column prop="id" label="ID" width="180" />
<el-table-column prop="name" label="Name" />
<el-table-column prop="amount1" label="Amount 1" />
<el-table-column prop="amount2" label="Amount 2" />
<el-table-column prop="amount3" label="Amount 3" />
</el-table>
</div>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
let basicTableData = ref([]);
basicTableData.value = [
{
id: "12987122".name: "Tom".amount1: "234".amount2: "3.2".amount3: 10}, {id: "12987123".name: "".amount1: "165".amount2: "4.43".amount3: 12}, {id: "12987124".name: "Jerry".amount1: "324".amount2: "1.9".amount3: 9}, {id: "12987125".name: "Jerry".amount1: "621".amount2: "2.2".amount3: 17}, {id: "12987126".name: "Jerry".amount1: "539".amount2: "4.1".amount3: 15,}]const basicObjectSpanMethod = ({column,rowIndex}) = > {
if(column.label === 'Name') {
return {
rowspan: 1.colspan: 1}}};</script>
<style lang="scss" scoped>
.cell-merge-container {
padding: 10px;
box-sizing: border-box;
}
</style>
Copy the code
Use this data to get the array of cell Settings that we merge, in this case the Name column.
Clear your mind before you implement the code.
- Initialize to generate a one-dimensional array of the same length as the data, and assign a value of 0; Initialize the left pointer to 0 and the right pointer to 1; Initialize the left pointer index of the array at 1.
- Moves the right pointer to compare the same value as the index position of the left pointer. If it is the same, the position of the left pointer increases by 1 and the right pointer moves backward; If not, update the left pointer to the right pointer, initialize the left pointer to 1, and move the right pointer backward.
The idea is to draw on the idea of sliding window, or the idea of drawing on the left and right double Pointers is more appropriate
let basicRowSpan = calculateBasicRowSpan(basicTableData.value)
function calculateBasicRowSpan(data) {
let length = data.length
let basicRowSpan = new Array(length).fill(0)
let prev = 0
let cur = 1
basicRowSpan[prev] = 1
while(cur < length) {
let prevItem = data[prev]
let currentItem = data[cur]
if(prevItem.name === currentItem.name) {
basicRowSpan[prev]++
cur++
} else {
prev = cur
cur++
basicRowSpan[prev] = 1}}return basicRowSpan
}
Copy the code
Let’s change the basicObjectSpanMethod.
const basicObjectSpanMethod = ({column,rowIndex}) = > {
if(column.label === 'Name') {
return {
rowspan: basicRowSpan[rowIndex],
colspan: 1}}};Copy the code
Table tree cell row merge
Write table tree page, also add a fake data.
<template>
<div class="cell-merge-container">
<div class="tree">
<div class="tree-header">Cell merge of table tree (with merge Name as an example)</div>
<div class="tree-table">
<el-table
:data="treeTableData"
:span-method="treeObjectSpanMethod"
row-key="id"
style="width: 100%; margin-top: 18px;"
@expand-change="expandChange"
>
<el-table-column prop="id" label="ID" width="180" />
<el-table-column prop="name" label="Name" />
<el-table-column prop="amount1" label="Amount 1" />
<el-table-column prop="amount2" label="Amount 2" />
<el-table-column prop="amount3" label="Amount 3" />
</el-table>
</div>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
let treeTableData = ref([])
treeTableData.value = [
{
id: "12987122".name: "Tom".amount1: "234".amount2: "3.2".amount3: 10.children: [{
id: "12987127".name: "Tom".amount1: "236".amount2: "3.3".amount3: 11.children: [{
id: "12987129".name: "Tom".amount1: "236".amount2: "3.7".amount3: 11.children] : []}}, {id: "12987128".name: "Tom".amount1: "136".amount2: "2.3".amount3: 11.children: []}]}, {id: "12987123".name: "".amount1: "165".amount2: "4.43".amount3: 12.children: []}, {id: "12987124".name: "Jerry".amount1: "324".amount2: "1.9".amount3: 9.children: [{
id: "12987130".name: "Jerry".amount1: "324".amount2: "1.9".amount3: 9}, {id: "12987131".name: "Jerry".amount1: "34".amount2: "1.9".amount3: 9.children: [{
id: "12987132".name: "Jerry".amount1: "124".amount2: "0.9".amount3: 9,}]}]}, {id: "12987125".name: "Jerry".amount1: "621".amount2: "2.2".amount3: 17.children: [{
id: "12987133".name: "Jerry".amount1: "324".amount2: "1.9".amount3: 9}]}, {id: "12987126".name: "Jerry".amount1: "539".amount2: "4.1".amount3: 15.children: []},]const treeObjectSpanMethod = ({ column, rowIndex }) = > {
if(column.label === 'Name') {
return {
rowspan: 1.colspan: 1}}}// Table count collapse event
const expandChange = (row, expanded) = >{}Copy the code
Extend the idea of cell combination of basic table and disassemble the realization of cell combination of table tree.
- Initialize the traversal data by adding the expand property to each node and assigning it to false.
- Depth-first recursive table tree. If the node is hidden, put ‘none’ in the array, otherwise put the value of the merged column.
- Get the one-dimensional array that sets the rowSPAN value using the sliding window idea.
- Collapse expansion event, first look for the value of expand set on the node corresponding to the collapse expansion, and then repeat steps 2 and 3.
- Combined with the spAN-method method.
Add the implementation code as follows.
const recursiveTraversalTree = (data) = > {
for (let i = 0; i < data.length; i++) {
data[i].expand = false
data[i].children &&
data[i].children.length &&
recursiveTraversalTree(data[i].children)
}
}
// The recursive table tree initializes the expand field to false
recursiveTraversalTree(treeTableData.value)
let mergeRowArr = []
let treeMergeArr = []
// The recursive table tree descends the merged rows from above into a one-dimensional array. If the node is hidden, add no field. The node is not hidden, then the column value is placed.
const getMergeRowArr = (data, bool, key) = > {
for (let i = 0; i < data.length; i++) {
let item = data[i]
let value = bool ? item[key] : 'no'
mergeRowArr.push(value)
if (item.children && item.children.length) {
// item.expand && bool Ensures that the child expands and the parent closes
getMergeRowArr(item.children, item.expand && bool, key)
}
}
}
// Get a one-dimensional array from the top down of the table tree
const calculateTreeRowSpan = (data) = > {
let length = data.length
let basicRowSpan = new Array(length).fill(0)
let prev = 0
let cur = 1
basicRowSpan[prev] = 1
while (cur < length) {
// If you encounter a hidden node, you can skip it directly
if (data[cur] === 'no') {
cur++
continue
}
if (data[prev] === data[cur]) {
basicRowSpan[prev]++
cur++
} else {
prev = cur
cur++
basicRowSpan[prev] = 1}}return basicRowSpan
}
getMergeRowArr(treeTableData.value, true.'name')
treeMergeArr = calculateTreeRowSpan(mergeRowArr)
// Merge cells in the table tree
const treeObjectSpanMethod = ({ column, rowIndex }) = > {
if (column.label === 'Name') {
return {
rowspan: treeMergeArr[rowIndex],
colspan: 1}}}// Recursive table tree sets the value of expand in the tree node
const setTreeNodeExpand = (data, id, expand) = > {
for (let i = 0; i < data.length; i++) {
let item = data[i]
if (item.id === id) {
item.expand = expand
break
}
if (item.children && item.children.length)
setTreeNodeExpand(item.children, id, expand)
}
}
// Collapse the expansion event
const expandChange = (row, expanded) = > {
setTreeNodeExpand(treeTableData.value, row.id, expanded)
// Empty the array
mergeRowArr = []
getMergeRowArr(treeTableData.value, true.'name')
treeMergeArr = calculateTreeRowSpan(mergeRowArr)
}
Copy the code
conclusion
An actual combat article, welcome to comment section exchange, looking forward to better ideas.
If you find it helpful, like + favorites + follow ❤
reference
Basic principle and practice of sliding window algorithm sliding window algorithm is the smallest size array