用ReactJs编写的带斜线,行和列都分组的表格

NewUserTrackTable.js文件

/**
 * Created by Administrator on 2017/3/3 0003.
 */
import React, {Component} from "react"
import "./NewUserTrackTable.less"
var g_index = -1;
export default class NewUserTrackTable extends Component {
    constructor(props) {
        super(props);
        this.state = {
            "kpi": {
                "id": "01",
                "title": "发展用户"
            },
            "thData": [
                {
                    "year": "2015年",
                    "months": [
                        "1月",
                        "2月"
                    ]
                },
                {
                    "year": "2016年",
                    "months": [
                        "1月",
                        "2月",
                        "3月",
                        "4月"
                    ]
                },
                {
                    "year": "2017年",
                    "months": [
                        "1月",
                        "2月",
                        "3月"
                    ]
                }
            ],
            "tbodyData": [
                {
                    "year": "2015年",
                    "months": [
                        {
                            "month": "1月",
                            "net_value": "220",
                            "obs_values": [
                                "111",
                                "222",
                                "333",
                                "333",
                                "3333",
                                "3333",
                                "444",
                                "3333",
                                "444"
                            ]
                        },
                        {
                            "month": "2月",
                            "net_value": "220",
                            "obs_values": [
                                "111",
                                "222",
                                "333",
                                "333",
                                "3333",
                                "3333",
                                "444",
                                "3333",
                                "444"
                            ]
                        },
                        {
                            "month": "3月",
                            "net_value": "220",
                            "obs_values": [
                                "111",
                                "222",
                                "333",
                                "333",
                                "3333",
                                "3333",
                                "444",
                                "3333",
                                "444"
                            ]
                        },
                        {
                            "month": "4月",
                            "net_value": "220",
                            "obs_values": [
                                "111",
                                "222",
                                "333",
                                "333",
                                "3333",
                                "3333",
                                "444",
                                "3333",
                                "444"
                            ]
                        }
                    ]
                },
                {
                    "year": "2016年",
                    "months": [
                        {
                            "month": "1月",
                            "net_value": "220",
                            "obs_values": [
                                "111",
                                "222",
                                "333",
                                "333",
                                "3333",
                                "3333",
                                "444",
                                "3333",
                                "444"
                            ]
                        },
                        {
                            "month": "2月",
                            "net_value": "220",
                            "obs_values": [
                                "111",
                                "222",
                                "333",
                                "333",
                                "3333",
                                "3333",
                                "444",
                                "3333",
                                "444"
                            ]
                        },
                        {
                            "month": "3月",
                            "net_value": "220",
                            "obs_values": [
                                "111",
                                "222",
                                "333",
                                "333",
                                "3333",
                                "3333",
                                "444",
                                "3333",
                                "444"
                            ]
                        },
                        {
                            "month": "4月",
                            "net_value": "220",
                            "obs_values": [
                                "111",
                                "222",
                                "333",
                                "333",
                                "3333",
                                "3333",
                                "444",
                                "3333",
                                "444"
                            ]
                        }
                    ]
                }
            ]
        }
    }

