穿梭框 (Transfer)

穿梭框组件,用于在两个列表之间移动数据。

组件特性

  • 🔄 数据穿梭:在源列表和目标列表之间无缝移动数据。
  • 🔍 搜索过滤:内置搜索功能,方便在大量数据中快速查找。
  • 🖱️ 拖拽排序:支持对已选择的目标列表项进行拖拽排序。
  • 📝 表单集成:完美支持与 BrForm 结合使用,实现表单校验。
  • 🎨 高度定制:提供丰富的插槽支持自定义渲染,支持主题定制。

基础用法

最基本的用法。你需要提供 data 作为数据源,并使用 v-model 绑定已选择的项的 key。

<script setup lang="ts">
import { ref } from 'vue'
import { BrTransfer } from '@breezeui/vue'

const generateData = (count = 15) => {
  return Array.from({ length: count }).map((_, i) => ({
    key: i,
    label: `Item ${i + 1}`,
    desc: `Description for item ${i + 1}`,
    disabled: i % 5 === 0,
  }))
}

const data = ref(generateData())
const value = ref([1, 4])
</script>

<template>
  <BrTransfer
    v-model="value"
    :data="data"
    :titles="['Source List', 'Target List']"
  />
</template>

搜索与拖拽排序

通过设置 filterable 开启搜索功能。通过设置 draggable 开启目标列表的拖拽排序功能。

<script setup lang="ts">
import { ref } from 'vue'
import { BrTransfer } from '@breezeui/vue'

const generateData = (count = 20) => {
  return Array.from({ length: count }).map((_, i) => ({
    key: i,
    label: `Item ${i + 1}`,
    desc: `Description for item ${i + 1}`,
    disabled: i % 5 === 0,
  }))
}

const data = ref(generateData())
const value = ref([2, 5])
</script>

<template>
  <BrTransfer
    v-model="value"
    :data="data"
    filterable
    draggable
    :titles="['Available', 'Selected (Draggable)']"
    filter-placeholder="Type to search..."
  >
    <template #option="{ item }">
      <div class="flex flex-col">
        <span class="font-medium">{{ item.label }}</span>
        <span class="text-xs text-muted-foreground">{{ item.desc }}</span>
      </div>
    </template>
  </BrTransfer>
</template>

表单集成

BrTransfer 可以与 BrForm 无缝集成,实现表单验证。

<script setup lang="ts">
import { ref } from 'vue'
import { BrTransfer, BrForm, BrFormItem, BrButton } from '@breezeui/vue'

const formData = ref({
  roles: []
})

const rolesData = ref([
  { key: 'admin', label: 'Admin (Admin)' },
  { key: 'editor', label: 'Editor (Editor)' },
  { key: 'viewer', label: 'Viewer (Viewer)' },
  { key: 'guest', label: 'Guest (Guest)' },
])

const handleSubmit = (values: any) => {
  alert(JSON.stringify(formData.value))
}

const handleInvalidSubmit = (errors: any) => {
  console.error('Form validation failed:', errors)
}
</script>

<template>
  <BrForm @submit="handleSubmit" @invalid-submit="handleInvalidSubmit">
    <BrFormItem
      name="roles"
      label="Assign Roles"
      required
      :rules="(val: any[]) => {
        if (!val || val.length === 0) return 'Please select at least one role'
        if (val.length < 2) return 'Select at least 2 roles for security'
        return true
      }"
    >
      <BrTransfer
        v-model="formData.roles"
        :data="rolesData"
        :titles="['Roles', 'Assigned']"
        target-order="push"
      />
    </BrFormItem>
    
    <BrButton type="submit" class="mt-4">Submit Form</BrButton>
  </BrForm>
</template>

主题定制

使用 BrConfigProvider 可以轻松自定义组件的主题颜色和圆角。

<script setup lang="ts">
import { ref } from 'vue'
import { BrTransfer, BrConfigProvider } from '@breezeui/vue'

const generateData = (count = 5) => {
  return Array.from({ length: count }).map((_, i) => ({
    key: i,
    label: `Item ${i + 1}`,
  }))
}

const data = ref(generateData())
const value = ref([2])
</script>

<template>
  <BrConfigProvider
    :theme="{
      primary: '280 84% 67%',
      radius: '1rem',
    }"
  >
    <div class="p-6 border rounded-2xl bg-card shadow-sm">
      <h3 class="mb-4 font-medium text-primary">Custom Primary Color & Radius</h3>
      <BrTransfer
        v-model="value"
        :data="data"
        :titles="['Theme Left', 'Theme Right']"
      />
    </div>
  </BrConfigProvider>
</template>

API

Transfer 属性 (Props)

属性名类型默认值说明
modelValue / v-model(string | number)[][]绑定值,表示已选择的项
dataTransferDataItem[][]数据源
filterablebooleanfalse是否开启搜索
filterPlaceholderstring'Search here'搜索框占位符
filterMethod(query: string, item: TransferDataItem) => boolean-自定义搜索方法
titles[string, string]['Source', 'Target']左右面板的标题
buttonTexts[string, string]['', '']左右按钮的文本
draggablebooleanfalse是否允许拖拽目标面板的项进行排序
targetOrder'original' | 'push' | 'unshift''original'目标面板的数据排序策略
size'sm' | 'md' | 'lg''md'穿梭框尺寸
disabledbooleanfalse是否禁用
emptyTextstring'No data'数据为空时的文本

TransferDataItem 数据结构

属性名类型说明
keystring | number唯一标识符
labelstring显示文本
disabledboolean是否禁用该项
[key: string]any其他自定义属性

Transfer 事件 (Emits)

事件名参数说明
update:modelValue(value: (string | number)[])绑定值改变时触发
change(value: (string | number)[], direction: 'left' | 'right', movedKeys: (string | number)[])选项在两边移动时触发
search(query: string, direction: 'left' | 'right')搜索内容改变时触发
left-check-change(checkedKeys: (string | number)[], checkedNodes: TransferDataItem[])左侧面板选中项改变时触发
right-check-change(checkedKeys: (string | number)[], checkedNodes: TransferDataItem[])右侧面板选中项改变时触发

Transfer 插槽 (Slots)

插槽名说明
option自定义数据项的内容
leftEmpty左侧面板无数据时的内容
rightEmpty右侧面板无数据时的内容
leftFooter左侧面板的底部内容
rightFooter右侧面板的底部内容