生态产品多个设计器现已发布正式版

查看生态总览
跳转到内容

Tree 树 ​

层级数据的展开与选择:分支可展开,节点可选。

用法 ​

collection 是层级元信息的唯一事实源;不写结构时组件照它铺出标题与整棵树,缩进由子层容器自行撑开

项目文件
src
main.ts
README.md

组件结构 ​

加粗的是必需部件。

data-scope="tree":root · label · tree · item · item-indicator · item-text · item-description · item-suffix · branch · branch-control · branch-trigger · branch-indicator · branch-text · branch-description · branch-content · branch-loading · branch-error · branch-retry-trigger · branch-empty · node-drag-trigger · empty · loading · live-region

示例 ​

多选 ​

选择模式缺省是单选,写 multiple 后点击与确认键都变为切换,选中集合形状不变仍是数组

投放城市
华东
上海
杭州
南京
华北
北京
天津
选中:hz

受控 ​

传入 expandedValue / selection 后由宿主决定,组件只发事件不落内部值,宿主写回后才变化

文档目录
接口
鉴权
用户
展开:api · 选中:(无)

点击行展开与禁用节点 ​

缺省点行只选中、展开归箭头与左右方向键,expandOnClick 打开后点行同时切换展开态;禁用节点仍可聚焦,只是确认键不响应它

构建产物
build
vite.config.ts
pnpm-lock.yaml(禁用)
README.md

关键词过滤 ​

collection 换一份树即换一棵:标记跟随数据重新铺设,过滤后剩余的分支一并全部展开

投放城市
华东
上海
杭州
南京

异步加载子节点 ​

节点写 hasChildren,首次展开时组件调 loadChildren 取子项:在途转圈并报告 aria-busy,取回后由组件暂存,收起再展开不重复请求;运维中心第一次会失败,点重试或在该行按 Enter 再取

组织架构
董事办

前缀与行尾 ​

行中放置什么由标记决定:文字前放图标、文字后放操作,展开箭头也可以移到行尾

工作区
src
index.ts
app.vue
(还没动过)

只让叶子进入选中集合 ​

选中受控后由宿主决定:分支的值直接不写回,点击目录只剩展开收起这一个效果

要提交的文件
src
index.ts
app.vue
已选:(无)

级联勾选 ​

multiple 加 cascade 内建父子传导:点击分支整枝勾选、子全勾则父勾、部分勾选为半选;勾选与半选都画在行尾,半选是一道横杠,两态都由组件报告

投放城市
华东
上海
杭州
南京
华北
北京
天津

选中值(默认只收叶):hz

拖拽移动 ​

整个节点都是拖动源:按住拖到目标位置松手,也可以 Tab 进树后用 Alt + 上下键在同层移动、Alt + 左右键改变层级。三档落点(插在前 / 插在后 / 放进目录)连同指示线、自我后代守卫与读屏播报都归库;树仍不拥有数据,宿主只需按库报告的 value、parent、index 调整数组,外加一条 allowDrop 决定本次是否允许

邮箱目录
收件箱3
报价单.pdf
周报.md
会议纪要.md
归档1
去年总结.docx
回收站0
按住任意一行拖走,或 Tab 进树里按 Alt + 方向键搬

末端横排 ​

leaf-orientation 按结构判据横排子节点全为叶子的层;要指定哪一层横排就在节点上标注 childrenOrientation,它比树级值优先,标注 vertical 也可覆盖

菜单授权
系统管理
用户管理
新增
编辑
删除
导出
角色管理
新增
授权
删除
日志管理
查看
导出

范围选择 ​

按住 Shift 点击某一项,选中锚点到它的一段;按可见序取值,折叠的子节点不会被选入

点「上海」,再按住 Shift 点「北京」 —— 中间整段一起选上。 再按住 Shift 点「南京」,选区往回收,起点不变。

投放城市
华东
上海
杭州
南京
华北
北京
天津
选中:(无)

变体 ​

variant="ghost" 去掉外框与底色,树直接落在页面上;默认 outline 保持带框的外观

src
main.ts
App.vue
README.md
src
main.ts
App.vue
README.md

大树虚拟化 ​

完整树数据负责层级与键盘语义,窗口只挂载当前可见行

项目文件

连接线 ​

lines 从父节点的展开箭头引出竖线,每个子节点横出一段接到行首、最后一个子节点拐成直角收住,层级深的时候一眼看得出谁挂在谁下面;只是外观,不改结构与键盘

项目文件
src
components
Button.vue
Dialog.vue
main.ts
docs
guide.md
api.md
README.md

尺寸 ​

size 写到 root 的 data-size:行高、字号、展开箭头与对号盒、层级缩进一起随档;三档并排,缺省即 md

sm
src
main.ts
App.vue
README.md
缺省(md)
src
main.ts
App.vue
README.md
lg
src
main.ts
App.vue
README.md

条目说明 ​

一句名称说不清的解释写进说明,叶子与分支都可以带,落在名称下面一行;窄的时候截断,不把树撑宽

字段
订单一笔订单抬头上的字段
订单号系统生成的唯一编号,打印在单据抬头与条码里
下单日期按下单时所在时区记
实付金额

文件管理器式多选 ​

选择模式写 extended:点击换成这一项,按住 Ctrl(macOS 为 ⌘)点击加选或取消,按住 Shift 点击从锚点选一段

点「上海」,再按住 Ctrl(macOS 为 ⌘)点「北京」把它加进来;按住 Shift 点「南京」,从「北京」到「南京」那一段换成新的选中;不按键直接点,只留这一项。

投放城市
华东
上海
杭州
南京
华北
北京
天津
选中:(无)

设计指引 ​

何时使用 ​

  • 文件目录、组织架构、权限节点等任意深度的层级数据。
  • 需要在树上多选并处理父子级联。

何时不用 ​

  • 树只用于选一个值时,使用树选择,它把树收进浮层。
  • 层级规整、层数固定且只为选值时,使用级联选择。
  • 数据是扁平的时,使用列表或表格。

