Skip to content

Instantly share code, notes, and snippets.

@xyzdata
Created July 12, 2017 01:21
Show Gist options
  • Save xyzdata/a2a2943e8338452a8c6c8b7c254a4d79 to your computer and use it in GitHub Desktop.
Save xyzdata/a2a2943e8338452a8c6c8b7c254a4d79 to your computer and use it in GitHub Desktop.
dva-router

dva-router

https://github.com/pmg1989/dva-admin/blob/master/src/index.js

    
import dva from 'dva';
import { browserHistory } from 'dva/router';
import createLoading from 'dva-loading';
import { message } from 'antd';

import './index.html';
import './index.css';

// 3 秒
const ERROR_MSG_DURATION = 3; 

// 1. Initialize
const app = dva({
    history: browserHistory,
    onError(e) {
        message.error(e.message, ERROR_MSG_DURATION);
        console.error("app onError -- ", error);
    }
});

// 2. Plugins
app.use(createLoading());

// 3. Model
// Moved to router.js
// app.model(require('./models/users'))

// 4. Router for browserHistory
app.router(require('./router'));

// 5. Start
app.start('#root');

dva knowledge map

https://github.com/dvajs/dva-knowledgemap#通过-connect-绑定数据

https://github.com/dvajs/dva-knowledgemap#增删改

@xyzdata
Copy link
Author

xyzdata commented Jul 13, 2017

卡片式页签 Tab Pane

Tab Page 标签页

https://ant.design/components/tabs-cn/

@xyzdata
Copy link
Author

xyzdata commented Jul 13, 2017

DropOption

// Warning: Failed prop type: The prop `menuOptions` is marked as required in `DropOption`, but its value is `undefined`.

import {DropOption} from '../utils/DropOption';



    {
        title: '编辑',
        dataIndex: 'edit',
        key: 'editRole',
        render: (text, record, index) => {
            const clickOK = (record) => {
                return record.pid = "new pid";
            };
            const menu = (
                <Menu>
                    <Menu.Item>
                    <a rel="noopener noreferrer" href="https://www.xgqfrms.xyz/">1st</a>
                    </Menu.Item>
                    <Menu.Item>
                    <a rel="noopener noreferrer" href="https://www.xgqfrms.xyz/">2nd</a>
                    </Menu.Item>
                    <Menu.Item>
                    <a rel="noopener noreferrer" href="https://www.xgqfrms.xyz/">3rd</a>
                    </Menu.Item>
                </Menu>
            );
            return(
                <span>
                    <DropOption 
                        onMenuClick={e => handleMenuClick(record, e)} 
                        overlay={menu}
                        menuOptions={[
                            {key: '1', name: '更新'},
                            {key: '2', name: '删除'}
                        ]} 
                    />
                    <EMC
                        data={record}
                        clickOK={clickOK}
                    >
                        <span>{text} 编辑</span>
                    </EMC>
                </span>
            );
        }
    }

@xyzdata
Copy link
Author

xyzdata commented Jul 13, 2017

二次封装 Dropdown

import React from 'react';
import PropTypes from 'prop-types';

import {Dropdown, Button, Icon, Menu} from 'antd';


// 二次封装 Dropdown

const DropOption = ({onMenuClick, menuOptions = [], buttonStyle, dropdownProps}) => {
    // 列出 menu 所有的 items
    const menuItems = menuOptions.map(
        (item) => {
            // console.log(`item `, item);
            // console.log(`item.key `, item.key);
            // console.log(`typeof item.key `, typeof(item.key));
            // if(item.key === "2" || item.name === "删除")
            const styles = {
                css1: {
                    color: "red", 
                    border: '1px solid red', 
                    borderRadius: '5px', 
                    textAlign: 'center'
                },
                css2: {
                    color: "#000", 
                    border: '1px solid #ccc', 
                    borderRadius: '5px', 
                    textAlign: 'center'
                }
            };
            if(item.name === "删除"){
                return(
                    <Menu.Item key={item.key} style={styles.css1}>
                        {item.name}
                    </Menu.Item>
                )
            }else{
                return(
                    <Menu.Item key={item.key} style={styles.css2}>
                        {item.name}
                    </Menu.Item>
                )
            }
        }
    );
    // Dropdown
    return (
        <Dropdown
            overlay={
                <Menu onClick={onMenuClick}>
                    {menuItems}
                </Menu>
            }
            trigger={['click']}
            {...dropdownProps}
            >
            <Button
                style={
                    {
                        border: 'none', 
                        background: '#ccc',
                        ...buttonStyle
                    }
                }
                >
                <Icon 
                    style={{marginRight: 5}} 
                    type="bars"
                />
                <Icon type="down" />
            </Button>
        </Dropdown>
    );
};

DropOption.propTypes = {
    onMenuClick: PropTypes.func,
    menuOptions: PropTypes.array.isRequired,
    buttonStyle: PropTypes.object,
    dropdownProps: PropTypes.object
};

export {DropOption};
export default DropOption;

@xyzdata
Copy link
Author

xyzdata commented Jul 13, 2017

