生态产品多个设计器现已发布候选版本

查看生态总览
跳转到内容

JsonViewer JSON 视图 ​

把一份 JSON 展开为可折叠的树:键名、值与值类型各自成块,对象与数组可以逐层收起。

用法 ​

一份 JSON 展开为可折叠的树:键名与值各自成块,六种类型各自上色,默认只展开根行

root
name"曦寒视图"
version"1.0.0-alpha.2"
stars128
activetrue
homepagenull

组件结构 ​

加粗的是必需部件。

data-scope="json-viewer":root · tree · item · item-key · item-value · branch · branch-control · branch-trigger · branch-indicator · branch-text · branch-summary · branch-content · preview · text · token · empty · mark · toolbar · expand-trigger · wrap-trigger · copy-trigger · view-trigger · status

示例 ​

默认展开层数 ​

defaultExpandedDepth 决定初次展开到第几层:1 只展开根行,3 连孙层一起铺开

root
root
server
host"127.0.0.1"
port5173
tls
enabledfalse
certnull
build
target"es2022"
minifytrue

受控展开 ​

传入 expandedValue 后由宿主决定,组件只发 expanded-value-change 不落内部值,写回后才变化

root
展开了 1 处

大数据 ​

maxItems 把超长数组折为一行占位,maxStringLength 截断过长的字符串,一份大 JSON 不会拖慢页面

root
total240
cursor"eyJvZmZzZXQiOjAsImxpbWl0…"
items
0"第 1 条"
1"第 2 条"
2"第 3 条"
3"第 4 条"
4"第 5 条"
… 235 more

键排序 ​

sortKeys 使对象键按字典序排列,数组顺序不变;接口返回的字段顺序不稳定时使用它

root
action"deploy"
meta
at"2026-08-20"
by"ci"
retries2
steps
0"build"
1"test"
2"publish"
zone"cn-east-1"

循环引用 ​

值出现在自己的祖先链上即停止并标为 [Circular],不会无限递归;共享引用不算环,照常展开

root
name"root"
left
id1
right
id1
parent[Circular]

尺寸 ​

size 三档只改变字号与层级缩进,行的结构与配色都不变

root
id7
label"曦寒"
nested
oktrue
root
id7
label"曦寒"
nested
oktrue
root
id7
label"曦寒"
nested
oktrue

原文视图 ​

view="text" 直接输出缩进后的 JSON 原文:整块可框选可复制,且不受 maxStringLength / maxItems 折减

{
  "orderNo": "SO-2026-0825-0417",
  "amount": 12.5,
  "items": [
    {
      "sku": "A-1001",
      "qty": 2
    },
    {
      "sku": "B-2003",
      "qty": 1
    }
  ],
  "remark": "跨境订单,需人工复核收件地址与税号"
}

空态与形态 ​

一行都无法展开时显示空态格;variant="ghost" 去掉外框与底色

这份接口还没有返回内容
No data

搜索 ​

search 标出键名与值里含有搜索词的行并展开它们的祖先,命中的那一段铺成 mark;工具条里的上一条 / 下一条在命中之间逐个走,停住的那一条换成实心并滚进视野

0 / 4
root
name"曦寒视图"
version"1.0.0-alpha.2"

内建工具条 ​

tools 打开内建工具条:树档有展开全部 / 收起全部,原文档有自动换行,复制原文与原文开关固定在末端;数组只铺列出的几项

root
traceId"9ef5a8c3e1b44f0f"
request
method"POST"
url"/api/workflow/definition/new-version?tenant=hangzhou-branch&operator=owner&reason=quarterly-review"
response
status200
elapsed35
{
  "traceId": "9ef5a8c3e1b44f0f",
  "request": {
    "method": "POST",
    "url": "/api/workflow/definition/new-version?tenant=hangzhou-branch&operator=owner&reason=quarterly-review",
    "headers": {
      "content-type": "application/json",
      "x-request-id": "c0d1e2f3"
    }
  },
  "response": {
    "status": 200,
    "elapsed": 35,
    "body": {
      "id": "207795978470952990",
      "version": 3
    }
  }
}

设计指引 ​

何时使用 ​

  • 调试面板、接口返回体、配置文件的只读呈现。
  • 日志详情中的大段结构化字段,直接铺开会淹没正文。

何时不用 ​

  • 数据可编辑时,本组件只读;修改值需要自行接入表单与文本字段。
  • 数据只是一段带语法高亮的源码时,使用代码视图。
  • 层级数据不是 JSON、键名与类型没有语义时,使用树;它处理通用层级数据与选中,本组件处理 JSON 的类型语义(键名、值形态、按类型着色、循环引用)。
  • 只有几个字段需要平铺展示时,使用描述列表。