特性 ​

  • 展开集合与选中集合两套值各自可受控。
  • variant 决定外框形态,默认 ghost,树直接落在页面或宿主面上;outline 加一圈描边与底色,subtle 换成淡底无描边。
  • size 取 sm / md / lg,默认 md,走集合家族的尺寸档:行高、行内内衬、字号、展开箭头与对号盒、拖拽把手与层级缩进一起随档。
  • 选择模式 selectionMode:缺省 single 单选;multiple 点击与确认键切换,按住 Shift 点击把锚点到这一项那一段并进来;extended 照文件管理器,点击与确认键换成这一项,按住 Ctrl / Cmd 点击或按 Ctrl / Cmd + Space 切换这一项,按住 Shift 点击选锚点到这一项那一段(同时按 Ctrl / Cmd 则并进)。锚点是最近一次点击或切换的那一项;选中从外面换了(受控时宿主另写了值、setSelection、初始的选中),锚点落到多出来的最后一项,清空了就没有锚点。级联勾选只在 multiple 下生效。
  • 选中与树形选择器同一种读法:行不换面,单选、多选与级联都只在行尾画对号;分支行也摆 item-indicator,级联下的半选画横杠。
  • cascade 与 checkedStrategy 决定勾选父节点是否带子节点,以及回显给哪一层。
  • 支持只让叶子进选中集合、关键词过滤、子节点异步加载、拖放换父。拖放与 Alt + 方向键落下之后,宿主写回 collection 的那一次重排里,行从旧位置滑到新位置(换了父被重建的节点按节点值认回);落点线取品牌实心色,与表格、排序同一种。
  • 展开与选中分开:点行只选中,展开归箭头与左右方向键;expandOnClick 打开后点整行才顺带展开。
  • 节点可逐条声明语气,不向下传导;叶子行与分支行同样表达。
  • 节点可写副文本,第 2 行放一句解释,不进连打检索串。
  • 开着 nodeDraggable 时,节点数据写 draggable: false 的那一个拖不起来:指针按住、Alt + 方向键都不搬它,行上不写 data-draggable,它的拖拽把手报禁用;它照常能选、能展开,也照样是别的节点的落点。不向下传导,它的子节点各自照常可拖。大纲里的区域、页、页眉这类「能选能当容器、自己不能挪」的行用它,不必禁用。
  • 节点行尾留一格给作者(计数、徽标),排在对号之前;行首那一格归展开箭头与拖拽把手。
  • 空(empty)与在途(loading)两个相位各有部件,都放在 root 内作为 tree 的兄弟;loading 为真时树报告 aria-busy,空态让位。在途分两种:还没有节点时在途占位露面,一枚加载环排在文案之前;已有节点时重新取数不换成占位,行保留上一帧淡下,取完再淡回。
  • leafOrientation 按结构判据横排:子节点全是叶子的层跟随它,其余始终竖排。
  • 懒分支:节点写 hasChildren: true 且不给 children,首次展开时调 loadChildren({ node, signal }) 取它的直接子项,取回的子项由组件暂存、不写回 collection;在途时分支报告 aria-busy、展开箭头换成转圈(减弱动效下停住)。收起会中止在途的一轮,收起再展开不重复请求。失败与「取回空数组」是两个终态:失败露出说明与重试钮,再次展开不自动重试,点重试钮或在分支上按 Enter / Space 才重发;空数组露出空结果。在途、失败说明、重试钮与空结果四个部件由组件在分支里自己补,手写结构时也一样。取数与树选择、级联选择同一套规则,事件是 branch-load-start / branch-load / branch-load-error。
  • 取数由作者自己编排时,把在途的分支写进 loadingValue:同样报告 aria-busy 并换成转圈,回来后写回 collection 并移出。
  • lines 打开连接线:父节点展开箭头的中线向下引一道竖线,每个子节点从竖线横出一段接到行首(分支接到展开箭头,叶子穿过占位那一格接到正文前),最后一个子节点的竖线止于它那一行的中线;展开着的分支,竖线沿它的整棵子树接到下一个兄弟。颜色取内部分隔线(--xh-tree-line-color),只是外观,不改结构与键盘。顶层节点没有父节点可连,不画线;线画在嵌套的子层里,虚拟化平铺渲染的行不画。
  • 节点上标 childrenOrientation: 'horizontal' | 'vertical' 指定该层子节点的排列方向,优先于 leafOrientation;标 vertical 可以把树级的 horizontal 改回竖排。根层不受影响,始终竖排。

组合 ​

  • 不写结构时照标准结构铺:标题(给了 label 时)与整棵树,分支是一行控制行(展开箭头、文字、副文本、对号)加一层子层,叶子是文字、副文本与对号;收起的分支照样铺出子层,节点按值复用。Vue / React 不写默认插槽与 Web Components 不写部件(或只写 root)时生成的节点出自同一个结构函数。行尾内容、自定义指示符、拖动把手与播报区、空态与在途占位不在标准结构里,要用时整棵手写。
  • 前缀放图标,行尾放菜单;放入分栏的一侧。
  • 大树把 visibleNodes 的长度交给 Virtualizer,并把其 collectionVirtualizer 回传给根;展开收起后同步更新 count。

最佳实践 ​

  • 大树必须虚拟化或按需加载,一次展开全部会卡顿。
  • 级联勾选的策略与后端约定一致。
  • 只需要某一层横排时标 childrenOrientation,不开启树级 leafOrientation:后者按结构判断,其他恰好“子节点全是叶子”的层也会横排,并随数据增减变化。

反模式 ​

  • 展开状态不持久,用户每次进入都要重新展开。
  • 拖放换父没有落点提示。

API 参考 ​

产物 ​

层值
自定义元素<xh-tree>
Vue 组件XhTreeBranch XhTreeBranchContent XhTreeBranchControl XhTreeBranchDescription XhTreeBranchEmpty XhTreeBranchError XhTreeBranchIndicator XhTreeBranchLoading XhTreeBranchRetryTrigger XhTreeBranchText XhTreeBranchTrigger XhTreeEmpty XhTreeItem XhTreeItemDescription XhTreeItemIndicator XhTreeItemSuffix XhTreeItemText XhTreeLabel XhTreeLiveRegion XhTreeLoading XhTreeNodeDragTrigger XhTreeRoot XhTreeTree
组合式函数useTree
状态机treeMachine
皮肤@xihan-ui/styles/tree.css

Props ​

