使用rowSpan,如何在HTML表格上正确显示为单个单元递归分组的数据?

时间:2018-10-29 23:49:31

标签: javascript html reactjs

我已经开发了以下ReactJS组件,作为可将相似数据分组在一起的网格的模板:

汽车数据:

let cars = [
    {
        brand: "Audi",
        color: "Red",
        year: "1993",
        miles: "1234"
    },
    {
        brand: "Audi",
        color: "Blue",
        year: "1992",
        miles: "1234"
    },
    {
        brand: "Audi",
        color: "White",
        year: "1992",
        miles: "1234"
    },
    {
        brand: "Audi",
        color: "Red",
        year: "1991",
        miles: "1234"
    },
    {
        brand: "Audi",
        color: "Black",
        year: "1995",
        miles: "1234"
    },
    {
        brand: "Mercedes",
        color: "Red",
        year: "1992",
        miles: "1234"
    },
    {
        brand: "Mercedes",
        color: "Red",
        year: "1993",
        miles: "1234"
    },
    {
        brand: "Mercedes",
        color: "Blue",
        year: "1994",
        miles: "1234"
    },
    {
        brand: "Mercedes",
        color: "Black",
        year: "1994",
        miles: "1234"
    },
    {
        brand: "Mercedes",
        color: "White",
        year: "1992",
        miles: "1234"
    },
    {
        brand: "BMW",
        color: "Red",
        year: "1995",
        miles: "1234"
    },
    {
        brand: "BMW",
        color: "Blue",
        year: "1992",
        miles: "1234"
    },
    {
        brand: "BMW",
        color: "Red",
        year: "1994",
        miles: "1234"
    },
    {
        brand: "BMW",
        color: "Black",
        year: "1992",
        miles: "1234"
    },
    {
        brand: "BMW",
        color: "White",
        year: "1993",
        miles: "1234"
    }
];

组件:

const groupBy = (arr, fields) => {
    let field = fields[0];

    if (!field) return arr;

    let retArr = Object.values(
        arr.reduce((obj, current) => {
            let val = current[field];
            if (!obj[val]) obj[val] = { rows: [] };
            obj[val].rows.push(current);
            return obj;
        }, {})
    );

    if (fields.length) {
        retArr.forEach((obj, index) => {
            obj.rows = groupBy(obj.rows, fields.slice(1));
        });
    }

    return retArr;
};

const getRowsFromGrouped = rows => {
    let ret = [];

    rows.map(row => {
        if (row.rows) {
            ret = ret.concat(getRowsFromGrouped(row.rows));
        } else {
            ret.push(row);
        }
    });

    return ret;
};

class App extends Component {
    state = {
        groups: []
    };

    handleClick = key => {
        let groups = this.state.groups;

        let index = groups.findIndex(item => {
            return key === item;
        });

        if (index < 0) groups.push(key);
        else groups.splice(index, 1);

        this.setState({
            groups: groups
        });
    };

    getHeader = row => {
        let data = Object.keys(row).map((col, index) => {
            return <td key={"Head" + index}>{col}</td>;
        });

        return (
            <thead>
                <tr>{data}</tr>
            </thead>
        );
    };

    getColumns = row => {
        return Object.keys(row).map((col, index) => {
            return <td key={"Col" + index}>{row[col]}</td>;
        });
    };

    getRows = rows => {
        let data = rows.map((row, index) => {
            return <tr key={index}>{this.getColumns(row)}</tr>;
        });

        return <tbody>{data}</tbody>;
    };

    renderGrid = rows => {
        return (
            <table>
                {this.getHeader(rows[0])}
                {this.getRows(rows)}
            </table>
        );
    };

    renderGroupOptions = () => {
        return (
            <div>
                <p>
                    <input
                        type="checkbox"
                        onClick={() => this.handleClick("brand")}
                    />
                    Group By Brand
                </p>
                <p>
                    <input
                        type="checkbox"
                        onClick={() => this.handleClick("color")}
                    />
                    Group By Color
                </p>
                <p>
                    <input
                        type="checkbox"
                        onClick={() => this.handleClick("year")}
                    />
                    Group By Year
                </p>
            </div>
        );
    };

    render = () => {
        let rows = cars;
        if (this.state.groups.length > 0) {
            let data = groupBy(cars, this.state.groups);
            rows = getRowsFromGrouped(data);
        }

        return (
            <div>
                <h1>AUTO GRID</h1>
                {this.renderGrid(rows)}
                {this.renderGroupOptions()}
            </div>
        );
    };
}

经开发,分组效果很好。根据组的选择顺序,网格结果会有所不同,因为组是在无限结构中现有组之上构建的。

很好,但是现在我仍在寻找一种方法,可以使用rowSpan属性在表格的单个单元格中正确显示网格分组数据。像这样:

enter image description here

单元格分组必须紧随组,然后按照分组后的顺序将分组后的数据连接在一起。

我一直困扰着这个单元格跨度问题,却没有找到一种合理的方式来渲染然后一起渲染。

0 个答案:

没有答案