{ "schemaVersion": 1, "sourceKind": "authored-spec", "provenance": "authored-in-repo", "specFile": "spec/移动端规格.md", "specSection": "44 · 级联选择器 Cascader", "confidence": "high", "slug": "mobile-cascader", "name": "级联选择器 Cascader", "semanticTypeCandidates": [ "cascader", "tree-select", "region-picker" ], "variantDimensions": [ { "name": "mode", "values": [ "panel", "popup" ] }, { "name": "showPath", "values": [ "true", "false" ] }, { "name": "round", "values": [ "false", "true" ] } ], "representativeVariants": [ { "mode": "panel", "showPath": "true", "round": "false", "label": "内嵌面板(页面内逐级选择)" }, { "mode": "popup", "showPath": "true", "round": "true", "label": "底部浮层(带遮罩与确定取消)" }, { "mode": "panel", "showPath": "false", "round": "false", "label": "不显示路径条(层级少时省一行高度)" } ], "anatomy": { "cascader": "根元素,mode=panel 时内嵌在页面里,mode=popup 时是底部浮层", "mask": "遮罩(仅 mode=popup),点击关闭", "cascader__header": "取消 / 标题 / 确定三格(仅 mode=popup)", "cascader__path": "路径条,按已选深度渲染;除末位外都可点,点了回退到该级", "cascader__panel": "选项区,role=listbox + aria-label 说明当前在选第几级", "cascader__option": "单个选项,role=option + aria-selected;有下级显示箭头,叶子显示勾号" }, "structurePatterns": { "mode": "panel(内嵌在页面里)/ popup(底部浮层,自带遮罩与确定取消)", "showPath": "true(显示路径条,可回退)/ false(不显示,层级少的场景省一行高度)", "round": "false(直角)/ true(浮层靠内容一侧切圆角)" }, "usageHints": [ "在有层级关系的选项里逐级选到末级(省 → 市 → 区、品类 → 子品类 → SKU)", "移动端一次只展示当前一层,已选路径收进上方路径条,靠路径条回退而不是靠「上一级」按钮", "点某一级后下一级选项随之变化:面板始终只渲染当前一层,选择即下钻", "点路径条里的上级可回退:回退到该级并重新展示它的下一级;末位是「你在这里」的锚点,不可点", "级数不写死:路径条按已选深度渲染,两级与四级用同一份实现", "选项行高与路径条各项热区均不小于 44px" ], "doNotInvent": [ "层级数据源(由宿主传入 options 树,本组件不发明省市区库)", "搜索定位某级选项(那需要把整棵树拍平,是独立的检索组件)", "异步逐级加载的占位与重试流程", "多选(一次选多条路径)" ], "unknowns": [ "路径很长时路径条是折行还是横向滚动(当前折行,四级以上会占两行)", "叶子被选中后是否要自动收起浮层(当前不自动收,等宿主决定)", "是否要保留「上一级」按钮作为路径条之外的第二种回退入口" ], "interaction": [ "点某一级后下一级选项随之变化:面板始终只渲染当前一层,选择即下钻", "点路径条里的上级可回退:回退到该级并重新展示它的下一级;末位是「你在这里」的锚点,不可点", "级数不写死:路径条按已选深度渲染,两级与四级用同一份实现", "点到叶子结点后再点同级另一项,会截断更深的层级(改选不会留下旧的深层残留)", "选项行高与路径条各项热区均不小于 44px;选项区滚动容器 -webkit-overflow-scrolling: touch" ], "accessibility": [ "mode=panel 根元素 role=\"group\" + aria-label;mode=popup 根元素 role=\"dialog\" + aria-modal=\"true\"", "选项区 role=\"listbox\",aria-label 随层级变化(如「级联选项 · 城市」),读屏能播报当前在第几级", "选项 role=\"option\" + aria-selected;禁用项写 aria-disabled=\"true\"", "路径条末位写 aria-current=\"true\",读屏播报「当前项」", "路径条每一项是原生 button(键盘可达),末位用 disabled 让键盘跳过" ], "api": { "source": "implementation", "note": "props / events / slots 为 6 端实现的公共接口(说明文字取自规格对应小节)。字段名与各端源码逐名核对:node tools/verify-mobile-docs.mjs", "requiredNote": "「必传」按严格定义:实现里**没有默认值**时才为 Y(本门禁逐条核对 props 与各端源码的默认值,防止契约与实现脱节)。", "props": [ { "name": "mode", "type": "'panel' | 'popup'", "default": "'panel'", "desc": "变体 mode:panel 内嵌在页面里,popup 是底部浮层(规格 §44.3)", "required": false }, { "name": "round", "type": "boolean", "default": "false", "desc": "变体 round:浮层靠内容一侧是否切圆角(规格 §44.3)", "required": false }, { "name": "showPath", "type": "boolean", "default": "true", "desc": "变体 showPath:是否显示路径条(规格 §44.3)", "required": false }, { "name": "open", "type": "boolean", "default": "false", "desc": "状态 open:mode=popup 时浮层是否展开(规格 §44.4)", "required": false }, { "name": "closeOnMask", "type": "boolean", "default": "true", "desc": "遮罩点击是否关闭(规格 §44.5)", "required": false }, { "name": "value", "type": "Array", "default": "[]", "desc": "当前选中路径,从根到当前级的 value 序列(规格 §44.6)", "required": false }, { "name": "options", "type": "Array", "default": "[]", "desc": "层级数据树(宿主提供,本组件不发明省市区库)(规格 §44.7)", "required": false }, { "name": "disabled", "type": "boolean", "default": "false", "desc": "状态 disabled:整块置灰且不响应(规格 §44.4)", "required": false }, { "name": "title", "type": "string", "default": "''", "desc": "浮层标题(空串时用默认「选择地区」)(规格 §44.2 cascader__header)", "required": false }, { "name": "label", "type": "string", "default": "'级联选项'", "desc": "选项区 aria-label 的前缀,读屏靠它知道这组在选什么(规格 §44.6)", "required": false } ], "events": [ { "name": "change", "params": "value: Array", "desc": "路径变化时触发(下钻或回退),回传从根到当前级的 value 序列(规格 §44.5)" }, { "name": "confirm", "params": "value: Array", "desc": "mode=popup 时点击确定触发(规格 §44.5)" }, { "name": "close", "params": "—", "desc": "mode=popup 时点击取消或遮罩(closeOnMask=true)触发(规格 §44.5)" } ], "slots": [ { "name": "default", "desc": "自定义内容(追加在面板之前,常见用法是放触发器)" } ] }, "variantClasses": { "mode": { "panel": [ ".kole-m-cascader--panel" ], "popup": [ ".kole-m-cascader--popup" ] }, "showPath": { "true": [], "false": [ ".kole-m-cascader--no-path" ] }, "round": { "false": [], "true": [ ".kole-m-cascader--round" ] } }, "demos": [ { "id": "levels", "group": "01 组件类型", "title": "逐级下钻", "desc": "点省份后下一级换成城市:面板只渲染当前一层,避免 375px 下横向挤压。", "variant": "mode=panel" }, { "id": "popup", "group": "01 组件类型", "title": "底部浮层", "desc": "mode=popup:自带遮罩与确定取消,遮罩点击关闭。", "variant": "mode=popup" }, { "id": "back", "group": "02 组件状态", "title": "回退上一级", "desc": "点路径条里的上级即退回该级,重新展示它的下一级;末位是「你在这里」的锚点。", "variant": "状态 selected(路径条回退)" }, { "id": "states", "group": "02 组件状态", "title": "禁用项与空态", "desc": "禁用结点置灰并写 aria-disabled;当前级无子项时显示占位文案。", "variant": "状态 disabled | empty" } ], "related": [ { "slug": "mobile-picker", "why": "选项之间没有层级关系(城市平铺)时用选择器,不要用级联去拼一棵假树" }, { "slug": "mobile-popup", "why": "通用弹出层;mode=popup 本身就是底部浮层,不要在弹出层里再套一层" }, { "slug": "cell", "why": "「已选地区」的展示入口用单元格,点开才拉起级联" }, { "slug": "mobile-list", "why": "只需要展示一层可选项且不需要回退路径时,列表更轻" }, { "slug": "actionsheet", "why": "动作面板面向「点一下即执行」,级联面向「逐级缩小范围再确认」" } ] }