属性类型必填说明
labelledboolean作者渲染了 label 部件时置真,由适配器统计而不是判断标题文字是否有值。 为假时可聚焦部件不把 label 的 id 写进 aria-labelledby:指向未渲染的 id 是无效引用,作者写在控件上的 aria-label 也会被它压住。
collectionTreeNode[]树数据,层级元信息的唯一事实源。默认为空树。
virtualizerCollectionVirtualizer完整 collection 与 Virtualizer 的焦点桥;count 必须等于当前 visibleNodes.length。
variantControlVariant外框形态:ghost 去掉描边与底色只保留行(默认),outline 带描边与底色,subtle 淡底无描边。
sizeSize尺寸:sm / md / lg,默认 md。行高、行内内衬、字号、指示符盒(展开箭头、对号、拖拽把手)与层级缩进随档。
leafOrientationOrientation末端层的排布方式,默认 vertical(每行一个)。horizontal 使它们并排铺开。 只作用于子节点全是叶子的层:菜单授权中即按钮层: 一个菜单下十几个按钮,横向排成一行,省去纵向翻找。中间层与整棵树恒为纵向, 它们承载的是层级本身,横向排布会失去层级信息。 这是结构判据,逐层自动识别。需要精确指定哪一层横向排布时,在节点上标注 childrenOrientation,它优先于本项。 只影响排布,不改变键盘:方向键在树上是层级操作(左右收展、上下移动可见行), 这是 treeview 的规范语义,不随排布方向改写。
expandedValuestring[]展开集合。提供即受控:cell 直读 prop,写入只发 onExpandedValueChange 不落内部值。
defaultExpandedValuestring[]
selectionstring[]选中集合。提供即受控,语义同上。
defaultSelectionstring[]
selectionModeTreeSelectionMode选择模式,默认 single;multiple 与 extended 下 tree 带 aria-multiselectable=true。
cascadebooleanselectionMode 为 multiple 时父子级联勾选:点击分支整枝传导、子全勾父勾、部分勾选半选, 禁用子树整棵冻结。默认 false(朴素切换);single 与 extended 下无效。
checkedStrategyCascadeStrategy级联下对外值的收敛策略,默认 child(只收叶);parent = 最高整枝,all = 全部勾选节点。
expandOnClickboolean点击分支行(与确认键)是否同时展开 / 收起,默认 false:展开与选中分开,只有 branch-trigger 与左右方向键能改变展开态。
disabledboolean整棵树禁用:所有节点为 aria-disabled,键盘与点击都不再改变展开 / 选中。
loadingboolean节点加载中:树报告 aria-busy、隐藏空态占位;还没有节点时显示在途占位,已有节点时行保留上一帧淡下。
loadingValuestring[]正在取子节点的分支(节点 value)。在其中的分支报告 aria-busy,展开箭头换成转圈。 取数由作者自己编排时用它;交给 loadChildren 的懒分支由库自己标出在途,不必写在这里。
loadChildrenBranchLoadChildren<TreeNode>取回 hasChildren: true 分支的直接子项。首次展开自动调用,失败后用 api.retryBranch 或 branch-retry-trigger 显式重试;收起分支会中止在途的那一轮。旧请求的兑现或拒绝不会覆盖更新的一轮, 也不会写回已移除的分支。取回的子项暂存在组件里,不写回 collection。
linesboolean连接线:父节点展开箭头的中线向下引一道竖线,每个子节点横出一段接到行首,最后一个子节点止于行中线,默认 false。只是外观,不改结构与键盘。
loopboolean上下键到达首尾是否回绕,默认 false。
typeaheadboolean连打检索,默认开启。关闭后可打印字符一律放行给页面。
dirDirection文字方向,默认 ltr;只对调左右方向键的展开 / 收起语义。
translationsPartial<TreeTranslations>
nodeDraggableboolean节点可以拖动移动。整个节点都是拖动源,不另设把手。
allowDrop(move: TreeMove) => boolean本次移动是否允许。收到的是折算后的落点(移到哪个父节点下的第几位)。 未提供时全部允许:落进自身后代与落在禁用节点上两条由库自行拦截。
onNodeMove(move: TreeMove) => void
onExpandedValueChange(details: TreeExpandedValueChangeDetails) => void
onSelectionChange(details: TreeSelectionChangeDetails) => void
onBranchLoadStart(details: TreeBranchLoadStartDetails) => void一轮有效分支请求开始;retry 与首次展开由 reason 区分。
onBranchLoad(details: TreeBranchLoadDetails) => void一轮有效分支请求成功;children 为空仍是成功,不转换为错误。
onBranchLoadError(details: TreeBranchLoadErrorDetails) => void一轮有效分支请求失败;保留 loadChildren 给出的原始 error。

TreeNode ​

collection 的元素。

字段类型必填说明
valuestring是
labelstring展示名,也是连打检索与分支可及名的取字来源;默认回退为 value。
disabledboolean节点禁用:方向键与连打检索跳过它,但它仍可聚焦、仍是导航起点。不向下传导给子节点。
draggableboolean写 false 时这一个节点拖不起来(nodeDraggable 开着时指针按住、Alt + 方向键都不搬它), 照常能选、能展开、能当别的节点的落点。缺省可拖。不向下传导给子节点。
toneTone该节点自身的性质:已失效的写 danger、需要留意的写 warning。不写即与其余节点同档, 也不向下传导给子节点——每一层各自声明。只换字色与悬停 / 按下的面,不改字重与缩进, 也不表达选中或校验;选中的标记与禁用都压过它。彩字不是唯一通道,要紧的差别仍要配图标。
descriptionstring副文本:叶子写入 item-description、分支写入 branch-description 部件;未提供时本条不铺该部件。 它是第 2 行的说明,跟着条目走 muted 档,不跟语气;放不下一行的解释才用它, 一句话能说清的写进 label。
childrenTreeNode[]子节点。提供数组即判定为分支,空数组也计入:暂时没有子项的目录仍要报告 aria-expanded。
hasChildrenboolean懒分支:写 true 且不给 children 时,这一枝在首次展开时由 loadChildren 取子项。 已提供 children 时它没有额外作用。取回的子项由 headless 暂存,不需要宿主重写整棵 collection。
childrenOrientationOrientation该层子节点的排布方式,由作者在数据上标注。提供后以它为准,vertical 也优先于树级的 leafOrientation;未提供时才回退为 leafOrientation 加子节点全是叶子的结构判据。 标注在哪一层,横向排布就只落在哪一层:菜单授权中标注在按钮的父菜单上,其他目录不受影响, 也不随子节点增减漂移。只影响排布,不改变键盘。

事件 ​

自定义元素将载荷放在 detail;Vue 使用同名 emit。

事件载荷说明
expanded-value-changeTreeExpandedValueChangeDetails展开集合变化;detail 为 { value: string[] }
selection-changeTreeSelectionChangeDetails选中集合变化;detail 为 { value: string[] }
node-moveTreeNodeMoveDetails节点已移动;detail 为 { value, parent, index },parent 为 null 即根层,index 是在该层的落位(已经过先移除后插入的修正)
branch-load-startTreeBranchLoadStartDetails分支请求开始;detail 为 { value, node, reason }
branch-loadTreeBranchLoadDetails分支请求成功;detail 为 { value, node, children }
branch-load-errorTreeBranchLoadErrorDetails分支请求失败;detail 为 { value, node, error }

插槽 ​

仅列出带载荷的插槽。

Vue 组件插槽载荷说明
XhTreeRootdefaultTreeRootSlotProps
XhTreeRootlabel—标准结构里标题的内容;手写结构时不用它。

React 适配器 props ​

只列各组件自己声明的那些:继承自 ComponentPropsWithRef 的 DOM 属性不在其中,根组件上与上面 Props 表同名的也不重复列。Vue 的对应物是上面的插槽表。

React 组件属性类型必填说明
XhTreeBranchvaluestring是
XhTreeItemvaluestring是
XhTreeRootlabelReactNode标题:不写 children 时铺进标准结构的 label;手写结构时用 XhTreeLabel。
XhTreeRootchildrenSlotChildren<TreeRootSlotProps>

状态 ​

公开状态写入 data-state。

部件取值
branch'open' | 'closed'
branch-control'open' | 'closed'
branch-trigger'open' | 'closed'
branch-indicator'open' | 'closed'
branch-text'open' | 'closed'
branch-description'open' | 'closed'
branch-content'open' | 'closed'
branch-loading'open' | 'closed'
branch-error'open' | 'closed'
branch-retry-trigger'open' | 'closed'
branch-empty'open' | 'closed'

以下名称仅用于内部状态机。

状态:idle

事件:EXPANDED.SET · BRANCH.EXPAND · BRANCH.COLLAPSE · BRANCH.TOGGLE · BRANCH.RETRY · SELECTION.SET · NODE.SELECT · NODE.FOCUS · TREE.BLUR · NODE_DRAG.START · NODE_DRAG.MOVE · NODE_DRAG.END · NODE_DRAG.CANCEL · NODE.MOVE_BY · PRESS.START · PRESS.END

判据:canPress

connect API ​

getXxxProps() 返回对应部件的宿主属性。

成员类型说明
collectionreadonly TreeNode[]有效树数据:作者的 collection,懒分支补上已取回的子项(还没取回的补空数组)。
visibleNodesreadonly TreeVisibleNode[]当前可见行序列(收起分支的子树不在其中)。 方向键、Home/End 与连打检索都在它上面移动,不在原始树上移动。
dropTargetDropTarget | null当前的落点;松手即落在此处。不合法或未落在任何节点上时为 null。
announcementstring读屏播报文本。渲染进 live-region,不进入视觉版面。
expandedValuestring[]
selectionstring[]
focusedValuestring | null焦点锚点;焦点不在树内、或它已被收起而不可见时为 null。
selectionModeTreeSelectionMode生效的选择模式。
disabledboolean
translationsTreeTranslations生效的文案:内建英文与 translations 合并后的那一份。
isExpanded(value: string) => boolean
isSelected(value: string) => boolean
isIndeterminate(value: string) => boolean级联模式下该分支是否半选(有效叶后代部分勾选);非级联恒为 false。
branchLoadState(value: string) => TreeBranchLoadSnapshot | null非懒分支返回 null;懒分支即使尚未请求也返回 idle。
setExpandedValue(next: string[]) => void
setSelection(next: string[]) => void
expand(value: string) => void
collapse(value: string) => void
retryBranch(value: string) => void失败后重新取该分支;非懒分支与未知 value 不产生副作用。
select(value: string, options?: { extend?: boolean, additive?: boolean }) => void选中某个节点,与点击同一语义:extend 对应按住 Shift(选锚点到该节点的范围,单选与级联下不认), additive 对应按住 Ctrl/Cmd(extended 下切换这一项)。
getRootProps() => T['element']
getLabelProps() => T['element']
getTreeProps() => T['element']
getEmptyProps() => T['element']空态占位:放在 root 中、tree 的兄弟(role=tree 只允许拥有 treeitem 与 group)。 提供 collection 时由连接层按条数收放;节点手写时不写 hidden,是否显示由作者决定。
getLoadingProps() => T['element']在途占位:与空态占位同一位置,两者不同时显示:加载期间显示它,空态让位。 提供 collection 时由连接层按条数收放;节点手写时只按 loading 收放。
getNodeDragTriggerProps(props: TreeNodeProps) => T['element']节点拖动把手。触屏路径唯一的入口,不占 Tab 位。 常驻即可:nodeDraggable 关闭或该节点禁用时它声明 data-disabled、也不再让出滚动, 渲染不会出错。按是否可拖动决定是否渲染,会使 DOM 结构随状态变化。
getLiveRegionProps() => T['element']
getItemProps(props: TreeNodeProps) => T['element']
getItemTextProps(props: TreeNodeProps) => T['element']
getItemDescriptionProps(props: TreeNodeProps) => T['element']
getItemSuffixProps(props: TreeNodeProps) => T['element']
getItemIndicatorProps(props: TreeNodeProps) => T['element']
getBranchProps(props: TreeNodeProps) => T['element']
getBranchControlProps(props: TreeNodeProps) => T['element']
getBranchTriggerProps(props: TreeNodeProps) => T['element']
getBranchIndicatorProps(props: TreeNodeProps) => T['element']
getBranchTextProps(props: TreeNodeProps) => T['element']
getBranchDescriptionProps(props: TreeNodeProps) => T['element']分支行的第 2 行副文本,与叶子的 item-description 同一档。
getBranchContentProps(props: TreeNodeProps) => T['element']
getBranchLoadingProps(props: TreeNodeProps) => T['element']懒分支取数在途:组件或元素在分支里自己补出,展开且在途时露面。
getBranchErrorProps(props: TreeNodeProps) => T['element']懒分支取数失败的说明:展开且失败时露面。
getBranchRetryTriggerProps(props: TreeNodeProps) => T['button']懒分支失败后的重试按钮:不占 Tab 位,键盘在分支上按确认键即重试。
getBranchEmptyProps(props: TreeNodeProps) => T['element']懒分支取回了空数组:展开时露面。

无障碍 ​

键盘 ​

规格出处:W3C APG

