一、引言
穿梭框(Transfer)是前端开发中常用的组件,用于在两个列表之间移动数据项。虽然 Element UI 提供了基础的 el-transfer 组件,但在实际项目中我们往往需要更丰富的功能和更灵活的定制。本文将详细讲解如何基于 Vue2 和 Element UI 封装一个功能强大的穿梭框组件,并分析其特点、优势及使用方法。
二、先上效果图

三、组件封装详解
想跳过步骤直接使用的,可以直接划到底部看 使用指南 和 完整组件代码.
1. 基础结构搭建
首先我们来看组件的基础模板结构:
<template>
<div class="transfer">
<!-- 左框 -->
<div class="transfer_left" :style="{ width: props.leftWidth }">
<!-- 左侧内容 -->
</div>
<!-- 按钮 -->
<div class="transfer_center">
<el-button @click="leftClick"></el-button>
<el-button @click="rightClick"></el-button>
</div>
<!-- 右框 -->
<div class="transfer_right" :style="{ width: props.rightWidth }">
<!-- 右侧内容 -->
</div>
</div>
</template>
这个结构创建了一个包含左右两个面板和中间操作按钮的基础布局。通过 props.leftWidth 和 props.rightWidth 可以动态设置两侧面板的宽度。
2. 数据管理
组件的数据管理是核心功能:
data() {
return {
allCheck_left: false, // 左侧全选状态
allCheck_right: false, // 右侧全选状态
checked_left: [], // 左侧已选数据
checked_right: [], // 右侧已选数据
leftList: [], // 左侧总数据列表
rightList: [], // 右侧总数据列表
left_search: "", // 左侧搜索词
right_search: "" // 右侧搜索词
};
}
组件通过 data 属性管理所有状态,包括选择状态、数据列表和搜索条件。
这里比较核心的是左右两侧的数据解耦,毕竟我就是为了解决这个问题才封装的这个组件,在element-ui 的 el-transfer 中因左右框共用一套数据的原因,不能在一侧框单独添加检索条件,数据解耦完美的解决了这个问题。
3. 属性配置
组件提供了丰富的配置选项:
props: {
props: {
type: Object,
default() {
return {
label: "name", // 显示文本内容字段
key: "id", // 唯一标识字段
disabled: "disabled", // 多选框禁用字段
leftWidth: "300px", // 左侧宽度
rightWidth: "300px", // 右侧宽度
};
},
},
// 源数据
data: {
type: Array,
default() {
return [];
},
},
// 已选数据
value: {
type: Array,
default() {
return [];
},
},
// 是否可搜索
filterable: {
type: Boolean,
default() {
return false;
},
},
// 搜索框提示文字
filterPlaceholder: {
type: String,
default() {
return "请输入关键字";
},
},
// 两侧标题
titles: {
type: Array,
default() {
return ["未选数据", "已选数据"];
},
},
// 自定义搜索条件
search: {
type: Object,
default() {
return {
left: [],
right: [],
};
},
},
}
这些属性使得组件可以高度定制化,适应各种业务场景。
为减少学习成本,这里封装的和 el-transfer 相同的属性保持了对齐。
有额外定制需求,也可以在这里继续添加定制化属性。
4. 核心功能实现
数据移动功能
// 将右边选中的数据移动到左边
leftClick() {
let arr = [];
this.rightList = this.rightList.filter((item) => {
if (this.checked_right.includes(item[this.props.key])) {
this.leftList.push(item);
arr.push(item);
return false;
} else {
return true;
}
});
this.$emit(
"change",
this.rightList.map((item) => item[this.props.key]),
"left",
this.checked_right
);
this.checked_right = [];
}
// 将左边选中的数据移动到右边
rightClick() {
let arr = [];
this.leftList = this.leftList.filter((item) => {
if (this.checked_left.includes(item[this.props.key])) {
this.rightList.push(item);
arr.push(item);
return false;
} else {
return true;
}
});
this.$emit(
"change",
this.rightList.map((item) => item[this.props.key]),
"right",
this.checked_left
);
this.checked_left = [];
}
这两个方法实现了数据在左右面板之间的移动,并在移动后触发 change 事件通知父组件。
搜索过滤功能
computed: {
// 左边要显示的数据列表
leftList_bak() {
let arr = this.leftList.filter((item) =>
item[this.props.label].includes(this.left_search)
);
let array = [arr];
if (this.search.left && this.search.left.length) {
array.push(...th

最低0.47元/天 解锁文章
1907

被折叠的 条评论
为什么被折叠?



