Figma 穿梭框与双向列表选择系统(Transfer & Dual Listbox System)组件架构实战:从双列 Auto Layout 弹性分配、全选/反选计数状态机、Variables 跨列表数据穿梭原型到 Dev Mode 前端代码交付

2026 年 11 月 13 日

在企业级 ERP、SaaS 权限中台、数据仓库指标配置、用户角色指派以及复杂业务流水线编排中,穿梭框(Transfer / Dual Listbox) 是承载“大量候选数据向目标集合进行多选、转移与排序”的核心重型交互控件。相比常规的下拉多选框(Multi-Select),穿梭框提供了更加直观的双栏对照视图,允许用户在海量候选项与已选项之间自由对比、批量移动并清晰感知当下的集合边界。

然而,在许多团队的 Figma 设计系统资产中,穿梭框组件往往存在诸多工程痛点:

  1. 容器拉伸变形与尺寸塌陷:双栏面板未遵循弹性 Auto Layout 自动布局 规范,一旦将组件放入弹窗或宽屏栅格,中央操作按钮发生偏斜,列表项文本撑破容器或出现异常留白;
  2. 列表滚动与溢出裁剪混淆:未正确设置固定高度与垂直内滚动(Scroll Vertical),导致长列表项在画布中无限纵向延展,甚至与下层卡片内容产生重叠穿透;
  3. 计数联动与状态机断裂:全选框(Select All)、半选态(Indeterminate)、单项勾选以及底部已选计数器(如 已选 3/10 项)缺乏原子级组件逻辑,难以表现穿梭后的数据联动;
  4. 原型演示难以模拟真实穿梭:传统方式需要针对“选中 -> 穿梭 -> 取消”绘制多达数十个画板,极耗画布渲染性能;
  5. 前端研发交付鸿沟:开发在 Dev Mode 开发模式 中看到的仅仅是重复的静态列表项,缺少底层对应 Ant Design 或 Headless UI 的数据驱动属性(如 dataSource、targetKeys、selectedKeys)及 WAI-ARIA 无障碍键盘焦点流转规范。

本文将深入剖析穿梭框系统的物理拓扑解耦、列表项原子状态机、Auto Layout 双栏弹性约束、Variables 跨栏穿梭原型到前端工程代码交付的全生命周期。


穿梭框的物理拓扑模型与模块解耦 #

一个工业级的穿梭框由源数据列表(Source Panel)、中央操作区(Operation Controls)与目标数据列表(Target Panel)三大骨架构成。

┌─────────────────────────────────────────────────────────────────────────────────┐
│                           Transfer System (穿梭框主组件)                        │
│                                                                                 │
│  ┌──────────────────────────────┐    ┌─────────────┐    ┌─────────────────────┐ │
│  │ 源数据面板 (Source List)      │    │ 操作按钮区  │    │ 目标面板 (Target)   │ │
│  │ ──────────────────────────── │    │ ─────────── │    │ ─────────────────── │ │
│  │ [☑] 待选列表 (共 12 项)       │    │             │    │ [☐] 已选列表 (3 项) │ │
│  │ [ 🔍 搜索候选人员...       ]  │    │  [ > ] 穿梭 │    │ [ 🔍 搜索已选...  ] │ │
│  │ ──────────────────────────── │    │             │    │ ─────────────────── │ │
│  │ [☑] 01 张三 (财务部)         │    │  [ < ] 移出 │    │ [☐] 04 钱七 (研发)  │ │
│  │ [☑] 02 李四 (风控部)         │    │             │    │ [☐] 05 孙八 (设计)  │ │
│  │ [☐] 03 王五 (运维部)         │    │  [ >>] 全转 │    │ [☐] 06 周九 (测试)  │ │
│  │ [☐] ... (滚动列表项)         │    │             │    │                     │ │
│  │ ──────────────────────────── │    │  [ <<] 全清 │    │ ─────────────────── │ │
│  │ 底部操作区: 已选 2 项 / 清空  │    │             │    │ 底部操作区: 共 3 项 │ │
│  └──────────────────────────────┘    └─────────────┘    └─────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────────────┘

1. 核心子模块的职责矩阵 #