特性 ​

  • 行结构由 value 展开,作者不写任何行标记:Vue 与自定义元素两侧铺出同一棵 DOM,根容器内原有内容由组件接管。
  • 自定义渲染器可调用 groupJsonViewerNodesByParent(nodes) 把可见行按父路径分组;返回值保留父路径首次出现顺序、组内输入顺序与节点身份。
  • 未提供 value 时是空视图,不展开任何行;对象内确实存在值为 undefined 的成员时,该行照常展开。
  • 展开集合可受控(expandedValue / defaultExpandedValue),非受控时按 defaultExpandedDepth 计算:数据晚于组件挂载到达(自定义元素常先升级、再由脚本写 .value)也能计算,第一次展开或收起之后固定,不再跟随数据。
  • maxStringLength 截断长字符串,maxItems 折叠超长数组,sortKeys 让对象键按字典序排列。
  • 循环引用展开到即停,标记为 [Circular],不会无限递归。
  • 每一行带 data-value-type,六种值形态各自着色。原文档同样着色:原文按类别切成 token 部件(data-kind 为 key、string、number、boolean、null、punctuation),与树档使用同一组覆盖槽与语法令牌;原文无法识别为 JSON 时整段不着色。
  • 尺寸轴与其他组件同源;variant 决定外框形态,默认 outline;subtle 换成淡底无描边,ghost 去掉外框与底色只保留内容。
  • 没有任何行可展开时由 empty 部件说明,文案使用 translations.empty,作者也可以自行写入内容。
  • 内建工具条按需打开:tools 不提供即没有工具条;true 铺出全部工具;数组只铺列出的几项(expand、wrap、copy、view),数组里出现未知的工具名会抛错。条是根的第一个孩子,钮的排列由组件决定:展开 / 收起全部是一颗切换钮,只在树档出现:还有收着的分支时按下展开全部,已经全部展开时按下收回顶层,名称与字形随之变化;「自动换行」只在原文档出现;复制与树 / 原文切换钮固定在末端,切换形态时这两颗不移动,切换钮的名称与字形取要切去的那一档。
  • 树 / 原文切换钮改写 view:view 提供即受控,开关只触发 onViewChange;defaultView 是非受控初值。自动换行同理(wrap / defaultWrap / onWrapChange),开启后原文的长行折到下一行而不是横向滚动。
  • 复制钮写入的是原文档那一份文本(不受 maxStringLength / maxItems 折减),无论当前处于哪一档;成功后钮换成对钩约 3 秒,写入失败时回到常态并触发 onCopyError。剪贴板接口要求安全上下文。
  • 手里有值的原文(如后端下发的 JSON 文本)时传给 source:原文档与复制钮改用它,能解析成 JSON 就只按两格缩进重排,数字、字符串等字面量保持不变,解析不了就原样显示。value 是解析过的值,超出安全整数的数字(如 64 位 ID)已经失真,只有原文与来源一致;树档仍展示 value。headless 另导出同一个重排函数 formatJsonSource。
  • 只支持 JSON 能表达的形状,传入活对象时呈现有损:Date / Map / Set 一律按自有可枚举键展开,因此显示为 {};undefined 归入 null 一档、显示为 undefined;bigint 归入 number;函数与 symbol 归入 string,按各自的字符串形式呈现。需要如实展示这些值时先转换为 JSON 能表达的形状。
  • 自定义元素侧:value 属性接受一段 JSON 文本(无法解析时按字符串值展示),对象与数组直接赋 property(el.value = { … });expandedValue / defaultExpandedValue / translations 没有对应属性,只能通过 property 设置,写成 expanded-value='["$"]' 不会生效。

组合 ​

  • 搜索:search 标出键名与值里含有搜索词的行(不区分大小写),命中行的祖先分支自动展开(写进展开集合,之后照常能收起),命中的那一段铺成 mark 部件。搜索框与上一条 / 下一条由作者摆在树之前:Vue 写进 toolbar 插槽,React 经 toolbar 传入,载荷是 searchMatches、activeMatch、nextMatch、prevMatch;Web Components 在元素上取 searchMatches / activeMatch 并调用 nextMatch() / prevMatch()。停住的那一条投影 data-current、命中片段换成实心,并被滚进视野。

  • 放入标签页或抽屉作为调试面板;行数多时套一层滚动区域。

  • 只需要复制原文时打开 tools 的 copy 一项;复制钮要放在别处或换成带文字的样式时,改用剪贴板并把 jsonText(value, sortKeys) 的结果交给它。

  • 搜索框(toolbar 插槽)与内建工具条可以同时使用:插槽内容排在根之前,内建工具条排在根内的最前面。

最佳实践 ​

  • 大数据必须提供 maxItems 与 maxStringLength:一次展开几万行会让页面停滞。
  • 默认展开层数不宜过大:defaultExpandedDepth 超过 2 会把整份数据铺满屏幕。
  • 值的类型只靠颜色区分不够,字符串的引号、null 的字面量都要保留。
  • 一行被收起时,其内部持有焦点的行会离开 DOM,焦点回到 <body>。应在收起前把焦点交回分支行本身,键盘用户才不会每收一层就丢失位置。