    getDepth = (data)=> {
        return data.months.length;
    }
    componentDidMount = ()=> {
        /*给表格画表头斜线*/
        // var myCanvas = document.getElementById("myCanvas-nutt");
        var myCanvas=this.refs.myCanvasNUTT;
        var width = myCanvas.width;
        var height = myCanvas.height;
        var ctx = myCanvas.getContext("2d");
        ctx.strokeStyle = "#ffffff";
        ctx.moveTo(0, 0);
        ctx.lineTo(width, height);
        ctx.stroke();


        /*根据表格列数给表格设置宽度*/
        var tableId=this.props.tableId;
        var _tds=this.state.tbodyData[0].months[0].obs_values.length+3;
        document.getElementById(tableId).width=_tds*100+"px";
    }
    getNormalTdStyle = (gindex)=> {
        return gindex % 2 == 0 ? "bg-white" : "bg-gray border-bottom";
    }
    getTableNode = (table, _net_year, data, depth, obsLastMontIndex)=> {
        if (data.length > 0) {
            data.map((netMonth, index)=> {
                g_index++;
                var obj = null;
                var _obs_values = netMonth.obs_values;
                if (_obs_values.length > 0) {
                    var normalTd = _obs_values.map((obsValue, index)=> {
                        return (
                            <td className={this.getNormalTdStyle(g_index, index) + " " + this.isShowBorderRight(index, obsLastMontIndex)}>{obsValue}</td>
                        );
                    })
                }
                if (index == 0) {

                    obj = <tr>
                        <td rowSpan={depth} className="kpi-bg">{_net_year}</td>
                        <td className="kpi-bg">{netMonth.month}</td>
                        <td className="kpi-bg">{netMonth.net_value}</td>
                        {normalTd}
                    </tr>

                }
                else {

                    obj = <tr>
                        <td className="kpi-bg">{netMonth.month}</td>
                        <td className="kpi-bg">{netMonth.net_value}</td>
                        {normalTd}
                    </tr>

                }
                if (obj) {
                    table.push(obj);
                }
            })
        }
    }
    getTable = (tree, data, obsLastMontIndex)=> {
        if (data.length > 0) {
            data.map((netYear, index)=> {
                var _data = netYear.months;
                var _depth = this.getDepth(netYear);
                var _net_year = netYear.year;
                this.getTableNode(tree, _net_year, _data, _depth, obsLastMontIndex);
            })
        }
    }
    /*
     * 该函数用来给相应的td或th添加右边的边框线
     * index改td或th的索引
     * obsMonth记录观察年月中每个年中最后一个月份所对应的索引。
     * */
    isShowBorderRight = (index, obsMonth)=> {
        return obsMonth.indexOf(index + 1) != -1 ? "border-right" : "";
    }
    render = ()=> {
        var table_id = this.props.tableId;
        var kpi = this.state.kpi;
        var thData = this.state.thData;
        var obs_month = thData[0].months;
        var tree = [];
        var _obs_lastmonth_index = [thData[0].months.length];//记录观察年月中每个年中最后一个月份所对应的索引。
        var tbodyData = this.state.tbodyData;
        if (thData.length > 0) {
            var obs_year_th = thData.map((obsYear, index)=> {
                var _depth = this.getDepth(obsYear);
                if (index > 0) {
                    _obs_lastmonth_index.push(_obs_lastmonth_index[_obs_lastmonth_index.length - 1] + obsYear.months.length);
                    Array.prototype.push.apply(obs_month, obsYear.months);
                }
                return (
                    <th colSpan={_depth} className="bg-gray border-right">
                        {obsYear.year}
                    </th>
                );
            })
        }
        if (obs_month.length > 0) {
            var obs_month_th = obs_month.map((obsMonth, index)=> {
                return (
                    <th className={this.isShowBorderRight(index, _obs_lastmonth_index) + " bg-gray border-bottom"}>
                        {obsMonth}
                    </th>
                );
            })
        }
        this.getTable(tree, tbodyData, _obs_lastmonth_index);
        return (
            <div className="new-user-track-table-box">
                <canvas ref="myCanvasNUTT" className="myCanvas"></canvas>
                <table id={table_id} className="new-user-track-table">
                    <thead>
                    <tr>
                        <th colSpan="2" rowSpan="2" className="kpi-bg">
                            <div style={{textAlign: "right", marginRight: "20px"}}>观察年月</div>
                            <div style={{textAlign: "left", marginLeft: "20px"}}>入网年月</div>
                        </th>
                        <th rowSpan="2" className="kpi-bg">{kpi.title}</th>
                        {obs_year_th}
                    </tr>
                    <tr>
                        {obs_month_th}
                    </tr>
                    </thead>
                    <tbody>
                    {tree}
                    </tbody>
                </table>
            </div>
        );
    }
}



NewUserTrackTable.less文件

.new-user-track-table-box{
  width: 100%;
  height: auto;
  overflow-x: scroll;
}
.new-user-track-table{
  margin-left: 10px;
  margin-top: -75px;
  height: auto;
}
.kpi-bg{
  text-align: center;
  width: 100px;
  height: 40px;
  color:#FFF7F6;
  border: solid 1px #AEBECF;
  background-color: #B7CDE5;
}
.bg-gray{
  text-align: center;
  width: 100px;
  height: 40px;
  background-color: #FAFAFA;
}
@border:solid 1px #cfcfcf;
.border-bottom{
  border-bottom: @border;
}
.bg-white{
  text-align: center;
  width: 100px;
  height: 40px;
  background-color: #ffffff;
  border-bottom: @border;
}
.border-right{
  border-right: @border;
}
.myCanvas{
  position: relative;
  top: 10px;
  left: 10px;
  width: 200px;
  height: 80px;
}

表格截图如下

