This commit is contained in:
izbz wh 2019-07-13 11:03:31 +08:00
commit 9c969e56a6
14 changed files with 402 additions and 367 deletions

View File

@ -1,5 +1,10 @@
<a name="2.0.15"></a> <a name="2.0.16"></a>
## [2.0.15](https://github.com/tinper-bee/bee-tree/compare/v2.0.14...v2.0.15) (2019-07-04) ## [2.0.16](https://github.com/tinper-bee/bee-tree/compare/v2.0.15-new...v2.0.16) (2019-07-05)
<a name="2.0.15-new"></a>
## [2.0.15-new](https://github.com/tinper-bee/bee-tree/compare/v2.0.15...v2.0.15-new) (2019-07-04)
### Bug Fixes ### Bug Fixes
@ -14,7 +19,7 @@
<a name="2.0.13"></a> <a name="2.0.13"></a>
## [2.0.13](https://github.com/tinper-bee/bee-tree/compare/v2.0.12...v2.0.13) (2019-05-24) ## [2.0.13](https://github.com/tinper-bee/bee-tree/compare/v2.0.11...v2.0.13) (2019-05-24)
### Features ### Features
@ -24,7 +29,7 @@
<a name="2.0.12"></a> <a name="2.0.12"></a>
## [2.0.12](https://github.com/tinper-bee/bee-tree/compare/v2.0.11...v2.0.12) (2019-05-17) ## 2.0.12 (2019-05-17)
### Bug Fixes ### Bug Fixes
@ -75,7 +80,7 @@
<a name="2.0.2"></a> <a name="2.0.2"></a>
## [2.0.2](https://github.com/tinper-bee/bee-tree/compare/2.0.2...v2.0.2) (2019-03-02) ## [2.0.2](https://github.com/tinper-bee/bee-tree/compare/v1.1.16...v2.0.2) (2019-03-02)
@ -225,34 +230,14 @@
<a name="1.0.5"></a> <a name="1.0.5"></a>
## [1.0.5](https://github.com/tinper-bee/bee-tree/compare/v11.0.3...v1.0.5) (2018-01-25) ## [1.0.5](https://github.com/tinper-bee/bee-tree/compare/v1.0.3...v1.0.5) (2018-01-25)
### Bug Fixes
* children 为0时不显示图标 ([5481ec6](https://github.com/tinper-bee/bee-tree/commit/5481ec6))
### Features
* 含有[3~[B[3~heckStrictly复选框tree ([932b9fa](https://github.com/tinper-bee/bee-tree/commit/932b9fa))
* **子节节点children为空数组时不显示扩展图图标:** 子节点children属性为空数组时不显示扩展图标 ([3536f71](https://github.com/tinper-bee/bee-tree/commit/3536f71))
### BREAKING CHANGES
* 示例文档描述优化
<a name="11.0.3"></a>
## [11.0.3](https://github.com/tinper-bee/bee-tree/compare/v1.0.3...v11.0.3) (2018-01-24)
### Bug Fixes ### Bug Fixes
* **解决配置冲突:** 解决配置冲突 ([fb15e37](https://github.com/tinper-bee/bee-tree/commit/fb15e37)) * **解决配置冲突:** 解决配置冲突 ([fb15e37](https://github.com/tinper-bee/bee-tree/commit/fb15e37))
* checkStrictly ([5fa28b2](https://github.com/tinper-bee/bee-tree/commit/5fa28b2)) * checkStrictly ([5fa28b2](https://github.com/tinper-bee/bee-tree/commit/5fa28b2))
* children 为0时不显示图标 ([5481ec6](https://github.com/tinper-bee/bee-tree/commit/5481ec6))
* 修改示例 ([6770417](https://github.com/tinper-bee/bee-tree/commit/6770417)) * 修改示例 ([6770417](https://github.com/tinper-bee/bee-tree/commit/6770417))
@ -274,8 +259,15 @@
* **文档补充:** 文档补充 ([c123353](https://github.com/tinper-bee/bee-tree/commit/c123353)) * **文档补充:** 文档补充 ([c123353](https://github.com/tinper-bee/bee-tree/commit/c123353))
### Features
* 含有[3~[B[3~heckStrictly复选框tree ([932b9fa](https://github.com/tinper-bee/bee-tree/commit/932b9fa))
* **子节节点children为空数组时不显示扩展图图标:** 子节点children属性为空数组时不显示扩展图标 ([3536f71](https://github.com/tinper-bee/bee-tree/commit/3536f71))
### BREAKING CHANGES ### BREAKING CHANGES
* 示例文档描述优化
* **依赖修改、object-assign修改:** 依赖修改、object-assign修改 * **依赖修改、object-assign修改:** 依赖修改、object-assign修改
* **依赖组件修改:** y * **依赖组件修改:** y
* **组件依赖指向具体版本修改:** 组件依赖指向具体版本修改 * **组件依赖指向具体版本修改:** 组件依赖指向具体版本修改

View File

@ -135,6 +135,8 @@
background-color: rgb(255, 247, 231); } background-color: rgb(255, 247, 231); }
.u-tree li a.u-tree-node-selected .u-tree-title { .u-tree li a.u-tree-node-selected .u-tree-title {
color: rgb(245, 60, 50); } color: rgb(245, 60, 50); }
.u-tree li.u-tree-treenode-focused > a {
background-color: rgb(235, 236, 240); }
.u-tree li span.u-checkbox { .u-tree li span.u-checkbox {
margin: 2px 4px 0 0; } margin: 2px 4px 0 0; }
.u-tree li span.u-tree-switcher, .u-tree li span.u-tree-switcher,

View File

@ -57,7 +57,8 @@ var Tree = function (_React$Component) {
selectedKeys: _this.getDefaultSelectedKeys(props), selectedKeys: _this.getDefaultSelectedKeys(props),
dragNodesKeys: '', dragNodesKeys: '',
dragOverNodeKey: '', dragOverNodeKey: '',
dropNodeKey: '' dropNodeKey: '',
focusKey: '' //上下箭头选择树节点时用于标识focus状态
}; };
return _this; return _this;
} }
@ -486,7 +487,11 @@ var Tree = function (_React$Component) {
var parentEle = (0, _util.closest)(e.target, ".u-tree"); var parentEle = (0, _util.closest)(e.target, ".u-tree");
var focusEle = parentEle ? parentEle.querySelector(queryInfo) : null; var focusEle = parentEle ? parentEle.querySelector(queryInfo) : null;
focusEle && focusEle.focus(); focusEle && focusEle.focus();
this.onSelect(nextTreeNode); var eventKey = nextTreeNode.props.eventKey || nextTreeNode.key;
this.setState({
focusKey: eventKey
});
// this.onSelect(nextTreeNode);
} }
}; };
@ -535,7 +540,11 @@ var Tree = function (_React$Component) {
} }
} }
preElement && preElement.focus(); preElement && preElement.focus();
this.onSelect(prevTreeNode); var eventKey = prevTreeNode.props.eventKey || prevTreeNode.key;
this.setState({
focusKey: eventKey
});
// this.onSelect(prevTreeNode);
}; };
// all keyboard events callbacks run from here at first // all keyboard events callbacks run from here at first
@ -558,6 +567,7 @@ var Tree = function (_React$Component) {
// 展开树节点 // 展开树节点
this.onExpand(treeNode, 'right'); this.onExpand(treeNode, 'right');
} else if (e.keyCode == _tinperBeeCore.KeyCode.SPACE && props.checkable) { } else if (e.keyCode == _tinperBeeCore.KeyCode.SPACE && props.checkable) {
this.onSelect(treeNode);
// 如果是多选tree则进行选中或者反选该节点 // 如果是多选tree则进行选中或者反选该节点
this.onCheck(treeNode); this.onCheck(treeNode);
} else if (e.keyCode == _tinperBeeCore.KeyCode.ENTER) { } else if (e.keyCode == _tinperBeeCore.KeyCode.ENTER) {
@ -789,6 +799,7 @@ var Tree = function (_React$Component) {
_dropTrigger: this._dropTrigger, _dropTrigger: this._dropTrigger,
expanded: state.expandedKeys.indexOf(key) !== -1, expanded: state.expandedKeys.indexOf(key) !== -1,
selected: state.selectedKeys.indexOf(key) !== -1, selected: state.selectedKeys.indexOf(key) !== -1,
focused: state.focusKey === key,
openTransitionName: this.getOpenTransitionName(), openTransitionName: this.getOpenTransitionName(),
openAnimation: props.openAnimation, openAnimation: props.openAnimation,
filterTreeNode: this.filterTreeNode.bind(this), filterTreeNode: this.filterTreeNode.bind(this),

View File

@ -532,10 +532,11 @@ var TreeNode = function (_React$Component) {
return _react2["default"].createElement('span', { className: (0, _classnames2["default"])(cls) }); return _react2["default"].createElement('span', { className: (0, _classnames2["default"])(cls) });
}; };
var selectedCls = props.selected ? prefixCls + '-treenode-selected' : ''; var selectedCls = props.selected ? prefixCls + '-treenode-selected' : '';
var focusedCls = props.focused ? prefixCls + '-treenode-focused' : '';
return _react2["default"].createElement( return _react2["default"].createElement(
'li', 'li',
_extends({}, liProps, { style: props.style, _extends({}, liProps, { style: props.style,
className: (0, _classnames2["default"])(props.className, disabledCls, dragOverCls, filterCls, selectedCls) className: (0, _classnames2["default"])(props.className, disabledCls, dragOverCls, filterCls, selectedCls, focusedCls)
}), }),
canRenderSwitcher ? this.renderSwitcher(props, expandedState) : noopSwitcher(), canRenderSwitcher ? this.renderSwitcher(props, expandedState) : noopSwitcher(),
props.checkable ? this.renderCheckbox(props) : null, props.checkable ? this.renderCheckbox(props) : null,

2
dist/demo.css vendored
View File

@ -123,6 +123,8 @@
background-color: rgb(255, 247, 231); } background-color: rgb(255, 247, 231); }
.u-tree li a.u-tree-node-selected .u-tree-title { .u-tree li a.u-tree-node-selected .u-tree-title {
color: rgb(245, 60, 50); } color: rgb(245, 60, 50); }
.u-tree li.u-tree-treenode-focused > a {
background-color: rgb(235, 236, 240); }
.u-tree li span.u-checkbox { .u-tree li span.u-checkbox {
margin: 2px 4px 0 0; } margin: 2px 4px 0 0; }
.u-tree li span.u-tree-switcher, .u-tree li span.u-tree-switcher,

2
dist/demo.css.map vendored

File diff suppressed because one or more lines are too long

20
dist/demo.js vendored
View File

@ -34248,7 +34248,8 @@
selectedKeys: _this.getDefaultSelectedKeys(props), selectedKeys: _this.getDefaultSelectedKeys(props),
dragNodesKeys: '', dragNodesKeys: '',
dragOverNodeKey: '', dragOverNodeKey: '',
dropNodeKey: '' dropNodeKey: '',
focusKey: '' //上下箭头选择树节点时用于标识focus状态
}; };
return _this; return _this;
} }
@ -34677,7 +34678,11 @@
var parentEle = (0, _util.closest)(e.target, ".u-tree"); var parentEle = (0, _util.closest)(e.target, ".u-tree");
var focusEle = parentEle ? parentEle.querySelector(queryInfo) : null; var focusEle = parentEle ? parentEle.querySelector(queryInfo) : null;
focusEle && focusEle.focus(); focusEle && focusEle.focus();
this.onSelect(nextTreeNode); var eventKey = nextTreeNode.props.eventKey || nextTreeNode.key;
this.setState({
focusKey: eventKey
});
// this.onSelect(nextTreeNode);
} }
}; };
@ -34726,7 +34731,11 @@
} }
} }
preElement && preElement.focus(); preElement && preElement.focus();
this.onSelect(prevTreeNode); var eventKey = prevTreeNode.props.eventKey || prevTreeNode.key;
this.setState({
focusKey: eventKey
});
// this.onSelect(prevTreeNode);
}; };
// all keyboard events callbacks run from here at first // all keyboard events callbacks run from here at first
@ -34749,6 +34758,7 @@
// 展开树节点 // 展开树节点
this.onExpand(treeNode, 'right'); this.onExpand(treeNode, 'right');
} else if (e.keyCode == _tinperBeeCore.KeyCode.SPACE && props.checkable) { } else if (e.keyCode == _tinperBeeCore.KeyCode.SPACE && props.checkable) {
this.onSelect(treeNode);
// 如果是多选tree则进行选中或者反选该节点 // 如果是多选tree则进行选中或者反选该节点
this.onCheck(treeNode); this.onCheck(treeNode);
} else if (e.keyCode == _tinperBeeCore.KeyCode.ENTER) { } else if (e.keyCode == _tinperBeeCore.KeyCode.ENTER) {
@ -34980,6 +34990,7 @@
_dropTrigger: this._dropTrigger, _dropTrigger: this._dropTrigger,
expanded: state.expandedKeys.indexOf(key) !== -1, expanded: state.expandedKeys.indexOf(key) !== -1,
selected: state.selectedKeys.indexOf(key) !== -1, selected: state.selectedKeys.indexOf(key) !== -1,
focused: state.focusKey === key,
openTransitionName: this.getOpenTransitionName(), openTransitionName: this.getOpenTransitionName(),
openAnimation: props.openAnimation, openAnimation: props.openAnimation,
filterTreeNode: this.filterTreeNode.bind(this), filterTreeNode: this.filterTreeNode.bind(this),
@ -36078,10 +36089,11 @@
return _react2['default'].createElement('span', { className: (0, _classnames2['default'])(cls) }); return _react2['default'].createElement('span', { className: (0, _classnames2['default'])(cls) });
}; };
var selectedCls = props.selected ? prefixCls + '-treenode-selected' : ''; var selectedCls = props.selected ? prefixCls + '-treenode-selected' : '';
var focusedCls = props.focused ? prefixCls + '-treenode-focused' : '';
return _react2['default'].createElement( return _react2['default'].createElement(
'li', 'li',
_extends({}, liProps, { style: props.style, _extends({}, liProps, { style: props.style,
className: (0, _classnames2['default'])(props.className, disabledCls, dragOverCls, filterCls, selectedCls) className: (0, _classnames2['default'])(props.className, disabledCls, dragOverCls, filterCls, selectedCls, focusedCls)
}), }),
canRenderSwitcher ? this.renderSwitcher(props, expandedState) : noopSwitcher(), canRenderSwitcher ? this.renderSwitcher(props, expandedState) : noopSwitcher(),
props.checkable ? this.renderCheckbox(props) : null, props.checkable ? this.renderCheckbox(props) : null,

2
dist/demo.js.map vendored

File diff suppressed because one or more lines are too long

View File

@ -76,7 +76,7 @@ import 'bee-tree/build/Tree.css';
| 快捷键 | 类型 |快捷键说明 | | 快捷键 | 类型 |快捷键说明 |
| --- | :---: | --- | | --- | :---: | --- |
| focusable | function | 是否开启快捷键 | | focusable | bool | 是否开启快捷键 |
| tab | - | tab 进入焦点,且选中第一行。| | tab | - | tab 进入焦点,且选中第一行。|
| ↑、↓ | - | ↑(上箭)、↓(下箭) 选中上一行、选中下一行。 | | ↑、↓ | - | ↑(上箭)、↓(下箭) 选中上一行、选中下一行。 |
| ←、→ | - | ←(左箭)、→(右箭) 收起、展开。 | | ←、→ | - | ←(左箭)、→(右箭) 收起、展开。 |

View File

@ -1,6 +1,6 @@
{ {
"name": "bee-tree", "name": "bee-tree",
"version": "2.0.16-beta.1", "version": "2.0.16",
"description": "Tree ui component for react", "description": "Tree ui component for react",
"keywords": [ "keywords": [
"react", "react",

View File

@ -34,6 +34,7 @@ class Tree extends React.Component {
dragNodesKeys: '', dragNodesKeys: '',
dragOverNodeKey: '', dragOverNodeKey: '',
dropNodeKey: '', dropNodeKey: '',
focusKey: '', //上下箭头选择树节点时用于标识focus状态
}; };
} }
@ -461,7 +462,11 @@ onExpand(treeNode,keyType) {
const parentEle = closest(e.target,".u-tree") const parentEle = closest(e.target,".u-tree")
const focusEle = parentEle?parentEle.querySelector(queryInfo):null; const focusEle = parentEle?parentEle.querySelector(queryInfo):null;
focusEle && focusEle.focus() focusEle && focusEle.focus()
this.onSelect(nextTreeNode); const eventKey = nextTreeNode.props.eventKey || nextTreeNode.key;
this.setState({
focusKey: eventKey
})
// this.onSelect(nextTreeNode);
} }
} }
@ -511,7 +516,11 @@ onExpand(treeNode,keyType) {
} }
preElement && preElement.focus(); preElement && preElement.focus();
this.onSelect(prevTreeNode); const eventKey = prevTreeNode.props.eventKey || prevTreeNode.key;
this.setState({
focusKey: eventKey
})
// this.onSelect(prevTreeNode);
} }
// all keyboard events callbacks run from here at first // all keyboard events callbacks run from here at first
onKeyDown(e,treeNode) { onKeyDown(e,treeNode) {
@ -532,6 +541,7 @@ onExpand(treeNode,keyType) {
// 展开树节点 // 展开树节点
this.onExpand(treeNode,'right'); this.onExpand(treeNode,'right');
}else if (e.keyCode == KeyCode.SPACE && props.checkable){ }else if (e.keyCode == KeyCode.SPACE && props.checkable){
this.onSelect(treeNode);
// 如果是多选tree则进行选中或者反选该节点 // 如果是多选tree则进行选中或者反选该节点
this.onCheck(treeNode); this.onCheck(treeNode);
}else if(e.keyCode == KeyCode.ENTER){ }else if(e.keyCode == KeyCode.ENTER){
@ -763,6 +773,7 @@ onExpand(treeNode,keyType) {
_dropTrigger: this._dropTrigger, _dropTrigger: this._dropTrigger,
expanded: state.expandedKeys.indexOf(key) !== -1, expanded: state.expandedKeys.indexOf(key) !== -1,
selected: state.selectedKeys.indexOf(key) !== -1, selected: state.selectedKeys.indexOf(key) !== -1,
focused: state.focusKey === key,
openTransitionName: this.getOpenTransitionName(), openTransitionName: this.getOpenTransitionName(),
openAnimation: props.openAnimation, openAnimation: props.openAnimation,
filterTreeNode: this.filterTreeNode.bind(this), filterTreeNode: this.filterTreeNode.bind(this),

View File

@ -184,6 +184,9 @@ $treePrefixCls : "u-tree";
color: $brand-primary; color: $brand-primary;
} }
} }
li.u-tree-treenode-focused>a{
background-color: $tree-node-bg-color;
}
li span.u-checkbox { li span.u-checkbox {
margin: 2px 4px 0 0; margin: 2px 4px 0 0;
} }

View File

@ -492,9 +492,10 @@ class TreeNode extends React.Component {
return <span className={classNames(cls)}></span>; return <span className={classNames(cls)}></span>;
}; };
const selectedCls = props.selected?`${prefixCls}-treenode-selected`:''; const selectedCls = props.selected?`${prefixCls}-treenode-selected`:'';
const focusedCls = props.focused ? `${prefixCls}-treenode-focused` : '';
return ( return (
<li {...liProps} style={props.style} <li {...liProps} style={props.style}
className={classNames(props.className, disabledCls, dragOverCls, filterCls,selectedCls) } className={classNames(props.className, disabledCls, dragOverCls, filterCls,selectedCls,focusedCls) }
> >
{canRenderSwitcher ? this.renderSwitcher(props, expandedState) : noopSwitcher()} {canRenderSwitcher ? this.renderSwitcher(props, expandedState) : noopSwitcher()}
{props.checkable ? this.renderCheckbox(props) : null} {props.checkable ? this.renderCheckbox(props) : null}

View File

@ -1,325 +1,325 @@
/* eslint no-loop-func: 0*/ /* eslint no-loop-func: 0*/
import React from 'react'; import React from 'react';
export function browser(navigator) { export function browser(navigator) {
let tem; let tem;
const ua = navigator.userAgent; const ua = navigator.userAgent;
let M = ua.match(/(opera|chrome|safari|firefox|msie|trident(?=\/))\/?\s*(\d+)/i) || []; let M = ua.match(/(opera|chrome|safari|firefox|msie|trident(?=\/))\/?\s*(\d+)/i) || [];
if (/trident/i.test(M[1])) { if (/trident/i.test(M[1])) {
tem = /\brv[ :]+(\d+)/g.exec(ua) || []; tem = /\brv[ :]+(\d+)/g.exec(ua) || [];
return `IE ${tem[1] || ''}`; return `IE ${tem[1] || ''}`;
} }
if (M[1] === 'Chrome') { if (M[1] === 'Chrome') {
tem = ua.match(/\b(OPR|Edge)\/(\d+)/); tem = ua.match(/\b(OPR|Edge)\/(\d+)/);
if (tem) return tem.slice(1).join(' ').replace('OPR', 'Opera'); if (tem) return tem.slice(1).join(' ').replace('OPR', 'Opera');
} }
M = M[2] ? [M[1], M[2]] : [navigator.appName, navigator.appVersion, '-?']; M = M[2] ? [M[1], M[2]] : [navigator.appName, navigator.appVersion, '-?'];
tem = ua.match(/version\/(\d+)/i); tem = ua.match(/version\/(\d+)/i);
if (tem) { if (tem) {
M.splice(1, 1, tem[1]); M.splice(1, 1, tem[1]);
} }
return M.join(' '); return M.join(' ');
} }
// export function getOffset(el) { // export function getOffset(el) {
// const obj = el.getBoundingClientRect(); // const obj = el.getBoundingClientRect();
// return { // return {
// left: obj.left + document.body.scrollLeft, // left: obj.left + document.body.scrollLeft,
// top: obj.top + document.body.scrollTop, // top: obj.top + document.body.scrollTop,
// width: obj.width, // width: obj.width,
// height: obj.height // height: obj.height
// }; // };
// } // }
// // iscroll offset // // iscroll offset
// offset = function (el) { // offset = function (el) {
// var left = -el.offsetLeft, // var left = -el.offsetLeft,
// top = -el.offsetTop; // top = -el.offsetTop;
// // jshint -W084 // // jshint -W084
// while (el = el.offsetParent) { // while (el = el.offsetParent) {
// left -= el.offsetLeft; // left -= el.offsetLeft;
// top -= el.offsetTop; // top -= el.offsetTop;
// } // }
// // jshint +W084 // // jshint +W084
// return { // return {
// left: left, // left: left,
// top: top // top: top
// }; // };
// } // }
/* eslint-disable */ /* eslint-disable */
export function getOffset(ele) { export function getOffset(ele) {
let doc, win, docElem, rect; let doc, win, docElem, rect;
if (!ele.getClientRects().length) { if (!ele.getClientRects().length) {
return { top: 0, left: 0 }; return { top: 0, left: 0 };
} }
rect = ele.getBoundingClientRect(); rect = ele.getBoundingClientRect();
if (rect.width || rect.height) { if (rect.width || rect.height) {
doc = ele.ownerDocument; doc = ele.ownerDocument;
win = doc.defaultView; win = doc.defaultView;
docElem = doc.documentElement; docElem = doc.documentElement;
return { return {
top: rect.top + win.pageYOffset - docElem.clientTop, top: rect.top + win.pageYOffset - docElem.clientTop,
left: rect.left + win.pageXOffset - docElem.clientLeft left: rect.left + win.pageXOffset - docElem.clientLeft
}; };
} }
return rect; return rect;
} }
/* eslint-enable */ /* eslint-enable */
function getChildrenlength(children) { function getChildrenlength(children) {
let len = 1; let len = 1;
if (Array.isArray(children)) { if (Array.isArray(children)) {
len = children.length; len = children.length;
} }
return len; return len;
} }
function getSiblingPosition(index, len, siblingPosition) { function getSiblingPosition(index, len, siblingPosition) {
if (len === 1) { if (len === 1) {
siblingPosition.first = true; siblingPosition.first = true;
siblingPosition.last = true; siblingPosition.last = true;
} else { } else {
siblingPosition.first = index === 0; siblingPosition.first = index === 0;
siblingPosition.last = index === len - 1; siblingPosition.last = index === len - 1;
} }
return siblingPosition; return siblingPosition;
} }
export function loopAllChildren(childs, callback, parent) { export function loopAllChildren(childs, callback, parent) {
const loop = (children, level, _parent) => { const loop = (children, level, _parent) => {
const len = getChildrenlength(children); const len = getChildrenlength(children);
React.Children.forEach(children, (item, index) => { React.Children.forEach(children, (item, index) => {
const pos = `${level}-${index}`; const pos = `${level}-${index}`;
if (item.props.children && item.type && item.type.isTreeNode) { if (item.props.children && item.type && item.type.isTreeNode) {
loop(item.props.children, pos, { node: item, pos }); loop(item.props.children, pos, { node: item, pos });
} }
callback(item, index, pos, item.key || pos, getSiblingPosition(index, len, {}), _parent); callback(item, index, pos, item.key || pos, getSiblingPosition(index, len, {}), _parent);
}); });
}; };
loop(childs, 0, parent); loop(childs, 0, parent);
} }
export function isInclude(smallArray, bigArray) { export function isInclude(smallArray, bigArray) {
return smallArray.every((ii, i) => { return smallArray.every((ii, i) => {
return ii === bigArray[i]; return ii === bigArray[i];
}); });
} }
// console.log(isInclude(['0', '1'], ['0', '10', '1'])); // console.log(isInclude(['0', '1'], ['0', '10', '1']));
// arr.length === 628, use time: ~20ms // arr.length === 628, use time: ~20ms
export function filterParentPosition(arr) { export function filterParentPosition(arr) {
const levelObj = {}; const levelObj = {};
arr.forEach((item) => { arr.forEach((item) => {
const posLen = item.split('-').length; const posLen = item.split('-').length;
if (!levelObj[posLen]) { if (!levelObj[posLen]) {
levelObj[posLen] = []; levelObj[posLen] = [];
} }
levelObj[posLen].push(item); levelObj[posLen].push(item);
}); });
const levelArr = Object.keys(levelObj).sort(); const levelArr = Object.keys(levelObj).sort();
for (let i = 0; i < levelArr.length; i++) { for (let i = 0; i < levelArr.length; i++) {
if (levelArr[i + 1]) { if (levelArr[i + 1]) {
levelObj[levelArr[i]].forEach(ii => { levelObj[levelArr[i]].forEach(ii => {
for (let j = i + 1; j < levelArr.length; j++) { for (let j = i + 1; j < levelArr.length; j++) {
levelObj[levelArr[j]].forEach((_i, index) => { levelObj[levelArr[j]].forEach((_i, index) => {
if (isInclude(ii.split('-'), _i.split('-'))) { if (isInclude(ii.split('-'), _i.split('-'))) {
levelObj[levelArr[j]][index] = null; levelObj[levelArr[j]][index] = null;
} }
}); });
levelObj[levelArr[j]] = levelObj[levelArr[j]].filter(p => p); levelObj[levelArr[j]] = levelObj[levelArr[j]].filter(p => p);
} }
}); });
} }
} }
let nArr = []; let nArr = [];
levelArr.forEach(i => { levelArr.forEach(i => {
nArr = nArr.concat(levelObj[i]); nArr = nArr.concat(levelObj[i]);
}); });
return nArr; return nArr;
} }
// console.log(filterParentPosition( // console.log(filterParentPosition(
// ['0-2', '0-3-3', '0-10', '0-10-0', '0-0-1', '0-0', '0-1-1', '0-1'] // ['0-2', '0-3-3', '0-10', '0-10-0', '0-0-1', '0-0', '0-1-1', '0-1']
// )); // ));
function stripTail(str) { function stripTail(str) {
const arr = str.match(/(.+)(-[^-]+)$/); const arr = str.match(/(.+)(-[^-]+)$/);
let st = ''; let st = '';
if (arr && arr.length === 3) { if (arr && arr.length === 3) {
st = arr[1]; st = arr[1];
} }
return st; return st;
} }
function splitPosition(pos) { function splitPosition(pos) {
return pos.split('-'); return pos.split('-');
} }
export function handleCheckState(obj, checkedPositionArr, checkIt) { export function handleCheckState(obj, checkedPositionArr, checkIt) {
// console.log(stripTail('0-101-000')); // console.log(stripTail('0-101-000'));
let objKeys = Object.keys(obj); let objKeys = Object.keys(obj);
// let s = Date.now(); // let s = Date.now();
objKeys.forEach((i, index) => { objKeys.forEach((i, index) => {
const iArr = splitPosition(i); const iArr = splitPosition(i);
let saved = false; let saved = false;
checkedPositionArr.forEach((_pos) => { checkedPositionArr.forEach((_pos) => {
// 设置子节点,全选或全不选 // 设置子节点,全选或全不选
const _posArr = splitPosition(_pos); const _posArr = splitPosition(_pos);
if (iArr.length > _posArr.length && isInclude(_posArr, iArr)) { if (iArr.length > _posArr.length && isInclude(_posArr, iArr)) {
obj[i].halfChecked = false; obj[i].halfChecked = false;
obj[i].checked = checkIt; obj[i].checked = checkIt;
objKeys[index] = null; objKeys[index] = null;
} }
if (iArr[0] === _posArr[0] && iArr[1] === _posArr[1]) { if (iArr[0] === _posArr[0] && iArr[1] === _posArr[1]) {
// 如果 // 如果
saved = true; saved = true;
} }
}); });
if (!saved) { if (!saved) {
objKeys[index] = null; objKeys[index] = null;
} }
}); });
// TODO: 循环 2470000 次耗时约 1400 ms。 性能瓶颈! // TODO: 循环 2470000 次耗时约 1400 ms。 性能瓶颈!
// console.log(Date.now()-s, checkedPositionArr.length * objKeys.length); // console.log(Date.now()-s, checkedPositionArr.length * objKeys.length);
objKeys = objKeys.filter(i => i); // filter non null; objKeys = objKeys.filter(i => i); // filter non null;
for (let pIndex = 0; pIndex < checkedPositionArr.length; pIndex++) { for (let pIndex = 0; pIndex < checkedPositionArr.length; pIndex++) {
// 循环设置父节点的 选中 或 半选状态 // 循环设置父节点的 选中 或 半选状态
const loop = (__pos) => { const loop = (__pos) => {
const _posLen = splitPosition(__pos).length; const _posLen = splitPosition(__pos).length;
if (_posLen <= 2) { // e.g. '0-0', '0-1' if (_posLen <= 2) { // e.g. '0-0', '0-1'
return; return;
} }
let sibling = 0; let sibling = 0;
let siblingChecked = 0; let siblingChecked = 0;
const parentPosition = stripTail(__pos); const parentPosition = stripTail(__pos);
objKeys.forEach((i /* , index*/) => { objKeys.forEach((i /* , index*/) => {
const iArr = splitPosition(i); const iArr = splitPosition(i);
if (iArr.length === _posLen && isInclude(splitPosition(parentPosition), iArr)) { if (iArr.length === _posLen && isInclude(splitPosition(parentPosition), iArr)) {
sibling++; sibling++;
if (obj[i].checked) { if (obj[i].checked) {
siblingChecked++; siblingChecked++;
const _i = checkedPositionArr.indexOf(i); const _i = checkedPositionArr.indexOf(i);
if (_i > -1) { if (_i > -1) {
checkedPositionArr.splice(_i, 1); checkedPositionArr.splice(_i, 1);
if (_i <= pIndex) { if (_i <= pIndex) {
pIndex--; pIndex--;
} }
} }
} else if (obj[i].halfChecked) { } else if (obj[i].halfChecked) {
siblingChecked += 0.5; siblingChecked += 0.5;
} }
// objKeys[index] = null; // objKeys[index] = null;
} }
}); });
// objKeys = objKeys.filter(i => i); // filter non null; // objKeys = objKeys.filter(i => i); // filter non null;
const parent = obj[parentPosition]; const parent = obj[parentPosition];
// sibling 不会等于0 // sibling 不会等于0
// 全不选 - 全选 - 半选 // 全不选 - 全选 - 半选
if (siblingChecked === 0) { if (siblingChecked === 0) {
parent.checked = false; parent.checked = false;
parent.halfChecked = false; parent.halfChecked = false;
} else if (siblingChecked === sibling) { } else if (siblingChecked === sibling) {
parent.checked = true; parent.checked = true;
parent.halfChecked = false; parent.halfChecked = false;
} else { } else {
parent.halfChecked = true; parent.halfChecked = true;
parent.checked = false; parent.checked = false;
} }
loop(parentPosition); loop(parentPosition);
}; };
loop(checkedPositionArr[pIndex], pIndex); loop(checkedPositionArr[pIndex], pIndex);
} }
// console.log(Date.now()-s, objKeys.length, checkIt); // console.log(Date.now()-s, objKeys.length, checkIt);
} }
export function getCheck(treeNodesStates) { export function getCheck(treeNodesStates) {
const halfCheckedKeys = []; const halfCheckedKeys = [];
const checkedKeys = []; const checkedKeys = [];
const checkedNodes = []; const checkedNodes = [];
const checkedNodesPositions = []; const checkedNodesPositions = [];
Object.keys(treeNodesStates).forEach((item) => { Object.keys(treeNodesStates).forEach((item) => {
const itemObj = treeNodesStates[item]; const itemObj = treeNodesStates[item];
if (itemObj.checked) { if (itemObj.checked) {
checkedKeys.push(itemObj.key); checkedKeys.push(itemObj.key);
checkedNodes.push(itemObj.node); checkedNodes.push(itemObj.node);
checkedNodesPositions.push({ node: itemObj.node, pos: item }); checkedNodesPositions.push({ node: itemObj.node, pos: item });
} else if (itemObj.halfChecked) { } else if (itemObj.halfChecked) {
halfCheckedKeys.push(itemObj.key); halfCheckedKeys.push(itemObj.key);
} }
}); });
return { return {
halfCheckedKeys, checkedKeys, checkedNodes, checkedNodesPositions, treeNodesStates, halfCheckedKeys, checkedKeys, checkedNodes, checkedNodesPositions, treeNodesStates,
}; };
} }
export function getStrictlyValue(checkedKeys, halfChecked) { export function getStrictlyValue(checkedKeys, halfChecked) {
if (halfChecked) { if (halfChecked) {
return { checked: checkedKeys, halfChecked }; return { checked: checkedKeys, halfChecked };
} }
return checkedKeys; return checkedKeys;
} }
export function arraysEqual(a, b) { export function arraysEqual(a, b) {
if (a === b) return true; if (a === b) return true;
if (a === null || typeof a === 'undefined' || b === null || typeof b === 'undefined') { if (a === null || typeof a === 'undefined' || b === null || typeof b === 'undefined') {
return false; return false;
} }
if (a.length !== b.length) return false; if (a.length !== b.length) return false;
// If you don't care about the order of the elements inside // If you don't care about the order of the elements inside
// the array, you should sort both arrays here. // the array, you should sort both arrays here.
for (let i = 0; i < a.length; ++i) { for (let i = 0; i < a.length; ++i) {
if (a[i] !== b[i]) return false; if (a[i] !== b[i]) return false;
} }
return true; return true;
} }
export function closest(el, selector) { export function closest(el, selector) {
const matchesSelector = el.matches || el.webkitMatchesSelector || el.mozMatchesSelector || el.msMatchesSelector; const matchesSelector = el.matches || el.webkitMatchesSelector || el.mozMatchesSelector || el.msMatchesSelector;
while (el) { while (el) {
if (matchesSelector.call(el, selector)) { if (matchesSelector.call(el, selector)) {
return el; return el;
} else { } else {
el = el.parentElement; el = el.parentElement;
} }
} }
return null; return null;
} }
export function isTreeNode(node) { export function isTreeNode(node) {
return node && node.type && node.type.isTreeNode; return node && node.type && node.type.isTreeNode;
} }
export function toArray(children) { export function toArray(children) {
const ret = []; const ret = [];
React.Children.forEach(children, (c) => { React.Children.forEach(children, (c) => {
ret.push(c); ret.push(c);
}); });
return ret; return ret;
} }
export function getNodeChildren(children) { export function getNodeChildren(children) {
return toArray(children).filter(isTreeNode); return toArray(children).filter(isTreeNode);
} }
let onlyTreeNodeWarned = false; let onlyTreeNodeWarned = false;
export function warnOnlyTreeNode() { export function warnOnlyTreeNode() {
if (onlyTreeNodeWarned) return; if (onlyTreeNodeWarned) return;
onlyTreeNodeWarned = true; onlyTreeNodeWarned = true;
console.warn('Tree only accept TreeNode as children.'); console.warn('Tree only accept TreeNode as children.');
} }