反模式 ​

  • 将它用作日志流:日志是时间序的条目,使用日志。
  • 把几 MB 的响应体原样传入,让用户自行查找。

API 参考 ​

产物 ​

层值
自定义元素<xh-json-viewer>
Vue 组件XhJsonViewerRoot
组合式函数useJsonViewer
状态机jsonViewerMachine
皮肤@xihan-ui/styles/json-viewer.css

Props ​

属性类型必填说明
valueunknown要展示的值,任意形状。未提供时为空视图(不展开任何行)。
viewJsonViewerView展示形态。提供即受控:cell 直读 prop,原文开关只发 onViewChange 不落内部值。 text 档直接输出 JSON 原文:整块可框选可复制,且不受 maxStringLength / maxItems 折减: 目的是与后端下发的内容完全一致。展开集合与键盘导航在该档上不生效。
defaultViewJsonViewerView非受控初值,默认 tree。
sourcestring值的原文(如后端下发的那段 JSON 文本)。提供时原文档与复制钮一律取它:能解析成 JSON 就只按两格缩进重排, 数字、字符串等字面量一字不改;解析不了就原样。value 是解析过的值,超出安全整数的数字已经失真, 原文才是与后端一致的那一份。不提供时由 value 序列化。树档照旧展示 value。
wrapboolean原文档是否自动换行。提供即受控,写入只发 onWrapChange。缺省不换行:长行横向滚动,缩进不被折乱。
defaultWrapboolean非受控初值,默认 false。
toolsboolean | readonly JsonViewerTool[]内建工具条:不提供即没有工具条;true 铺出全部工具;数组只铺列出的几项。 钮的排列由组件定(展开 / 收起、换行、复制、原文开关依次排在条的末端),与数组顺序无关; 数组里出现未知的工具名即抛错。
variantControlVariant外框形态:outline 带描边与底色(默认),subtle 淡底无描边,ghost 去掉描边与底色只保留内容。
expandedValuestring[]展开集合(元素是行路径)。提供即受控:cell 直读 prop,写入只发 onExpandedValueChange 不落内部值。
defaultExpandedValuestring[]非受控初值;未提供时按 defaultExpandedDepth 计算。
defaultExpandedDepthnumber初始展开到第几层(层级号不超过它的分支全部展开),默认 1,即只展开根行。
maxStringLengthnumber字符串值超过该字符数即截断并补省略号;未提供时不截断。
maxItemsnumber同一层最多展开该数量的成员,其余收为一行占位;未提供时全部展开。
sortKeysboolean对象键按字典序排列;数组顺序不受影响。
loopboolean上下键到达首尾是否回绕,默认 false。
dirDirection文字方向,只对调左右方向键的展开 / 收起语义;未提供时从 DOM 读取。
sizeSize尺寸:sm / md / lg。
searchstring搜索词:键名与值文本里含有它(不区分大小写)的行即为命中。 命中行的祖先分支自动展开(写进展开集合),命中片段由作者按 api.segments 铺成 mark 部件。 空串与只含空白视为没有搜索。
translationsPartial<JsonViewerTranslations>
onExpandedValueChange(details: JsonViewerExpandedValueChangeDetails) => void
onViewChange(details: JsonViewerViewChangeDetails) => void原文开关切换了展示形态;受控时由宿主据此回写 view。
onWrapChange(details: JsonViewerWrapChangeDetails) => void换行开关切换了原文档的换行;受控时由宿主据此回写 wrap。
onCopyError(details: JsonViewerCopyErrorDetails) => void复制钮写入剪贴板失败时通知;此时复制钮已回到常态,不留下「已复制」的假象。

事件 ​

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

事件载荷说明
expanded-value-changeJsonViewerExpandedValueChangeDetails展开集合变化;detail 为 { value: string[] }
view-changeJsonViewerViewChangeDetails原文开关切换了展示形态;detail 为 { view: 'tree' | 'text' }
wrap-changeJsonViewerWrapChangeDetails换行开关切换了原文档的换行;detail 为 { wrap: boolean }
copy-errorJsonViewerCopyErrorDetails复制钮写入剪贴板失败;detail 为 { error: unknown, value: string }

插槽 ​

仅列出带载荷的插槽。

Vue 组件插槽载荷说明
XhJsonViewerRootempty—
XhJsonViewerRoottoolbarJsonViewerToolbarSlotProps树之前的一条:放搜索框与上一条 / 下一条,渲染为根的前一个兄弟。

React 适配器 props ​

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

React 组件属性类型必填说明
XhJsonViewerRootemptyReactNode空态格子的内容;未写时铺设 translations 中的兜底文案。
XhJsonViewerRoottoolbarSlotChildren<JsonViewerToolbarSlotProps>树之前的一条:放搜索框与上一条 / 下一条,渲染为根的前一个兄弟。