按键生效条件行为
Tab / Shift+Tabfocus outside the tree整棵树只占一个 Tab 位:焦点进入锚点节点,无锚点时先落容器再由它转投
ArrowDownfocus in tree焦点移到下一个可见行(禁用行跳过;loop 默认关,末行不回绕)
ArrowUpfocus in tree焦点移到上一个可见行(禁用行跳过;loop 默认关,首行不回绕)
Homefocus in tree焦点移到首个可见行
Endfocus in tree焦点移到末个可见行(展开着的子树也算行)
ArrowRightfocus on branch(dir=rtl 时改由 ArrowLeft 承担)收起的分支就地展开;已展开则把焦点移到首个子节点;叶子上什么都不做且不吞键
ArrowLeftfocus in tree(dir=rtl 时改由 ArrowRight 承担)展开的分支就地收起;收起的分支与叶子则把焦点移到父节点;根层的行什么都不做
Enter / Spacefocus on node, 节点未禁用选中焦点节点:selectionMode 为 single 或 extended 时换成这一项,multiple 时切换;焦点在分支上且 expandOnClick 打开时顺带切换展开态
Enter / Spacefocus on branch, 懒分支取数失败重试该分支,焦点留在分支行;不改变选中值与展开集合
Ctrl+Space / Cmd+Spacefocus on node, selectionMode 为 multiple 或 extended、节点未禁用只切换焦点节点的选中态,其余选中不动,不改展开态
Enter / Spaceheld on node, 树未禁用、未加载且节点未禁用按住期间叶子行或分支行(branch-control)投影 data-pressed,与指针 :active 同一副按压面;抬起或失焦撤下。选中与展开语义照旧由这一次按键承担
*focus in tree展开与焦点行同一父级的全部分支(已展开与禁用的不动);同级没有可展开的分支时不吞这个键
单个可打印字符focus in tree, typeahead 未关连打检索在可见行上按 label 首字母搬焦点,不改选中值,也不展开任何分支
Alt+ArrowUp / Alt+ArrowDownfocus in tree, draggable 开启把焦点节点在同一层的兄弟里往前 / 往后挪一位,按一下就是一次完整提交,不进拖动态;纵轴与文字方向无关,rtl 下两键不对调;已是同层首位 / 末位就不动,也不回绕;落点节点禁用或 allowDrop 不许就不搬。裸方向键仍是走可见行、确认键仍是选中
Alt+ArrowLeft / Alt+ArrowRightfocus in tree, draggable 开启改焦点节点的缩进层级:往里去是认上一个兄弟当父、落进它子层末位,往外去是变成父节点的下一个兄弟;rtl 下两键对调,「往里去」的那个方向恒是缩进。没有上一个兄弟就缩不进去,已在根层就退不出去,两种情形都不动;落点节点禁用或 allowDrop 不许就不搬

ARIA ​

以下属性由 connect 生成。

部件属性值
treearia-busy'true' | undefined
treearia-disabled'true' | 'false'
treearia-labelledbylabel 部件的 id | undefined
treearia-multiselectable'true' | 'false'
treearia-orientation'vertical'
treerole'tree'
itemaria-checked'true' | 'mixed' | 'false' | undefined
itemaria-disabled'true' | 'false'
itemaria-levelmeta?.level
itemaria-posinsetmeta?.posInSet
itemaria-selected'true' | 'false'
itemaria-setsizemeta?.setSize
itemrole'treeitem'
item-indicatoraria-hidden'true'
brancharia-busy'true' | undefined
brancharia-checked'true' | 'mixed' | 'false' | undefined
brancharia-disabled'true' | 'false'
brancharia-expanded'true' | 'false'
brancharia-levelmeta?.level
brancharia-posinsetmeta?.posInSet
brancharia-selected'true' | 'false'
brancharia-setsizemeta?.setSize
branchrole'treeitem'
branch-triggeraria-hidden'true'
branch-indicatoraria-hidden'true'
branch-contentrole'group'
branch-loadingrole'status'
branch-errorrole'alert'
branch-retry-triggeraria-labeltranslations.retry
branch-emptyrole'status'
node-drag-triggeraria-hidden'true'
live-regionaria-atomic'true'
live-regionaria-live'polite'
live-regionrole'status'

样式参考 ​

皮肤 ​

@xihan-ui/styles/tree.css 按 [data-scope="tree"][data-part="root"] 部件选择器书写,发布产物以挂载类 .xh-scope-tree 代替其中的 data-scope(特异性相同),位于 xihan.components 层。覆盖样式使用 xihan.overrides,部件选择器照常可用。

forced-colors: active 下另有一套规则:颜色交给系统,边框与状态标记改用系统色关键字。

数据属性 ​

由 connect 生成;条件不成立时不输出无值属性。

