Build a wheel and implement a table component for a complex scene (UniApp)
Make writing a habit together! This is my first day to participate in the “Gold Digging Day New Plan · April More text challenge”, click to see the details of the activity.
Is a mature program ape, to know how to build their own wheels (uniApp’s plug-in market has not found the need for a plug-in, there is no way, can only build a wheel). This paper aims to replicate + record. Usage scenario: uniApp, mobile terminal (compatible with small program, App, H5)
To the chase
Organize specific functions according to requirements:
Need to sort out
- Table name
- Configurable background
- Font style modifiable (size, color)
- Menu button (external exposure event required)
- header
- Supports multiple table headers
- Header fixed
- Table header rows support custom names
- form
- Support for setting cell width
- Fixed the first column
- Support tree data
- Content support images, links
- other
- Internal implementation sort
- Internal implementation of paging
- Internal calculation of total rows
Some thoughts on the whole component
- More complex functionality, less elegant and messy to squeeze into a file -> split into several modules in a large direction (fine granularity)
- More requirements, intuitive is the need to pass a lot of parameters -> according to the module definition, the parameters are also classified
- More parameters, how to more elegant management, reduce the difficulty of getting started? -> Configuration file
config.js
And set the default value in it, toFields thatandDefault State ManagementThe role of - Some ICONS will be used -> selected
iconfont
Icon library
Technical Implementation difficulties
Due to the limitation of using environment: uniApp’s table related components are relatively simple, and there is a large limitation for non-H5 environment (for example, rowSPAN and ColSPAN cannot be set), which is also troublesome to use and cannot meet the requirements of the project. Finally, WE decided to build a wheel by ourselves.
Header section
The main difficulty lies in the processing of multi-level table headers and how to drive the display according to the data. At the beginning, I planned to implement it in the way of HTML table. During the development process, I encountered many problems. Firstly, data processing was troublesome, including calculating the number of rows, colSPAN and Rowspan of each row cell. And there is no TD, TR and other components, need their own additional implementation.
The data of columns is a tree, as follows
columns = [
{ "title": "Area"."dataIndex": "Area" },
{
"title": "Guangzhou District 1"."children": [{"title": "Sales"."dataIndex": "Sales in Guangzhou District 1"},
{ "title": "Planned sale"."dataIndex": "Planned Sales in Guangzhou Area 1" },
{ "title": "A"."dataIndex": "Reached in Guangzhou District 1"}},// ...
]
Copy the code
The flex layout seems to center each grid vertically, traversing the recursive rendering if there are children, and separating the recursive part into a component called titleColumn since the rendering needs to be recursively called. First post a code (the code has been posted to the community, you can check out the portal if you are interested) :
table-header.vue
titleColumn.vue
There is a catch: in normal VUE recursive components are not introduced, but in uniApp they are.
// titleColumn.vue
import titleColumn from "./title-column.vue"
Copy the code
The style aspect is not expanded, so it is not easy to write. See the results directly (feel good about yourself, hahaha) :
Form and content
Here we first need to process the data of columns (considering multi-level table headers), and obtain the actual columns to be rendered according to the columns above:
- Create a new variable
dataIndexs
Is used to hold the column data that needs to be actually rendered - Recursive processing
columns
Take the final leaf node and save it.
Key code:
// Get the actual rendered Column in the body based on Column
fmtColumns(list) {
// Save the leaf node
this.dataIndexs = []
if(! list || ! list.length)return
// Get the actual line
this.columnsDeal(list)
},
//
columnsDeal(list, level = 0) {
list.forEach(item= > {
let{ children, ... res } = itemif (children && children.length) {
this.columnsDeal(children, level + 1)}else {
this.dataIndexs.push({ ... res }) } }) },Copy the code
The next step is to deal with the tree structure in the list data. Let’s look at the data structure tableData:
tableData = [
{
"key": 1."Area": "Guangzhou"."Sales": 100."Planned sale": 200."A": "50.0%"."Reach the rank": 1."GroupIndex": 1."GroupLayer": 1."GroupKey": "Guangzhou"."children": [{
"key": 11."Area": "Guangzhou District 1"."Community": "Guangzhou District 1"."Sales": 60."Planned sale": 120."A": "50.0%"."Reach the rank": 1.children: [{
"key": 111."Area": "Guangzhou District 1 1"."Community": "Guangzhou District 1 1"."Sales": 60."Planned sale": 120."A": "50.0%"."Reach the rank": 1,}}, {"key": 12."Area": "Guangzhou District 2"."Community": "Guangzhou District 2"."Sales": 40."Planned sale": 80."A": "50.0%"."Reach the rank": 1},],},]Copy the code
Tree structure, key is the unique value. I thought about using recursive components, but it would involve expansion and collapse. It’s also a hassle. The final solution is to flatten the data, adding hierarchy, child data, parent ID and other attributes to each data. An array variable is used to record the expanded row and control the display of child data. The processed data is stored in dataList flat processing function:
// Recursively process data, tree => Array
listFmt(list, level, parentIds = []) {
return list.reduce((ls, item) = > {
let{ children, ... res } = item// Error message
if (res[this.idKey] === undefined| |! res[this.idKey] === null) {
// console.error(' tableData has [idKey] property in data, no data, please check ')
}
letnowItem = { ... res, level,hasChildren: children && children.length,
parentIds,
children,
[this.idKey]: res[this.idKey] && res[this.idKey].toString()
}
ls.push(nowItem)
if (children && children.length) {
this.isTree = true
ls = ls.concat(this.listFmt(children, level + 1, [...parentIds, nowItem[this.idKey]]))
}
return ls
}, [])
},
Copy the code
The final data are as follows:
I’m ready to render the data,
Need to nest two layers of traversal:
First layer traversaldataList
Get the line
Layer 2 traversaldataIndexs
Get the column
Final render:
Fix the first column, fix the table header
usecss
Properties:position: sticky
The implementation. Stickily positioned elements. We are all mature front-end ape ~~, I will not be specific. A few details to pay attention to:
compatibility
Uniapp small program mode, App mode is supported!!
limit
-
If position:sticky is set, either top left right bottom must be specified. Unset performance and relative positioning is the same. If top and bottom or left and right are set at the same time, the priorities of top and left are high.
-
The overflow property of any parent of the position:sticky element must be visible otherwise it will not take effect.
other
It’s easy to make a wheel, not easy to make a wheel that works.
Involve some layout and CSS part of the things in the article is not good to express, not in detail, interested can pull the code to see. portal
During the development process, I also encountered a lot of problems, which were patched up all the way. If the idea was not well conceived in the early stage, the subsequent development would be hit and miss (at the beginning, the modules and parameters were not well divided, and the whole logic was chaotic. Later, I stopped to rethink and adjust, and felt suddenly happy).
To move bricks ~