状态 ​

公开状态写入 data-state。

部件取值
branch'open' | 'closed'
branch-control'open' | 'closed'
branch-trigger'open' | 'closed'
branch-indicator'open' | 'closed'
branch-text'open' | 'closed'
branch-summary'open' | 'closed'
branch-content'open' | 'closed'
preview'open' | 'closed'
expand-trigger'open' | 'closed'
wrap-trigger'on' | 'off'
copy-trigger'idle' | 'copying' | 'copied'
status'idle' | 'copying' | 'copied'

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

状态:idle · copying · copied

事件:EXPANDED.SET · BRANCH.EXPAND · BRANCH.COLLAPSE · BRANCH.TOGGLE · NODE.FOCUS · VIEWER.BLUR · PRESS.START · PRESS.END · MATCH.SET · SEARCH.SYNC · VIEW.SET · WRAP.SET · COPY.TRIGGER · COPY.SUCCESS · COPY.ERROR · after.timeout · TOOL.PRESS.START · TOOL.PRESS.END

connect API ​

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

成员类型说明
visibleNodesreadonly JsonViewerNode[]当前可见行序列(收起分支的子行不在其中)。 方向键、Home/End 都在它上面移动,适配器也按它铺设 DOM。
expandedValuestring[]
focusedValuestring | nullroving tabindex 的锚点行:焦点在树内时即当前行,焦点离开后仍保留(Tab 回来时落回它); 它已随分支收起而不再可见时为 null。
isFocusWithinboolean焦点当前是否在树内。行的高亮标记随它变化,锚点不随之变化。
isExpanded(value: string) => boolean
previewText(node: JsonViewerNode) => string分支收起摘要的显示文字(如 {…} 3),只用于视觉;叶子行返回空串。
branchSummary(node: JsonViewerNode) => string分支的可及名字(键名,根行取 translations.root;收起时带上成员数),铺进 branch-summary。
valueText(node: JsonViewerNode) => string值的显示文字;截断占位行返回其余 N 项的文案。
setExpandedValue(next: string[]) => void
expand(value: string) => void
collapse(value: string) => void
toggle(value: string) => void
viewJsonViewerView当前生效的展示形态。
wrapboolean原文档当前是否自动换行。
toolsreadonly JsonViewerTool[]工具条上铺的工具,按条上的排列顺序;没有工具条时为空。
copyStatusJsonViewerCopyStatus复制钮的写入相位。
copiedboolean已复制成功且仍在停留窗口内:复制钮换成对钩、播报区念出成功回执的唯一判据。
announcementstring播报区该念的语句;未到已复制档时为空串。
setView(view: JsonViewerView) => void
setWrap(wrap: boolean) => void
expandAll() => void展开全部分支(maxItems 折掉的成员与循环引用照旧不展开)。
collapseAll() => void收起到只剩顶层:根行留着展开,其下的分支全部收起。
allExpandedboolean每一层的分支都已展开(maxItems 折掉的成员与循环引用不算分支)。展开 / 收起钮据此决定这一下是展开还是收起; 只有根一层分支、没有可展开的子层时为 false。原文档不算,恒为 false。
copy() => void把 JSON 原文写进剪贴板,与点复制钮走同一路径。
isEmptyboolean无法展开任何一行:value 未提供或为 undefined。空态部件随它显隐。
emptyTextstring空态的兜底文案,作者未向空态部件写入内容时铺设它。
textstring原文档展示、复制钮写入的那份文本:提供了 source 时是它重排缩进后的样子,否则由 value 序列化(键序与环路记号与树档一致)。
textSegmentsreadonly JsonViewerTextSegment[]原文按类别切成的段,依次拼接恒等于 text:键名、标量与标点各成一段,铺成 token 部件着色,空白按纯文本铺。 原文解析不了时整段一个不着色的段。只在原文档切分,树档为空:树档用不上,不白算一遍。
searchMatchesreadonly string[]命中搜索词的行路径,按树序排列;没有搜索时为空。
activeMatchstring | null在命中之间逐个走时停在哪一行;没有时为 null。
nextMatch() => void停到下一条命中(走到末尾回到第一条),并把它滚进视野。
prevMatch() => void停到上一条命中(走到开头回到最后一条),并把它滚进视野。
setActiveMatch(value: string | null) => void
keySegments(node: JsonViewerNode) => readonly HighlightSegment[]键名按搜索词切成的片段,依次拼接恒等于键名;命中的片段铺成 mark 部件。 没有搜索或没有键名时整段是一个不命中的片段。
valueSegments(node: JsonViewerNode) => readonly HighlightSegment[]值文本(即 valueText)按搜索词切成的片段;截断占位行的文案不参与命中。
getRootProps() => T['element']
getTreeProps() => T['element']
getTextProps() => T['element']
getTokenProps(props: JsonViewerTokenProps) => T['element']原文档里有类别的一段(键名、标量、标点),带 data-kind 供皮肤按树档同一套颜色着色。
getItemProps(props: JsonViewerNodeProps) => T['element']
getItemKeyProps(props: JsonViewerNodeProps) => T['element']
getItemValueProps(props: JsonViewerNodeProps) => T['element']
getBranchProps(props: JsonViewerNodeProps) => T['element']
getBranchControlProps(props: JsonViewerNodeProps) => T['element']
getBranchTriggerProps(props: JsonViewerNodeProps) => T['element']
getBranchIndicatorProps(props: JsonViewerNodeProps) => T['element']
getBranchTextProps(props: JsonViewerNodeProps) => T['element']
getBranchSummaryProps(props: JsonViewerNodeProps) => T['element']视觉隐藏的分支名字,分支行的可及名字即取自它。
getBranchContentProps(props: JsonViewerNodeProps) => T['element']
getPreviewProps(props: JsonViewerNodeProps) => T['element']
getEmptyProps() => T['element']
getMarkProps() => T['element']键名与值文本里命中搜索词的那一段。
getToolbarProps() => T['element']内建工具条:根的第一个孩子,各颗钮按 tools 铺在其中。 报告 role=group:一组有名字的控件,每颗钮各占一个 Tab 位; 不报告 role=toolbar,那个角色承诺条内靠方向键移动。
getExpandTriggerProps() => T['button']展开 / 收起全部的切换钮:data-state 为 open 时已全部展开(再按收起),closed 时还有收着的(再按展开)。
getWrapTriggerProps() => T['button']
getCopyTriggerProps() => T['button']
getViewTriggerProps() => T['button']
getStatusProps() => T['element']复制成功的播报区:视觉隐藏的 polite 实时区,只要有复制钮就常驻,内容取 announcement。