部件属性值
rootdata-disabled''(条件成立时才出现)
rootdata-loading''(条件成立时才出现)
rootdata-orientation'vertical'
rootdata-sizeprops.size
rootdata-variantprops.variant
labeldata-disabled''(条件成立时才出现)
treedata-disabled''(条件成立时才出现)
treedata-lines''(条件成立时才出现)
treedata-loading''(条件成立时才出现)
treedata-orientation'vertical'
itemdata-disabled''(条件成立时才出现)
itemdata-draggable''(条件成立时才出现)
itemdata-dragging''(条件成立时才出现)
itemdata-drop'before' | 'after' | 'inside'
itemdata-highlighted''(条件成立时才出现)
itemdata-indeterminate''(条件成立时才出现)
itemdata-pressed''(条件成立时才出现)
itemdata-selected''(条件成立时才出现)
itemdata-tonemetaOf(value)?.tone
itemdata-xh-collection-context'overlay'
itemdata-xh-collection-item''
itemdata-xh-collection-sizeprops.size
item-indicatordata-disabled''(条件成立时才出现)
item-indicatordata-highlighted''(条件成立时才出现)
item-indicatordata-indeterminate''(条件成立时才出现)
item-indicatordata-selected''(条件成立时才出现)
item-indicatordata-xh-collection-slot'indicator'
item-textdata-disabled''(条件成立时才出现)
item-textdata-highlighted''(条件成立时才出现)
item-textdata-indeterminate''(条件成立时才出现)
item-textdata-selected''(条件成立时才出现)
item-textdata-xh-collection-slot'text'
item-descriptiondata-disabled''(条件成立时才出现)
item-descriptiondata-highlighted''(条件成立时才出现)
item-descriptiondata-indeterminate''(条件成立时才出现)
item-descriptiondata-selected''(条件成立时才出现)
item-descriptiondata-xh-collection-slot'description'
item-suffixdata-disabled''(条件成立时才出现)
item-suffixdata-highlighted''(条件成立时才出现)
item-suffixdata-indeterminate''(条件成立时才出现)
item-suffixdata-selected''(条件成立时才出现)
item-suffixdata-xh-collection-slot'suffix'
branchdata-disabled''(条件成立时才出现)
branchdata-empty''(条件成立时才出现)
branchdata-error''(条件成立时才出现)
branchdata-highlighted''(条件成立时才出现)
branchdata-indeterminate''(条件成立时才出现)
branchdata-load-statebranchLoadState(value)?.status
branchdata-loading''(条件成立时才出现)
branchdata-selected''(条件成立时才出现)
branchdata-state'open' | 'closed'
branch-controldata-disabled''(条件成立时才出现)
branch-controldata-draggable''(条件成立时才出现)
branch-controldata-dragging''(条件成立时才出现)
branch-controldata-drop'before' | 'after' | 'inside'
branch-controldata-highlighted''(条件成立时才出现)
branch-controldata-indeterminate''(条件成立时才出现)
branch-controldata-pressed''(条件成立时才出现)
branch-controldata-selected''(条件成立时才出现)
branch-controldata-state'open' | 'closed'
branch-controldata-tonemetaOf(value)?.tone
branch-controldata-xh-collection-context'overlay'
branch-controldata-xh-collection-item''
branch-controldata-xh-collection-sizeprops.size
branch-triggerdata-disabled''(条件成立时才出现)
branch-triggerdata-highlighted''(条件成立时才出现)
branch-triggerdata-indeterminate''(条件成立时才出现)
branch-triggerdata-selected''(条件成立时才出现)
branch-triggerdata-state'open' | 'closed'
branch-triggerdata-xh-collection-slot'prefix'
branch-indicatordata-disabled''(条件成立时才出现)
branch-indicatordata-highlighted''(条件成立时才出现)
branch-indicatordata-indeterminate''(条件成立时才出现)
branch-indicatordata-selected''(条件成立时才出现)
branch-indicatordata-state'open' | 'closed'
branch-indicatordata-xh-collection-slot'prefix'
branch-textdata-disabled''(条件成立时才出现)
branch-textdata-highlighted''(条件成立时才出现)
branch-textdata-indeterminate''(条件成立时才出现)
branch-textdata-selected''(条件成立时才出现)
branch-textdata-state'open' | 'closed'
branch-textdata-xh-collection-slot'text'
branch-descriptiondata-disabled''(条件成立时才出现)
branch-descriptiondata-highlighted''(条件成立时才出现)
branch-descriptiondata-indeterminate''(条件成立时才出现)
branch-descriptiondata-selected''(条件成立时才出现)
branch-descriptiondata-state'open' | 'closed'
branch-descriptiondata-xh-collection-slot'description'
branch-contentdata-disabled''(条件成立时才出现)
branch-contentdata-highlighted''(条件成立时才出现)
branch-contentdata-indeterminate''(条件成立时才出现)
branch-contentdata-orientation'horizontal' | 'vertical'
branch-contentdata-selected''(条件成立时才出现)
branch-contentdata-state'open' | 'closed'
branch-loadingdata-disabled''(条件成立时才出现)
branch-loadingdata-empty''(条件成立时才出现)
branch-loadingdata-error''(条件成立时才出现)
branch-loadingdata-highlighted''(条件成立时才出现)
branch-loadingdata-indeterminate''(条件成立时才出现)
branch-loadingdata-load-statebranchLoadState(value)?.status
branch-loadingdata-loading''(条件成立时才出现)
branch-loadingdata-selected''(条件成立时才出现)
branch-loadingdata-state'open' | 'closed'
branch-loadingdata-xh-loading-ring''
branch-errordata-disabled''(条件成立时才出现)
branch-errordata-empty''(条件成立时才出现)
branch-errordata-error''(条件成立时才出现)
branch-errordata-highlighted''(条件成立时才出现)
branch-errordata-indeterminate''(条件成立时才出现)
branch-errordata-load-statebranchLoadState(value)?.status
branch-errordata-selected''(条件成立时才出现)
branch-errordata-state'open' | 'closed'
branch-retry-triggerdata-disabled''(条件成立时才出现)
branch-retry-triggerdata-empty''(条件成立时才出现)
branch-retry-triggerdata-error''(条件成立时才出现)
branch-retry-triggerdata-highlighted''(条件成立时才出现)
branch-retry-triggerdata-indeterminate''(条件成立时才出现)
branch-retry-triggerdata-load-statebranchLoadState(value)?.status
branch-retry-triggerdata-selected''(条件成立时才出现)
branch-retry-triggerdata-state'open' | 'closed'
branch-emptydata-disabled''(条件成立时才出现)
branch-emptydata-empty''(条件成立时才出现)
branch-emptydata-error''(条件成立时才出现)
branch-emptydata-highlighted''(条件成立时才出现)
branch-emptydata-indeterminate''(条件成立时才出现)
branch-emptydata-load-statebranchLoadState(value)?.status
branch-emptydata-selected''(条件成立时才出现)
branch-emptydata-state'open' | 'closed'
node-drag-triggerdata-disabled''(条件成立时才出现)
node-drag-triggerdata-dragging''(条件成立时才出现)
node-drag-triggerdata-xh-collection-slot'prefix'
emptydata-disabled''(条件成立时才出现)
loadingdata-disabled''(条件成立时才出现)
loadingdata-loading''(条件成立时才出现)
loadingdata-xh-loading-ring''

CSS 变量 ​

本组件公开覆盖槽由独立皮肤的实际消费位生成;默认来源、作用部件和状态均与 CSS 同源。

