0.3.6 • Published 1 year ago

wasabi-tree v0.3.6

Weekly downloads
-
License
ISC
Repository
github
Last release
1 year ago

树组件开发文档

toc

1.开发目的

  1. 实现对树组件的增删改查
  2. 实现树组件的拖动,停靠
  3. 实现树组件的父子勾选,单选,展开
  4. 实现树组件的节点图标,节点,虚线,皮肤的自定义
  5. 实现树组件通过 url 来加载数据
  6. 子节点数据可以异步加载
  7. 通过数据遍历算法优化及虚拟列表来实现大量数据时高性能渲染
  8. 提供外部调用 api,获取树组件各类数据
  9. 实现容器高度变化自适应

使用方式

2.1 下载方式

npm install wasabi-tree yarn add wasabi-tree

2.2 引入方式

1 data 形式

import Tree from "wasabi-tree";
import "wasabi-tree/lib/index.css";

function Demo(props) {
  return <Tree data={props.data}></Tree>;
}

2 url 形式

import Tree from "wasabi-tree";
import "wasabi-tree/lib/index.css";

function Demo(props) {
  return <Tree url={props.url}></Tree>;
}

2.3 树属性

属性名类型说明默认值
namestring树名称null
idFieldstring指定哪个字段是节点的 idid
parentFieldstring指定哪个字段是节点的 pIdpId
textFieldstring指定哪个字段是节点的 texttext
childrenFieldstring指定哪个字段是节点的 childrenchildren
urlstring1.后台查询地址,第一次自动查询 2.节点展开时如果asyncAble为true,而oAsync函数为空,则自动根据这个url地址查询null
paramsobject向后台传输的额外参数null
dataSourcestring有 url 参数时的返回的数据源中哪个属性作为数据源,可以分层比如data.listdata
headersarray请求时传的表头参数null
dataarray父组件传的固定数据null
isSimpleDatabool是否使用简单的数据格式:。目的是在前端将扁平化数据转成树状结构false
dottedAblebool是否有虚线true
selectAblebool是否允许勾选false
checkStyleoneOf("checkbox", "radio", func)单选还是多选,可以通过函数返回自定义组件,func(row){retrun node;} 注意: 宽度20px,高度 30pxcheckbox
checkTypeobject勾选对于父子节点的关联关系[y]代表选中,[n]代表取消 [p]父节点 [s]代表子节点{ "y": "ps", "n": "ps" }
radioTypeoneOf("level", "all")单选时影响的层级[level]同级 [all]整个树all
renameAblebool是否允许重命名false
removeAblebool是否允许移除false
draggAblebool是否允许拖动false
dropAblebool是否允许停靠false
dropTypearray停靠模式null,["before","in","after"
asyncAblebool展开节点是否可以异步加载数据false
textFormatterfunc(row)自定义节点文本样式函数 例子:(row)=>{return <div className="red">{row.text}</div>null

2.4 事件

属性名类型说明参数返回值
onClickfunc单击的事件id,text,rownull
onDoubleClickfunc双击事件id,text,rownull
onCheckfunc勾选/取消勾选事件isChecked, id, text, rownull
onExpandfunc展开/折叠事件open, id, text, rownull
onAddfunc新增事件id, text, parentNodenull
onRenamefunc重命名事件id, text, row, newTextnull
onRemovefunc删除事件id, text, rownull
onContextMenufunc自定义右键菜单视图id, text, row,eventnull
onDragfunc拖动事件id, text, rownull
onDropfunc停靠事件dragNode(移动节点),dropNode(停靠节点)dragType(停靠方式)null
onAsyncfunc节点异步查询,为 null,则会通过 url 来处理id, text, row返回值即异步加载后节点数据
onAsyncfunc节点异步查询,为 null,则会通过 url 来处理id, text, row返回值即异步加载后节点数据
loadSuccessfunc有 url 时请求成功后的事件,用于加工数据data返回加工后的数据
beforeAddfunc新增前事件id, text, rowtrue(同意),false(不同意)
beforeRemovefunc删除前事件id, text, rowtrue(同意),false(不同意)
beforeRenamefunc重命名前事件id, text, rowtrue(同意),false(不同意)
beforeDragfunc拖动前事件id, text, rowtrue(同意),false(不同意)
beforeDropfunc停靠前事件dragNode(移动节点), dropNode(停靠节点), dragType(停靠方式true(同意),false(不同意)

2.5 组件方法(ref)

属性名类型说明参数返回值
findNodefunc获取某个节点idnode
findParentsfunc获取某个节点所有父节点包括自身idnodes
getDatafunc获取所有节点nulldata
getCheckedfunc获取勾选节点nullisCheckedData
setCheckedfunc设置勾选节点id,isCheckednull
setDisabledfunc设置不可操作id,disablednull
clearCheckedfunc清除全部勾选节点nullnull
checkedAllfunc勾选全部节点nulldata
selectNodefunc设置节点单击选中,并且滚动到此处,祖先节点全部展开idnull
removefunc删除节点,可以传数组,代表删除多个id 或者id,idnull
removeAllfunc删除所有节点nullnull
appendfunc追加某个节点,id 为空时即为更新全部children,idnull
updatefunc更新某个节点,或者某组node,nodenodesnull
updateAllfunc更新整个树datanull
filterfunc过滤节点,过滤的视图请自行设计valuenull
adjustfunc重新调整容器,适应容器高度发生变化nullnull

2.6 节点 Node 属性

属性名类型说明默认值
isParentbool是否是父节点null
idstringkey 值,如果没有会根据树组件设定的 idField 来转换""
pIdstring父节点 key 值 如果没有会根据树组件设定的 parentField 来转换""
textstring节点文本,如果没有会根据树组件设定的 textField 来转换""
titlestring提示信息""
iconClsstring /node默认图标,可以是组件icon-text
iconClosestring/node父节点关闭图标 可以是组件icon-folder
iconOpenstring/node父节点展开图标 可以是组件icon-folder
arrowUnFoldIconnode节点展开的箭头图标组件icon-arrow-down
arrowFoldIconnode节点折叠的箭头图标组件icon-arrow-right
isOpenedbool是否处于打开状态null
isCheckedbool是否被勾选null
addAblebool是否允许新增null
removeAblebool是否允许删除null
removeIconAblebool是否允许删除图null
renameAblebool是否允许重命名null
renameIconAblebool是否允许重命名图标null
selectAblebool是否允许勾选null
draggAblebool是否允许拖动null
dropAblebool是否允许停靠null
hidebool是否隐藏null
disabledbool是否不可操作null
childrenarray子节点,如果没有会根据树组件设定的 childrenField 来转换null

3 树组件性能设计

3.1 性能策略

3.1.1 虚拟列表
  1. 容器渲染完成后,拿到可见高度,通过节点行高,得到可见区域的节点个数
  2. 要渲染的数据是visibleData:上部预留区域+可见区域-下部预留区域
  3. 扁平化后切割数据,得到渲染数据:visibleData
  4. 监听容器的滚动事件,得到起始下标,重新计算要渲染的数据,并且进行了节流
3.1.2 树型结构与格式化,扁平化数据时优化算法
  1. 在 toTreeData 函数中将后端二维表格数据转树型结构时,利用 hash,并且不破坏原始数据结构来优化算法。
  2. formatTreeNodeData【格式化】与 treeDataToFlatData【扁平化】时:循环与递归过程中不使用浅复制,不创建新的对象,不删除, 只是单纯的 for
3.1.3 格式化数据时,标准化节点数据结构:id,pId,text,children

通过字段属性名,标准化节点这四个字段值,方便对树节点的渲染与操作

3.1.4 格式化数据,增加节点路径属性:_path 并且根据 id 作为 key 保存在 map 数据中hashData
  1. 对传递的数据先进行预处理,设置节点_path 属性,保存节点在树结构的路径
  2. 能够通过_path 快速找到节点,及祖先节点,快速操作树节点的勾选,增,删,修改,移动
  3. 通过_path 字段来确实节点前面空白占位宽度大小,扁平化后依然能显示层级关系
  4. 通过hashData中的_path,方便通过 id 快速找到节点 方便上层组件
3.1.5 除可见数据等少数状态外,整个树结构的数据不参与 State
  1. 树的全部全部 data,扁平化数据 flatData,筛选后的数据 filterData 等都不参与 State
  2. 设置异步更新,将多次数据操作合并成一次更新(父组件可能同时调用几个方法)
  3. state 只有四个属性:visibleData,loadingId,clickId,scrollIndex
  4. scrollIndex为是 selectNode 方法,选中节点要滚动的位置,设置为对象,能够更好的监听变化,防止鼠标滚动后,再设置时值相同的问题
3.1.6 提供通过ref来操作的多种方法方便父组件操作节点避免更新整个data
  1. 父组件可以通过,findNode,findParents,getisChecked,getData 等多种方法来获取即时数据状态,
  2. 父组件可以通过 setChecked,selectNode, append,remove,update,moveIn 等来勾选,选中,追加,删除,更新,移动等节点等多种操作
  3. 这样避免父组件更新data,从而导致整体重新计算
3.1.7 缓存所有方法与组件,避免重复渲染,最大限度的优化组件

利用 useCallBack,useReduce,memo 等方式来减少重定义与渲染次数

3.1.8 利用上下文传递透传树组件的属性与方法

利用 context 来缓存树组件本身的属性避属性在节点中一级一级传递

3.1 十万数据量的渲染情况

渲染情况不完全准确: 2.2.1 isSimpleData 为 true 格式化数据平均时长:约155ms, 2.2.1 树状结格式化数据平均时长:约33ms 2.2.2 扁平化数据平均时长:约25ms 2.2.3 首屏时间:约0.8s 2.2.4 删除节点:约73ms 2.2.4 移动节点:约126ms

4 树组件的设计思路

4.1 树的关系图

@startuml
 class func{
       公共函数,扁平数据转树状结构
    }
    class treeFunc{
       数据加工
    }
    class handlerData {
            reducer计算
    }
    class TreeContainer{
    树组件的容器,负责数据处理
    }
    class TreeView{
        树组件View渲染,
    }

    class TreeNode{
        树节点,处理节点事件
    }
    class NodeView{
        树节点视图,负责渲染
    }
    class CheckBox{
        复选框
    }
    class Radio{
        单选框
    }
     class Text{
        文本框
    }

func-->treeFunc:【isSimpleData为true时toTreeData】扁平数据转树结构
treeFunc-->handlerData:操作数据:加工数据,并格式化,扁平化
handlerData-->TreeContainer:响应树的事件,得到新的状态
    TreeContainer-->TreeView:树组件View
    TreeView-->TreeNode:树节点
    TreeNode-->NodeView:树节点View
    NodeView-->CheckBox:复选框
      NodeView-->Radio:单选框
      NodeView-->Text:文本框

@enduml

4.2 树的数据流图示

4.2.1 状态数据流
@startuml
父组件-->TreeContainer:将父组件传递的【data】
父组件-->TreeContainer:通过父组件传递的url加载后的【data】
父组件-->TreeContainer:其他控制权限的props
getVisibleCount-->TreeContainer:计算可见高度visibleHeight,scrollTop:滚动位置,得到可视区节点个数及下标
TreeContainer-->handlerData:传递gobalData,action,payload用于加工数据
handlerData-->TreeContainer:加工数据,【reduce】计算返回新的state
@enduml
4.2.1 data 加工流程
@startuml
formatTreeNodeData-->handlerData:格式化data,生成id,pId,text,children必需属性, 追加_path属性,
formatTreeNodeData-->handlerData:追加_path属性的渲染与查询
formatTreeNodeData-->handlerData:生成hashData(Map) 方便通过id查询节点
treeDataToFlatData-->handlerData:扁平化数据flatData,并且追加_isLast,_openDescendant 属性 方便渲染虚线
getVisibleData-->handlerData:【reduce】生成新的visibleData,可见数据
@enduml
4.2.1 data 组件数据流
@startuml
TreeContainer-->TreeView:传递visibleData,props,events作为上下文传递给节点,渲染可见的节点
TreeView-->TreeNode:for循环visibleData,渲染具体的节点
TreeNode-->TreeContainer: 设置节点的事件,借助上下文处理数据
TreeNode-->NodeView:渲染节点视图
@enduml

4.3 函数与类的作用

4.3.1 getVisibleCount-获取可见区域节点数量
  1. 根据容器高度得到可渲染的数据个数 visibleCount
  2. 得到可见区域的起始结束下标(startIndex,endIndex),不是了可见数据visibleData的起始下标,因为有上下预留区
4.3.2 getVisibleData-得到可见数据
  1. 将 data 扁平化得到 flatData
  2. 得到visibleData[可见数据],filterData【过滤的数据】,flatData【扁平化数据】,data[原始可操作数据]
  3. 得到 sliceBeginIndex[切割的起始下标],sliceEndIndex[切割的结束下标]
  4. 在滚动过程不再扁平化,直接使用上次的 flatData
  5. 除非有新的 filterValue,或者更新 Data 的结构,再重新扁平化
4.3.3 getData-请求数据

如果传递的 url,进行 fetch 请求,得到传递的数据

4.3.4 func-toTreeData 转成树状结构
  1. 将简单数据转成树结构
4.3.5 treeFunc-树的操作
  1. 树节点的寻址
  2. 树节点的增删改查
  3. 树节点选中,勾选
  4. 树节点的移动,停靠
  5. 树节点的筛选
  6. 树节点的格式化
  7. 树节点的扁平化
4.3.6 treeFunc-formatTreeNodeData-格式化数据
  1. 格式化数据,方便后期树节点的操作
  2. 通过 idFeild,parentFeild,textFeild,childFeild 得到·id,pId,text,children属性
  3. id[key],pId[父节点id],text[文本】,children[子节点]
  4. 生成_path属性,即节点的路径,用于寻址及渲染
  5. 生成hashDatamap,方便通过 id 来查询节点
4.3.7 myReducer-树的 reduce 函数

处理树组件的 state

4.3.8 TreeContainer-树的容器
  1. 调用【getVisibleCount】 【showVisibleData】进行第一次渲染
  2. 处理树所有的事件,调用[myReducer]得到新的 state
  3. 提供 ref 调用的方法,方便获树相关的数据
  4. 利用上下文将 state,props 传递给[TreeView]
4.3.9 TreeView-树的视图
  1. 渲染树组件的节点
4.3.10 TreeNode-树节点容器
  1. 处理树节点的所有事件,回传给树容器
4.3.11 NodeView,CheckBox,Radio.Text-树节点视图,复选框,单选框

NodeView:渲染树的节点视图 CheckBox:复选框 Radio:单选框 Text:编辑时的文本框

0.2.91

1 year ago

0.3.0

1 year ago

0.3.6

1 year ago

0.3.5

1 year ago

0.2.9

1 year ago

0.2.8

1 year ago

0.3.2

1 year ago

0.3.1

1 year ago

0.3.4

1 year ago

0.3.3

1 year ago

0.2.7

2 years ago

0.2.5

2 years ago

0.2.4

2 years ago

0.2.3

2 years ago

0.2.2

2 years ago

0.2.1

2 years ago

0.2.0

2 years ago

0.1.7

2 years ago

0.1.6

2 years ago

0.1.5

2 years ago

0.1.4

2 years ago

0.1.3

2 years ago

0.1.2

2 years ago

0.1.0

2 years ago