无障碍 ​

键盘 ​

规格出处: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 branch切换该分支的展开态;焦点在标量行上时不吞这两个键
Enter / Spaceheld on branch按住期间该分支行(branch-control)投影 data-pressed,与指针 :active 同一副按压面(行只换面不缩放);抬起或失焦撤下。展开态的切换照旧由这一次按键承担
*focus in tree展开与焦点行同一父级的全部分支(已展开的不动);同级没有可展开的分支时不吞这个键
Enter / Spacefocus on a toolbar trigger(开启 tools 时)触发该钮:展开 / 收起全部、切换自动换行或原文、复制原文;按住期间投影 data-pressed,抬起或失焦撤下。工具钮各占一个 Tab 位,条内不靠方向键移动

ARIA ​

以下属性由 connect 生成。

部件属性值
treearia-labellabel.tree
treerole'tree'
itemaria-levelnode?.level
itemaria-posinsetnode?.posInSet
itemaria-setsizenode?.setSize
itemrole'treeitem'
brancharia-expanded'true' | 'false'
brancharia-levelnode?.level
brancharia-posinsetnode?.posInSet
brancharia-setsizenode?.setSize
branchrole'treeitem'
branch-triggeraria-hidden'true'
branch-indicatoraria-hidden'true'
branch-textaria-hidden'true'
branch-contentrole'group'
previewaria-hidden'true'
textaria-labellabel.text
textrole'region'
toolbararia-labellabel.toolbar
toolbarrole'group'
wrap-triggeraria-pressed'true' | 'false'
statusaria-atomic'true'
statusaria-live'polite'
statusrole'status'
  • 树是 role=tree,每一行是 role=treeitem,层级三项(aria-level / aria-posinset / aria-setsize)取自展开结果。
  • 整棵树只占一个 Tab 位:首次进入落在首行,之后 Tab 离开再返回时落回上次停留的行;组内靠上下键移动。
  • 展开箭头对读屏隐藏,它重复的是分支自身已报出的 aria-expanded 与左右方向键。
  • 分支的名称显式提供(aria-label):它包裹整棵子层,从内容计算名称会把所有子孙的文字一并读出。
  • 收起摘要({…} 3)是排版记号,对读屏隐藏;其中的成员数并入分支的可访问名称(默认读为 tags, 3 items,整句可用 translations.collapsedBranchLabel 替换)。
  • 工具条是 role=group 并带可访问名称(translations.toolbar),每颗钮各占一个 Tab 位;不报告 role=toolbar,条内不靠方向键移动。钮里只有字形,名称取自 translations;自动换行是开关钮,开关状态由 aria-pressed 报告、名称不变;展开 / 收起与树 / 原文两颗切换钮的名称随动作变化(如「展开全部」「收起全部」),不再另报 aria-pressed,免得名称与按下态各说各的。
  • 复制成功的回执由视觉隐藏的 status 部件(aria-live="polite")读出,钮上的对钩只是视觉标记。

