首页 > 代码库 > React使用antd Table生成层级多选组件

React使用antd Table生成层级多选组件

一、需求

  用户对不同的应用需要有不同的权限,用户一般和角色关联在一起,新建角色的时候会选择该角色对应的应用,然后对应用分配权限。于是写了一种实现的方式。首先应用是一个二级树,一级表示的是应用分组,二级表示的是应用,这是table的最左边的数据。然后是按钮的数据,这里显示在table的头部。

二、效果图如下

  技术分享

 三、具体代码

  1.RoleApplicationTable.js

技术分享
import React from ‘react‘;import RoleCheckbox from ‘components/role/RoleCheckbox‘;import {Menu, Table, message} from ‘antd‘;import Btn from ‘components/public/BaseBtn‘;import {connect} from ‘react-redux‘; import ‘styles/less/personType.less‘;import ‘styles/less/basebtn.less‘;import Map from ‘components/role/Map‘;import { operationRoleAppBtn, queryRoleAppBtnData} from ‘actions/role‘;var mapStateToProps = function(state){  return {    roleData: state.getRole    }};//规范属性类型var propTypes = {  personTypes: React.PropTypes.object,  dispatch : React.PropTypes.func};class RoleApplicationTable extends React.Component {    constructor(props) {    super(props);    this.state = {          };    this.chooseApp = this.chooseApp.bind(this);    this.addColName = this.addColName.bind(this);    this.addDataPid = this.addDataPid.bind(this);    this.onChecked = this.onChecked.bind(this);    this.addChildrenRow = this.addChildrenRow.bind(this);    this.addData = http://www.mamicode.com/this.addData.bind(this);    this.isGroupRow = this.isGroupRow.bind(this);    this.checkGroupAndColumnState = this.checkGroupAndColumnState.bind(this);//确保 组全选 和 列 全选    this.cid = 0;    this.rowNum = 0;    this.colNum = 0;    //map    this.checkboxIdMapState= new Map();//checkboxId 映射 State    this.parentRow = new Map();//每个checkboxId节点 对应最左边的哪个应用    this.parentCol = new Map();//每个checkboxId节点 对应最上边的哪个按钮    this.childrenRow = new Map();//当前行的所有子行    this.checkboxIdMapData = http://www.mamicode.com/new Map();//每个checkbox对应的 appid,btnGroupId    //保存数据    this.checked = null;//标识数据是 新增 还是 删除    this.dataQueue = [];// appid,btngroupId队列    //测试数据    this.appData = http://www.mamicode.com/[{name: ‘报表‘,id:"456",key: ‘5‘, children: [{ name: ‘合同价款‘, id: "45xx61", key: ‘6‘, },{ name: ‘合同台账‘, id: "45xf61", key: ‘7‘, }], }, { name: ‘图标‘, id: "789", key: ‘1‘, children: [{ name: ‘小图标‘, id: "45xx60", key: ‘4‘ },{ name: ‘大图标‘,  id: "4xx560", key: ‘8‘ }] }];    this.btnGroupColumns = [{id: ‘12xx3‘, name: ‘小部件‘, colname: ‘name‘}, {id:‘43xx5‘, name:‘显示‘}, {id:‘43xfffx5‘, name:‘test‘}];    }  componentDidMount() {    //const roleId = ‘4028968156b025da0156b027d0180000‘;    const roleId = this.props.roleId;    if(roleId) {//通过角色id加载 数据      const { dispatch } = this.props;      const querydata = {roleId: roleId};      dispatch(queryRoleAppBtnData(querydata));    }  }  componentWillReceiveProps(nextProps) {    const {roleData} = nextProps;    if (roleData.msg) {      if(roleData.msg.indexOf(‘成功‘) >= 0)        message.success(roleData.msg, 5);      else if(roleData.msg.indexOf(‘失败‘) >= 0)        message.error(roleData.msg, 5);      else         message.info(roleData.msg, 5);      // if (roleData.msg == ‘保存成功‘) {//角色保存成功后 仍然留在当前页面, 继续 角色按钮组权限      //   this.props.history.pushState(null, ‘rolecenter‘);      // }    }  }  chooseApp(){    this.props.chooseApp();  }  sendCheckData(){    const { dispatch } = this.props;    const queryData = {      vos: this.dataQueue,//对应后端的字段    };    dispatch(operationRoleAppBtn(this.checked, queryData));  }  ////////////////////////////////////////////////////////////////////////////////    addChildrenRow(appData){//添加所有子行 标识    if(!appData) return;    for(var i=0; i<appData.length; ++i) {//获取行头的checkboxId      this.rowNum++;//获取行号      var curRowHeadCheckboxId = appData[i].name.split(‘_‘)[1];      var childrenRow = this.childrenRow;      if(!childrenRow.get(curRowHeadCheckboxId)) childrenRow.put(curRowHeadCheckboxId, []);      this.addChildrenRow(appData[i].children);      childrenRow.get(curRowHeadCheckboxId).push(curRowHeadCheckboxId);//加入当前行      if(appData[i].children) {//加入子行        for(var j=0; j<appData[i].children.length; ++j) {          var childCurRowHeadCheckboxId = appData[i].children[j].name.split(‘_‘)[1];          var descendants = childrenRow.get(childCurRowHeadCheckboxId);//孙子们节点          for(var k=0; k<descendants.length; ++k){            childrenRow.get(curRowHeadCheckboxId).push(descendants[k]);          }        }      }    }  }  addDataPid(btnGroupColumns, appData) {//生成新的列, 并且为非表头的每一个单元格设置固定 id,(防止表格渲染时 id发生变化)    if(!appData) return;    for(var i=0; i<appData.length; ++i) {      for(var j=0; j<btnGroupColumns.length; ++j) {        if(!appData[i][btnGroupColumns[j].colname]) {          appData[i][btnGroupColumns[j].colname] = btnGroupColumns[j].id + ‘_‘ + (++this.cid);//为这一行数据添加新的列          //判断应用对应的按钮是否已经选择上, judgeDefaultChecked                    if(appData[i].select && appData[i].select[btnGroupColumns[j].id]) {//btnGroupColumns[j].id == btnGroupId            this.checkboxIdMapState.put(this.cid, true);          } else {            this.checkboxIdMapState.put(this.cid, false);          }        } else if(btnGroupColumns[j].colname == ‘name‘){          if(appData[i][btnGroupColumns[j].colname].indexOf(‘_‘) >= 0) continue;          appData[i][btnGroupColumns[j].colname] += ‘_‘ + (++this.cid);          this.checkboxIdMapState.put(this.cid, false);        }      }      this.addDataPid(btnGroupColumns, appData[i].children);    }  }  addColName(btnGroupColumns, appData){    if(btnGroupColumns) {      btnGroupColumns.map((elem, index)=> {         if(!elem.colname) {          elem.colname = elem.id;        }        elem.cid = ++this.cid;      });    }    if(appData) {      this.addDataPid(btnGroupColumns, appData);      /////清空数据      var keySet = this.childrenRow.keySet();      for(var key in keySet){        if(this.childrenRow.get(keySet[key]) && this.childrenRow.get(keySet[key]).length)          this.childrenRow.get(keySet[key]).length = 0;      }      /////总行数      this.rowNum = 0;      this.addChildrenRow(appData);      ++this.rowNum;      /////判断应用对应的checkbox是否选中,列头对应的checkbox是否选中      this.checkGroupAndColumnState();    }  }  addData(cid, checked){    var curCheckboxData = http://www.mamicode.com/this.checkboxIdMapData.get(cid);    if(curCheckboxData) {      var curQueueData =http://www.mamicode.com/ {        roleId: this.props.roleId,        btnGroupId: curCheckboxData.btnGroupId,        appId: curCheckboxData.appId,      };      this.dataQueue.push(curQueueData);    }  }  isGroupRow(cid){//判断是否为分组    //第一行当做分组    if(parseInt((cid-1)/this.colNum)*this.colNum+1 == 1) return true;    const parentRow = this.parentRow;    const childrenRow = this.childrenRow;    var curRowHeadCheckboxId = parentRow.get(cid) ? parentRow.get(cid) : parseInt((cid-1)/this.colNum)*this.colNum+1;//通过cid 和 curRowHeadCheckboxId获取到cid对应的checkbox到左边的距离    var rowIds = childrenRow.get(curRowHeadCheckboxId);//所有子行的行头的 checkboxId    return rowIds.length > 1 ? true : false;  }  checkGroupAndColumnState() {    const childrenRow = this.childrenRow;    const checkboxIdMapState = this.checkboxIdMapState;    const colNum = this.colNum;    const rowNum = this.rowNum;    const rowState = [];    for(var i=0; i<=rowNum; ++i)      rowState.push(true)//默认所有的行全选    rowState[1] = false;    for(var row=2; row <= rowNum; ++row) {      var cb = (row-1)*colNum+2;//这一行从第2个 checkbox 开始      if(this.isGroupRow(cb)) {//分组行,不算入        rowState[row] = false;        continue;      }      var ce = row*colNum;      var curRowState = true;//默认这一行全选      for(var cid=cb; cid<=ce; ++cid) {//遍历这一行        if(checkboxIdMapState.get(cid) == false) {          curRowState = false;          break;        }      }      rowState[row] = curRowState;      if(rowState[row] == true) {//应用对应的checkbox选中        checkboxIdMapState.put((row-1)*colNum+1, true);      } else {        checkboxIdMapState.put((row-1)*colNum+1, false);      }    }    //判断分组是否选中    for(var row=2; row <= rowNum; ++row) {      const cid = (row-1)*colNum+1;//每一行的第一个      if(!this.isGroupRow(cid)) continue;      //计算分组行      var cids = childrenRow.get(cid);      var groupState = true;//默认这个分组被选中      for(var i=0; i<cids.length; ++i){        if(cids[i] != cid) {//不是分组行          var cur_row = (cids[i]-1)/this.colNum+1;          if(rowState[cur_row] == false) {            groupState = false;            break;          }        }      }      for(var cur_cid=cid; cur_cid <= row*colNum; ++cur_cid){//当前分组行的 checkbox 状态        checkboxIdMapState.put(cur_cid, groupState);      }      if(groupState == false) {//如果当前分组行没有状态改变,查看这一行的某一个分组列是否有变化        const childRowNum = cids.length-1;        for(var curRowCid = cid; curRowCid<cid+this.colNum; ++curRowCid) {//遍历这一分组行的checkboxId          var curColState = true;          for(var childRowCid = curRowCid+this.colNum, cnt = 0; cnt < childRowNum; childRowCid += this.colNum, ++cnt) {            if(checkboxIdMapState.get(childRowCid) == false) {              curColState = false;              break;            }          }          checkboxIdMapState.put(curRowCid, curColState);        }      }    }    // 判断列 是否被选中    if(rowNum > 1) {      for(var col=1; col<=colNum; ++col) {        var curColState = true;        for(var cid=col+colNum; cid<=colNum*rowNum; cid+=colNum){          if(checkboxIdMapState.get(cid) == false) {            curColState = false;            break;          }        }        var cid = col;        checkboxIdMapState.put(cid, curColState);//这一列的状态      }    }  }  onChecked(cid, btnGroupId, appId, checked){//checkboxId, 按钮id,应用id    const checkboxIdMapState = this.checkboxIdMapState;    const parentRow = this.parentRow;    const parentCol = this.parentCol;    const childrenRow = this.childrenRow;    const colNum = this.colNum;    const rowNum = this.rowNum;    //清空数据队列    this.dataQueue.length = 0;    //标识当前的操作    this.checked = checked;    if(btnGroupId == null && appId == null) {      for(var cur_cid=1; cur_cid<=colNum*rowNum; ++cur_cid) {        checkboxIdMapState.put(cur_cid, checked);        if(!this.isGroupRow(cur_cid))          this.addData(cur_cid, checked);      }    } else if(btnGroupId == null) {//appId 不为null, 这一行全选      var rowHeadCheckboxIds = childrenRow.get(cid);//所有子行的行头的 checkboxId      for(var i=0; i<rowHeadCheckboxIds.length; ++i) {        var cur_cid = rowHeadCheckboxIds[i];        var cur_row_max_cid = parseInt(cur_cid) + colNum;        while(cur_cid < cur_row_max_cid){          checkboxIdMapState.put(cur_cid, checked);          if(!this.isGroupRow(cur_cid))            this.addData(cur_cid, checked);          ++cur_cid;        }      }    } else if(appId == null) {//btnId不为null,这一列全部check      var cur_cid = cid;      while(cur_cid <= rowNum*colNum) {        checkboxIdMapState.put(cur_cid, checked);        if(!this.isGroupRow(cur_cid))           this.addData(cur_cid, checked);        cur_cid += colNum;      }    } else {//都不为null      var curRowHeadCheckboxId = parentRow.get(cid);//通过cid 和 curRowHeadCheckboxId获取到cid对应的checkbox到左边的距离      var rowIds = childrenRow.get(curRowHeadCheckboxId);//所有子行的行头的 checkboxId      for(var i=0; i<rowIds.length; ++i) {//这一列全部check        var cur_cid = parseInt(rowIds[i]) + (cid-curRowHeadCheckboxId);        checkboxIdMapState.put(cur_cid, checked);        if(!this.isGroupRow(cur_cid))          this.addData(cur_cid, checked);      }          }    this.setState({});    this.sendCheckData();//发送数据  }  ////////////////////////////////////////////////////////////////////////////////    render() {    const appData = this.appData;    const btnGroupColumns = this.btnGroupColumns;    console.log(appData)    let self = this;    this.cid = 0;    this.colNum = btnGroupColumns.length;//获得列宽    const checkboxIdMapState = this.checkboxIdMapState;    const parentRow = this.parentRow;    const parentCol = this.parentCol    if(btnGroupColumns) {      this.addColName(btnGroupColumns, appData);//对应用的数据进行一个简单的处理      btnGroupColumns.map((elem, index)=> {         //elem.colname==‘name‘ ? null : elem.id, 默认左上角的id 没有 appId 和 btnGroupId        elem.title= <RoleCheckbox btnGroupId={elem.colname==‘name‘ ? null : elem.id} appId={null} cid={elem.cid} onChecked={self.onChecked} checked={checkboxIdMapState.get(elem.cid)} title={elem.name}/>,        elem.key = elem.dataIndex = elem.colname;        elem.render = function(text, record, index){// text的值 == 对应表头列的Id == elem.id          var contents = text.split(‘_‘);          text = contents[0];          var cur_cid = contents[1];//当前列顶端 checkboxId          //判断是否是第一列          if(record.name.split(‘_‘)[0] != text) {//不是第一列            var leftCheckBoxId = record.name.split(‘_‘)[1];            parentRow.put(cur_cid, leftCheckBoxId);//该 checkboxId 对应的 (应用Id == leftCheckBoxId)            //加入每个checkbox  要传输的数据(appId, btnGroupId)            self.checkboxIdMapData.put(cur_cid, {appId: record.id, btnGroupId: elem.id})          }          //该 checkboxId 对应的 最上边的 checkboxId          parentCol.put(cur_cid, elem.cid);//该 checkboxId 对应的 (按钮Id == elem.cid)          //record.name.split(‘_‘)[0] 最原始的 name 的value          return <RoleCheckbox btnGroupId={record.name.split(‘_‘)[0] == text ? null : elem.id} appId={record.id} cid={cur_cid} onChecked={self.onChecked} checked={checkboxIdMapState.get(cur_cid)} title={text==elem.id ? null : text}/>        }      });    }    return (      <div>        <Btn iconName="icon-add" onClick={this.chooseApp} btnClass="add-btn" btnName="选择应用"/>        <Table           indentSize={15}          className="personType-table"           columns={btnGroupColumns}           dataSource={appData}           pagination={false}        />      </div>    );  }}module.exports = RoleApplicationTable;RoleApplicationTable.propTypes = propTypes;module.exports = connect(mapStateToProps)(RoleApplicationTable);
View Code

  利用antd table实现层级多选组件。

  具体思路:

addDataPid(btnGroupColumns, appData) {//生成新的列, 并且为非表头的每一个单元格设置固定 id,(防止表格渲染时 id发生变化)  if(!appData) return;  for(var i=0; i<appData.length; ++i) {    for(var j=0; j<btnGroupColumns.length; ++j) {      if(!appData[i][btnGroupColumns[j].colname]) {        appData[i][btnGroupColumns[j].colname] = btnGroupColumns[j].id + ‘_‘ + (++this.cid);//为这一行数据添加新的列        //判断应用对应的按钮是否已经选择上, judgeDefaultChecked                if(appData[i].select && appData[i].select[btnGroupColumns[j].id]) {//btnGroupColumns[j].id == btnGroupId          this.checkboxIdMapState.put(this.cid, true);        } else {          this.checkboxIdMapState.put(this.cid, false);        }      } else if(btnGroupColumns[j].colname == ‘name‘){        if(appData[i][btnGroupColumns[j].colname].indexOf(‘_‘) >= 0) continue;        appData[i][btnGroupColumns[j].colname] += ‘_‘ + (++this.cid);        this.checkboxIdMapState.put(this.cid, false);      }    }    this.addDataPid(btnGroupColumns, appData[i].children);  }}addColName(btnGroupColumns, appData){//为每一列添加 映射字段 colname  if(btnGroupColumns) {    btnGroupColumns.map((elem, index)=> {       if(!elem.colname) {        elem.colname = elem.id;      }      elem.cid = ++this.cid;    });  }  if(appData) {    this.addDataPid(btnGroupColumns, appData);    /////清空数据    var keySet = this.childrenRow.keySet();    for(var key in keySet){      if(this.childrenRow.get(keySet[key]) && this.childrenRow.get(keySet[key]).length)        this.childrenRow.get(keySet[key]).length = 0;    }    /////总行数    this.rowNum = 0;    this.addChildrenRow(appData);    ++this.rowNum;    /////判断应用对应的checkbox是否选中,列头对应的checkbox是否选中    this.checkGroupAndColumnState();  }}

 

  2.RoleCheckbox.js

技术分享
import {Checkbox} from ‘antd‘;import React from ‘react‘;class RoleCheckbox extends React.Component{  constructor(props) {    super(props);    this.onChange = this.onChange.bind(this);  }  onChange(e){    const cid = this.props.cid;    const btnGroupId = this.props.btnGroupId;    const appId = this.props.appId;    this.props.onChecked(cid, btnGroupId, appId, e.target.checked);  }      render() {    const checked = this.props.checked;    const title = this.props.title;    const cid = this.props.cid;        return(        <div>          <Checkbox checked={checked} onChange={this.onChange}/>{title}        </div>        );    }}module.exports = RoleCheckbox;
View Code

   封装antd 的Checkbox组件

  3.Map.js

技术分享
class Map {    constructor(){        this.container = new Object();    }    put(key, value){        this.container[key] = value;    }    get(key){        return this.container[key];    }    keySet() {        var keyset = new Array();        var count = 0;        for (var key in this.container) {            // 跳过object的extend函数            if (key == ‘extend‘) {            continue;        }            keyset[count] = key;            count++;        }        return keyset;    }    size() {        var count = 0;        for (var key in this.container) {            // 跳过object的extend函数            if (key == ‘extend‘){                continue;            }            count++;        }        return count;    }    remove(key) {        delete this.container[key];    }    toString(){        var str = "";        for (var i = 0, keys = this.keySet(), len = keys.length; i < len; i++) {            str = str + keys[i] + "=" + this.container[keys[i]] + ";\n";        }        return str;    }}module.exports = Map;
View Code

  js实现的Map工具类。

 四、需求变更

  功能虽然完成了,但是总是避免不了需求的变更。要求选择左边应用对应的checkbox时,不在操作该应用对应的按钮的checkbox,也就是整个行不是全选了。应用对应的checkbox用来进行删除操作。

  1.改变后的Table效果

  技术分享

  2.RoleApplicationTable.js

技术分享
import React from ‘react‘;import RoleCheckbox from ‘components/role/RoleCheckbox‘;import {Menu, Table, message, Modal} from ‘antd‘;const confirm = Modal.confirm;import Btn from ‘components/public/BaseBtn‘;import {connect} from ‘react-redux‘; import ‘styles/less/personType.less‘;import ‘styles/less/basebtn.less‘;import Map from ‘components/role/Map‘;import { operationRoleAppBtn, queryRoleAppBtnData, deleteAppAction} from ‘actions/role‘;var mapStateToProps = function(state){  return {    roleData: state.getRole    }};//规范属性类型var propTypes = {  personTypes: React.PropTypes.object,  dispatch : React.PropTypes.func};class RoleApplicationTable extends React.Component {    constructor(props) {    super(props);    this.state = {      isEdit: true,    };    this.chooseApp = this.chooseApp.bind(this);    this.addColName = this.addColName.bind(this);    this.addDataPid = this.addDataPid.bind(this);    this.onChecked = this.onChecked.bind(this);    this.addChildrenRow = this.addChildrenRow.bind(this);    this.addAppBtnData = http://www.mamicode.com/this.addAppBtnData.bind(this);    this.addAppData = http://www.mamicode.com/this.addAppData.bind(this);    this.isGroupRow = this.isGroupRow.bind(this);    this.checkGroupAndColumnState = this.checkGroupAndColumnState.bind(this);//确保 组全选 和 列 全选    this.deleteApp = this.deleteApp.bind(this);    this.showConfirm = this.showConfirm.bind(this);    this.initRoleAppBtnData = http://www.mamicode.com/this.initRoleAppBtnData.bind(this);    this.cancelChooseState = this.cancelChooseState.bind(this);    this.saveCheckedAppBtn = this.saveCheckedAppBtn.bind(this);    this.afterSaveCheckedAppBtn = this.afterSaveCheckedAppBtn.bind(this);    this.cid = 0;    this.rowNum = 0;    this.colNum = 0;    //map    this.checkboxIdMapState= new Map();//checkboxId 映射 State    this.parentRow = new Map();//每个checkboxId节点 对应最左边的哪个应用    this.parentCol = new Map();//每个checkboxId节点 对应最上边的哪个按钮    this.childrenRow = new Map();//当前行的所有子行    this.checkboxIdMapAppBtnData = http://www.mamicode.com/new Map();//每个checkbox对应的 appid,btnGroupId    this.checkboxIdMapAppData = http://www.mamicode.com/new Map();//记录被选中的应用    //保存数据    this.dataQueue = [];// appid,btngroupId队列    //删除应用    this.deleteAppIds = [];    //测试数据    this.appData = http://www.mamicode.com/[{name: ‘报表‘,id:"456",key: ‘5‘, children: [{ name: ‘合同价款‘, id: "45xx61", key: ‘6‘, },{ name: ‘合同台账‘, id: "45xf61", key: ‘7‘, }], }, { name: ‘图标‘, id: "789", key: ‘1‘, children: [{ name: ‘小图标‘, id: "45xx60", key: ‘4‘ },{ name: ‘大图标‘,  id: "4xx560", key: ‘8‘ }] }];    this.btnGroupColumns = [{id: ‘12xx3‘, name: ‘小部件‘, colname: ‘name‘}, {id:‘43xx5‘, name:‘显示‘}, {id:‘43xfffx5‘, name:‘test‘}];    }  //确认提示框  showConfirm(title,message,dispatch,functionT,functionQueryData) {    confirm({      title: title,      content: message,      onOk() {        dispatch(functionT(functionQueryData));        },      onCancel() {              }    });  }  componentDidMount() {    //const roleId = ‘4028968156b025da0156b027d0180000‘;    this.initRoleAppBtnData();  }  initRoleAppBtnData(){    const roleId = this.props.roleId;    if(roleId) {//通过角色id加载 数据      const { dispatch } = this.props;      const querydata = {roleId: roleId};      dispatch(queryRoleAppBtnData(querydata));    }  }  cancelChooseState(){//取消权限的更改    this.initRoleAppBtnData();  }  componentWillReceiveProps(nextProps) {    const {roleData} = nextProps;    if (roleData.msg) {      if(roleData.msg.indexOf(‘成功‘) >= 0)        message.success(roleData.msg, 5);      else if(roleData.msg.indexOf(‘失败‘) >= 0)        message.error(roleData.msg, 5);      else         message.info(roleData.msg, 5);      // if (roleData.msg == ‘保存成功‘) {//角色保存成功后 仍然留在当前页面, 继续 角色按钮组权限      //   this.props.history.pushState(null, ‘rolecenter‘);      // }    }  }  chooseApp(){    this.props.chooseApp();  }  sendCheckData(){    const { dispatch } = this.props;    const queryData = {      ‘vos‘: this.dataQueue,//对应后端的字段      ‘roleId‘: this.props.roleId,    };    dispatch(operationRoleAppBtn(queryData, this.afterSaveCheckedAppBtn));  }  ////////////////////////////////////////////////////////////////////////////////    addChildrenRow(appData){//添加所有子行 标识    if(!appData) return;    for(var i=0; i<appData.length; ++i) {//获取行头的checkboxId      this.rowNum++;//获取行号      var curRowHeadCheckboxId = appData[i].name.split(‘_‘)[1];      var childrenRow = this.childrenRow;      if(!childrenRow.get(curRowHeadCheckboxId)) childrenRow.put(curRowHeadCheckboxId, []);      this.addChildrenRow(appData[i].children);      childrenRow.get(curRowHeadCheckboxId).push(curRowHeadCheckboxId);//加入当前行      if(appData[i].children) {//加入子行        for(var j=0; j<appData[i].children.length; ++j) {          var childCurRowHeadCheckboxId = appData[i].children[j].name.split(‘_‘)[1];          var descendants = childrenRow.get(childCurRowHeadCheckboxId);//孙子们节点          for(var k=0; k<descendants.length; ++k){            childrenRow.get(curRowHeadCheckboxId).push(descendants[k]);          }        }      }    }  }  addDataPid(btnGroupColumns, appData) {//生成新的列, 并且为非表头的每一个单元格设置固定 id,(防止表格渲染时 id发生变化)    if(!appData) return;    for(var i=0; i<appData.length; ++i) {      for(var j=0; j<btnGroupColumns.length; ++j) {        if(!appData[i][btnGroupColumns[j].colname]) {          appData[i][btnGroupColumns[j].colname] = btnGroupColumns[j].id + ‘_‘ + (++this.cid);//为这一行数据添加新的列          //判断应用对应的按钮是否已经选择上, judgeDefaultChecked                    if(appData[i].select && appData[i].select[btnGroupColumns[j].id]) {//btnGroupColumns[j].id == btnGroupId            this.checkboxIdMapState.put(this.cid, true);          } else {            this.checkboxIdMapState.put(this.cid, false);          }        } else if(btnGroupColumns[j].colname == ‘name‘){          if(appData[i][btnGroupColumns[j].colname].indexOf(‘_‘) >= 0) continue;          appData[i][btnGroupColumns[j].colname] += ‘_‘ + (++this.cid);          this.checkboxIdMapState.put(this.cid, false);        }      }      this.addDataPid(btnGroupColumns, appData[i].children);    }  }  addColName(btnGroupColumns, appData){    if(btnGroupColumns) {      btnGroupColumns.map((elem, index)=> {         if(!elem.colname) {          elem.colname = elem.id;        }        elem.cid = ++this.cid;      });    }    if(appData) {      this.addDataPid(btnGroupColumns, appData);      /////清空数据      var keySet = this.childrenRow.keySet();      for(var key in keySet){        if(this.childrenRow.get(keySet[key]) && this.childrenRow.get(keySet[key]).length)          this.childrenRow.get(keySet[key]).length = 0;      }      /////总行数      this.rowNum = 0;      this.addChildrenRow(appData);      ++this.rowNum;      /////判断应用对应的checkbox是否选中,列头对应的checkbox是否选中      this.checkGroupAndColumnState();    }  }  addAppBtnData(cid){    var curCheckboxData = http://www.mamicode.com/this.checkboxIdMapAppBtnData.get(cid);    if(curCheckboxData) {      var curQueueData =http://www.mamicode.com/ {        roleId: this.props.roleId,        btnGroupId: curCheckboxData.btnGroupId,        appId: curCheckboxData.appId,      };      this.dataQueue.push(curQueueData);    }  }  addAppData(cid){    var checked = this.checkboxIdMapState.get(cid);    if(checked == false) return;    var curAppId = this.checkboxIdMapAppData.get(cid);    if(curAppId) {      var curQueueData =http://www.mamicode.com/ {        roleId: this.props.roleId,        appId: curAppId,      };      this.deleteAppIds.push(curQueueData);    }  }  isGroupRow(cid){//判断是否为分组    //第一行当做分组    if(parseInt((cid-1)/this.colNum)*this.colNum+1 == 1) return true;    const parentRow = this.parentRow;    const childrenRow = this.childrenRow;    var curRowHeadCheckboxId = parentRow.get(cid) ? parentRow.get(cid) : parseInt((cid-1)/this.colNum)*this.colNum+1;//通过cid 和 curRowHeadCheckboxId获取到cid对应的checkbox到左边的距离    var rowIds = childrenRow.get(curRowHeadCheckboxId);//所有子行的行头的 checkboxId    return rowIds.length > 1 ? true : false;  }  checkGroupAndColumnState() {    const childrenRow = this.childrenRow;    const checkboxIdMapState = this.checkboxIdMapState;    const colNum = this.colNum;    const rowNum = this.rowNum;    const rowState = [];    for(var i=0; i<=rowNum; ++i)      rowState.push(true)//默认所有的行全选    rowState[1] = false;    //判断分组列    for(var row=2; row <= rowNum; ++row) {      const cid = (row-1)*colNum+1;//每一行的第一个      if(!this.isGroupRow(cid)) continue;      var cids = childrenRow.get(cid);      const childRowNum = cids.length-1;      for(var curRowCid = cid; curRowCid<cid+this.colNum; ++curRowCid) {//遍历这一分组行的checkboxId        var curColState = true;        for(var childRowCid = curRowCid+this.colNum, cnt = 0; cnt < childRowNum; childRowCid += this.colNum, ++cnt) {          if(checkboxIdMapState.get(childRowCid) == false) {            curColState = false;            break;          }        }        checkboxIdMapState.put(curRowCid, curColState);      }    }    // 判断列 是否被选中    if(rowNum > 1) {      for(var col=1; col<=colNum; ++col) {        var curColState = true;        for(var cid=col+colNum; cid<=colNum*rowNum; cid+=colNum){          if(checkboxIdMapState.get(cid) == false) {            curColState = false;            break;          }        }        var cid = col;        checkboxIdMapState.put(cid, curColState);//这一列的状态      }    } else if(rowNum == 1) {//每一列的状态清空      for(var cid = 1; cid <= this.colNum; ++cid)        checkboxIdMapState.put(cid, false);    }  }  onChecked(cid, btnGroupId, appId, checked){//checkboxId, 按钮id,应用id    if(this.state.isEdit == true && cid%this.colNum != 1) {//第一列为应用列,随时可以编辑      message.info(‘请进入编辑状态‘, 2);      return ;    }    const checkboxIdMapState = this.checkboxIdMapState;    const parentRow = this.parentRow;    const parentCol = this.parentCol;    const childrenRow = this.childrenRow;    const colNum = this.colNum;    const rowNum = this.rowNum;    if(btnGroupId == null && appId == null) {      for(var cur_cid=1; cur_cid<=colNum*rowNum; cur_cid+=colNum) {        checkboxIdMapState.put(cur_cid, checked);      }    } else if(btnGroupId == null) {//appId 不为null, 所有的子应用全选      var rowHeadCheckboxIds = childrenRow.get(cid);//所有子行的行头的 checkboxId(对应应用)      for(var i=0; i<rowHeadCheckboxIds.length; ++i) {        var cur_cid = rowHeadCheckboxIds[i];        checkboxIdMapState.put(cur_cid, checked);      }    } else if(appId == null) {//btnId不为null,这一列全部check      var cur_cid = cid;      while(cur_cid <= rowNum*colNum) {        checkboxIdMapState.put(cur_cid, checked);        cur_cid += colNum;      }    } else {//都不为null      var curRowHeadCheckboxId = parentRow.get(cid);//通过cid 和 curRowHeadCheckboxId获取到cid对应的checkbox到左边的距离      var rowIds = childrenRow.get(curRowHeadCheckboxId);//所有子行的行头的 checkboxId      for(var i=0; i<rowIds.length; ++i) {//这一列全部check        var cur_cid = parseInt(rowIds[i]) + (cid-curRowHeadCheckboxId);        checkboxIdMapState.put(cur_cid, checked);      }          }    this.setState({});  }  deleteApp(){    this.deleteAppIds.length = 0;//清空数据    const {dispatch} = this.props;    for(var cid = 1; cid <= this.rowNum*this.colNum; cid += this.colNum) {      if(!this.isGroupRow(cid)) {        this.addAppData(cid);      }    }    if(this.deleteAppIds.length == 0) {      message.success(‘请选择应用‘, 5);      return;    }    const queryData = {      vos: this.deleteAppIds,    }    this.showConfirm(‘删除应用‘, ‘确定删除应用?‘, dispatch, deleteAppAction, queryData);   }  afterSaveCheckedAppBtn(){    this.setState({      isEdit: true,    });  }  saveCheckedAppBtn(){    if(this.state.isEdit == true) {      this.setState({        isEdit: false,      });      return ;    }     //清空数据队列    this.dataQueue.length = 0;    for(var cid = this.colNum+1; cid <= this.colNum*this.rowNum; ++cid) {//从第二行的checkbox 开始      if(this.isGroupRow(cid)) {        cid += this.colNum;      }      if(cid%this.colNum != 1) {//第一列为 应用列        if(this.checkboxIdMapState.get(cid) == true)          this.addAppBtnData(cid);      }    }    this.sendCheckData();  }  ////////////////////////////////////////////////////////////////////////////////    render() {    let {roleData} = this.props;    var appData =http://www.mamicode.com/ [];    var btnGroupColumns = [];    if(roleData.permissiondData) {      if(roleData.permissiondData.listAppBtnGroup) {        btnGroupColumns = roleData.permissiondData.listAppBtnGroup;      }      if(roleData.permissiondData.listPermissionApp) {        appData = roleData.permissiondData.listPermissionApp;      }    }    // const appData = http://www.mamicode.com/this.appData;    // const btnGroupColumns = this.btnGroupColumns;    // console.log(appData)    let self = this;    this.cid = 0;    this.colNum = btnGroupColumns.length;//获得列宽    const checkboxIdMapState = this.checkboxIdMapState;    const parentRow = this.parentRow;    const parentCol = this.parentCol    if(btnGroupColumns) {      this.addColName(btnGroupColumns, appData);//对应用的数据进行一个简单的处理      btnGroupColumns.map((elem, index)=> {         //elem.colname==‘name‘ ? null : elem.id, 默认左上角的id 没有 appId 和 btnGroupId        elem.title= <RoleCheckbox btnGroupId={elem.colname==‘name‘ ? null : elem.id} appId={null} cid={elem.cid} onChecked={self.onChecked} checked={checkboxIdMapState.get(elem.cid)} title={elem.name}/>,        elem.key = elem.dataIndex = elem.colname;        elem.render = function(text, record, index){// text的值 == 对应表头列的Id == elem.id          var contents = text.split(‘_‘);          text = contents[0];          var cur_cid = contents[1];//当前列顶端 checkboxId          //判断是否是第一列          if(record.name.split(‘_‘)[0] != text) {//不是第一列            var leftCheckBoxId = record.name.split(‘_‘)[1];            parentRow.put(cur_cid, leftCheckBoxId);//该 checkboxId 对应的 (应用Id == leftCheckBoxId)            //加入每个checkbox  要传输的数据(appId, btnGroupId)            self.checkboxIdMapAppBtnData.put(cur_cid, {appId: record.id, btnGroupId: elem.id})          } else {//应用列            self.checkboxIdMapAppData.put(cur_cid, record.id);          }          //该 checkboxId 对应的 最上边的 checkboxId          parentCol.put(cur_cid, elem.cid);//该 checkboxId 对应的 (按钮Id == elem.cid)          //record.name.split(‘_‘)[0] 最原始的 name 的value          return <RoleCheckbox btnGroupId={record.name.split(‘_‘)[0] == text ? null : elem.id} appId={record.id} cid={cur_cid} onChecked={self.onChecked} checked={checkboxIdMapState.get(cur_cid)} title={text==elem.id ? null : text}/>        }      });    }    return (      <div>        <Btn iconName="icon-add" isdisabled={self.props.roleId ? false : true} onClick={this.chooseApp} btnClass="add-btn" btnName="选择应用"/>        &nbsp;&nbsp;&nbsp;&nbsp;        <Btn iconName="icon-jianhao" isdisabled={self.props.roleId ? false : true} btnClass="delete-btn" btnName="删除应用" onClick={self.deleteApp}/>          <Table style={{marginTop: "10px", marginBottom: "10px"}}          indentSize={15}          className="personType-table"           columns={btnGroupColumns}           dataSource={appData}           pagination={false}        />        <div style={{display: self.rowNum > 1 ? ‘‘ : ‘none‘}}>          <Btn btnClass="save-btn" btnName={self.state.isEdit == true ? "编辑" : "保存"} onClick={this.saveCheckedAppBtn}/>          &nbsp;&nbsp;&nbsp;&nbsp;          <Btn btnClass="cancel-btn" btnName="取消" onClick={self.cancelChooseState}/>        </div>      </div>    );  }}module.exports = RoleApplicationTable;RoleApplicationTable.propTypes = propTypes;module.exports = connect(mapStateToProps)(RoleApplicationTable);
View Code

五、心得体会

  最近使用react + redux + webpack进行web开发,感觉进步很快,已经熟悉了基本的流程。后续要研究一下webpack。

React使用antd Table生成层级多选组件