date.toString().substr(0,10)

        {
            title: '创建时间',
            dataIndex: 'createTime',
            key: 'createTime',
            render: (date) => (
                // 2017-02-12 08:11:08
                // substr(begin [,end])
                // substr(10) === " 08:11:08"
                // substr(0,10) === "2017-02-12"
                date.toString().substr(0,10)
            )
        },

@xyzdata
Copy link
Author

xyzdata commented Jul 13, 2017

image

react-redux

@xyzdata
Copy link
Author

xyzdata commented Jul 13, 2017

Layout

Layout:布局容器,其下可嵌套 Header Sider Content Footer 或 Layout 本身,可以放在任何父容器中。
Header:顶部布局,自带默认样式,其下可嵌套任何元素,只能放在 Layout 中。
Sider:侧边栏,自带默认样式及基本功能,其下可嵌套任何元素,只能放在 Layout 中。
Content:内容部分,自带默认样式,其下可嵌套任何元素,只能放在 Layout 中。
Footer:底部布局,自带默认样式,其下可嵌套任何元素,只能放在 Layout 中。

https://ant.design/components/layout-cn/

https://ant.design/components/tabs-cn/

@xyzdata
Copy link
Author

xyzdata commented Jul 14, 2017

React table

React table with column sorting (asc, desc), input filtering, and row ordering

https://codereview.stackexchange.com/questions/106908/react-table-with-column-sorting-asc-desc-input-filtering-and-row-ordering

https://codepen.io/reggi/pen/KdqdMW?editors=001

2.10.6/moment.min.js, react-with-addons-0.13.3.js, 3.0.1/lodash.min.js

function recursive(collection, callback, recursiveIndexCb) {
    var indexed = (recursiveIndexCb)
        ? recursive.recursiveIndex(collection, recursiveIndexCb)
        : false;
    var meta = (recursiveIndexCb)
        ? recursive.meta(indexed)
        : false;
    function wrapper(callback) {
        return function () {
            var args = _.values(arguments);
            var id = args[1];
            var recursiveId = (this.id === 0)
                ? id.toString()
                : id + '.' + this.id;
            args.push(recursiveId);
            return callback.apply({
                'meta': meta,
                'indexed': indexed
            }, args);
        }.bind(this);
    }
    var recursed = false;
    function _recursive(collection, callback) {
        recursed = (recursed === false)
            ? 0
            : recursed + 1;
        return callback(collection, _.partialRight(_recursive, callback), wrapper.bind({'id': recursed}));
    }
    return _recursive(collection, callback);
};

recursive.compare = function (n1, n2) {
    var path1 = n1.split('.');
    var path2 = n2.split('.');
    var maxLen = Math.max(path1.length, path2.length);
    var i = 0;
    while (i < maxLen) {
        if (!path1[i] || + path1[i] < + path2[i]) {
            return -1;
        }
        if (!path2[i] || + path1[i] > + path2[i]) {
            return 1;
        }
        i++;
    }
    return 0;
};

recursive.subset = function (ids, id) {
    return _.filter(ids, function (_id) {
        var _idArr = _id.split('.');
        var idArr = id.split('.');
        var _idChop = _.take(_idArr, _idArr.length - 1).join('.');
        var idChop = _.take(idArr, idArr.length - 1).join('.');
        if (_idChop === idChop) 
            return true;
        return false;
    });
};
/* 
wrapper(function (node, id, nodes, recursiveId) {
    if (node.children) 
        recursive(node.children);
    result[recursiveId] = node;
}
 */
recursive.recursiveIndex = function (nodes, recursiveIndexCb) {
    var result = {};
    recursive.recursive(nodes, function (node, recursive, wrapper) {
        _.each(node, function (value, key, values, rId) {
            var args = _.values(arguments);
            var val = recursiveIndexCb.apply(null, args);
            result[rId] = val;
        });
    }, true);
    return result;
};

recursive.meta = function (indexed) {
    var ids = _.keys(indexed);
    return function (id, distance) {
        distance = (distance)
            ? distance
            : 1;
        ids = ids.sort(recursive.compare);
        var idIndex = ids.indexOf(id);
        var meta = {};
        meta.prev = (ids[idIndex - distance])
            ? ids[idIndex - distance]
            : false;
        meta.next = (ids[idIndex + distance])
            ? ids[idIndex + distance]
            : false;
        var idsSubset = recursive.subset(ids, id);
        var idSubsetIndex = idsSubset.indexOf(id);
        meta.prevSibling = (idsSubset[idSubsetIndex - distance])
            ? idsSubset[idSubsetIndex - distance]
            : false;
        meta.nextSibling = (idsSubset[idSubsetIndex + distance])
            ? idsSubset[idSubsetIndex + distance]
            : false
        return meta;
    };
};

var st = {};

/** ensure children or reactFragment is an array of reactElements */
st.ensureChildrenArray = function (children) {
    var results = [];
    React.Children.forEach(children, function (child) {
            results.push(child);
        });
    return results;
};

// I know this is bad practice but I'm not sure of an alternative
/** map children and clone with props assign random key */
st.cloneChildren = function (children) {
    return React.Children.map(children, function (child, i) {
        return React.addons.cloneWithProps(child, {'key': Math.random()});
    });
};