样式参考 ​

皮肤 ​

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

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

数据属性 ​

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

部件属性值
rootdata-sizeprops.size
rootdata-variantprops.variant
rootdata-viewcontext.get('view')
itemdata-circular''(条件成立时才出现)
itemdata-current''(条件成立时才出现)
itemdata-highlighted''(条件成立时才出现)
itemdata-match''(条件成立时才出现)
itemdata-truncated''(条件成立时才出现)
itemdata-value-typenode?.type
item-keydata-circular''(条件成立时才出现)
item-keydata-current''(条件成立时才出现)
item-keydata-highlighted''(条件成立时才出现)
item-keydata-match''(条件成立时才出现)
item-keydata-truncated''(条件成立时才出现)
item-keydata-value-typenode?.type
item-valuedata-circular''(条件成立时才出现)
item-valuedata-current''(条件成立时才出现)
item-valuedata-highlighted''(条件成立时才出现)
item-valuedata-match''(条件成立时才出现)
item-valuedata-truncated''(条件成立时才出现)
item-valuedata-value-typenode?.type
branchdata-circular''(条件成立时才出现)
branchdata-current''(条件成立时才出现)
branchdata-highlighted''(条件成立时才出现)
branchdata-match''(条件成立时才出现)
branchdata-state'open' | 'closed'
branchdata-truncated''(条件成立时才出现)
branchdata-value-typenode?.type
branch-controldata-circular''(条件成立时才出现)
branch-controldata-current''(条件成立时才出现)
branch-controldata-highlighted''(条件成立时才出现)
branch-controldata-match''(条件成立时才出现)
branch-controldata-pressed''(条件成立时才出现)
branch-controldata-state'open' | 'closed'
branch-controldata-truncated''(条件成立时才出现)
branch-controldata-value-typenode?.type
branch-triggerdata-circular''(条件成立时才出现)
branch-triggerdata-current''(条件成立时才出现)
branch-triggerdata-highlighted''(条件成立时才出现)
branch-triggerdata-match''(条件成立时才出现)
branch-triggerdata-state'open' | 'closed'
branch-triggerdata-truncated''(条件成立时才出现)
branch-triggerdata-value-typenode?.type
branch-indicatordata-circular''(条件成立时才出现)
branch-indicatordata-current''(条件成立时才出现)
branch-indicatordata-highlighted''(条件成立时才出现)
branch-indicatordata-match''(条件成立时才出现)
branch-indicatordata-state'open' | 'closed'
branch-indicatordata-truncated''(条件成立时才出现)
branch-indicatordata-value-typenode?.type
branch-textdata-circular''(条件成立时才出现)
branch-textdata-current''(条件成立时才出现)
branch-textdata-highlighted''(条件成立时才出现)
branch-textdata-match''(条件成立时才出现)
branch-textdata-state'open' | 'closed'
branch-textdata-truncated''(条件成立时才出现)
branch-textdata-value-typenode?.type
branch-summarydata-circular''(条件成立时才出现)
branch-summarydata-current''(条件成立时才出现)
branch-summarydata-highlighted''(条件成立时才出现)
branch-summarydata-match''(条件成立时才出现)
branch-summarydata-state'open' | 'closed'
branch-summarydata-truncated''(条件成立时才出现)
branch-summarydata-value-typenode?.type
branch-contentdata-circular''(条件成立时才出现)
branch-contentdata-current''(条件成立时才出现)
branch-contentdata-highlighted''(条件成立时才出现)
branch-contentdata-match''(条件成立时才出现)
branch-contentdata-state'open' | 'closed'
branch-contentdata-truncated''(条件成立时才出现)
branch-contentdata-value-typenode?.type
previewdata-circular''(条件成立时才出现)
previewdata-current''(条件成立时才出现)
previewdata-highlighted''(条件成立时才出现)
previewdata-match''(条件成立时才出现)
previewdata-state'open' | 'closed'
previewdata-truncated''(条件成立时才出现)
previewdata-value-typenode?.type
textdata-wrap''(条件成立时才出现)
tokendata-kindprops.kind
toolbardata-viewcontext.get('view')
expand-triggerdata-state'open' | 'closed'
expand-triggerdata-xh-action-control''
expand-triggerdata-xh-action-display'always'
expand-triggerdata-xh-action-profile'icon'
expand-triggerdata-xh-action-size'md' | 'sm'
expand-triggerdata-xh-action-variant'ghost'
wrap-triggerdata-state'on' | 'off'
wrap-triggerdata-xh-action-control''
wrap-triggerdata-xh-action-display'always'
wrap-triggerdata-xh-action-profile'icon'
wrap-triggerdata-xh-action-size'md' | 'sm'
wrap-triggerdata-xh-action-variant'ghost'
copy-triggerdata-copied''(条件成立时才出现)
copy-triggerdata-state'idle' | 'copying' | 'copied'
copy-triggerdata-xh-action-control''
copy-triggerdata-xh-action-display'always'
copy-triggerdata-xh-action-profile'icon'
copy-triggerdata-xh-action-size'md' | 'sm'
copy-triggerdata-xh-action-variant'ghost'
view-triggerdata-viewcontext.get('view')
view-triggerdata-xh-action-control''
view-triggerdata-xh-action-display'always'
view-triggerdata-xh-action-profile'icon'
view-triggerdata-xh-action-size'md' | 'sm'
view-triggerdata-xh-action-variant'ghost'
statusdata-state'idle' | 'copying' | 'copied'

