Home Reference Source Repository

src/Table.js

/**
 * @file melon/Table
 * @author leon([email protected])
 */

import React, {Component, PropTypes, Children} from 'react';
import Row from './table/Row';
import * as dom from './common/util/dom';
import {create} from 'melon-core/classname/cxBuilder';
import Column from './table/Column';

const cx = create('Table');

export default class Table extends Component {

    constructor(props) {

        super(props);

        this.state = {
            columns: this.getColumns(this.props)
        };

        this.onWindowResize = this.onWindowResize.bind(this);
    }

    componentDidMount() {
        this.onWindowResize();
        dom.on(window, 'resize', this.onWindowResize);
    }

    componentWillReceiveProps(nextProps) {
        this.setState({
            columns: this.getColumns(nextProps)
        });
    }

    componentWillUnmount() {
        dom.off(window, 'resize', this.onWindowResize);
    }

    getColumns(props) {

        return Children
            .toArray(props.children)
            .reduce(
                (children, child) => {

                    if (child != null) {

                        if (child.type._TABLE_COMPONENT_ !== 'COLUMN') {
                            throw new Error('Table child must be a TableColumn');
                        }

                        children.push(child);

                    }

                    return children;
                },
                []
            );

    }

    renderHeader(columns, width) {
        const {props} = this;
        return (
            <div className={cx().part('header').build()}>
                <Row
                    part='header'
                    height={props.headerRowHeight}
                    columns={columns}
                    tableWidth={width} />
            </div>
        );
    }

    renderBody(columns, width) {

        const {dataSource, noDataContent} = this.props;

        const body = dataSource && dataSource.length
            ? dataSource.map(
                (rowData, index) => this.renderRow(columns, rowData, index, width)
            )
            : (
                <div
                    className={cx().part('body-empty').build()}
                    style={{width: width - 2}}>
                    {noDataContent}
                </div>
            );

        return (
            <div className={cx().part('body').build()}>
                {body}
            </div>
        );

    }

    renderRow(columns, rowData, index, tableWidth) {
        const {rowHeight, highlight} = this.props;
        return (
            <Row
                height={rowHeight}
                highlight={highlight}
                key={index}
                rowIndex={index}
                part='body'
                columns={columns}
                data={rowData}
                tableWidth={tableWidth} />
        );
    }

    renderFooter(columns) {
        return null;
    }

    onWindowResize() {

        const {main} = this;

        if (this.main) {
            this.setState({
                width: main.offsetWidth
            });
        }

    }

    render() {

        let {width, columns} = this.state;

        if (width) {
            // 计算出tableWidth和所有的columnWidth,将更大的一个传递给row使用
            width = Math.max(
                width,
                columns.reduce(
                    (width, columns) => width + columns.props.width,
                    0
                )
            );
        }
        else {
            width = '';
        }

        return (
            <div
                className={cx(this.props).build()}
                ref={main => {
                    this.main = main;
                }}>
                {this.renderHeader(columns, width)}
                {this.renderBody(columns, width)}
                {this.renderFooter(columns, width)}
            </div>
        );

    }



}

Table.displayName = 'Table';

Table.propTypes = {
    rowHeight: PropTypes.number.isRequired,
    highlight: PropTypes.bool,
    headerRowHeight: PropTypes.number,
    dataSource: PropTypes.array.isRequired,
    noDataContent: PropTypes.node
},

Table.defaultProps = {
    highlight: true,
    rowHeight: 48,
    headerRowHeight: 56,
    noDataContent: '没有数据'
};

Table.Column = Column;