/** sorts chilren based on column property */
st.sortChildren = function (children, column, format, direction) {
    children = st.ensureChildrenArray(children);
    var results = _.sortBy(children, function (item) {
        var match = _.find(item.props.children, function (child) {
            return (child.props.column === column);
        });
        if (format) 
            return moment(match.props.children, format).toDate();
        return match.props.children;
    })
    if (direction === 'asc') 
        results = results.reverse();
    return st.cloneChildren(results);
};

/** filters array of children based on value */
st.filterChildren = function (children, filterValue, caseSensitive) {
    children = st.ensureChildrenArray(children);
    var results = recursive(children, function (children, recursion, wrapper) {
        return _.filter(children, wrapper(function (child) {
            if (typeof child.props.children !== 'string') {
                var result = recursion(child.props.children);
                return Boolean(result.length);
            } else {
                var flag = (caseSensitive)
                    ? ''
                    : 'i';
                var pattern = new RegExp(filterValue, flag);
                var value = child.props.children.match(pattern);
                return value;
            }
        }))
    });
    return st.cloneChildren(results);
};

st.objectWithOneProp = function (prop, val) {
    var temp = {};
    temp[prop] = val;
    return temp;
};

st.invokeSort = function (column, dateFormat) {
    return function (event) {
        var data = {};
        data.stateCycle = ['desc', 'asc'];
        data.column = 'header_' + column;
        data.headerState = this.state[data.column];
        data.index = _.indexOf(data.stateCycle, data.headerState);
        data.nextState = (data.index !== (data.stateCycle.length - 1))
            ? data.stateCycle[data.index + 1]
            : data.stateCycle[0];
        data.setState = st.objectWithOneProp('header_' + column, data.nextState);
        data.sortedChildren = st.sortChildren(this.refs.tbody.state.children, column, dateFormat, data.headerState);
        this.setState(data.setState)
        this.refs.tbody.setState({children: data.sortedChildren});
    }.bind(this);
};

st.invokeFilter = function (event) {
    var data = {};
    data.filteredChildren = st.filterChildren(this.refs.tbody.props.children, event.target.value, false);
    this.refs.tbody.setState({children: data.filteredChildren});
};

st.onMountOrder = function (elm) {
    return _.sortBy(elm.state.children, function (item) {
        return item.props.column;
    });
};



var StatefulChildren = React.createClass({
    displayName: 'StatefulChildren',
    propTypes: {
        children: React.PropTypes.node,
        element: React.PropTypes.string,
        defaultElement: React.PropTypes.string,
        modify: React.PropTypes.array || React.PropTypes.func
    },
    getDefaultProps: function () {
        return {defaultElement: 'span'};
    },
    getInitialState: function () {
        return {children: this.props.children};
    },
    componentWillMount: function () {
        if (typeof this.props.modify === 'function') {
            this.setState({
                children: this.props.modify(this)
            })
        } else if (this.props.modify) {
            this.props.modify.forEach(
                function (mod) {
                    this.setState({children: mod(this)})
                }.bind(this)
            );
        }
    },
    render: function () {
        var props = _.omit(this.props, ['element', 'defaultElement', 'children']);
        if (this.props.element) {
            return React.createElement(this.props.element, props, this.state.children);
        } else if (typeof this.state.children === 'string' || !React.isValidElement(this.state.children)) {
            return React.createElement(this.props.defaultElement, props, this.state.children);
        } else {
            return this.state.children;
        }
    }
})

var Table = React.createClass({
    getInitialState: function () {
        return {
            'header_date': 'desc',
            'header_name': 'desc'
        }
    },
    render: function () {
        return (
            <div>
                <input type='text' onChange={st.invokeFilter.bind(this)}/>
                <table>
                    <StatefulChildren element='thead' modify={[st.onMountOrder.bind(this)]}>
                        <th column='date' onClick={st.invokeSort.bind(this)('date', 'MMMM Do, YYYY')}>Date</th>
                        <th column='name' onClick={st.invokeSort.bind(this)('name')}>Name</th>
                    </StatefulChildren>
                    <StatefulChildren element='tbody' ref='tbody'>
                        <StatefulChildren element='tr' modify={[st.onMountOrder.bind(this)]}>
                        <td column='name'>Velma</td>
                        <td column='date'>October 28th, 2014</td>
                        </StatefulChildren>
                        <StatefulChildren element='tr' modify={[st.onMountOrder.bind(this)]}>
                        <td column='date'>October 4th, 2015</td>
                        <td column='name'>Julie</td>
                        </StatefulChildren>
                        <StatefulChildren element='tr' modify={[st.onMountOrder.bind(this)]}>
                        <td column='date'>December 1th, 2011</td>
                        <td column='name'>Becky</td>
                        </StatefulChildren>
                        <StatefulChildren element='tr' modify={[st.onMountOrder.bind(this)]}>
                        <td column='date'>January 4th, 2015</td>
                        <td column='name'>Ashley</td>
                        </StatefulChildren>
                    </StatefulChildren>
                </table>
            </div>
        )
    }
});

// React.render(<Table/>, document.getElementById('container'));

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment