Skip to content

Transfer 组件设计 ​

概述 ​

Transfer 组件是本组件库中用于实现穿梭框功能的核心组件。它延续了我们组件库一贯的设计理念,采用"容器-面板"分离和"状态驱动"的原则,通过 transfer.vue 和 transferPanel.vue 等核心组件实现了一套完整且易用的穿梭框解决方案。

Transfer 组件专注于处理双向选择场景中的数据流转和交互体验,为用户提供了一套直观、高效的批量选择操作界面,支持自定义样式、禁用项、标题配置和灵活的数据绑定,有效提升用户在数据迁移和选择操作时的体验。

设计理念 ​

容器-面板分离架构 ​

Transfer 组件采用清晰的容器-面板分离架构:

  1. 容器层 transfer.vue - 负责整体布局、数据管理和状态流转
  2. 面板层 transferPanel.vue - 专注于单个面板的数据展示和交互
  3. 数据层 type.ts - 定义数据结构和类型

这种设计使组件各部分职责单一,便于维护和扩展。

状态驱动设计 ​

Transfer 组件采用状态驱动的设计思想:

  • 数据驱动 - 通过 modelValue 和 data 属性驱动界面展示
  • 状态隔离 - 左右面板的状态相互隔离,通过容器层统一管理
  • 事件驱动 - 通过事件机制实现数据流动

这种设计确保了组件的状态可预测性和一致性。

核心功能设计 ​

数据管理机制 ​

Transfer 组件的核心在于数据管理机制:

typescript
const leftData = computed(() => props.data.filter(item => !props.modelValue.includes(item.key)))
const rightData = computed(() => props.data.filter(item => props.modelValue.includes(item.key)))

数据管理特点: ​

  • 双向绑定 - 使用 modelValue 实现 v-model 双向绑定
  • 自动拆分 - 根据 modelValue 自动拆分左右面板数据
  • 数据隔离 - 左右面板数据互不影响,通过容器层统一管理

操作交互设计 ​

Transfer 组件的操作交互设计简洁高效:

typescript
const addToRight = () => {
  const newKeys = [...props.modelValue, ...leftSelected.value]
  emit('update:modelValue', newKeys)
  leftSelected.value = []
}

const removeFromRight = () => {
  const newKeys = props.modelValue.filter(k => !rightSelected.value.includes(k))
  emit('update:modelValue', newKeys)
  rightSelected.value = []
}

交互特点: ​

  • 单向流动 - 数据只能通过操作按钮在左右面板间移动
  • 批量操作 - 支持同时选择多个项进行移动
  • 禁用控制 - 禁用项无法被选择和移动
  • 状态反馈 - 按钮状态根据选择情况动态变化

组件结构设计 ​

整体结构 ​

Transfer 组件的整体结构如下:

html
<div class="my-transfer">
  <TransferPanel
    v-model:selected="leftSelected"
    :title="leftTitle"
    :data="leftData"
    :style="transferStyle"
    :hoverBackground="hoverBackground"
  />
  <div class="my-transfer__buttons">
    <button :disabled="!leftSelected.length" @click="addToRight">→</button>
    <button :disabled="!rightSelected.length" @click="removeFromRight">←</button>
  </div>
  <TransferPanel
    v-model:selected="rightSelected"
    :title="rightTitle"
    :data="rightData"
    :style="transferStyle"
    :hoverBackground="hoverBackground"
  />
</div>

组件层次 ​

Transfer 组件包含多个关键部分:

  1. 容器 - .my-transfer - 包裹整个穿梭框组件
  2. 操作按钮区 - .my-transfer__buttons - 包含左右移动按钮
  3. 面板 - .transfer-panel - 单个数据面板
  4. 面板标题 - .transfer-panel__title - 面板标题区域
  5. 数据列表 - .transfer-panel__list - 数据项列表
  6. 数据项 - .transfer-panel__item - 单个数据项

TransferPanel 组件的核心结构:

html
<div class="transfer-panel" :style="{ ...transferStyle, '--hover-background': hoverBackground }">
  <div class="transfer-panel__title">{{ title }}</div>
  <ul class="transfer-panel__list">
    <li
      v-for="item in data"
      :key="item.key"
      :class="['transfer-panel__item', { 'is-disabled': item.disabled, 'is-selected': selected.includes(item.key) }]"
      :style="{ '--hover-background': hoverBackground }"
      @click="toggleSelect(item)"
    >
      <input class="transfer-panel__checkbox" type="checkbox" :checked="selected.includes(item.key)" :disabled="item.disabled" />
      {{ item.label }}
    </li>
  </ul>
</div>

交互设计 ​

选择机制 ​

TransferPanel 组件的选择机制设计如下:

typescript
const toggleSelect = (item: Option) => {
  if (item.disabled) return
  const selected = [...props.selected]
  const index = selected.indexOf(item.key)
  if (index > -1) {
    selected.splice(index, 1)
  } else {
    selected.push(item.key)
  }
  emit('update:selected', selected)
}

选择规则: ​

  • 点击选择 - 点击数据项切换选择状态
  • 禁用控制 - 禁用项无法被选择
  • 状态同步 - 通过 update:selected 事件同步选择状态
  • 批量操作 - 支持同时选择多个项

数据流转 ​

Transfer 组件的数据流转设计如下:

  1. 初始状态 - 根据 modelValue 和 data 计算左右面板数据
  2. 选择状态 - 用户在左右面板选择数据项
  3. 数据移动 - 用户点击操作按钮,触发数据移动
  4. 状态更新 - 更新 modelValue,触发界面重新渲染

数据流转特点: ​

  • 单向数据流 - 数据只能通过操作按钮在左右面板间移动
  • 状态一致性 - 确保 modelValue 与界面展示一致
  • 操作原子性 - 每次移动操作都是原子操作

扩展性设计 ​

Transfer 组件具备出色的扩展性:

  1. 样式扩展 - 通过 backgroundColor、colorText 和 hoverBackground 属性支持自定义样式
  2. 标题扩展 - 通过 titles 属性支持自定义标题
  3. 数据扩展 - 通过 Option接口支持自定义数据结构
  4. 交互扩展 - 通过事件机制支持自定义交互逻辑
  5. 样式变量 - 通过 CSS 变量支持细粒度样式控制

样式细节 ​

Transfer 组件在样式处理上有以下特点:

  1. 视觉层次 - 通过颜色和间距创建清晰的视觉层次
  2. 状态反馈 - 不同状态有明确的视觉反馈
    scss
    &.is-disabled {
      color: $disabled-color;
      cursor: not-allowed;
    }
    
    &.is-selected {
      background-color: var(--hover-background, $selected-color) !important;
      font-weight: 500;
    }
  3. 过渡效果 - 使用过渡效果增强用户体验
  4. 滚动优化 - 针对长列表优化滚动体验
    scss
    &__list {
      max-height: 350px;
      overflow-y: auto;
      scrollbar-width: thin;
      scrollbar-color: $border-color transparent;
    }
  5. 响应式设计 - 适应不同屏幕尺寸

性能优化 ​

通过以下方式优化性能:

  1. 计算属性 - 使用计算属性缓存数据拆分结果
  2. 虚拟滚动 - 通过限制最大高度和优化滚动实现虚拟滚动效果
  3. 事件委托 - 通过事件委托减少事件监听器数量
  4. 样式优化 - 使用 CSS 变量动态调整样式,减少重排
  5. 批量操作 - 支持批量选择和移动,减少操作次数

设计价值 ​

Transfer 组件延续了我们组件库的设计哲学:

  1. 职责分离 - 容器和面板职责清晰分离
  2. 状态驱动 - 通过状态变化驱动界面更新
  3. 数据抽象 - 通过Option接口抽象数据结构
  4. 交互一致性 - 保持与组件库其他组件一致的交互模式
  5. 可定制性 - 通过属性和样式变量提供丰富的定制能力

基于 MIT 协议