diff --git a/components/tree/PropsType.tsx b/components/tree/PropsType.tsx index 30e2eca8..6efaf266 100644 --- a/components/tree/PropsType.tsx +++ b/components/tree/PropsType.tsx @@ -1,45 +1,95 @@ -import { MouseEvent, ReactNode } from 'react'; +import { MouseEvent, ReactNode, createContext } from 'react'; import TreeNode from './TreeNode'; -export default interface PropsType { - prefixCls?: string; - treeData?: object[]; - canCheck?: boolean; - checkedKeys?: string[]; - expandedKeys: string[]; - defaultExpandAll?: boolean; +type TreeCheckEventHandler = ( + checkedMap: { + checkedKeys: Array; + halfCheckedKeys: Array; + }, + checkedObj: { + node: TreeNode; + checked: boolean; + event: MouseEvent; + }) => void; - onCheck?( - checkedMap: { - checkedKeys: Array; - halfCheckedKeys: Array; - }, - checkedObj: { - node: TreeNode; - checked: boolean; - event: MouseEvent; - }): void; - - onExpand?(expandedObj: { - expandedKeys: Array; +type TreeExpandEventHandler = ( + expandedKeys: Array, + expandedObj: { node: TreeNode; expanded: boolean; event: MouseEvent; - }): void; + }) => void; + +type TreeSelectEventHandler = ( + selectedKeys: Array, + selectedObj: { + node: EventDataNode; + selected: boolean; + event: MouseEvent; + }) => void; +type TreeNodeExpandEventHandler = (treeNode: EventDataNode, targetExpanded: boolean, event: MouseEvent) => void; +type TreeNodeCheckEventHandler = (treeNode: EventDataNode, targetChecked: boolean, event: MouseEvent) => void; +type TreeNodeSelectEventHandler = (treeNode: EventDataNode, targetSelected: boolean, event: MouseEvent) => void; +type TreeNodeClickEventHandler = (event: MouseEvent) => void; + +export interface PropsType { + prefixCls?: string; + treeData: TreeNode[]; + checkable?: boolean; + checkedKeys?: string[]; + expandedKeys?: string[]; + defaultExpandAll?: boolean; + autoExpandParent?: boolean; + selectedKeys?: string[]; + selectable?: boolean; + multiple?: boolean; + disabled?: boolean; // 禁掉树 + showIcon?: boolean; + icon?: ReactNode; + showLine?: boolean; + className?: string; + switcherIcon?: ReactNode; + children?: ReactNode; + + onCheck: TreeCheckEventHandler; + onExpand: TreeExpandEventHandler; + onSelect: TreeSelectEventHandler; + onClick?: TreeNodeClickEventHandler; } export interface TreeNodePropsType { - prefixCls?: string; title?: string|ReactNode; keys: string; expanded?: boolean; checked?: boolean; halfChecked?: boolean; - canCheck?: boolean; checkDisabled?: boolean; + selectDisabled?: boolean; + disabled?: boolean; // 禁掉响应 isLeaf?: boolean; + selected?: boolean; + checkable?: boolean; + icon?: ReactNode; + children?: React.ReactNode; +} + +export type EventDataNode = Omit; - onNodeExpand?(treeNode: TreeNode, targetExpanded: boolean, event: MouseEvent): void; +export interface TreeContextProps { + prefixCls?: string; + checkable?: boolean; + selectable?: boolean; + disabled?: boolean; // 禁掉树 + showIcon?: boolean; + icon: ReactNode; + showLine?: boolean; + switcherIcon?: ReactNode; + children?: React.ReactNode; - onNodeCheck?(treeNode: TreeNode, targetChecked: boolean, event: MouseEvent): void; + onNodeExpand: TreeNodeExpandEventHandler; + onNodeCheck: TreeNodeCheckEventHandler; + onNodeSelect: TreeNodeSelectEventHandler; + onNodeClick: TreeNodeClickEventHandler; } + +export const TreeContext = createContext(null); diff --git a/components/tree/Tree.tsx b/components/tree/Tree.tsx index c3bd3030..64d68056 100644 --- a/components/tree/Tree.tsx +++ b/components/tree/Tree.tsx @@ -1,88 +1,110 @@ import React, { Component } from 'react'; +import classnames from 'classnames'; import TreeNode from './TreeNode'; -import PropsType from './PropsType'; +import { PropsType, TreeContext } from './PropsType'; + import { getTreeNodeChildren, convertTreeToData, initialTreeData, conductExpandParent, - conductCheck, arrDel, arrAdd, deepCopy, + conductCheck, arrDel, arrAdd, calcSelectedKeys, } from './utils'; interface StateType { - checkedKeys?: Array; + checkedKeys: Array; + selectedKeys: Array; halfCheckedKeys?: Array; - expandedKeys?: Array; + expandedKeys: Array; treeData: Array; + prevProps?: PropsType; } class Tree extends Component { static defaultProps = { - prefixCls: 'ui-tree', + prefixCls: 'zw-tree', checkedKeys: [], + selectedKeys: [], expandedKeys: [], + treeData: [], + disabled: false, + checkable: false, + defaultExpandAll: false, + autoExpandParent: true, + multiple: false, + selectable: true, + showLine: false, + showIcon: true, }; static TreeNode: any; - state = { + state: StateType = { checkedKeys: [], halfCheckedKeys: [], expandedKeys: [], treeData: [], + selectedKeys: [], }; - componentWillMount() { - this.initTreeNodes(); - } - - initTreeNodes = (): void => { - const { treeData = [], checkedKeys, expandedKeys, defaultExpandAll, children } = this.props; - const newState = { - treeData: [] as object[], - halfCheckedKeys: [] as string[], - checkedKeys: [] as string[], - expandedKeys: [] as string[], + static getDerivedStateFromProps(nextProps: Tree['props'], prevState: StateType) { + const { prevProps } = prevState; + const newState: Partial = { + prevProps: nextProps, }; + function needUpdate(key: string) { + return (!prevProps && key in nextProps) || (prevProps && prevProps[key] !== nextProps[key]); + } + let treeData: TreeNode[] = []; let TreeDataInformationSet = { allExpandDataMap: {}, treeData: [] }; - if (treeData.length > 0) { - // 深拷贝treeData - newState.treeData = deepCopy(treeData); - TreeDataInformationSet = initialTreeData(newState.treeData); - } else if (children) { - const treeNodeChildren = getTreeNodeChildren({ children }); + if (needUpdate('treeData')) { + ({ treeData } = nextProps); + TreeDataInformationSet = initialTreeData(treeData); + treeData = TreeDataInformationSet.treeData; + } else if (needUpdate('children')) { + const treeNodeChildren = getTreeNodeChildren({ children: nextProps.children }); if (treeNodeChildren.length > 0) { TreeDataInformationSet = initialTreeData(convertTreeToData(treeNodeChildren)); } + treeData = TreeDataInformationSet.treeData; + } + if (treeData && treeData.length) { + newState.treeData = treeData; + // newState.treeData = deepCopy(treeData); } - const { allExpandDataMap, treeData: initialedTreeData } = TreeDataInformationSet; - newState.treeData = initialedTreeData; + const currentTreeData = newState.treeData || prevState.treeData; // 初始化checkedKeys,更新treeData - if (checkedKeys && checkedKeys.length > 0) { + if (needUpdate('checkedKeys')) { const { checkedKeys: finalCheckedKeys, halfCheckedKeys: finalHalfCheckedKeys, treeData: finaltreeDataAfter, - } = conductCheck(checkedKeys, true, newState.treeData); + } = conductCheck(nextProps.checkedKeys, true, currentTreeData); newState.checkedKeys = finalCheckedKeys; newState.halfCheckedKeys = finalHalfCheckedKeys; newState.treeData = finaltreeDataAfter; } + // selected + if (nextProps.selectable) { + if (needUpdate('selectedKeys')) { + newState.selectedKeys = calcSelectedKeys(nextProps.selectedKeys, nextProps); + } + } /* 初始化expandedKeys 如果要展开所有结点,则取到所有根结点作为展开结点; 否则展开传入的展开结点 */ - if (defaultExpandAll) { - newState.expandedKeys = conductExpandParent(Object.keys(allExpandDataMap), newState.treeData); - } else if (expandedKeys && expandedKeys.length > 0) { - newState.expandedKeys = conductExpandParent(expandedKeys, newState.treeData); + if (!prevProps && nextProps.defaultExpandAll) { + newState.expandedKeys = conductExpandParent(Object.keys(TreeDataInformationSet.allExpandDataMap), currentTreeData); + } else if (needUpdate('expandedKeys') || (prevProps && needUpdate('autoExpandParent'))) { + newState.expandedKeys = nextProps.autoExpandParent ? conductExpandParent(nextProps.expandedKeys, currentTreeData) : nextProps.expandedKeys; } - this.setState(newState); - }; + return newState; + } onNodeCheck = (node, targetChecked, event) => { const { onCheck } = this.props; - const { keys } = node.props; + const { keys } = node; const { treeData: originalTreeData } = this.state; - const { checkedKeys: originalCheckedKeys, halfCheckedKeys: originHalfCheckedKeys } = this.state; + const { checkedKeys: originalCheckedKeys = [], halfCheckedKeys: originHalfCheckedKeys = [] } = this.state; const { checkedKeys, halfCheckedKeys, treeData } = conductCheck([keys], targetChecked, originalTreeData, { checkedKeys: originalCheckedKeys, halfCheckedKeys: originHalfCheckedKeys, @@ -104,48 +126,81 @@ class Tree extends Component { }; onNodeExpand = (node, targetExpanded, event) => { - let { expandedKeys } = this.state; + let { expandedKeys = [] } = this.state; const { onExpand } = this.props; - const { keys } = node.props; - + const { keys } = node; if (targetExpanded) { expandedKeys = arrAdd(expandedKeys, keys); } else { expandedKeys = arrDel(expandedKeys, keys); } + this.setState({ expandedKeys, }); if (onExpand) { - onExpand({ - expandedKeys, + onExpand( + expandedKeys, { + node, + expanded: targetExpanded, + event, + }, + ); + } + }; + + onNodeSelect = (node, targetSelected, event) => { + let { selectedKeys = [] } = this.state; + const { onSelect, multiple } = this.props; + const { keys } = node; + + if (!targetSelected) { + selectedKeys = arrDel(selectedKeys, keys); + } else if (!multiple) { + selectedKeys = [keys]; + } else { + selectedKeys = arrAdd(selectedKeys, keys); + } + this.setState({ + selectedKeys, + }); + + if (onSelect) { + onSelect(selectedKeys, { + selected: targetSelected, node, - expanded: targetExpanded, event, }); } }; + onNodeClick = (e: React.MouseEvent) => { + const { onClick } = this.props; + if (onClick) { + onClick(e); + } + }; + renderTreeNodes = (data) => { - const { prefixCls, canCheck } = this.props; - const { expandedKeys, checkedKeys, halfCheckedKeys } = this.state; - return data.map((item, index) => { - const { keys, title, checkDisabled, children } = item; + const { expandedKeys, checkedKeys, halfCheckedKeys, selectedKeys } = this.state; + return data.map((item) => { + const { keys, title, checkDisabled, selectDisabled, children, icon, disabled, checkable } = item; return ( {children ? this.renderTreeNodes(children) : null} @@ -154,12 +209,32 @@ class Tree extends Component { }; render() { - const { prefixCls } = this.props; + const { prefixCls, className, showLine, checkable, selectable, disabled, showIcon, icon, switcherIcon } = this.props; const { treeData } = this.state; + const cls = classnames(prefixCls, className, { + [`${prefixCls}-show-line`]: showLine, + }); return ( -
    - {this.renderTreeNodes(treeData)} -
+ +
    + {this.renderTreeNodes(treeData)} +
+
); } } diff --git a/components/tree/TreeNode.tsx b/components/tree/TreeNode.tsx index 86f8dcbf..87222315 100644 --- a/components/tree/TreeNode.tsx +++ b/components/tree/TreeNode.tsx @@ -2,18 +2,31 @@ import React, { Component } from 'react'; import Animate from 'rc-animate'; import classnames from 'classnames'; import Checkbox from '../checkbox'; -import { TreeNodePropsType } from './PropsType'; +import Icon from '../icon'; +import { TreeNodePropsType, TreeContext } from './PropsType'; import animation from './openAnimation'; -import { isCheckDisabled } from './utils'; +import { convertNodePropsToEventData } from './utils'; const ICON_OPEN = 'open'; const ICON_CLOSE = 'close'; const ICON_NOOP = 'noop'; +const ICONS_TREE = Icon.createFromIconfont('//at.alicdn.com/t/font_1733827_ormtmokxywk.js'); class TreeNode extends Component { + static contextType = TreeContext; + static defaultProps = { - prefixCls: 'ui-tree', title: '', + expanded: false, + checked: false, + halfChecked: false, + selected: false, + checkDisabled: false, + selectDisabled: false, + disabled: false, + isLeaf: false, + icon: null, + children: null, }; isLeaf = () => { @@ -24,6 +37,41 @@ class TreeNode extends Component { return false; }; + isSelectable = () => { + const { selectDisabled } = this.props; + const { + context: { selectable }, + } = this; + + if (typeof selectDisabled === 'boolean') { + return !selectDisabled; + } + return selectable; + }; + + isDisabled = () => { + const { disabled } = this.props; + const { + context: { disabled: ParentDisabled }, + } = this; + + if (!disabled && !ParentDisabled) { + return false; + } + return true; + }; + + isCheckable = () => { + const { checkable } = this.props; + const { + context: { checkable: parentCheckable }, + } = this; + if (checkable !== false && parentCheckable) { + return true; + } + return false; + }; + getNodeState = () => { const { expanded } = this.props; let nodeState; @@ -36,55 +84,91 @@ class TreeNode extends Component { }; renderSwitcher = () => { - const { prefixCls } = this.props; + const { expanded } = this.props; + const { switcherIcon, showLine, prefixCls } = this.context; const switcherState = this.getNodeState(); - + const clsIconWrapper = classnames({ + [`${prefixCls}-switcher-icon`]: !showLine, + [`${prefixCls}-switcher-line-icon`]: showLine, + }); return ( + > + + {this.renderSwitcherIcon(expanded, switcherIcon, showLine)} + + ); }; + renderSwitcherIcon = (expanded, switcherIcon: React.ReactNode | null | undefined, showLine: boolean) => { + if (this.isLeaf()) { + return showLine ? : null; + } + // 只有showLine为true的模式下,可以用switcherIcon修改默认图标 + if (showLine && switcherIcon) { + return switcherIcon; + } + if (showLine) { + return expanded ? ( + + ) : ( + + ); + } + return ; + }; + renderCheckbox = () => { - const { checkDisabled, canCheck, checked, prefixCls, halfChecked } = this.props; - const isHalfChecked = checkDisabled ? false : halfChecked; - if (!canCheck) { + const { halfChecked, checked, checkDisabled } = this.props; + const { prefixCls } = this.context; + if (!this.isCheckable()) { return null; } return ( this.onCheck(e)} - disabled={checkDisabled} - checked={checked || isHalfChecked} - indeterminate={isHalfChecked} + onClick={(e) => this.onCheck(e)} + disabled={this.isDisabled() || checkDisabled} + checked={checked} + indeterminate={halfChecked} /> ); }; renderContent = () => { - const { prefixCls, title } = this.props; + const { showIcon, icon: treeIcon, prefixCls } = this.context; + const { title, icon, selected } = this.props; const nodeState = this.getNodeState(); - - const wrapClass = `${prefixCls}-node-content-wrapper ${prefixCls}-node-content-wrapper-${nodeState}`; - + const nodeIcon = icon || treeIcon; + const disabled = this.isDisabled(); + const isSelectable = !disabled && this.isSelectable(); + const wrapClass = classnames( + `${prefixCls}-node-content-wrapper`, + `${prefixCls}-node-content-wrapper-${nodeState}`, + { [`${prefixCls}-node-selected`]: isSelectable && selected }, + ); + const iconRender = (showIcon && nodeIcon) ? ({nodeIcon}) : null; return ( + {iconRender} {title} ); }; renderChildren = () => { - const { children, expanded, prefixCls = '' } = this.props; + const { prefixCls } = this.context; + const { children, expanded } = this.props; if (this.isLeaf()) { return null; } @@ -116,28 +200,61 @@ class TreeNode extends Component { }; onCheck = (e) => { - const { checked, onNodeCheck } = this.props; - const targetChecked = !checked; - if (!isCheckDisabled(this) && onNodeCheck) { - onNodeCheck(this, targetChecked, e); + const { checkDisabled, checked } = this.props; + const { onNodeCheck } = this.context; + if (this.isDisabled() || checkDisabled) { + return null; } + e.preventDefault(); + const targetChecked = !checked; + onNodeCheck(convertNodePropsToEventData(this.props), targetChecked, e); }; onExpand = (e) => { - const { expanded, onNodeExpand } = this.props; + const { expanded } = this.props; + const { onNodeExpand } = this.context; const targetExpanded = !expanded; - if (onNodeExpand) { - onNodeExpand(this, targetExpanded, e); + onNodeExpand(convertNodePropsToEventData(this.props), targetExpanded, e); + }; + + onSelectorClick = (e) => { + const { selected } = this.props; + const { onNodeClick, onNodeSelect } = this.context; + const targetSelected = !selected; + onNodeClick(e); + + if (this.isSelectable()) { + if (this.isDisabled()) { + return; + } + e.preventDefault(); + onNodeSelect(convertNodePropsToEventData(this.props), targetSelected, e); + } else { + this.onCheck(e); } }; render() { - const { keys } = this.props; + const { keys, checked } = this.props; + const { prefixCls } = this.context; + const disabled = this.isDisabled(); + const selected = this.isSelectable(); + const switcherState = this.getNodeState(); + + const cls = classnames(`${prefixCls}-node`, + `${prefixCls}-treenode-switcher-${switcherState}`, { + [`${prefixCls}-treenode-disabled`]: disabled, + [`${prefixCls}-treenode-selected`]: selected, + [`${prefixCls}-treenode-checked`]: checked, + }); + return (
  • - {this.renderSwitcher()} - {this.renderCheckbox()} - {this.renderContent()} +
    + {this.renderSwitcher()} + {this.renderCheckbox()} + {this.renderContent()} +
    {this.renderChildren()}
  • ); diff --git a/components/tree/__tests__/__snapshots__/index.test.jsx.snap b/components/tree/__tests__/__snapshots__/index.test.jsx.snap index 5202e408..7200e83c 100644 --- a/components/tree/__tests__/__snapshots__/index.test.jsx.snap +++ b/components/tree/__tests__/__snapshots__/index.test.jsx.snap @@ -2,227 +2,347 @@ exports[`Tree renders basic Tree correctly 1`] = `
    • - - - 根结点1 + + + + + + + - + + + 根结点1 + + +
    `; -exports[`Tree renders basic Tree with TreeNode children 1`] = ` +exports[`Tree renders basic Tree with TreeNodes children 1`] = ` +
      +`; + +exports[`Tree renders basic Tree with defaultExpandAll checkable correctly 1`] = `
      • - - + + + + + + + + + + + + - - - - 根结点1 + + 根结点1 + - +
        • - - + + + + + + + + + + + + - - - - 父结点 0-0 + + 父结点 0-0 + - +
          • - - + + + + + + + + + + + + - - - - 父结点 0-0-0 + + 父结点 0-0-0 + - +
            • - - + + + + + + - - - - 子结点 0-0-0-0 + + 子结点 0-0-0-0 + - +
            • - - + + + + + + - - - - 子结点 0-0-0-1 + + 子结点 0-0-0-1 + - +
            @@ -233,152 +353,201 @@ exports[`Tree renders basic Tree with TreeNode children 1`] = `
          • - - + + + + + + + + + + + + - - - - 父结点 0-1 + + 父结点 0-1 + - +
            • - - + + + + + + - - - - 子结点 0-1-0 + + 子结点 0-1-0 + - +
            • - - + + + + + + - - - - 子结点 0-1-1 + + 子结点 0-1-1 + - +
            • - - + + + + + + - - - - 子结点 0-1-2 + + 子结点 0-1-2 + - +
            @@ -386,232 +555,330 @@ exports[`Tree renders basic Tree with TreeNode children 1`] = `
          • - - + + + + + + + + + + + + - - - - 父结点 0-2 + + 父结点 0-2 + - +
            • - - + + + + + + - - - - 父结点 0-2-0 + + 父结点 0-2-0 + - +
            • - - - + + + + + - - - - 父结点 0-2-1 - - - -
                -
              • + + + - + + + + 父结点 0-2-1 + + + + +
                  +
                • +
                  + + + + + + + + + + + + - - - - 子结点 0-2-1-0 + + 子结点 0-2-1-0 + - +
                  • - - - - - - - - 子结点 0-2-1-0-0 + + 子结点 0-2-1-0-0 + - +
                  • - - + + + + + + - - - - 子结点 0-2-1-0-1 + + + + + + + + + 子结点 0-2-1-0-1 + - +
                  @@ -619,39 +886,46 @@ exports[`Tree renders basic Tree with TreeNode children 1`] = `
                • - - + + + + + + - - - - 子结点 0-2-1-1 + + 子结点 0-2-1-1 + - +
                @@ -659,38 +933,46 @@ exports[`Tree renders basic Tree with TreeNode children 1`] = `
              • - - + + + + + + - - - - 子结点 0-2-2 + + 子结点 0-2-2 + - +
              @@ -701,164 +983,199 @@ exports[`Tree renders basic Tree with TreeNode children 1`] = `
            `; -exports[`Tree renders basic Tree with TreeNodes children 1`] = ` +exports[`Tree renders basic Tree with defaultExpandAll correctly 1`] = `
            • - - - + + + + + - - - - parent 1 + + 根结点1 + - +
              • - - - + + + + + - - - - parent 1-0 + + 父结点 0-0 + - +
                • - - - + + + + + - - - - - - leaf - -
                • -
                • - - - + 父结点 0-0-0 - - - - + +
                    - leaf - +
                  • +
                    + + + + + + 子结点 0-0-0-0 + + +
                    +
                  • +
                  • +
                    + + + + + + 子结点 0-0-0-1 + + +
                    +
                  • +
                @@ -867,445 +1184,743 @@ exports[`Tree renders basic Tree with TreeNodes children 1`] = `
              • - - - + + + + + - - - - parent 1-1 + + 父结点 0-1 + - +
                • - - + + + - + 子结点 0-1-0 - - - +
                • +
                • +
                  + + + - sss + 子结点 0-1-1 - +
                • -
                -
                -
              • -
              -
              -
            • -
            -`; - -exports[`Tree renders basic Tree with defaultExpandAll canCheck correctly 1`] = ` -
              -
            • - - - - - - - - - - - - 根结点1 - - - -
                +
              • +
                + + + + + + 子结点 0-1-2 + + +
                +
              • +
              +
              +
            • - - - + + + + + - - - - 父结点 0-0 + + 父结点 0-2 + - +
              • - - + + + - + 父结点 0-2-0 - - - +
              • +
              • +
                + + + + + + + + + - 父结点 0-0-0 + + 父结点 0-2-1 + - +
                • - - - + + + + + - - - - 子结点 0-0-0-0 + + 子结点 0-2-1-0 + + + +
                    +
                  • +
                    + + + + + + 子结点 0-2-1-0-0 + + +
                    +
                  • +
                  • +
                    + + + + + + + + + + + + + 子结点 0-2-1-0-1 + + +
                    +
                  • +
                • - - - - - - - - 子结点 0-0-0-1 + + 子结点 0-2-1-1 + - +
              • +
              • +
                + + + + + + 子结点 0-2-2 + + +
                +
            • +
            +
            +
          • +
          +`; + +exports[`Tree renders basic Tree with defaultExpandAll correctly 2`] = ` +
            +
          • +
            + + + + + + + + + + + + 根结点1 + + +
            + +
            • - - - + + + + + - - - - 父结点 0-1 + + 父结点 0-0 + - +
              • - - - + + + + + - - - - - 子结点 0-1-0 - - -
              • -
              • - - - + 父结点 0-0-0 - + + +
                  +
                • +
                  + + + + + + 子结点 0-0-0-0 + + +
                  +
                • +
                • +
                  + + + + + + 子结点 0-0-0-1 + + +
                  +
                • +
                - +
              +
              +
            • +
            • +
              + + + + + + + + + + + + 父结点 0-1 + + +
              + +
                +
              • +
                - 子结点 0-1-1 + - + + + 子结点 0-1-0 + + +
              • - - + + + - + 子结点 0-1-1 - - - +
              • +
              • +
                - 子结点 0-1-2 + - + + + 子结点 0-1-2 + + +
              @@ -1313,230 +1928,235 @@ exports[`Tree renders basic Tree with defaultExpandAll canCheck correctly 1`] =
            • - - - + + + + + - - - - 父结点 0-2 + + 父结点 0-2 + - +
              • - - - - - - - - 父结点 0-2-0 + + 父结点 0-2-0 + - +
              • - - - + + + + + - - - - 父结点 0-2-1 + + 父结点 0-2-1 + - +
                • - - - + + + + + - - - - 子结点 0-2-1-0 + + 子结点 0-2-1-0 + - +
                  • - - - - - - - - 子结点 0-2-1-0-0 + + 子结点 0-2-1-0-0 + - +
                  • - - - - - - - - 子结点 0-2-1-0-1 + + + + + + + + + 子结点 0-2-1-0-1 + - +
                  @@ -1544,38 +2164,27 @@ exports[`Tree renders basic Tree with defaultExpandAll canCheck correctly 1`] =
                • - - - - - - - - 子结点 0-2-1-1 + + 子结点 0-2-1-1 + - +
                @@ -1583,38 +2192,27 @@ exports[`Tree renders basic Tree with defaultExpandAll canCheck correctly 1`] =
              • - - - - - - - - 子结点 0-2-2 + + 子结点 0-2-2 + - +
              @@ -1625,106 +2223,293 @@ exports[`Tree renders basic Tree with defaultExpandAll canCheck correctly 1`] =
            `; -exports[`Tree renders basic Tree with defaultExpandAll correctly 1`] = ` +exports[`Tree renders basic Tree with defaultExpandAll, checkable correctly 1`] = `
            • - - - 根结点1 + + + + + + + - + + + + + + + + + + + 根结点1 + + +
              • - - - 父结点 0-0 - - + + + + + + + + + + + + + + + + + + + 父结点 0-0 + + +
                • - - + + + + + + + + + - 父结点 0-0-0 + + + + + + - + + + 父结点 0-0-0 + + +
                  • - - - 子结点 0-0-0-0 + - + + + + + + + + + + + 子结点 0-0-0-0 + + +
                  • - - - 子结点 0-0-0-1 + - + + + + + + + + + + + 子结点 0-0-0-1 + + +
                  @@ -1735,74 +2520,201 @@ exports[`Tree renders basic Tree with defaultExpandAll correctly 1`] = `
                • - - - 父结点 0-1 + + + + + + + - + + + + + + + + + + + 父结点 0-1 + + +
                  • - - - 子结点 0-1-0 + - + + + + + + + + + + + 子结点 0-1-0 + + +
                  • - - - 子结点 0-1-1 + - + + + + + + + + + + + 子结点 0-1-1 + + +
                  • - - - 子结点 0-1-2 + - + + + + + + + + + + + 子结点 0-1-2 + + +
                  @@ -1810,116 +2722,330 @@ exports[`Tree renders basic Tree with defaultExpandAll correctly 1`] = `
                • - - - 父结点 0-2 + + + + + + + - + + + + + + + + + + + 父结点 0-2 + + +
                  • - - - 父结点 0-2-0 + - + + + + + + + + + + + 父结点 0-2-0 + + +
                  • - - - 父结点 0-2-1 - - - -
                      -
                    • - - - - 子结点 0-2-1-0 - + + + + + + + + + + + + + + + 父结点 0-2-1 + + + + +
                        +
                      • +
                        + + + + + + + + + + + + + + + + + + + + 子结点 0-2-1-0 + + +
                        • - - - 子结点 0-2-1-0-0 + - + + + 子结点 0-2-1-0-0 + + +
                        • - - - 子结点 0-2-1-0-1 + - + + + + + + + + + + + + + + + + + + 子结点 0-2-1-0-1 + + +
                        @@ -1927,19 +3053,46 @@ exports[`Tree renders basic Tree with defaultExpandAll correctly 1`] = `
                      • - - - 子结点 0-2-1-1 + - + + + + + + + + + + + 子结点 0-2-1-1 + + +
                      @@ -1947,19 +3100,46 @@ exports[`Tree renders basic Tree with defaultExpandAll correctly 1`] = `
                    • - - - 子结点 0-2-2 + - + + + + + + + + + + + 子结点 0-2-2 + + +
                    @@ -1970,184 +3150,500 @@ exports[`Tree renders basic Tree with defaultExpandAll correctly 1`] = `
                  `; -exports[`Tree renders basic Tree with defaultExpandAll correctly 2`] = ` +exports[`Tree renders basic Tree with defaultExpandAll, checkable, checkedKeys correctly 1`] = `
                  • - - - 根结点1 + + + + + + + - + + + + + + + + + + + 根结点1 + + +
                    • - - - 父结点 0-0 + + + + + + + - + + + + + + + + + + + 父结点 0-0 + + +
                      • - - + + + + + + + + + - 父结点 0-0-0 + + + + + + - + + + 父结点 0-0-0 + + +
                        • - - - 子结点 0-0-0-0 + - + + + + + + + + + + + 子结点 0-0-0-0 + + +
                        • - - - 子结点 0-0-0-1 + - -
                        • -
                        -
                        -
                      • -
                      -
                      -
                    • -
                    • - - + + + + + + + + + + + 子结点 0-0-0-1 + + + +
                    • +
                    +
                    +
                  • +
                  +
                  +
                • +
                • +
                  + + + + + + + + + - 父结点 0-1 + + + + + + - + + + 父结点 0-1 + + +
                  • - - - 子结点 0-1-0 + - + + + + + + + + + + + 子结点 0-1-0 + + +
                  • - - - 子结点 0-1-1 + - + + + + + + + + + + + 子结点 0-1-1 + + +
                  • - - - 子结点 0-1-2 + - + + + + + + + + + + + 子结点 0-1-2 + + +
                  @@ -2155,136 +3651,378 @@ exports[`Tree renders basic Tree with defaultExpandAll correctly 2`] = `
                • - - + + + + + + + + + - 父结点 0-2 + + + + + + - + + + 父结点 0-2 + + +
                  • - - - 父结点 0-2-0 + - + + + + + + + + + + + 父结点 0-2-0 + + +
                  • - - + + + + + + + + + - 父结点 0-2-1 + + + + + + - + + + 父结点 0-2-1 + + +
                    • - - - 子结点 0-2-1-0 + + + + + + + - + + + + + + + + + + + 子结点 0-2-1-0 + + +
                      • - - - 子结点 0-2-1-0-0 + - + + + 子结点 0-2-1-0-0 + + +
                      • - - - 子结点 0-2-1-0-1 + - -
                      • -
                      -
                      -
                    • -
                    • - - - - 子结点 0-2-1-1 - - + + + + + + + + + + + + + + + + + + 子结点 0-2-1-0-1 + + + +
                    • +
                    +
                    +
                  • +
                  • +
                    + + + + + + + + + + + + + + 子结点 0-2-1-1 + + +
                  @@ -2292,19 +4030,46 @@ exports[`Tree renders basic Tree with defaultExpandAll correctly 2`] = `
                • - - - 子结点 0-2-2 + - + + + + + + + + + + + 子结点 0-2-2 + + +
                @@ -2315,202 +4080,197 @@ exports[`Tree renders basic Tree with defaultExpandAll correctly 2`] = `
              `; -exports[`Tree renders basic Tree with defaultExpandAll, canCheck correctly 1`] = ` +exports[`Tree renders basic Tree with disabled 1`] = `
              • - - - + + + + + - - - - 根结点1 + + 根结点1 + - +
                • - - - + + + + + - - - - 父结点 0-0 + + 父结点 0-0 + - +
                  • - - - + + + + + - - - - 父结点 0-0-0 + + 父结点 0-0-0 + - +
                    • - - - - - - - - 子结点 0-0-0-0 + + 子结点 0-0-0-0 + - +
                    • - - - - - - - - 子结点 0-0-0-1 + + 子结点 0-0-0-1 + - +
                    @@ -2521,151 +4281,123 @@ exports[`Tree renders basic Tree with defaultExpandAll, canCheck correctly 1`] =
                  • - - - + + + + + - - - - 父结点 0-1 + + 父结点 0-1 + - +
                    • - - - - - - - - 子结点 0-1-0 + + 子结点 0-1-0 + - +
                    • - - - - - - - - 子结点 0-1-1 + + 子结点 0-1-1 + - +
                    • - - - - - - - - 子结点 0-1-2 + + 子结点 0-1-2 + - +
                    @@ -2673,230 +4405,235 @@ exports[`Tree renders basic Tree with defaultExpandAll, canCheck correctly 1`] =
                  • - - - + + + + + - - - - 父结点 0-2 + + 父结点 0-2 + - +
                    • - - - - - - - - 父结点 0-2-0 + + 父结点 0-2-0 + - +
                    • - - - + + + + + - - - - 父结点 0-2-1 + + 父结点 0-2-1 + - +
                      • - - - + + + + + - - - - 子结点 0-2-1-0 - - + + 子结点 0-2-1-0 + + +
                        • - - - - - - - - 子结点 0-2-1-0-0 + + 子结点 0-2-1-0-0 + - +
                        • - - - - - - - - 子结点 0-2-1-0-1 + + + + + + + + + 子结点 0-2-1-0-1 + - +
                        @@ -2904,38 +4641,27 @@ exports[`Tree renders basic Tree with defaultExpandAll, canCheck correctly 1`] =
                      • - - - - - - - - 子结点 0-2-1-1 + + 子结点 0-2-1-1 + - +
                      @@ -2943,38 +4669,27 @@ exports[`Tree renders basic Tree with defaultExpandAll, canCheck correctly 1`] =
                    • - - - - - - - - 子结点 0-2-2 + + 子结点 0-2-2 + - +
                    @@ -2985,204 +4700,197 @@ exports[`Tree renders basic Tree with defaultExpandAll, canCheck correctly 1`] =
                  `; -exports[`Tree renders basic Tree with defaultExpandAll, canCheck, checkedKeys correctly 1`] = ` +exports[`Tree renders basic Tree with expandedKeys, autoExpandParent correctly 1`] = `
                  • - - - + + + + + - - - - 根结点1 + + 根结点1 + - +
                    • - - - + + + + + - - - - 父结点 0-0 + + 父结点 0-0 + - +
                      • - - - + + + + + - - - - 父结点 0-0-0 + + 父结点 0-0-0 + - +
                        • - - - - - - - - 子结点 0-0-0-0 + + 子结点 0-0-0-0 + - +
                        • - - - - - - - - 子结点 0-0-0-1 + + 子结点 0-0-0-1 + - +
                        @@ -3192,1103 +4900,2758 @@ exports[`Tree renders basic Tree with defaultExpandAll, canCheck, checkedKeys c
                      • +
                        + + + + + + + + + + + + 父结点 0-1 + + +
                        + +
                      • +
                      • +
                        + + + + + + + + + + + + 父结点 0-2 + + +
                        + +
                      • +
                      +
                      +
                    • +
                    +`; + +exports[`Tree renders basic Tree with expandedKeys, checkable correctly 1`] = ` +
                      +
                    • +
                      + + + + + + + + + + + + + + - + + + + 根结点1 + + +
                      + +
                        +
                      • +
                        + + + + + + + + + + + + - - - - 父结点 0-1 + + 父结点 0-0 + - +
                        • - - + + + + + + + + + + + + - - - - 子结点 0-1-0 - - + + 父结点 0-0-0 + + + + +
                            +
                          • +
                            + + + + + + + + + + + + + + 子结点 0-0-0-0 + + +
                            +
                          • +
                          • +
                            + + + + + + + + + + + + + + 子结点 0-0-0-1 + + +
                            +
                          • +
                          +
                          +
                        • +
                        +
                        +
                      • +
                      • +
                        + + + + + + + + + + + + + + + + + + + + 父结点 0-1 + + +
                        + +
                      • +
                      • +
                        + + + + + + + + + + + + + + + + + + + + 父结点 0-2 + + +
                        + +
                      • +
                      +
                      +
                    • +
                    +`; + +exports[`Tree renders basic Tree with expandedKeys, defaultExpandAll, checkable correctly 1`] = ` +
                      +
                    • +
                      + + + + + + + + + + + + + + + + + + + + 根结点1 + + +
                      + +
                        +
                      • +
                        + + + + + + + + + + + + + + + + + + + + 父结点 0-0 + + +
                        + +
                          +
                        • +
                          + + + + + + + + + + + + + + + + + + + + 父结点 0-0-0 + + +
                          + +
                            +
                          • +
                            + + + + + + + + + + + + + + 子结点 0-0-0-0 + + +
                            +
                          • +
                          • +
                            + + + + + + + + + + + + + + 子结点 0-0-0-1 + + +
                            +
                          • +
                          +
                          +
                        • +
                        +
                        +
                      • +
                      • +
                        + + + + + + + + + + + + + + + + + + + + 父结点 0-1 + + +
                        + +
                          +
                        • +
                          + + + + + + + + + + + + + + 子结点 0-1-0 + + +
                          +
                        • +
                        • +
                          + + + + + + + + + + + + + + 子结点 0-1-1 + + +
                          +
                        • +
                        • +
                          + + + + + + + + + + + + + + 子结点 0-1-2 + + +
                          +
                        • +
                        +
                        +
                      • +
                      • +
                        + + + + + + + + + + + + + + + + + + + + 父结点 0-2 + + +
                        + +
                          +
                        • +
                          + + + + + + + + + + + + + + 父结点 0-2-0 + + +
                          +
                        • +
                        • +
                          + + + + + + + + + + + + + + + + + + + + 父结点 0-2-1 + + +
                          + +
                            +
                          • +
                            + + + + + + + + + + + + + + + + + + + + 子结点 0-2-1-0 + + +
                            + +
                              +
                            • +
                              + + + + + + 子结点 0-2-1-0-0 + + +
                              +
                            • +
                            • +
                              + + + + + + + + + + + + + + + + + + + + + 子结点 0-2-1-0-1 + + +
                              +
                            • +
                            +
                            +
                          • +
                          • +
                            + + + + + + + + + + + + + + 子结点 0-2-1-1 + + +
                            +
                          • +
                          +
                        • - - - - - - - - - 子结点 0-1-1 - - -
                        • -
                        • - - + + + - - - - 子结点 0-1-2 + + 子结点 0-2-2 + - +
                      • -
                      • + +
                      • +
                      +`; + +exports[`Tree renders basic Tree with expandedKeys, defaultExpandAll, checkable, checkedKeys correctly 1`] = ` +
                        +
                      • +
                        + + + + + + + + + + + + + + - + + + + 根结点1 + + +
                        + +
                          +
                        • +
                          + + + + + + + + + + + + - - - - 父结点 0-2 + + 父结点 0-0 + - +
                          • - - - + + + + + - - - - - - 父结点 0-2-0 - -
                          • -
                          • - - + + + - - - - 父结点 0-2-1 + + 父结点 0-0-0 + - +
                            • - - - - - - - - 子结点 0-2-1-0 - - - -
                                -
                              • - - - - - - - - - - 子结点 0-2-1-0-0 - + class="zw-checkbox__inner" + /> -
                              • -
                              • - - - - - - - - - - - - 子结点 0-2-1-0-1 - - -
                              • -
                              -
                              +
                              +
                              + + + 子结点 0-0-0-0 + + +
                            • - - + + + + + + - - - - 子结点 0-2-1-1 + + 子结点 0-0-0-1 + - +
                          • -
                          • + +
                          • +
                          • +
                            + + - - - - - - - + - - + + + + + + - 子结点 0-2-2 - + class="zw-checkbox__inner" + /> -
                          • -
                          -
                          -
                        • -
                        -
                        -
                      • -
                      -`; - -exports[`Tree renders basic Tree with expandedKeys correctly 1`] = ` -
                        -
                      • - - - - 根结点1 - - - -
                          -
                        • - - + + + - 父结点 0-0 + + 父结点 0-1 + - +
                          • - - - 父结点 0-0-0 + - - -
                              -
                            • - - 子结点 0-0-0-0 - + class="zw-checkbox__inner" + /> -
                            • -
                            • + + + + + 子结点 0-1-0 + + + +
                            • +
                            • +
                              + + + + + + + + + + + + + 子结点 0-1-1 + + +
                              +
                            • +
                            • +
                              + + + + + - 子结点 0-0-0-1 - + class="zw-checkbox__inner" + /> -
                            • -
                            -
                            + +
                            +
                            + + + 子结点 0-1-2 + + +
                        • -
                        • - - - - 父结点 0-1 - - - -
                        • - - - 父结点 0-2 + + + + + + + - - -
                        • -
                        -
                        -
                      • -
                      -`; - -exports[`Tree renders basic Tree with expandedKeys, canCheck correctly 1`] = ` -
                        -
                      • - - - - - - - - - - - - 根结点1 - - - -
                          -
                        • - - + + + - - - - 父结点 0-0 + + 父结点 0-2 + - +
                          • +
                            + + + + + + + + + + + + + + 父结点 0-2-0 + + +
                            +
                          • +
                          • - - + + + + + + + + + + + + - - - - 父结点 0-0-0 + + 父结点 0-2-1 + - +
                            • - - + + + + + + + + + + + + - - - - 子结点 0-0-0-0 + + 子结点 0-2-1-0 + + + +
                                +
                              • +
                                + + + + + + 子结点 0-2-1-0-0 + + +
                                +
                              • +
                              • +
                                + + + + + + + + + + + + + + + + + + + + + 子结点 0-2-1-0-1 + + +
                                +
                              • +
                            • - - + + + + + + - - - - 子结点 0-0-0-1 + + 子结点 0-2-1-1 + - +
                          • +
                          • +
                            + + + + + + + + + + + + + + 子结点 0-2-2 + + +
                            +
                        • -
                        • + +
                        • +
                        +`; + +exports[`Tree renders basic Tree with multiple, selectable 1`] = ` +
                          +
                        • +
                          + + - - - - - - - - - - - - 父结点 0-1 - - - -
                        • -
                        • + + + + + - - - - - - - - - - - - 父结点 0-2 - - - -
                        • -
                        -
                        + 根结点1 +
                        +
                        + +
                      `; -exports[`Tree renders basic Tree with expandedKeys, defaultExpandAll, canCheck correctly 1`] = ` +exports[`Tree renders basic Tree with not completely TreeNodes children 1`] = ` +
                        +`; + +exports[`Tree renders basic Tree with showLine, showIcon, icon 1`] = `
                        • - - + + + + + + + + + + + + + + + + - + 根结点1 - - - - - - 根结点1 - +
                          • - - - + + + + + - - - - 父结点 0-0 + + + + + + + + + 父结点 0-0 + - +
                            • - - - + + + + + - - - - 父结点 0-0-0 + + + + + + + + + 父结点 0-0-0 + - +
                              • - - - + + + + + - - - - 子结点 0-0-0-0 + + + + + + + + + 子结点 0-0-0-0 + - +
                              • - - - + + + + + - - - - 子结点 0-0-0-1 + + + + + + + + + 子结点 0-0-0-1 + - +
                              @@ -4299,151 +7662,254 @@ exports[`Tree renders basic Tree with expandedKeys, defaultExpandAll, canCheck c
                            • - - - + + + + + - - - - 父结点 0-1 + + + + + + + + + 父结点 0-1 + - +
                              • - - - + + + + + - - - - 子结点 0-1-0 + + + + + + + + + 子结点 0-1-0 + - +
                              • - - - + + + + + - - - - 子结点 0-1-1 + + + + + + + + + 子结点 0-1-1 + - +
                              • - - - + + + + + - - - - 子结点 0-1-2 + + + + + + + + + 子结点 0-1-2 + - +
                              @@ -4451,230 +7917,386 @@ exports[`Tree renders basic Tree with expandedKeys, defaultExpandAll, canCheck c
                            • - - - + + + + + - - - - 父结点 0-2 + + + + + + + + + 父结点 0-2 + - +
                              • - - - + + + + + - - - - 父结点 0-2-0 + + + + + + + + + 父结点 0-2-0 + - +
                              • - - - + + + + + - - - - 父结点 0-2-1 + + + + + + + + + 父结点 0-2-1 + - +
                                • - - + + + + + + + + + - + + + + + + + + 子结点 0-2-1-0 - - - - - - 子结点 0-2-1-0 - +
                                  • - - - + + + + + - - - - 子结点 0-2-1-0-0 + + + + + + + + + 子结点 0-2-1-0-0 + - +
                                  • - - - + + + + + - - - - 子结点 0-2-1-0-1 + + + + + + + + + 子结点 0-2-1-0-1 + - +
                                  @@ -4682,38 +8304,64 @@ exports[`Tree renders basic Tree with expandedKeys, defaultExpandAll, canCheck c
                                • - - - + + + + + - - - - 子结点 0-2-1-1 + + + + + + + + + 子结点 0-2-1-1 + - +
                                @@ -4721,38 +8369,64 @@ exports[`Tree renders basic Tree with expandedKeys, defaultExpandAll, canCheck c
                              • - - - + + + + + - - - - 子结点 0-2-2 + + + + + + + + + 子结点 0-2-2 + - +
                              @@ -4763,204 +8437,231 @@ exports[`Tree renders basic Tree with expandedKeys, defaultExpandAll, canCheck c
                            `; -exports[`Tree renders basic Tree with expandedKeys, defaultExpandAll, canCheck, checkedKeys correctly 1`] = ` +exports[`Tree renders basic Tree with showLine, switcherIcon 1`] = `
                            • - - - + + + + + - - - - 根结点1 + + 根结点1 + - +
                              • - - - + + + + + - - - - 父结点 0-0 + + 父结点 0-0 + - +
                                • - - - + + + + + - - - - 父结点 0-0-0 + + 父结点 0-0-0 + - +
                                  • - - - + + + + + - - - - 子结点 0-0-0-0 + + 子结点 0-0-0-0 + - +
                                  • - - - + + + + + - - - - 子结点 0-0-0-1 + + 子结点 0-0-0-1 + - +
                                  @@ -4971,152 +8672,174 @@ exports[`Tree renders basic Tree with expandedKeys, defaultExpandAll, canCheck,
                                • - - - + + + + + - - - - 父结点 0-1 + + 父结点 0-1 + - +
                                  • - - - + + + + + - - - - 子结点 0-1-0 + + 子结点 0-1-0 + - +
                                  • - - - + + + + + - - - - 子结点 0-1-1 + + 子结点 0-1-1 + - +
                                  • - - - + + + + + - - - - 子结点 0-1-2 + + 子结点 0-1-2 + - +
                                  @@ -5124,232 +8847,286 @@ exports[`Tree renders basic Tree with expandedKeys, defaultExpandAll, canCheck,
                                • - - - + + + + + - - - - 父结点 0-2 + + 父结点 0-2 + - +
                                  • - - - + + + + + - - - - 父结点 0-2-0 + + 父结点 0-2-0 + - +
                                  • - - - + + + + + - - - - 父结点 0-2-1 + + 父结点 0-2-1 + - +
                                    • - - - + + + + + - - - - 子结点 0-2-1-0 + + 子结点 0-2-1-0 + - +
                                      • - - - + + + + + - - - - 子结点 0-2-1-0-0 + + 子结点 0-2-1-0-0 + - +
                                      • - - - + + + + + - - - - 子结点 0-2-1-0-1 + + + + + + + + + 子结点 0-2-1-0-1 + - +
                                      @@ -5357,39 +9134,44 @@ exports[`Tree renders basic Tree with expandedKeys, defaultExpandAll, canCheck,
                                    • - - - + + + + + - - - - 子结点 0-2-1-1 + + 子结点 0-2-1-1 + - +
                                    @@ -5397,292 +9179,44 @@ exports[`Tree renders basic Tree with expandedKeys, defaultExpandAll, canCheck,
                                  • - - - - - - - - - - - - 子结点 0-2-2 - - -
                                  • -
                                  -
                                  -
                                • -
                                -
                                -
                              • -
                              -`; - -exports[`Tree renders basic Tree with not completely TreeNodes children 1`] = ` -
                                -
                              • - - - - - - - - - - - - parent 1 - - - -
                                  -
                                • - - - - - - - - - - - - parent 1-0 - - - -
                                    -
                                  • - - - - - - - - - - - - leaf - - -
                                  • -
                                  • - - - - - - - - - - - - leaf - - -
                                  • -
                                  -
                                  -
                                • -
                                • - - - - - - - - - - - - parent 1-1 - - - -
                                    -
                                  • - - - + + + + + - - - - sss + 子结点 0-2-2 - +
                                  diff --git a/components/tree/__tests__/index.test.jsx b/components/tree/__tests__/index.test.jsx index a4e922ff..0d4e083b 100644 --- a/components/tree/__tests__/index.test.jsx +++ b/components/tree/__tests__/index.test.jsx @@ -2,6 +2,7 @@ import React from 'react'; import { render, mount } from 'enzyme'; import toJson from 'enzyme-to-json'; import Tree from '../index'; +import Icon from '../../icon/index'; const treeData = [ { @@ -31,8 +32,8 @@ const treeData = [ children: [ { keys: '0-1-0', title: '子结点 0-1-0', checkDisabled: true }, - { keys: '0-1-1', title: '子结点 0-1-1' }, - { keys: '0-1-2', title: '子结点 0-1-2' }, + { keys: '0-1-1', title: '子结点 0-1-1', selectDisabled: true }, + { keys: '0-1-2', title: '子结点 0-1-2', disabled: true }, ], }, { @@ -51,8 +52,8 @@ const treeData = [ title: '子结点 0-2-1-0', children: [ - { keys: '0-2-1-0-0', title: '子结点 0-2-1-0-0' }, - { keys: '0-2-1-0-1', title: '子结点 0-2-1-0-1' }, + { keys: '0-2-1-0-0', title: '子结点 0-2-1-0-0', checkable: false, isLeaf: true }, + { keys: '0-2-1-0-1', title: '子结点 0-2-1-0-1', icon: }, ], }, { keys: '0-2-1-1', title: '子结点 0-2-1-1' }, @@ -68,6 +69,7 @@ const checkedKeys = ['0-0-0-0', '0-2-1-1', '0-1-0']; const checkedKeys2 = ['0-0-0', '0-1']; const expandedKeys = ['0-0-0']; const expandedKeys2 = ['0-1']; +const selectedKeys = ['0-0-0']; const { TreeNode } = Tree; describe('Tree', () => { @@ -85,9 +87,9 @@ describe('Tree', () => { expect(toJson(wrapper)).toMatchSnapshot(); }); - it('renders basic Tree with defaultExpandAll canCheck correctly', () => { + it('renders basic Tree with defaultExpandAll checkable correctly', () => { const wrapper = render( - , + , ); expect(toJson(wrapper)).toMatchSnapshot(); }); @@ -99,58 +101,79 @@ describe('Tree', () => { expect(toJson(wrapper)).toMatchSnapshot(); }); - it('renders basic Tree with defaultExpandAll, canCheck correctly', () => { + it('renders basic Tree with defaultExpandAll, checkable correctly', () => { const wrapper = render( - , + , ); expect(toJson(wrapper)).toMatchSnapshot(); }); - it('renders basic Tree with defaultExpandAll, canCheck, checkedKeys correctly', () => { + it('renders basic Tree with defaultExpandAll, checkable, checkedKeys correctly', () => { const wrapper = render( - , + , ); expect(toJson(wrapper)).toMatchSnapshot(); }); - it('renders basic Tree with expandedKeys correctly', () => { + it('renders basic Tree with expandedKeys, autoExpandParent correctly', () => { const wrapper = render( - , + , ); expect(toJson(wrapper)).toMatchSnapshot(); }); - it('renders basic Tree with expandedKeys, canCheck correctly', () => { + it('renders basic Tree with expandedKeys, checkable correctly', () => { const wrapper = render( - , + , ); expect(toJson(wrapper)).toMatchSnapshot(); }); - it('renders basic Tree with expandedKeys, defaultExpandAll, canCheck correctly', () => { + it('renders basic Tree with expandedKeys, defaultExpandAll, checkable correctly', () => { const wrapper = render( - , + , ); expect(toJson(wrapper)).toMatchSnapshot(); }); - it('renders basic Tree with expandedKeys, defaultExpandAll, canCheck, checkedKeys correctly', () => { + it('renders basic Tree with expandedKeys, defaultExpandAll, checkable, checkedKeys correctly', () => { const wrapper = render( - , + , ); expect(toJson(wrapper)).toMatchSnapshot(); }); - it('renders basic Tree with TreeNode children', () => { + it('renders basic Tree with multiple, selectable', () => { const wrapper = render( - , + , + ); + expect(toJson(wrapper)).toMatchSnapshot(); + }); + + it('renders basic Tree with disabled', () => { + const wrapper = render( + , + ); + expect(toJson(wrapper)).toMatchSnapshot(); + }); + + it('renders basic Tree with showLine, showIcon, icon', () => { + const wrapper = render( + } defaultExpandAll />, + ); + expect(toJson(wrapper)).toMatchSnapshot(); + }); + + it('renders basic Tree with showLine, switcherIcon', () => { + const wrapper = render( + } defaultExpandAll />, ); expect(toJson(wrapper)).toMatchSnapshot(); }); it('renders basic Tree with TreeNodes children', () => { const wrapper = render( - + @@ -167,7 +190,7 @@ describe('Tree', () => { it('renders basic Tree with not completely TreeNodes children', () => { const wrapper = render( - +

                                  invalid element here invalid element here

                                  @@ -197,34 +220,38 @@ describe('Tree', () => { it('behave correctly when change treeNode checked status', () => { const onCheck = jest.fn(); const wrapper = mount( - , + , ); - expect(wrapper.state('checkedKeys')).toEqual(expect.arrayContaining(['0-2-1-1', '0-0-0-0', '0-1-0'])); - expect(wrapper.state('halfCheckedKeys')).toEqual(expect.arrayContaining(['0', '0-2-1', '0-2'])); - - wrapper.find('li[data-keys="0-0-0-1"] .zw-checkbox__input').at(0).simulate('change'); + wrapper.find('li[data-keys="0-0-0-1"] .zw-checkbox__input').at(0).simulate('click'); expect(onCheck).toBeCalled(); - expect(wrapper.state('checkedKeys')).toEqual(expect.arrayContaining(['0-2-1-1', '0-0-0-0', '0-1-0', '0-0-0-1', '0-0-0', '0-0'])); - expect(wrapper.state('halfCheckedKeys')).toEqual(expect.arrayContaining(['0', '0-2-1', '0-2'])); - - wrapper.find('li[data-keys="0-1"] .zw-checkbox__input').at(0).simulate('change'); - expect(onCheck).toBeCalled(); - expect(wrapper.state('checkedKeys')).toEqual(expect.arrayContaining(['0-0-0-0', '0-2-1-1', '0-1-0', '0-1', '0-1-1', '0-1-2'])); + expect(wrapper.state('checkedKeys')).toEqual(expect.arrayContaining(['0-0-0-0', '0-2-1-1', '0-1-0', '0-0-0-1', '0-0-0', '0-0'])); expect(wrapper.state('halfCheckedKeys')).toEqual(expect.arrayContaining(['0', '0-2-1', '0-2'])); }); it('behave correctly when expand treeNode', () => { const onExpand = jest.fn(); const wrapper = mount( - , + , ); expect(wrapper.state('expandedKeys')).toEqual(expect.arrayContaining(['0', '0-0-0', '0-0'])); - wrapper.find('li[data-keys="0-0-0"] .ui-tree-switcher').at(0).simulate('click'); + wrapper.find('li[data-keys="0-0-0"] .zw-tree-switcher').at(0).simulate('click'); expect(onExpand).toBeCalled(); - wrapper.find('li[data-keys="0-1"] .ui-tree-switcher').at(0).simulate('click'); + wrapper.find('li[data-keys="0-1"] .zw-tree-switcher').at(0).simulate('click'); expect(onExpand).toBeCalled(); }); + + it('behave correctly when select treeNode', () => { + const onSelect = jest.fn(); + const wrapper = mount( + , + ); + expect(wrapper.state('selectedKeys')).toEqual(expect.arrayContaining(['0-0-0'])); + + wrapper.find('li[data-keys="0-0-0"] .zw-tree-node-content-wrapper').at(0).simulate('click'); + expect(onSelect).toBeCalled(); + expect(wrapper.state('selectedKeys')).toEqual(expect.arrayContaining([])); + }); }); diff --git a/components/tree/style/component.scss b/components/tree/style/component.scss index 21211bf7..ef5b7a7f 100644 --- a/components/tree/style/component.scss +++ b/components/tree/style/component.scss @@ -1,16 +1,55 @@ -$treePrefixCls: ui-tree; +$prefixCls: zw; +$treePrefixCls: zw-tree; +$tree-node-switcher-width: 20px; +$tree-node-height: 20px; +$tree-node-line-height: 20px; +$tree-node-checkbox-width: 20px; .#{$treePrefixCls} { margin: 0; - padding: 5px; + padding: 0; li { - padding: 3px 0; + position: relative; + padding: 5px 0; margin: 0; list-style: none; white-space: nowrap; outline: 0; + & > div { + display: inline-flex; + + &:focus { + box-shadow: 0 0 2px 2px rgba(18, 194, 135, 0.1); + border-radius: 2px; + } + + &.#{$treePrefixCls}-treenode-disabled { + span.#{$treePrefixCls}-node-content-wrapper { + color: #bcbcbc; + cursor: not-allowed; + + &:hover { + background-color: transparent; + color: #bcbcbc; + } + + .#{$prefixCls}-icon { + color: #bcbcbc; + } + } + } + } + + &:first-child { + padding-top: 10px; + } + + &:last-child { + padding-bottom: 0; + } + .collapse { overflow: hidden; display: block; @@ -25,81 +64,145 @@ $treePrefixCls: ui-tree; padding: 0 0 0 18px; } - .#{$treePrefixCls}-node-content-wrapper { - display: inline-block; - cursor: pointer; - text-decoration: none; - vertical-align: top; - } - span { &.#{$treePrefixCls}-switcher { - width: 24px; - height: 24px; - line-height: 24px; + width: $tree-node-switcher-width; + height: $tree-node-height; + line-height: $tree-node-line-height; display: inline-block; - vertical-align: top; cursor: pointer; + text-align: center; + vertical-align: middle; &.#{$treePrefixCls}-switcher-open, &.#{$treePrefixCls}-switcher-close { - &:after { - width: 0; - height: 0; - content: ''; - display: inline-block; - border: 4px solid #000; - border-color: rgba(0, 0, 0, 0.65) transparent transparent; - transition: transform .3s; + .#{$treePrefixCls}-switcher-icon { + i { + font-size: 12px; + transition: transform .3s; + } } } - &.#{$treePrefixCls}-switcher-open:after { - transform: translate(8px, 0) rotate(0deg); - } - - &.#{$treePrefixCls}-switcher-close:after { - transform: translate(10px, -2px) rotate(-90deg); + &.#{$treePrefixCls}-switcher-open .#{$treePrefixCls}-switcher-icon i { + transform: rotate(90deg); } &.#{$treePrefixCls}-switcher-noop { cursor: default; } + + .#{$treePrefixCls}-switcher-line-icon i { + vertical-align: 1px; + } + + .#{$treePrefixCls}-switcher-icon i { + vertical-align: 2px; + } } &.#{$treePrefixCls}-checkbox { - width: 20px; - height: 24px; - line-height: 24px; + width: $tree-node-checkbox-width; + line-height: $tree-node-line-height; display: inline-block; - vertical-align: top; cursor: pointer; text-align: center; + vertical-align: middle; + + & > span { + vertical-align: 1px; + } } &.#{$treePrefixCls}-node-content-wrapper { - line-height: 24px; - height: 24px; + padding: 0 4px; display: inline-block; - color: rgba(0, 0, 0, 0.65); + line-height: $tree-node-line-height; font-size: 12px; + color: rgba(0, 0, 0, 0.65); + cursor: pointer; + text-decoration: none; + transition: all .3s; + border-radius: 1px; + vertical-align: middle; + + &.#{$treePrefixCls}-node-selected { + background-color: var(--theme-primary); + color: #fff; + + .#{$treePrefixCls}-node-content-icon { + i { + color: #fff; + } + } + } + + &:not(.#{$treePrefixCls}-node-selected):hover { + background-color: rgba(18, 194, 135, 0.1); + color: #12c287; + border-radius: 1px; + } + + .#{$treePrefixCls}-node-content-icon { + margin-right: 2px; + + i { + vertical-align: baseline; + } + } } - } - &-child-tree { - display: none; + &:not(.#{$treePrefixCls}-node-content-icon) { + > i.#{$prefixCls}-icon { + color: rgba(0, 0, 0, .7); + } + } - &-open { - display: block; + i.#{$prefixCls}-icon { + svg { + vertical-align: middle; + } } } - &-treenode-disabled { + .#{$treePrefixCls}-node-disabled { > span:not(.#{$treePrefixCls}-switcher), > a, - > a span { - color: #767676; + > span { + color: #bcbcbc; cursor: not-allowed; + background: none; + } + } + } + + &.#{$treePrefixCls}-show-line { + li { + .#{$treePrefixCls}-switcher-open { + .#{$treePrefixCls}-switcher-line-icon { + width: $tree-node-switcher-width; + height: $tree-node-height; + } + + .#{$treePrefixCls}-switcher-icon { + width: $tree-node-switcher-width; + height: $tree-node-height; + } + } + + &:not(:last-child) { + &:before { + position: absolute; + top: 23px; + left: 9px; + bottom: -8px; + border-right: 1px solid #ccc; + content: ""; + } + + &:first-child:before { + top: 29px; + } } } } diff --git a/components/tree/style/tree.scss b/components/tree/style/tree.scss index 8c404bbf..846a9b75 100644 --- a/components/tree/style/tree.scss +++ b/components/tree/style/tree.scss @@ -38,7 +38,6 @@ $treePrefixCls: ui-tree; height: 24px; line-height: 24px; display: inline-block; - vertical-align: top; cursor: pointer; &.#{$treePrefixCls}-switcher-open, @@ -55,11 +54,11 @@ $treePrefixCls: ui-tree; } &.#{$treePrefixCls}-switcher-open:after { - transform: translate(8px, 0) rotate(0deg); + transform: translate(4px, 2px) rotate(0deg); } &.#{$treePrefixCls}-switcher-close:after { - transform: translate(10px, -2px) rotate(-90deg); + transform: translate(6px, 0) rotate(-90deg); } &.#{$treePrefixCls}-switcher-noop { diff --git a/components/tree/tree.md b/components/tree/tree.md index 43ea5609..57aa2536 100644 --- a/components/tree/tree.md +++ b/components/tree/tree.md @@ -1,243 +1,509 @@ -## Tree +# Tree 树形组件 -### 基本用法1 -可默认展开全部,设置treeData props方式展示节点 +## 基本用法 +展示可勾选,可选中节点或多选节点,禁用单个节点或其checkbox,默认展开等功能。 -:::demo +```jsx +import { Tree } from 'zarm-web'; -```js - - constructor(props) { - super(props); - this.state = { - treeData: [ +class Demo1 extends React.Component { + state = { + treeData: [ + { + keys: '0', + title: '根结点1', + children: + [ + { + keys: '0-0', + title: '父结点 0-0', + disabled: true, + children: + [ { - keys: '0', - title: '根结点1', + keys: '0-0-0', + title: '父结点 0-0-0', + checkDisabled: true, children: [ - { - keys: '0-0', - title: '父结点 0-0', - children: - [ - { - keys: '0-0-0', - title: '父结点 0-0-0', - children: - [ - { keys: '0-0-0-0', title: '子结点 0-0-0-0' }, - { keys: '0-0-0-1', title: '子结点 0-0-0-1' }, - ], - }, - ], - }, - { - keys: '0-1', - title: '父结点 0-1', - children: - [ - { keys: '0-1-0', title: '子结点 0-1-0'}, - { keys: '0-1-1', title: '子结点 0-1-1' }, - { keys: '0-1-2', title: '子结点 0-1-2' }, - ], - }, - { - keys: '0-2', - title: '父结点 0-2', - children: - [ - { keys: '0-2-0', title: '父结点 0-2-0' }, - { - keys: '0-2-1', - title: '父结点 0-2-1', - children: - [ - { - keys: '0-2-1-0', - title: '子结点 0-2-1-0', - children: - [ - { keys: '0-2-1-0-0', title: '子结点 0-2-1-0-0' }, - { keys: '0-2-1-0-1', title: '子结点 0-2-1-0-1' }, - ], - }, - { keys: '0-2-1-1', title: '子结点 0-2-1-1' }, - ], - }, - { keys: '0-2-2', title: '子结点 0-2-2' }, - ], - }, + { keys: '0-0-0-0', title: '子结点 0-0-0-0' }, + { keys: '0-0-0-1', title: '子结点 0-0-0-1' }, ], }, - ] - }; + ], + }, + { + keys: '0-1', + title: '父结点 0-1', + children: + [ + { keys: '0-1-0', title: '子结点 0-1-0' }, + { keys: '0-1-1', title: '子结点 0-1-1' }, + { keys: '0-1-2', title: '子结点 0-1-2' }, + ], + }, + ], + }, + ], + }; + + + onSelect = (selectedKeys, selectedInfo) => { + console.log('onSelect', selectedKeys, selectedInfo); + }; + + onCheck = (checkedMap, checkedInfo) => { + console.log('onCheck', checkedMap, checkedInfo); + }; + + render() { + const { treeData, checkedKeys } = this.state; + return ( +
                                  + +
                                  + ); } +} +ReactDOM.render(, mountNode); +``` + +## 受控示例 +通过selectedKeys,checkedKeys, expandedKeys属性受控操作示例 + +```jsx +import { Tree } from 'zarm-web'; + +class Demo2 extends React.Component { + state = { + checkedKeys: ['0-1-0', '0-1-1'], + selectedKeys: ['0-1-0'], + expandedKeys: ['0-1'], + autoExpandParent: true, + treeData: [ + { + keys: '0', + title: '根结点1', + children: + [ + { + keys: '0-0', + title: '父结点 0-0', + disabled: true, + children: + [ + { + keys: '0-0-0', + title: '父结点 0-0-0', + checkDisabled: true, + children: + [ + { keys: '0-0-0-0', title: '子结点 0-0-0-0' }, + { keys: '0-0-0-1', title: '子结点 0-0-0-1' }, + ], + }, + ], + }, + { + keys: '0-1', + title: '父结点 0-1', + children: + [ + { keys: '0-1-0', title: '子结点 0-1-0' }, + { keys: '0-1-1', title: '子结点 0-1-1' }, + { keys: '0-1-2', title: '子结点 0-1-2' }, + ], + }, + ], + }, + ], + }; + + onCheck = (checkedMap, checkedInfo) => { + this.setState({ + checkedKeys: checkedMap.checkedKeys, + }); + console.log('onCheck', checkedMap, checkedInfo); + }; + + onSelect = (selectedKeys, selectedInfo) => { + this.setState({ + selectedKeys, + }); + console.log('onSelect', selectedKeys, selectedInfo); + }; + + onExpand = (expandedKeys, expandedObj) => { + this.setState({ + autoExpandParent: false, + expandedKeys, + }); + console.log('onExpand', expandedKeys, expandedObj); + }; + render() { - const { treeData } = this.state; + const { treeData, checkedKeys, selectedKeys, expandedKeys, autoExpandParent } = this.state; return ( -
                                  - +
                                  +
                                  - ) + ); } +} + +ReactDOM.render(, mountNode); + ``` -::: -### 基本用法2 -可选中,可设置默认展开节点, 可禁用子节点的选中状态 +## 连接线形式的树 +子节点之间带连接线的树,常用于文件目录结构展示。并且showLine为true的模式下,可以用switcherIcon修改默认图标(即父节点的展开图标)。 -:::demo +```jsx -```js +import { Tree, Switch, Icon } from 'zarm-web'; - constructor(props) { - super(props); - this.state = { - expandedKeys: ['0-0-0'], - checkedKeys: ['0-0-0'], - treeData: [ +const MyIcon = Icon.createFromIconfont('//at.alicdn.com/t/font_1733827_4scbzsuv5v2.js'); + +class Demo3 extends React.Component { + state = { + showLine: false, + showSwitcherIcon: false, + treeData: [ + { + keys: '0', + title: '根结点1', + children: + [ + { + keys: '0-0', + title: '父结点 0-0', + disabled: true, + children: + [ { - keys: '0', - title: '根结点1', + keys: '0-0-0', + title: '父结点 0-0-0', + checkDisabled: true, children: [ - { - keys: '0-0', - title: '父结点 0-0', - children: - [ - { - keys: '0-0-0', - title: '父结点 0-0-0', - children: - [ - { keys: '0-0-0-0', title: '子结点 0-0-0-0', checkDisabled: true }, - { keys: '0-0-0-1', title: '子结点 0-0-0-1' }, - ], - }, - ], - }, - { - keys: '0-1', - title: '父结点 0-1', - children: - [ - { keys: '0-1-0', title: '子结点 0-1-0', checkDisabled: true }, - { keys: '0-1-1', title: '子结点 0-1-1' }, - { keys: '0-1-2', title: '子结点 0-1-2' }, - ], - }, - { - keys: '0-2', - title: '父结点 0-2', - children: - [ - { keys: '0-2-0', title: '父结点 0-2-0' }, - { - keys: '0-2-1', - title: '父结点 0-2-1', - children: - [ - { - keys: '0-2-1-0', - title: '子结点 0-2-1-0', - children: - [ - { keys: '0-2-1-0-0', title: '子结点 0-2-1-0-0' }, - { keys: '0-2-1-0-1', title: '子结点 0-2-1-0-1' }, - ], - }, - { keys: '0-2-1-1', title: '子结点 0-2-1-1' }, - ], - }, - { keys: '0-2-2', title: '子结点 0-2-2' }, - ], - }, + { keys: '0-0-0-0', title: '子结点 0-0-0-0' }, + { keys: '0-0-0-1', title: '子结点 0-0-0-1' }, ], }, - ] - }; + ], + }, + { + keys: '0-1', + title: '父结点 0-1', + children: + [ + { keys: '0-1-0', title: '子结点 0-1-0' }, + { keys: '0-1-1', title: '子结点 0-1-1' }, + { keys: '0-1-2', title: '子结点 0-1-2' }, + ], + }, + ], + }, + ], + }; + + setShowLine = (showLine) => { + this.setState({ + showLine, + }); + }; + + setSwitcherIcon = (showSwitcherIcon) => { + this.setState({ + showSwitcherIcon, + }); + }; + + render() { + const { treeData, showLine, showSwitcherIcon } = this.state; + const otherProps = showSwitcherIcon ? { switcherIcon: } : {}; + return ( +
                                  +
                                  + showLine: +
                                  +
                                  + change switcherIcon to icon smile: + +
                                  + + +
                                  + ); } +} + +ReactDOM.render(, mountNode); + +``` + +## 自定义图标 +可以通过icon设置树的节点图标,也可以针对单个不同的节点定制图标。 + +```jsx + +import { Tree, Icon } from 'zarm-web'; + +const MyIcon = Icon.createFromIconfont('//at.alicdn.com/t/font_1733827_4scbzsuv5v2.js'); + +class Demo5 extends React.Component { + state = { + treeData: [ + { + keys: '0', + title: '根结点1', + children: + [ + { + keys: '0-0', + title: '父结点 0-0', + disabled: true, + children: + [ + { + keys: '0-0-0', + title: '父结点 0-0-0', + checkDisabled: true, + children: + [ + { keys: '0-0-0-0', title: '子结点 0-0-0-0', icon: }, + { keys: '0-0-0-1', title: '子结点 0-0-0-1' }, + ], + }, + ], + }, + { + keys: '0-1', + title: '父结点 0-1', + children: + [ + { keys: '0-1-0', title: '子结点 0-1-0' }, + { keys: '0-1-1', title: '子结点 0-1-1' }, + { keys: '0-1-2', title: '子结点 0-1-2' }, + ], + }, + ], + }, + ], + }; + render() { - const { expandedKeys, checkedKeys, treeData } = this.state; - console.log("checkedKeys",checkedKeys) + const { treeData } = this.state; return ( -
                                  - +
                                  + } + treeData={treeData} + defaultExpandAll + checkable + />
                                  - ) + ); } +} + +ReactDOM.render(, mountNode); + ``` -::: -### 基本用法3 -通过手写TreeNode结构来渲染树(会过滤非TreeNode节点) +## 可搜索 +可搜索的树。 + +```jsx + +import { Tree, Input, Icon } from 'zarm-web'; -:::demo -```js - constructor(props) { +const TData = [ + { + keys: '0', + title: '根结点1', + children: + [ + { + keys: '0-0', + title: '父结点 0-0', + children: + [ + { + keys: '0-0-0', + title: '父结点 0-0-0', + children: + [ + { keys: '0-0-0-0', title: '子结点 0-0-0-0', checkDisabled: true }, + { keys: '0-0-0-1', title: '子结点 0-0-0-1' }, + ], + }, + ], + }, + { + keys: '0-1', + title: '父结点 0-1', + children: + [ + { keys: '0-1-0', title: '子结点 0-1-0', checkDisabled: true }, + { keys: '0-1-1', title: '子结点 0-1-1' }, + { keys: '0-1-2', title: '子结点 0-1-2' }, + ], + }, + { + keys: '0-2', + title: '父结点 0-2', + children: + [ + { keys: '0-2-0', title: '父结点 0-2-0' }, + { + keys: '0-2-1', + title: '父结点 0-2-1', + children: + [ + { + keys: '0-2-1-0', + title: '子结点 0-2-1-0', + children: + [ + { keys: '0-2-1-0-0', title: '子结点 0-2-1-0-0' }, + { keys: '0-2-1-0-1', title: '子结点 0-2-1-0-1' }, + ], + }, + { keys: '0-2-1-1', title: '子结点 0-2-1-1' }, + ], + }, + { keys: '0-2-2', title: '子结点 0-2-2' }, + ], + }, + ], + }, +]; +class SearchTree extends React.Component { + constructor(props) { super(props); this.state = { - expandedKeys: ['0-1'], - checkedKeys: ['0-0-0', '0-1'], - } - } - - render() { - const { expandedKeys, checkedKeys } = this.state; - const { TreeNode } = Tree; - return ( - - -

                                  invalid element here invalid element here

                                  - - -
                                  invalid element here invalid element here
                                  - - - - sss} keys="0-1-0" /> - invalid element here invalid element here - - -
                                  invalid element here invalid element here -

                                  invalid element here invalid element here + autoExpandParent: true, + expandedKeys: ['0-0-0'], + checkedKeys: ['0-0-0'], + treeData: TData, + }; + this.filterSearchExpandedKeysMap = {}; + } + + filterTreeDataWithHighlight = (TreeArray, searchValue, parentNode) => { + // 过滤出来非叶子结点以及匹配到关键字的结点 + return (TreeArray || []).map((item) => { + const { children, title, keys, ...others } = item; + const isLeafNode = (children || []).length === 0; + const searchedIndex = title.indexOf(searchValue); + let titleNew = title; + if (searchedIndex > -1) { + const beforeStr = title.substr(0, searchedIndex); + const afterStr = title.substr(searchedIndex + searchValue.length); + titleNew = ( - invalid element here invalid element here + {beforeStr} + {searchValue} + {afterStr} -

                                  -
                                  - invalid element here invalid element here - invalid element here invalid element here -
                                  - ) - } + ); + if (parentNode) { + this.filterSearchExpandedKeysMap[parentNode.keys] = true; + } + } + if (!isLeafNode) { + return { title: titleNew, keys, children: this.filterTreeDataWithHighlight(children, searchValue, item), ...others }; + } + return { title: titleNew, keys, ...others }; + }); + }; + + onChangeSearchText = (e) => { + const { value: searchValue } = e.target; + this.filterSearchExpandedKeysMap = {}; + const treeDataWithHighlight = this.filterTreeDataWithHighlight(TData, searchValue); + this.setState({ + treeData: treeDataWithHighlight, + expandedKeys: Object.keys(this.filterSearchExpandedKeysMap), + autoExpandParent: true, + }); + }; + + render() { + const { expandedKeys, checkedKeys, treeData, autoExpandParent } = this.state; + return ( +
                                  + } onChange={this.onChangeSearchText} /> + +
                                  + ); + } +} + +ReactDOM.render(, mountNode); + ``` -::: - -### Tree Attributes -| 参数 | 说明 | 类型 | 可选值 | 默认值 | -|---------- |-------- |---------- |------------- |-------- | -| treeData | 树节点结构数组 | array | - | [] | -| canCheck | 节点前添加Checkbox 复选框 | boolean | true, false | false | -| checkedKeys | 选中复选框的树节点数组 | array | - | [] | -| expandedKeys | 展开指定的树节点 | array | - | [] | -| defaultExpandAll | 默认展开所有树节点 | boolean | true, false | false | - -### TreeNode Attributes -建议使用 treeData 来代替 TreeNode,免去手工构造麻烦 - -| 参数 | 说明 | 类型 | 可选值 | 默认值 | -|---------- |-------- |---------- |------------- |-------- | -| title | 标题 | string/ReactNode | - | - | -| keys | 被树的 expandedKeys /checkedKeys属性所用。注意:整个树范围内的所有节点的keys值不能重复!(根节点keys为"0") | string | - | - | -| checkDisabled | 禁掉 checkbox | boolean | true,false | false | -| isLeaf | 设置为叶子节点 | boolean | true,false | false | - -### Tree Events -| 事件名称 | 说明 | 回调参数 | -|---------- |-------- |---------- | -| onCheck | 点击复选框触发 | (checkedMap,checkedObj)| -| onExpand | 展开/收起节点时触发 | expandedObj | \ No newline at end of file + + + +## API + +

                                  Tree

                                  + +| 属性 | 类型 | 默认值 | 说明 | +| :--- | :--- | :--- | :--- | +| treeData | array / <{keys, title, children, [disabled, selectDisabled, checkDisabled, checkable, isLeaf, icon]}> | [] | treeNodes数据,如设置则不需要手动构造TreeNode节点(keys 在整个树内唯一)| +| checkable | true, false | false | 节点前添加Checkbox 复选框 | +| checkedKeys | array | [] | 选中复选框的树节点数组 | +| expandedKeys | array | [] | 展开指定的树节点 | +| selectedKeys | array | [] | 设置选中的树节点 | +| defaultExpandAll | boolean | false | 默认展开所有树节点 | +| autoExpandParent | boolean | true | 是否自动展开父节点 | +| showLine | boolean | false | 是否展示连接线 | +| showIcon | boolean | false | 是否节点title前的图标,如设置为true,需要icon属性自行定义图标相关样式 | +| icon | ReactNode | - | 自定义节点title前面的图标 | +| switcherIcon | ReactNode | - | 自定义树节点的展开/折叠图标 | +| disabled | boolean | false | 是否禁掉树 | +| multiple | boolean | false | 支持选择多个节点 | +| selectable | boolean | true | 是否可选中 | +| onCheck | (checkedMap,checkedObj)=> void | - | 点击复选框触发 | +| onExpand | (expandedKeys,expandedObj)=> void | - | 展开/收起节点时触发 | +| onSelect | (selectedKeys,selectedObj)=> void | - | 点击节点触发 | + +

                                  TreeNode

                                  + +| 属性 | 类型 | 默认值 | 说明 | +| :--- | :--- | :--- | :--- | +| title | string/ReactNode | - | 标题 | +| keys | string | - | 被树的 expandedKeys /checkedKeys属性所用。注意:整个树范围内的所有节点的keys值不能重复!(根节点keys为"0") | +| checkDisabled | boolean | false | 禁掉checkbox | +| selectDisabled | boolean | false | 禁掉节点选中 | +| disabled | boolean | false | 禁掉响应 | +| checkable | boolean | - | 当树为checkable时,当前节点前是否添加Checkbox | +| isLeaf | boolean | false | 设置为叶子节点 | +| icon | ReactNode | - | 自定义节点title前面的图标 | \ No newline at end of file diff --git a/components/tree/utils.tsx b/components/tree/utils.tsx index 73503d84..45afee0d 100644 --- a/components/tree/utils.tsx +++ b/components/tree/utils.tsx @@ -1,34 +1,6 @@ import React, { ReactElement, ReactNode } from 'react'; import TreeNode from './TreeNode'; - -// 判断当前对象是否是object类型 -function isPlainObject(obj) { - if (Object.prototype.toString.call(obj).toLowerCase() !== '[object object]') { - return false; - } - const proto = Object.getPrototypeOf(obj); - if (!proto) { - return true; - } - return proto.constructor && proto.constructor === Object; -} - -// 深拷贝对象 -export function deepCopy(data) { - if (Array.isArray(data)) { - return data.map((elem) => { - return deepCopy(elem); - }); - } - if (!isPlainObject(data)) { - return data; - } - return Object.keys(data).reduce((prev, key) => { - const value = data[key]; - prev[key] = deepCopy(value); - return prev; - }, {}); -} +import { TreeNodePropsType, EventDataNode, PropsType } from './PropsType'; /** * 对数组删除一个指定的值 @@ -98,8 +70,8 @@ export function convertTreeToData(treeNode): Array { // 判断当前节点是否是禁用状态 export function isCheckDisabled(node) { - const { checkDisabled = false } = node; - return checkDisabled; + const { checkDisabled = false, disabled = false } = node; + return checkDisabled || disabled; } /** @@ -130,6 +102,18 @@ function resetNodeCheckedState(node, isChecked, conductDirection) { } } + +export function calcSelectedKeys(selectedKeys: string[] = [], props: PropsType) { + const { multiple } = props; + if (multiple) { + return selectedKeys.slice(); + } + if (selectedKeys.length) { + return [selectedKeys[0]]; + } + return selectedKeys; +} + /** * 根据选中状态变化的结点的keys数组,经过父级以及子级层层遍历判断,得到最终选中结点的数组以及更新状态属性后的treeData * @param keysList {array} 状态变化的结点keys数组 @@ -333,3 +317,20 @@ export function initialTreeData(treeData) { treeData: finalTreeData, }; } + +export function convertNodePropsToEventData(props: TreeNodePropsType): EventDataNode { + const eventData = { + ...props, + }; + delete eventData.children; + + if (!('props' in eventData)) { + Object.defineProperty(eventData, 'props', { + get() { + return props; + }, + }); + } + + return eventData; +} diff --git a/site/site.config.js b/site/site.config.js index 630e21b0..967e424f 100644 --- a/site/site.config.js +++ b/site/site.config.js @@ -159,12 +159,12 @@ module.exports = { // module: () => import('@/components/pagination/pagination.md'), // style: false, // }, - // { - // key: 'tree', - // name: '树形控件', - // module: () => import('@/components/tree/tree.md'), - // style: false, - // }, + { + key: 'tree', + name: '树形控件', + module: () => import('@/components/tree/tree.md'), + style: false, + }, { key: 'avatar', name: '头像',