变量部件CSS 属性状态默认来源说明
--xh-tree-bgroot
tree
backgrounddefault
variant=subtle
--xh-bg-subtle
--xh-bg-surface
tree 的 root、tree 部件 background 覆盖槽。
--xh-tree-bordertreeborderdefault--xh-border-defaulttree 的 tree 部件 border 覆盖槽。
--xh-tree-branch-content-gapbranch
branch-content
branch-control
item
tree
background
gap
inset-block
row-gap
default
lines
not(:last-child)
orientation=horizontal
orientation=vertical
--xh-space-0tree 的 branch、branch-content、branch-control、item、tree 部件 background、gap、inset-block、row-gap 覆盖槽。
--xh-tree-branch-error-fgbranch-errorbackground-colordefault--xh-fg-dangertree 的 branch-error 部件 background-color 覆盖槽。
--xh-tree-branch-gapbranch
branch-content
branch-control
item
tree
background
gap
inset-block
default
first-child
lines
orientation=vertical
state=open
--xh-space-0tree 的 branch、branch-content、branch-control、item、tree 部件 background、gap、inset-block 覆盖槽。
--xh-tree-branch-indicator-fgbranch-indicator
branch-trigger
colordefault--xh-fg-mutedtree 的 branch-indicator、branch-trigger 部件 color 覆盖槽。
--xh-tree-branch-loading-fgbranch
branch-control
branch-indicator
branch-trigger
colorloading--xh-fg-brandtree 的 branch、branch-control、branch-indicator、branch-trigger 部件 color 覆盖槽。
--xh-tree-branch-retry-fgbranch-retry-triggercolordefault--xh-fg-brandtree 的 branch-retry-trigger 部件 color 覆盖槽。
--xh-tree-branch-status-fgbranch-empty
branch-error
branch-loading
coloris([data-part='branch-loading'], [data-part='branch-empty'], [data-part='branch-error'])--xh-fg-mutedtree 的 branch-empty、branch-error、branch-loading 部件 color 覆盖槽。
--xh-tree-branch-status-font-sizebranch-empty
branch-error
branch-loading
branch-retry-trigger
font-sizedefault
is([data-part='branch-loading'], [data-part='branch-empty'], [data-part='branch-error'])
--xh-_tree-font-sizetree 的 branch-empty、branch-error、branch-loading、branch-retry-trigger 部件 font-size 覆盖槽。
--xh-tree-branch-status-pybranch-empty
branch-error
branch-loading
padding-blockis([data-part='branch-loading'], [data-part='branch-empty'], [data-part='branch-error'])--xh-_tree-row-pytree 的 branch-empty、branch-error、branch-loading 部件 padding-block 覆盖槽。
--xh-tree-drag-fgnode-drag-triggercolordefault--xh-fg-subtletree 的 node-drag-trigger 部件 color 覆盖槽。
--xh-tree-drag-fg-activenode-drag-triggercolordisabled
dragging
hover
not([data-disabled])
--xh-fg-defaulttree 的 node-drag-trigger 部件 color 覆盖槽。
--xh-tree-drag-fg-disablednode-drag-triggercolordisabled--xh-fg-disabledtree 的 node-drag-trigger 部件 color 覆盖槽。
--xh-tree-drag-grip-longnode-drag-triggerinline-sizeempty--xh-space-2tree 的 node-drag-trigger 部件 inline-size 覆盖槽。
--xh-tree-drag-grip-shortnode-drag-triggerblock-sizeempty--xh-space-1tree 的 node-drag-trigger 部件 block-size 覆盖槽。
--xh-tree-drag-radiusnode-drag-triggerborder-radiusdefault--xh-shape-controltree 的 node-drag-trigger 部件 border-radius 覆盖槽。
--xh-tree-drag-sizenode-drag-triggerblock-size
inline-size
default--xh-_tree-indicatortree 的 node-drag-trigger 部件 block-size、inline-size 覆盖槽。
--xh-tree-dragging-opacitybranch-control
item
opacitydragging--xh-state-dragging-opacitytree 的 branch-control、item 部件 opacity 覆盖槽。
--xh-tree-drop-fgbranch-control
item
background
box-shadow
disabled
drop=after
drop=before
drop=inside
is([data-drop='before'], [data-drop='after'])
not([data-disabled])
--xh-bg-brandtree 的 branch-control、item 部件 background、box-shadow 覆盖槽。
--xh-tree-drop-inside-bgbranch-control
item
backgrounddisabled
drop=inside
not([data-disabled])
--xh-bg-subtle-hovertree 的 branch-control、item 部件 background 覆盖槽。
--xh-tree-drop-linebranch-control
item
block-size
box-shadow
disabled
drop=after
drop=before
drop=inside
is([data-drop='before'], [data-drop='after'])
not([data-disabled])
--xh-stroke-thicktree 的 branch-control、item 部件 block-size、box-shadow 覆盖槽。
--xh-tree-empty-fgemptycolordefault--xh-fg-mutedtree 的 empty 部件 color 覆盖槽。
--xh-tree-empty-font-sizeemptyfont-sizedefault--xh-_tree-font-sizetree 的 empty 部件 font-size 覆盖槽。
--xh-tree-empty-pxemptypadding-inlinedefault--xh-_tree-row-pxtree 的 empty 部件 padding-inline 覆盖槽。
--xh-tree-empty-pyemptypadding-blockdefault--xh-space-3tree 的 empty 部件 padding-block 覆盖槽。
--xh-tree-fgtreecolordefault--xh-fg-defaulttree 的 tree 部件 color 覆盖槽。
--xh-tree-gaprootgapdefault--xh-space-2tree 的 root 部件 gap 覆盖槽。
--xh-tree-icon-sizebranch-control
item
root
--xh-icon-sizedefault
size=lg
size=sm
--xh-_collection-glyph-size
--xh-glyph-size-lg
--xh-glyph-size-md
--xh-glyph-size-sm
tree 的 branch-control、item、root 部件 --xh-icon-size 覆盖槽。
--xh-tree-indentbranch
branch-content
branch-control
branch-empty
branch-error
branch-loading
branch-retry-trigger
item
tree
inline-size
inset-inline-start
margin-inline-start
padding-inline
padding-inline-start
default
is([data-part='branch-loading'], [data-part='branch-empty'], [data-part='branch-error'])
lines
not(:last-child)
orientation=vertical
--xh-_tree-indenttree 的 branch、branch-content、branch-control、branch-empty、branch-error、branch-loading、branch-retry-trigger、item、tree 部件 inline-size、inset-inline-start、margin-inline-start、padding-inline、padding-inline-start 覆盖槽。
--xh-tree-indicator-sizebranch
branch-content
branch-control
branch-description
branch-indicator
branch-trigger
item
item-indicator
tree
--xh-icon-size
inline-size
inset-inline-start
padding-inline-start
default
has(> [data-scope='tree'][data-part='branch-trigger']:first-child)
lines
not(:last-child)
orientation=vertical
--xh-_tree-indicatortree 的 branch、branch-content、branch-control、branch-description、branch-indicator、branch-trigger、item、item-indicator、tree 部件 --xh-icon-size、inline-size、inset-inline-start、padding-inline-start 覆盖槽。
--xh-tree-item-check-fgbranch-control
item
colordisabled
error
highlighted
hover
is(:active, [data-pressed])
is(:focus-visible, [data-highlighted])
is([aria-selected='true'], [data-selected])
not([aria-disabled='true'], [data-disabled], [aria-busy='true'], [data-error])
pressed
selected
state=checked
xh-collection-context=overlay
xh-collection-slot=indicator
--xh-tree-item-indicator-fgtree 的 branch-control、item 部件 color 覆盖槽。
--xh-tree-item-indicator-fgbranch-control
item
colordisabled
error
highlighted
hover
is(:active, [data-pressed])
is(:focus-visible, [data-highlighted])
is([aria-selected='true'], [data-selected])
not([aria-disabled='true'], [data-disabled], [aria-busy='true'], [data-error])
pressed
selected
state=checked
xh-collection-context=overlay
xh-collection-slot=indicator
--xh-fg-brandtree 的 branch-control、item 部件 color 覆盖槽。
--xh-tree-label-fglabelcolordefault--xh-fg-mutedtree 的 label 部件 color 覆盖槽。
--xh-tree-label-font-sizelabelfont-sizedefault--xh-text-label-sizetree 的 label 部件 font-size 覆盖槽。
--xh-tree-label-font-weightlabelfont-weightdefault--xh-text-label-weighttree 的 label 部件 font-weight 覆盖槽。
--xh-tree-leaf-row-gapbranch-contentcolumn-gaporientation=horizontal--xh-space-3tree 的 branch-content 部件 column-gap 覆盖槽。
--xh-tree-line-colorbranch
branch-content
branch-control
item
tree
background
border-block-end
border-inline-start
last-child
lines
not(:last-child)
orientation=vertical
--xh-border-defaulttree 的 branch、branch-content、branch-control、item、tree 部件 background、border-block-end、border-inline-start 覆盖槽。
--xh-tree-loading-fgloadingcolordefault--xh-fg-mutedtree 的 loading 部件 color 覆盖槽。
--xh-tree-loading-font-sizeloadingfont-sizedefault--xh-_tree-font-sizetree 的 loading 部件 font-size 覆盖槽。
--xh-tree-loading-gaploadinggapdefault--xh-_tree-row-gaptree 的 loading 部件 gap 覆盖槽。
--xh-tree-loading-pxloadingpadding-inlinedefault--xh-_tree-row-pxtree 的 loading 部件 padding-inline 覆盖槽。
--xh-tree-loading-pyloadingpadding-blockdefault--xh-space-3tree 的 loading 部件 padding-block 覆盖槽。
--xh-tree-max-htreemax-block-sizedefault--xh-viewport-h-lgtree 的 tree 部件 max-block-size 覆盖槽。
--xh-tree-pxtreepadding-inlinedefault--xh-space-1tree 的 tree 部件 padding-inline 覆盖槽。
--xh-tree-pytreepadding-blockdefault--xh-space-1tree 的 tree 部件 padding-block 覆盖槽。
--xh-tree-radiustreeborder-radiusdefault--xh-shape-surfacetree 的 tree 部件 border-radius 覆盖槽。
--xh-tree-row-bg-hoverbranch-control
item
background-colordisabled
error
highlighted
hover
is(:focus-visible, [data-highlighted])
is([aria-selected='true'], [data-selected])
not([aria-disabled='true'], [data-disabled], [aria-busy='true'], [data-error])
selected
xh-collection-context=overlay
--xh-bg-subtletree 的 branch-control、item 部件 background-color 覆盖槽。
--xh-tree-row-bg-pressedbranch-control
item
background-colordisabled
error
is(:active, [data-pressed])
is([aria-selected='true'], [data-selected])
not([aria-disabled='true'], [data-disabled], [aria-busy='true'], [data-error])
pressed
selected
xh-collection-context=overlay
--xh-bg-subtle-hovertree 的 branch-control、item 部件 background-color 覆盖槽。
--xh-tree-row-fgbranch-control
item
colordefault
disabled
error
highlighted
hover
is(:active, [data-pressed])
is(:focus-visible, [data-highlighted])
is([aria-selected='true'], [data-selected])
not([aria-disabled='true'], [data-disabled], [aria-busy='true'], [data-error])
pressed
selected
xh-collection-context=overlay
--xh-fg-defaulttree 的 branch-control、item 部件 color 覆盖槽。
--xh-tree-row-fg-selectedbranch-control
item
colordisabled
error
highlighted
hover
is(:active, [data-pressed])
is(:focus-visible, [data-highlighted])
is([aria-selected='true'], [data-selected])
not([aria-disabled='true'], [data-disabled], [aria-busy='true'], [data-error])
pressed
selected
xh-collection-context=overlay
--xh-tree-row-fgtree 的 branch-control、item 部件 color 覆盖槽。
--xh-tree-row-font-sizebranch-control
item
font-sizedefault--xh-_tree-font-sizetree 的 branch-control、item 部件 font-size 覆盖槽。
--xh-tree-row-gapbranch-control
branch-description
item
gap
padding-inline-start
default
has(> [data-scope='tree'][data-part='branch-trigger']:first-child)
orientation=vertical
--xh-_tree-row-gaptree 的 branch-control、branch-description、item 部件 gap、padding-inline-start 覆盖槽。
--xh-tree-row-leadingbranch-control
item
line-heightdefault--xh-leading-normaltree 的 branch-control、item 部件 line-height 覆盖槽。
--xh-tree-row-loading-opacitybranch-control
item
tree
opacityis([data-scope='tree'][data-part='item'], [data-scope='tree'][data-part='branch-control'])
loading
--xh-state-disabled-opacitytree 的 branch-control、item、tree 部件 opacity 覆盖槽。
--xh-tree-row-pxbranch
branch-content
branch-control
item
tree
inline-size
inset-inline-start
padding-inline
padding-inline-start
default
lines
not(:last-child)
orientation=vertical
--xh-_tree-row-pxtree 的 branch、branch-content、branch-control、item、tree 部件 inline-size、inset-inline-start、padding-inline、padding-inline-start 覆盖槽。
--xh-tree-row-pybranch-control
item
padding-blockdefault--xh-_tree-row-pytree 的 branch-control、item 部件 padding-block 覆盖槽。
--xh-tree-row-radiusbranch-control
item
border-radiusdefault--xh-shape-insettree 的 branch-control、item 部件 border-radius 覆盖槽。
--xh-tree-row-selected-font-weightbranch-control
item
font-weightdisabled
error
highlighted
hover
is(:active, [data-pressed])
is(:focus-visible, [data-highlighted])
is([aria-selected='true'], [data-selected])
not([aria-disabled='true'], [data-disabled], [aria-busy='true'], [data-error])
pressed
selected
xh-collection-context=overlay
--xh-font-weight-regulartree 的 branch-control、item 部件 font-weight 覆盖槽。
--xh-tree-tree-gaptreegapdefault--xh-space-0tree 的 tree 部件 gap 覆盖槽。

动效 ​

动效角色:按压 · 状态 · 指示与换位 · 披露 · 出现 · 循环(见动效规范)。

共享关键帧 xh-fade-in · xh-spin 由 family/motion.css 提供,皮肤 @import 它,单独引入仍成立;-webkit-mask-size · background-color · box-shadow · color · mask-size · opacity · rotate · text-decoration-color · translate 走 transition 过渡。时长与缓动读动效令牌,改令牌即改全局节奏。

prefers-reduced-motion: reduce 下本组件另有降级规则。

RTL ​

皮肤用逻辑属性排布(inline-start 一族),dir="rtl" 下自动镜像;只认物理方向的量乘 --xh-direction-sign 换向,按就近的 dir 走。

Released under The MIT License