CSS 变量 ​

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

变量部件CSS 属性状态默认来源说明
--xh-json-viewer-bgempty
root
text
tree
backgrounddefault
is([data-scope='json-viewer'][data-part='tree'], [data-scope='json-viewer'][data-part='text'], [data-scope='json-viewer'][data-part='empty'])
variant=subtle
--xh-bg-subtle
--xh-bg-surface
json-viewer 的 empty、root、text、tree 部件 background 覆盖槽。
--xh-json-viewer-boolean-fgitem-value
token
colorkind=boolean
value-type=boolean
--xh-syntax-keywordjson-viewer 的 item-value、token 部件 color 覆盖槽。
--xh-json-viewer-borderempty
text
tree
borderdefault--xh-border-defaultjson-viewer 的 empty、text、tree 部件 border 覆盖槽。
--xh-json-viewer-empty-fgemptycolordefault--xh-fg-mutedjson-viewer 的 empty 部件 color 覆盖槽。
--xh-json-viewer-empty-gapemptygapdefault--xh-space-2json-viewer 的 empty 部件 gap 覆盖槽。
--xh-json-viewer-empty-pxemptypadding-inlinedefault--xh-space-4json-viewer 的 empty 部件 padding-inline 覆盖槽。
--xh-json-viewer-empty-pyemptypadding-blockdefault--xh-space-6json-viewer 的 empty 部件 padding-block 覆盖槽。
--xh-json-viewer-fgrootcolordefault--xh-fg-defaultjson-viewer 的 root 部件 color 覆盖槽。
--xh-json-viewer-fontroot
text
font-familydefault--xh-font-family-monojson-viewer 的 root、text 部件 font-family 覆盖槽。
--xh-json-viewer-font-sizerootfont-sizedefault--xh-_json-viewer-font-sizejson-viewer 的 root 部件 font-size 覆盖槽。
--xh-json-viewer-icon-sizeroot--xh-icon-sizedefault
size=lg
size=sm
--xh-glyph-size-lg
--xh-glyph-size-md
--xh-glyph-size-sm
json-viewer 的 root 部件 --xh-icon-size 覆盖槽。
--xh-json-viewer-indentbranch-contentpadding-inline-startdefault--xh-_json-viewer-indentjson-viewer 的 branch-content 部件 padding-inline-start 覆盖槽。
--xh-json-viewer-indicator-fgbranch-triggercolordefault--xh-fg-subtlejson-viewer 的 branch-trigger 部件 color 覆盖槽。
--xh-json-viewer-indicator-sizebranch-trigger--xh-icon-size
inline-size
default--xh-control-indicator-sizejson-viewer 的 branch-trigger 部件 --xh-icon-size、inline-size 覆盖槽。
--xh-json-viewer-key-fgbranch-text
item-key
token
colordefault
kind=key
--xh-fg-brand-strongjson-viewer 的 branch-text、item-key、token 部件 color 覆盖槽。
--xh-json-viewer-key-font-weightbranch-text
item-key
token
font-weightdefault
kind=key
--xh-font-weight-mediumjson-viewer 的 branch-text、item-key、token 部件 font-weight 覆盖槽。
--xh-json-viewer-mark-bgmarkbackgrounddefault--xh-bg-brand-subtlejson-viewer 的 mark 部件 background 覆盖槽。
--xh-json-viewer-mark-bg-currentbranch
branch-control
branch-text
item
item-key
item-value
mark
backgroundcurrent--xh-bg-brandjson-viewer 的 branch、branch-control、branch-text、item、item-key、item-value、mark 部件 background 覆盖槽。
--xh-json-viewer-mark-fgmarkcolordefault--xh-fg-brand-strongjson-viewer 的 mark 部件 color 覆盖槽。
--xh-json-viewer-mark-fg-currentbranch
branch-control
branch-text
item
item-key
item-value
mark
colorcurrent--xh-fg-on-brandjson-viewer 的 branch、branch-control、branch-text、item、item-key、item-value、mark 部件 color 覆盖槽。
--xh-json-viewer-mark-radiusmarkborder-radiusdefault--xh-shape-insetjson-viewer 的 mark 部件 border-radius 覆盖槽。
--xh-json-viewer-max-htext
tree
max-block-sizedefault--xh-viewport-max-hjson-viewer 的 text、tree 部件 max-block-size 覆盖槽。
--xh-json-viewer-null-fgitem-value
token
colorkind=null
value-type=null
--xh-fg-subtlejson-viewer 的 item-value、token 部件 color 覆盖槽。
--xh-json-viewer-number-fgitem-value
token
colorkind=number
value-type=number
--xh-syntax-numberjson-viewer 的 item-value、token 部件 color 覆盖槽。
--xh-json-viewer-preview-fgpreviewcolordefault--xh-fg-mutedjson-viewer 的 preview 部件 color 覆盖槽。
--xh-json-viewer-preview-font-sizepreviewfont-sizedefault--xh-text-caption-sizejson-viewer 的 preview 部件 font-size 覆盖槽。
--xh-json-viewer-punctuation-fgbranch-text
item-key
item-value
token
colordefault
kind=punctuation
value-type=array
value-type=object
--xh-fg-subtlejson-viewer 的 branch-text、item-key、item-value、token 部件 color 覆盖槽。
--xh-json-viewer-pxtext
tree
padding-inlinedefault--xh-space-2json-viewer 的 text、tree 部件 padding-inline 覆盖槽。
--xh-json-viewer-pytext
tree
padding-blockdefault--xh-space-2json-viewer 的 text、tree 部件 padding-block 覆盖槽。
--xh-json-viewer-radiusempty
text
tree
border-radiusdefault--xh-shape-surfacejson-viewer 的 empty、text、tree 部件 border-radius 覆盖槽。
--xh-json-viewer-row-bg-activebranch-controlbackgrounddisabled
is(:active, [data-pressed])
not([data-disabled])
pressed
--xh-bg-subtle-hoverjson-viewer 的 branch-control 部件 background 覆盖槽。
--xh-json-viewer-row-bg-hoverbranch-control
item
backgroundhighlighted
is(:hover, [data-highlighted])
--xh-bg-subtlejson-viewer 的 branch-control、item 部件 background 覆盖槽。
--xh-json-viewer-row-gapbranch-control
item
gapdefault--xh-space-1json-viewer 的 branch-control、item 部件 gap 覆盖槽。
--xh-json-viewer-row-pxbranch-control
item
padding-inlinedefault--xh-space-1json-viewer 的 branch-control、item 部件 padding-inline 覆盖槽。
--xh-json-viewer-row-pybranch-control
item
padding-blockdefault--xh-_json-viewer-row-pyjson-viewer 的 branch-control、item 部件 padding-block 覆盖槽。
--xh-json-viewer-row-radiusbranch-control
item
border-radiusdefault--xh-shape-insetjson-viewer 的 branch-control、item 部件 border-radius 覆盖槽。
--xh-json-viewer-shadowempty
text
tree
box-shadowdefaultnonejson-viewer 的 empty、text、tree 部件 box-shadow 覆盖槽。
--xh-json-viewer-string-fgitem-value
token
colorkind=string
value-type=string
--xh-syntax-stringjson-viewer 的 item-value、token 部件 color 覆盖槽。
--xh-json-viewer-text-fgtextcolordefault--xh-fg-defaultjson-viewer 的 text 部件 color 覆盖槽。
--xh-json-viewer-tool-fgstatus
toolbar
colorwhere(:not([data-part='status'])--xh-fg-mutedjson-viewer 的 status、toolbar 部件 color 覆盖槽。
--xh-json-viewer-tool-fg-copiedcopy-triggercolorcopied
disabled
focus-visible
hover
is(:active, [data-pressed])
loading
not([data-disabled])
not([data-loading])
pressed
--xh-fg-successjson-viewer 的 copy-trigger 部件 color 覆盖槽。
--xh-json-viewer-tool-icon-sizestatus
toolbar
--xh-icon-sizewhere(:not([data-part='status'])--xh-_action-profile-glyph-sizejson-viewer 的 status、toolbar 部件 --xh-icon-size 覆盖槽。
--xh-json-viewer-toolbar-gaptoolbargapdefault--xh-space-0_5json-viewer 的 toolbar 部件 gap 覆盖槽。
--xh-json-viewer-toolbar-mbtoolbarmargin-block-enddefault--xh-space-1json-viewer 的 toolbar 部件 margin-block-end 覆盖槽。

动效 ​

动效角色:状态 · 切换(见动效规范)。

background-color · rotate 走 transition 过渡。时长与缓动读动效令牌,改令牌即改全局节奏。

系统开启减弱动效时由令牌层统一收敛,皮肤不另作判断。

RTL ​

皮肤用逻辑属性排布(inline-start 一族),dir="rtl" 下自动镜像;另有按 dir 分支的规则。

  • 左右方向键的展开 / 收起语义跟随书写方向:未传 dir 时从 DOM 读取,整页 dir="rtl" 也能识别。

Released under The MIT License