子模块 (Sub-component) 界面定位 包含的核心元素与交互能力 弹性与布局规范
Header Section (头部统计栏) 左右列表面板顶部 全选复选框(支持未选/半选/全选三态)、列表标题、总项数徽标 高度固定 40px,水平 Auto Layout,两端对齐
Search Filter (搜索过滤区) 头部下方(可选插槽) 搜索图标、占位输入框、一键清空按钮,支持实时关键字过滤 宽度 Fill container,外边距 8px 12px
List Body (滚动列表区) 面板主体承载区 纵向堆叠的列表项(Transfer Items),超出最大高度后截断 设为固定高度或最大高度(如 280px),开启 Clip content
Action Center (中央控制区) 左右面板正中间 向右穿梭(>)、向左移出(<)、批量全转(>> / <<)操作按钮 垂直 Auto Layout,居中对齐,与左右面板保持 16px 间距
Footer Section (底部操作栏) 面板最底部(可选) 刷新按钮、逆向选择、已勾选数与总数联动提示(如 2 / 12 items) 高度固定 36px,顶部 1px 细分割线,内边距 8px 12px

列表项(Transfer Item)原子级变体与状态机 #

列表项是穿梭框的最小交互原子。其必须承载文字截断、选中状态、悬停反馈与禁用边界。

1. 列表项的五大核心状态 #

状态 (State) 视觉样式表现 交互语义与前置条件
Default (常规待选) 白底,文字 #1E293B,复选框空心无勾选 项目在列表中静止展示,可被勾选
Hover (悬停聚焦) 浅灰背景(#F8FAFC),复选框边框高亮为品牌色(#4F46E5) 鼠标划过,给予视觉聚焦暗示
Checked (已勾选态) 浅蓝强调色背景(#EEF2FF),复选框实心打勾,文字清晰加粗 用户已圈定该项,等待点击中央穿梭按钮执行移动
Disabled (置灰禁用) 文字弱化(#94A3B8),复选框锁定灰色,指针呈现 not-allowed 锁定项(如超级管理员账号),禁止移出或移入
Active / Pressed (按下态) 背景色加深(#E0E7FF),产生微弱下压动效 鼠标真实按压瞬间反馈

2. 文本溢出与右侧插槽防撑破技巧 #

在真实业务场景中,列表项往往包含长姓名、邮箱或所属部门(如 张三 (基础架构与技术中台-资深架构师) zhangsan@corp.com):

  • 文本图层设置:列表项内部的主文本图层必须设置为 Fill container,并开启 Figma 文本属性中的 Truncate text(多余文本显示省略号);
  • 右侧辅助插槽(Slot):若需展示状态徽标或分类标签(Tag),应将其封装在独立 Auto Layout 容器中并锁定固定或自适应宽度,确保文本截断在标签左侧生效,绝不能将右侧标签挤出列表容器。

Auto Layout 双栏弹性约束与列表滚动规范 #

在搭建穿梭框整体组件时,很多设计师容易把宽度写死,导致组件在嵌入响应式弹窗时出现横向穿透。规范的搭建流程如下:

Transfer Root Container (Auto Layout 水平排列, Gap: 16px, Align: Center)
│
├── Left Panel: Source (Auto Layout 垂直, Fill Container 或 Fixed 240px, Min-Width: 200px)
│    ├── Header (Fixed Height 40px, Fill Container)
│    ├── Search Box (Fill Container)
│    ├── List Body (Fill Container, Height: 280px, Vertical Scroll, Clip content 勾选)
│    │    └── Stack of Items (Fill Container, Hug Contents)
│    └── Footer (Fixed Height 36px, Fill Container)
│
├── Operations Column (Auto Layout 垂直, Hug Contents, Width: Fixed 40px, Gap: 8px)
│    ├── Button Right [ > ] (Fixed 32×32px, 状态: Disabled / Enabled)
│    └── Button Left  [ < ] (Fixed 32×32px, 状态: Disabled / Enabled)
│
└── Right Panel: Target (与 Left Panel 完全同构对称)

1. 约束与滚动配置的关键排障要点 #

  1. Clip content(裁剪内容)的正确使用:
    • 列表项的父级容器 List Body 必须勾选 Clip content,防止列表项过多时向下方破框而出;
    • 在原型模式下,将 List Body 的滚动行为(Overflow)设置为 Scroll vertically(垂直滚动),这样在展示 20+ 条数据时,用户可以在有限的 280px 视口内平滑上下滚动浏览;
  2. 中央按钮的响应式垂直居中:
    • 中央操作列的外层 Auto Layout 必须配置为居中对齐(Align: Center),确保无论左右列表面板是否开启搜索栏或底部操作栏,穿梭箭头始终对齐在组件的正中心;
  3. 按钮状态机与禁选联动:
    • 向右箭头按钮 [ > ]:当左侧源列表中有任意项目被勾选(left_checked_count > 0)时,变体自动切换为 Enabled(高亮可用);否则保持 Disabled 灰色置灰;
    • 向左箭头按钮 [ < ]:同理,只有当右侧目标列表中有项目被勾选时才被激活。

Variables 驱动的高保真穿梭与计数原型实战 #

传统原型制作穿梭框时,每次点击穿梭都要跳转画板。借助 Figma 现代变量(Variables)与条件逻辑,可以在单个画板上实现高度拟真的跨栏穿梭效果。

1. 定义核心数字与布尔变量 #

在 Local Variables 面板中建立 Transfer_System 集合:

变量名称 (Variable Name) 数据类型 (Type) 初始值 (Default) 业务逻辑含义
left_total_count Number 10 左侧源列表总候选项数
left_selected_count Number 0 左侧当前已勾选等待穿梭的项数
right_total_count Number 3 右侧目标列表已存在项数
right_selected_count Number 0 右侧当前勾选等待退回的项数
item_01_visible_in_left Boolean true 项目 01 是否停留在左侧列表
item_01_checked Boolean false 项目 01 是否处于勾选高亮态
is_transfer_right_active Boolean false 向右穿梭按钮是否处于激活状态

2. 交互动作流配置 #

  1. 用户勾选左侧“项目 01”(On Click Item 01):
    if item_01_checked == false {
      Set variable item_01_checked = true;
      Set variable left_selected_count = left_selected_count + 1;
      Set variable is_transfer_right_active = true;
    } else {
      Set variable item_01_checked = false;
      Set variable left_selected_count = left_selected_count - 1;
      if left_selected_count == 0 {
        Set variable is_transfer_right_active = false;
      }
    }
    
  2. 用户点击中央向右穿梭按钮 [ > ](On Click Button Right):
    if is_transfer_right_active == true {
      Set variable item_01_visible_in_left = false;
      Set variable item_01_checked = false;
      Set variable left_total_count = left_total_count - 1;
      Set variable left_selected_count = 0;
      Set variable right_total_count = right_total_count + 1;
      Set variable is_transfer_right_active = false;
    }
    
  3. 文本与显隐属性绑定:
    • 头部计数文本通过文本属性与变量表达式绑定,实时渲染为 selected_count + " / " + total_count + " 项";
    • 项目 01 图层的显隐(Layer Visibility)直接绑定 item_01_visible_in_left 变量;
    • 按钮组件的变体直接由 is_transfer_right_active 状态驱动。

这种变量驱动方式不仅让原型演示完全还原真实系统,还彻底避免了多画板冗余,极大提升了文件加载性能。


Dev Mode 生产级代码交付与前端工程对齐 #

在 Dev Mode 开发模式 中,交付穿梭框必须向研发团队提供清晰的数据项结构与状态管理模型,严禁单纯交付切图。

1. 组件属性与现代前端框架(React / Ant Design)无损映射矩阵 #

Figma 设计系统属性 Ant Design (<Transfer />) Headless UI / 原生双列表 业务工程语义
Left List Items dataSource 数组 availableItems 状态数组 候选集全量数据源
Right List Items targetKeys (受控字符串数组) selectedItems 状态数组 已经被移入目标列表的主键 ID 集合
Checked Items selectedKeys 数组 选中高亮索引集合 当前正在被复选框勾选的高亮项
Show Search (Boolean) showSearch={true} 自定义 Search Filter 插槽 是否开启关键字搜索过滤栏
Disabled Item record.disabled = true <option disabled> 或 aria-disabled 单项锁定不可移入/移出
Titles titles={['待选角色', '已分配角色']} 两个面板的 <h3 id="..."> 左右面板顶部标题文案

2. 标准生产级 React + Ant Design 交付代码示例 #

import React, { useState } from 'react';
import { Transfer, Card, Tag } from 'antd';
import type { TransferDirection, TransferItem } from 'antd/es/transfer';

interface UserRecord extends TransferItem {
  key: string;
  title: string;
  description: string;
  department: string;
  disabled?: boolean;
}

const mockData: UserRecord[] = [
  { key: '1', title: '张三', description: 'zhangsan@corp.com', department: '财务部' },
  { key: '2', title: '李四', description: 'lisi@corp.com', department: '风控部' },
  { key: '3', title: '王五', description: 'wangwu@corp.com', department: '运维部' },
  { key: '4', title: '赵六', description: 'zhaoliu@corp.com', department: '架构部', disabled: true },
];

export const EnterpriseRoleTransfer: React.FC = () => {
  const [targetKeys, setTargetKeys] = useState<string[]>(['1']);
  const [selectedKeys, setSelectedKeys] = useState<string[]>([]);

  const handleChange = (newTargetKeys: string[], direction: TransferDirection, moveKeys: string[]) => {
    setTargetKeys(newTargetKeys);
    console.log(`向 ${direction} 移动了: `, moveKeys);
  };

  const handleSelectChange = (sourceSelectedKeys: string[], targetSelectedKeys: string[]) => {
    setSelectedKeys([...sourceSelectedKeys, ...targetSelectedKeys]);
  };

  return (
    <Card title="角色与权限分配 (Transfer System)" className="shadow-sm max-w-4xl">
      <Transfer
        dataSource={mockData}
        titles={['可分配人员', '已分配人员']}
        targetKeys={targetKeys}
        selectedKeys={selectedKeys}
        onChange={handleChange}
        onSelectChange={handleSelectChange}
        render={(item) => (
          <span className="flex items-center justify-between w-full pr-2">
            <span>{item.title} ({item.description})</span>
            <Tag color="blue">{item.department}</Tag>
          </span>
        )}
        showSearch
        filterOption={(inputValue, item) =>
          item.title.indexOf(inputValue) !== -1 || item.department.indexOf(inputValue) !== -1
        }
        listStyle={{
          width: 280,
          height: 320,
        }}
        operations={['穿梭入库', '移出列表']}
      />
    </Card>
  );
};

3. WAI-ARIA 无障碍键盘焦点与辅助技术支持 #

  1. Dual Listbox 角色声明:
    • 左右两栏列表容器必须赋予 role="listbox" 并声明 aria-multiselectable="true";
    • 列表项赋予 role="option",当前勾选状态输出 aria-selected="true" / "false";
  2. 全键盘可操作性(Keyboard Accessibility):
    • 用户通过 Tab 键在左列表、穿梭按钮区、右列表之间平滑移动;
    • 在列表内部,使用方向键 ↑ / ↓ 浏览项目,按 Space(空格键)或 Enter 快速切换勾选状态;
    • 支持快捷键 Ctrl + A(Mac 上为 Cmd + A)快速触发全选当前列表。

企业级穿梭框落地检查清单 #

在将穿梭框正式发布至团队设计系统之前,建议对照以下检查项逐一排查:

校验维度 工业级验收规范与避坑要点 状态
双栏布局 面板采用 Auto Layout,水平宽度自适应(Min-Width: 200px),避免容器拉伸时按钮错位 [x] 已通过
滚动裁剪 列表内容区域设定固定高度(280px~360px)并开启 Clip content,内部允许垂直滚动 [x] 已通过
文本防撑破 列表项内部主文案开启 Truncate text 省略号截断,右侧标签锁定宽度不被挤压 [x] 已通过
状态完备 具备常规态、悬停态、选中态、禁用态以及全选/半选/清空多态流转 [x] 已通过
按钮联动 中央穿梭箭头严格根据左右勾选数量动态激活或置灰,防无意义空操作 [x] 已通过
代码交付 Dev Mode 中输出完整的 targetKeys / selectedKeys 状态映射及 WAI-ARIA 属性 [x] 已通过

通过以上规范化的模块解耦、变量逻辑绑定与 Dev Mode 深度交付,团队可以快速构建出高可用、易扩展的穿梭框组件,不仅在复杂中后台系统的原型评审中游刃有余,更能极大赋能前端研发团队的无损还原。若需查阅更多复杂表单控件的排障经验,请参阅站内指南 设计系统常见故障排查手册 与 Tokens 设计令牌体系规范。

❓ 常见问题与答疑 (FAQ)

高频疑难解析与避坑指南
A

完全不需要。绝大多数核心功能在免费 Starter 计划中均可完整体验与实操练习,无需额外付费购买付费团队版。