<think>嗯,用户的问题是关于如何保存回显从动态查询生成的二维表格数据。首先,我需要理解用户的需求。他们提到数据是动态查询生成的,都不固定,需要动态渲染,并且支持修改后的保存回显。这可能涉及到前端后端的协作。 根据用户提供的引用[1],业务模型是动态表格由后台数据提供,需要动态构建可编辑。所以保存的时候,需要将表格的结构数据一起保存。可能的结构包括表头(名)数据,每个单元格的数据。回显的时候需要重新渲染这个结构,并且填入数据。 引用[2]提到在Vue3或Nuxt3中使用arco.design表格处理嵌套多维数组,合并单元格等。这可能涉及到前端如何将二维数组的数据渲染成表格,特别是在动态的情况下,可能需要根据数据动态生成配置。保存时,可能需要将表格数据转换为二维数组或对象数组,然后发送到后端存储。 引用[3]讨论了存储对象时使用String+JSON还是Hash。这里的数据结构可能更适合用JSON格式,因为表格的结构不固定,JSON可以灵活地表示动态的。 那保存数据的时候,前端需要将表格的数据结构(比如名)内容整合成一个数据结构,比如包含columnsrows的对象,然后序化为JSON保存到后端。后端可能需要存储这个JSON字符串,或者拆解到数据库中。如果是频繁查询动态结构,可能用NoSQL数据库更合适,比如MongoDB,因为它的文档结构灵活。或者,如果使用关系型数据库,可能需要设计一个弹性表结构,比如一个表存储定义,另一个表存储每个单元格的数据,关联。 回显的时候,后端返回之前保存的数据结构,前端解析后动态渲染表格。比如,使用arco.design的表格组件,根据columns动态生成表头,rows生成表格,并且绑定每个单元格的数据。编辑时,通过v-model或类似的双向绑定机制,实时更新数据,保存时提交整个结构。 难点可能在于动态表格的渲染编辑绑定,尤其是当不固定时,如何为每个单元格创建正确的数据绑定。另外,合并单元格的情况可能需要额外的配置,比如rowspancolspan的处理,这在动态生成表格时比较复杂,需要根据数据内容动态计算合并方式。 总结步骤应该是:1. 数据结构设计,包含信息数据。2. 前端动态渲染表格,支持编辑。3. 保存数据时序化结构并存储。4. 回显时读取数据并重新渲染。需要确保前后端的数据格式一致,并且处理可能的合并单元格需求。</think>### 动态二维表数据保存与回显解决方案 #### 一、数据结构设计(核心步骤) 1. **动态表头**:使用数组存储信息,例如: ```javascript columns: [ { key: 'x1', label: '字段1' }, { key: 'x2', label: '字段2' } ] ``` 2. **动态数据**:使用二维数组或对象数组存储: ```javascript // 二维数组格式(推荐) tableData: [ ['值11', '值12'], ['值21', '值22'] ] // 或对象数组格式 tableData: [ { x1: '值11', x2: '值12' }, { x1: '值21', x2: '值22' } ] ``` 推荐使用二维数组格式以简化动态处理[^1] #### 二、保存数据实现 1. **前端序化**: ```javascript const savePayload = { columns: this.columns.map(col => col.key), data: this.tableData } // 发送给后端 axios.post('/api/save', JSON.stringify(savePayload)) ``` 2. **后端存储方案**: - **方案1**:使用`TEXT`类型字段存储JSON字符串(适合低频修改) ```sql CREATE TABLE dynamic_table ( id INT PRIMARY KEY, config JSON ) ``` - **方案2**:拆分存储(适合高频查询) ```sql -- 定义表 CREATE TABLE columns ( table_id INT, col_key VARCHAR(50), col_order INT ) -- 数据存储表 CREATE TABLE cell_data ( row_id INT, col_key VARCHAR(50), value TEXT ) ``` #### 三、数据回显实现 1. **前端动态渲染**(以arco.design为例): ```vue <a-table :data="tableData"> <a-table-column v-for="(col, index) in columns" :key="index" :title="col.label" > <template #cell="{ record }"> <a-input v-model="record[index]" /> </template> </a-table-column> </a-table> ``` 2. **嵌套数据处理**: ```javascript // 从接口获取数据后重组结构 axios.get('/api/data').then(res => { this.columns = res.data.columns.map(key => ({ key, label: key.toUpperCase() })) this.tableData = res.data.rows }) ``` #### 四、合并单元格处理 ```vue <a-table :span-method="spanMethod"> <!-- 定义 --> </a-table> <script> // 合并策略函数 const spanMethod = ({ row, column }) => { if (column.dataIndex === 'x1') { return { rowspan: row.children?.length || 1 } } return { rowspan: 1 } } </script> ``` ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值