idea
Table is one of the more complex components in the component library, which needs to face more situations. CSS alone cannot write a complete table component. Our table component should be easy to use and extensible enough to meet requirements. Among the tables contacted by the front end, the most common and basic is the ordinary TWO-DIMENSIONAL table. We can start with this simple two-dimensional table and improve this component step by step.
Start to design
The following demos use React as an example, using the style integrated in SluckyUI. Vue and Angular are implemented differently, but the ideas are the same.
First, a table consists of a table header and a table content, whose data structure is two-dimensional, namely rows and columns.
The data structure
Imagine what kind of data structure would be required for a table presentation? Yes, the back-end interface should return an array like this, where the array is a column and the objects in the array contain all the data in a row.
const data=[{
sex:'man',
age:'the'
},{
sex:'feman',
age:'20'
}]
Copy the code
You now have the data structure for the input table component. How does the table know which column to render the key to, how does it know the length of the column, and how does it know the title of the column? Well, at this point our table component should have an option to configure for each column.
Ok, configure each column as follows
dataConf=[{
title:'Custom column name (alias)',
name:'Match the corresponding field in data such as age',
width:'200px||20%'
},{
title:'age',
name:'age',
width:'20%'
}]
Copy the code
Now that we have the configuration and data, all we need to do is render the data in the input table based on the configuration we wrote.
Table structure
Form the head
The header of the column, which is separate from the contents of the table, so we deal with it separately
. <div className="table-head">
{
this.props.dataconf.map((conf, i) => {
return <div style={{ 'width': conf.width }} key={i}>{conf.title||' '}</div>
})
}
</div>
...
Copy the code
It’s a simple process. It’s done in one loop
Form and content
Rendering a two-dimensional data structure is also easy, and two ordinary for loops are done.
// table.jsx
...
<div className="table-body">
{
dataset.map((data, i)=>{
return (
<div className="table-row">
{
dataconf.map((conf, k) => {
return <div className="table-data">data[conf.name]</div>
})
}
</div>
)
})
}
</div>
...
Copy the code
In this way, the basic parts of a table component are set up.
Layout consideration
I have thought about using
series directly to solve the layout problem of the table, which is really convenient, fast, and small change. However, as the requirements gradually became complicated, I found that many problems could not be solved by
Table-row {display: flex; justify-content: space-between; align-items: center; }Copy the code
Note: Div-flex is very flexible and adaptable to different scenarios, but it has a small disadvantage, which I learned later. After selecting the rendered table content with the mouse and pasting it into Excel, the format will be distorted, whereas the traditional table layout can display the complete table. I don’t know when Excel started supporting table recognition…
Expanded function
Most of the time we need tables not only to display data, but also to sort columns, add or subtract rows. Again, how can we easily get the row data to where it needs to be used? As convoluted as it may sound, to delete a row, all we need to do is get the ID of the row and make a network request to delete the row. Well, that’s very clear. How do YOU implement React?
// table.jsx
...
<div class="table-body">
{
dataset.map((data, i)=>{
return (
<div className="table-row">
{
dataconf.map((conf, k) => {
return (
<div style={{ 'width': conf.width }}> { ! conf.rander? <div className="table-data">data[conf.name]</div>:null
}
{
conf.rander?<div className="table-data">{conf.rander(data, i)}</div>:null
}
</div>
)
})
}
</div>
)
})
}
</div>
...
Copy the code
Yes, a function callback is cleverly set up in place to pass out the corresponding row, and we configure it this way.
dataConfig=[{
width: '10%',
rander:(data,index)=>{
return< div onClick = {() = > {conslog (data) HTTP. DelRecord (data. Id)}} > delete < / div >}}]Copy the code
When implementing a similar Api from Angular2+, the most important thing is to solve the problem of scoping, which is not as flexible as JSX, so I won’t go into too much analysis here.
Some interesting features
Of course, with the Rander option in our table, we have completely decoupled user actions. In this case, user action related functionality is integrated into the table component just for convenience.
The progress bar
// table.jsx
...
<div class="table-body">
{
dataset.map((data, i)=>{
return (
<div className="table-row">
{
dataconf.map((conf, k) => {
return (
<div style={{ 'width': conf.width }}>
...
<div className="d-il">
{
!conf.pipe ? (
<span className="p-r z10">{data[conf.name]}</span>
) : null
}
<progress max="100" value={conf.progress && conf.progress(data)}
className="progress-loading"></progress>
</div>
...
</div>
)
})
}
</div>
)
})
}
</div>
...
Copy the code
dataConfig=[{
width: '10%',
title: 'progress',
width: '20%', progress: () => {// Return 0-100 for progress percentagereturn50}}]Copy the code
A balloon
// table.jsx
...
<div class="table-body">
{
dataset.map((data, i)=>{
return (
<div className="table-row">
{
dataconf.map((conf, k) => {
return (
<div style={{ 'width': conf.width }}>
...
<div class="pop-box">
<div className="pop-toggle ptb4 mlr4">
<div className="pop-main pr8">
<div className="pop-content">
{conf.popup(data, i)}
</div>
</div>
</div>
</div>
...
</div>
)
})
}
</div>
)
})
}
</div>
...
Copy the code
dataConfig=[{
width: '10%',
title: 'popup',
width: '20%',
popup: () => {
return<button> </button>},}]Copy the code
See the full version of the Table component && used by the style, feel good if you might as well click a star ha ha.
Note: Style is another topic, see Re from Scratch UI Library Authoring life specification.
At the end
The table component is not as difficult as you might think, as long as you figure out how to separate the decoupled parts, the rest of the job is to use your imagination and add functionality to it. More interesting components in SluckyUI, welcome to more exchanges, looking forward to your participation.
Series of portals from scratch
- Re from scratch UI library authoring life specification
- Re from scratch UI library writing buttons for Life
- Re writing forms for Life from scratch UI Library
- Re from scratch UI library writing life table
- Re from scratch UI library writing life loading progress bar
- Re from scratch UI library writing Life pages
- Re from scratch UI library to write life’s menu navigation bar
- Re from scratch UI library writing life messages popover
- Re writing life step Manager from scratch UI library
- Re writing Life’s Bread Crumbs from scratch UI Library
- “Re from scratch webpack4 practical to full practice”
- Efficient React+Redux Project Architecture from Scratch
- Re back-end learning configuration for Ubuntu+Ngnix+Nodejs+Mysql environment from scratch