文章来源:https://www.toymoban.com/news/detail-692945.html
特性: 文章来源地址https://www.toymoban.com/news/detail-692945.html
- 表格宽度可以自定义
- 翻页器显示控件可以自定义
- 列配置项可以设置显示字段列名称、宽度、字段名
- 可以配置搜索框提示文本,支持搜索过滤
- 穿梭框顶部标题可以自定义
- 左右箭头按钮文本可以设置
sgTransfer源码
<template>
<div :class="$options.name">
<div
class="sg-start"
:style="{ width: width, height: height, ...style, ...style_start }"
>
<div class="sg-title" v-if="titles">
{{ titles[0] }}
</div>
<div class="sg-search">
<el-input
style="width: 100%"
v-model.trim="inputSearchValue_start"
maxlength="20"
:show-word-limit="false"
:placeholder="filterPlaceholder || `请输入搜索内容...`"
clearable
@keyup.native.enter="initListStart"
@clear="initListStart"
>
<el-button slot="append" icon="el-icon-search" @click="initListStart" />
</el-input>
</div>
<div class="sg-table">
<el-table
ref="table_start"
:data="tableData_start"
:header-cell-style="{ background: '#f5f7fa' }"
:height="height ? `calc(${height} - 150px)` : '300px'"
style="width: 100%"
stripe
@selection-change="selection_start_change"
:row-class-name="row_class_name"
@row-click="row_click_start"
@row-dblclick="row_dblclick_start"
>
<el-table-column type="selection" minWidth="50" :selectable="selectable" />
<el-table-column
v-for="(a, i) in tableItems_start"
:key="i"
:prop="a.prop"
:label="a.label"
:width="a.width || false"
:minWidth="a.minWidth || false"
show-overflow-tooltip
/>
</el-table>
</div>
<div class="sg-pagination">
<el-pagination
background
:hidden="startPage.total <= 10"
:layout="layout"
:page-sizes="[10, 20, 50]"
:pager-count="5"
:current-page.sync="startPage.currentPage"
:page-size.sync="startPage.pageSize"
:total="startPage.total"
@size-change="pageChange"
@current-change="pageChange"
/>
</div>
</div>
<div class="sg-center">
<el-button
:disabled="disabledLeftButton"
@click="remove"
type="primary"
icon="el-icon-arrow-left"
>{{ buttonTexts ? buttonTexts[0] : "" }}</el-button
>
<el-button :disabled="disabledRightButton" @click="add" type="primary"
>{{ buttonTexts ? buttonTexts[1] : ""
}}<i class="el-icon-arrow-right" style="margin-left: 5px"></i
></el-button>
</div>
<div class="sg-end" :style="{ width: width, height: height, ...style, ...style_end }">
<div class="sg-title" v-if="titles">
{{ titles[1] }}
</div>
<div class="sg-search">
<el-input
style="width: 100%"
v-model.trim="inputSearchValue_end"
maxlength="20"
:show-word-limit="false"
:placeholder="filterPlaceholder || `请输入搜索内容...`"
clearable
@keyup.native.enter="initListEnd({ currentPage: 1 })"
@clear="initListEnd"
>
<el-button
slot="append"
icon="el-icon-search"
@click="initListEnd({ currentPage: 1 })"
/>
</el-input>
</div>
<div class="sg-table">
<el-table
ref="table_end"
:data="tableData_end"
:header-cell-style="{ background: '#f5f7fa' }"
:height="height ? `calc(${height} - 150px)` : '300px'"
style="width: 100%"
stripe
@selection-change="selection_end_change"
@row-click="row_click_end"
>
<el-table-column type="selection" minWidth="50" />
<el-table-column
v-for="(a, i) in tableItems_end"
:key="i"
:prop="a.prop"
:label="a.label"
:width="a.width || false"
:minWidth="a.minWidth || false"
show-overflow-tooltip
/>
</el-table>
</div>
<div class="sg-pagination">
<el-pagination
background
:hidden="endPage.total <= 10"
:layout="layout"
:page-sizes="[10, 20, 50]"
:pager-count="5"
:current-page.sync="endPage.currentPage"
:page-size.sync="endPage.pageSize"
:total="endPage.total"
@size-change="initListEnd"
@current-change="initListEnd"
/>
</div>
</div>
</div>
</template>
<script>
export default {
name: "sgTransfer",
data() {
return {
width: "200px", //穿梭框宽度
height: null, //穿梭框高度
style: {}, //全局穿梭框样式
style_start: {}, //左侧穿梭框样式
style_end: {}, //右侧穿梭框样式
layout: `total, sizes, prev, pager, next, jumper`,
disabledForm: false,
inputSearchValue_start: "",
inputSearchValue_end: "",
tableItems_start: [], //表格列配置项
tableItems_end: [], //表格列配置项
tableData_start: [], //呈现的当前页数据
tableData_end: [], //呈现的当前页数据
tableData_end_bk: [], //最终选择的数据
selection_start: [],
selection_end: [],
startPage: { currentPage: 1, pageSize: 10, total: 0 },
endPage: { currentPage: 1, pageSize: 10, total: 0 },
mainKey: null, //主键
filterKey_end: null, //右侧穿梭表过滤关键词字段
};
},
props: [
"value",
"data",
/*格式说明
data: {
width: '400px',//表格宽度
layout: `total, sizes, prev, next, jumper`,//翻页器显示控件
// 列配置项
tableItems: [
{ prop: 'ID', label: '工号', minWidth: '50' },
{ prop: 'XM', label: '姓名', minWidth: '50' },
{ prop: 'YHM', label: '用户名', minWidth: '50' },
],
tableData: [],//表格显示内容
startPage: { total: 0, },//实际总数
}, */
"titles",
"buttonTexts",
"filterPlaceholder",
],
computed: {
disabledLeftButton(d) {
return this.selection_end.length === 0;
},
disabledRightButton(d) {
// 在左边表格选中项里面,遍历每一项,如果在右侧表格中都能找到匹配项就true
return this.selection_start.every((row) =>
this.tableData_end_bk.some((v) => this.isSameItem(v, row))
);
},
},
watch: {
value: {
handler(d) {
// 避免重复循环执行双向绑定
if (
d &&
JSON.stringify(JSON.parse(JSON.stringify(this.tableData_end_bk)).sort()) !==
JSON.stringify(JSON.parse(JSON.stringify(d)).sort())
) {
this.inputSearchValue_start = "";
this.inputSearchValue_end = "";
this.startPage.currentPage = 1;
this.endPage.currentPage = 1;
this.tableData_end_bk = d || [];
this.initListStart();
}
},
deep: true,
immediate: true,
},
data: {
handler(d) {
if (d) {
d.width && (this.width = d.width);
d.height && (this.height = d.height);
d.style && (this.style = d.style);
d.style_start && (this.style_start = d.style_start);
d.style_end && (this.style_end = d.style_end);
d.layout && (this.layout = d.layout);
this.tableData_start = d.tableData;
this.tableItems_start = d.tableItems_start || d.tableItems;
this.tableItems_end = d.tableItems_end || d.tableItems;
this.mainKey = (this.tableItems_start.find((v) => v.mainKey) || {}).prop; //主键
this.filterKey_end = (
this.tableItems_start.find((v) => v.filterKey_end) || {}
).prop; //右侧穿梭表过滤关键词字段
this.startPage.total = (d.startPage || {}).total || 0;
this.$nextTick(() => {
this.refreshCheckStatus();
}); // 刷新勾选状态
}
},
deep: true,
immediate: true,
},
tableData_end_bk: {
handler(d) {
this.$emit(`input`, d);
this.initListEnd();
},
deep: true,
immediate: true,
},
},
created() {
let d = this.value;
if (d && Object.keys(d).length) {
} else this.initListStart();
},
methods: {
// 双击选中移动到右侧
row_dblclick_start(row, column, event) {
this.$refs.table_start.toggleRowSelection(row, true);
this.add();
},
row_click_start(row, column, event) {
this.$refs.table_start.toggleRowSelection(row);
},
row_click_end(row, column, event) {
this.$refs.table_end.toggleRowSelection(row);
},
pageChange(d) {
this.initListStart();
},
// 刷新勾选状态
refreshCheckStatus() {
this.tableData_start.forEach((row) =>
this.$refs.table_start.toggleRowSelection(
row,
this.tableData_end_bk.some((v) => this.isSameItem(v, row))
)
);
},
selectable(row) {
return !this.tableData_end_bk.some((v) => this.isSameItem(v, row));
},
row_class_name({ row, rowIndex }) {
return this.tableData_end_bk.find((v) => this.isSameItem(v, row)) ? "selected" : "";
},
isSameItem(a_obj, b_obj) {
let isSame = true;
if (this.mainKey) {
isSame = a_obj[this.mainKey] == b_obj[this.mainKey];
} else {
isSame = Object.keys(a_obj).every((k) => a_obj[k] == b_obj[k]);
}
return isSame;
},
remove(d) {
if (this.mainKey) {
let selection_end_mainKeys = this.selection_end.map((v) => v[this.mainKey]);
this.tableData_end_bk = this.tableData_end_bk.filter(
(v) => !selection_end_mainKeys.includes(v[this.mainKey])
);
} else {
let selection_end = this.selection_end.map((v) => JSON.stringify(v));
this.tableData_end_bk = this.tableData_end_bk.filter(
(v) => !selection_end.includes(JSON.stringify(v))
);
}
this.$nextTick(() => {
this.refreshCheckStatus();
}); // 刷新勾选状态
},
add(d) {
this.selection_start.forEach(
(row) =>
this.tableData_end_bk.some((v) => this.isSameItem(v, row)) ||
this.tableData_end_bk.push(row)
);
this.$nextTick(() => {
this.refreshCheckStatus();
}); // 刷新勾选状态
},
selection_start_change(selection) {
this.selection_start = selection;
},
selection_end_change(selection) {
this.selection_end = selection;
},
initListStart() {
this.$emit("init", {
keyword: this.inputSearchValue_start,
currentPage: this.startPage.currentPage || 1,
pageSize: this.startPage.pageSize,
});
},
initListEnd({
keyword = this.inputSearchValue_end,
currentPage = this.endPage.currentPage || 1,
pageSize = this.endPage.pageSize,
} = {}) {
let maxPage = Math.ceil(this.tableData_end_bk.length / pageSize);
currentPage > maxPage && (currentPage = maxPage);
this.endPage.currentPage = currentPage;
this.endPage.pageSize = pageSize;
let results = [];
if (this.filterKey_end) {
results = this.tableData_end_bk.filter((obj) =>
keyword
? (obj[this.filterKey_end] || "")
.toString()
.toLocaleLowerCase()
.includes(keyword.toString().toLocaleLowerCase())
: true
);
} else {
results = this.tableData_end_bk.filter((obj) =>
keyword
? Object.keys(obj).some((k) =>
(obj[k] || "")
.toString()
.toLocaleLowerCase()
.includes(keyword.toString().toLocaleLowerCase())
)
: true
);
}
this.endPage.total = results.length;
this.tableData_end = results.slice(
(currentPage - 1) * pageSize,
currentPage * pageSize
);
if (this.tableData_end_bk.length) {
this.tableData_end.length === 0 &&
((this.inputSearchValue_end = ""), this.initListEnd());
}
},
},
};
</script>
<style lang="scss" scoped>
.sgTransfer {
display: flex;
align-items: center;
flex-wrap: nowrap;
white-space: nowrap;
& > .sg-start,
& > .sg-end {
border: 1px solid #ebeef5;
border-radius: 4px;
overflow: hidden;
background: #fff;
display: inline-block;
vertical-align: middle;
max-height: 100%;
box-sizing: border-box;
position: relative;
.sg-title {
height: 40px;
line-height: 40px;
background: #f5f7fa;
margin: 0;
padding-left: 15px;
border-bottom: 1px solid #ebeef5;
box-sizing: border-box;
color: #000;
}
.sg-search {
box-sizing: border-box;
padding: 10px;
}
.sg-table {
}
.sg-pagination {
height: 50px;
display: flex;
justify-content: center;
width: 100%;
box-sizing: border-box;
padding: 10px;
}
}
& > .sg-center {
margin: 0 10px;
}
& > .sg-end {
}
}
>>> .el-table {
tr.selected {
filter: brightness(0.95);
pointer-events: none;
}
.el-table__cell.gutter {
border-bottom: 1px solid #ebeef5;
background-color: #f5f7fa;
}
}
</style>
用例
<template>
<div>
<sgTransfer
v-model="transferValue"
:data="transferData"
:titles="['所有用户', '本组成员']"
:button-texts="['到左边', '到右边']"
:filter-placeholder="`请输入工号、姓名…`"
@init="initTransfer"
/>
<hr />
<div>
<h1>勾选的数据transferValue:</h1>
<div
v-html="JSON.stringify(transferValue).replace(/\,\{/g, ',\n{')"
style="word-wrap: break-word; word-break: break-all; white-space: break-spaces"
></div>
</div>
</div>
</template>
<script>
import sgTransfer from "@/vue/components/admin/sgTransfer";
export default {
components: { sgTransfer },
data() {
return {
// 穿梭框配置项
transferValue: [],
transferData: {
width: "400px", //表格宽度
height: "calc(100vh - 200px)", //表格高度
layout: `total, sizes, prev, next, jumper`, //翻页器显示控件
// 列配置项
tableItems: [
{ prop: "ID", label: "工号", minWidth: "50", mainKey: true }, //设置主键
{ prop: "XM", label: "姓名", minWidth: "50", filterKey_end: true },//设置右侧穿梭表过滤关键词字段
{ prop: "YHM", label: "用户名", minWidth: "50" },
],
tableData: [], //表格显示内容
startPage: { total: 0 }, //实际总数
},
// 渲染数据
tableData: [],
tableData_bk: [],
userList: [
{ key: 1, label: "梁冰露" },
{ key: 2, label: "吴梵听" },
{ key: 3, label: "卢令美" },
{ key: 4, label: "韩宛曼" },
{ key: 5, label: "郝海冬" },
{ key: 6, label: "傅优悦" },
{ key: 7, label: "郝幻莲" },
{ key: 8, label: "江嘉云" },
{ key: 9, label: "梁秋芳" },
{ key: 10, label: "郝悦颖" },
{ key: 11, label: "廖芝蓉" },
{ key: 12, label: "胡傲丝" },
{ key: 13, label: "赵珺琦" },
{ key: 14, label: "石心诺" },
{ key: 15, label: "丁翠芙" },
{ key: 16, label: "李夏河" },
{ key: 17, label: "范水悦" },
{ key: 18, label: "郑凝雪" },
{ key: 19, label: "李亦玉" },
{ key: 20, label: "袁三春" },
{ key: 21, label: "赵红叶" },
{ key: 22, label: "曹安琪" },
{ key: 23, label: "谭琴音" },
{ key: 24, label: "钟湛蓝" },
{ key: 25, label: "陆之柔" },
{ key: 26, label: "吕孒凡" },
{ key: 27, label: "熊野雪" },
{ key: 28, label: "曹叶澜" },
{ key: 29, label: "韩粟梅" },
{ key: 30, label: "孔杏儿" },
{ key: 31, label: "宋若彤" },
{ key: 32, label: "于淼淼" },
{ key: 33, label: "潘欣跃" },
{ key: 34, label: "石雅辰" },
{ key: 35, label: "白念珍" },
{ key: 36, label: "文爱茹" },
{ key: 37, label: "王如曼" },
{ key: 38, label: "宋丝琪" },
{ key: 39, label: "王凝荷" },
{ key: 40, label: "郑雨雪" },
{ key: 41, label: "梁映阳" },
{ key: 42, label: "徐新雨" },
{ key: 43, label: "毛恬雅" },
{ key: 44, label: "侯若蕊" },
{ key: 45, label: "杨云蔚" },
{ key: 46, label: "史之卉" },
{ key: 47, label: "胡千束" },
{ key: 48, label: "冯冷荷" },
{ key: 49, label: "金语心" },
{ key: 50, label: "江恬默" },
{ key: 51, label: "高香馨" },
{ key: 52, label: "江凌晴" },
{ key: 53, label: "梁列琴" },
{ key: 54, label: "邹鸾瑶" },
{ key: 55, label: "夏素洁" },
{ key: 56, label: "范秋玉" },
{ key: 57, label: "钟北嘉" },
{ key: 58, label: "谭水云" },
{ key: 59, label: "顾山柏" },
{ key: 60, label: "龙曼蔓" },
{ key: 61, label: "钟双儿" },
{ key: 62, label: "林林娜" },
{ key: 63, label: "邹溪儿" },
{ key: 64, label: "顾妙彤" },
{ key: 65, label: "傅茵茵" },
{ key: 66, label: "卢念露" },
{ key: 67, label: "罗冷亦" },
{ key: 68, label: "胡秋颖" },
{ key: 69, label: "姜怡月" },
{ key: 70, label: "傅和暄" },
{ key: 71, label: "赖布凡" },
{ key: 72, label: "郝念蕾" },
{ key: 73, label: "邱天欣" },
{ key: 74, label: "汤莉莉" },
{ key: 75, label: "段靖易" },
{ key: 76, label: "周之云" },
{ key: 77, label: "董映秋" },
{ key: 78, label: "汤玲琅" },
{ key: 79, label: "田雁梅" },
{ key: 80, label: "石雨雪" },
{ key: 81, label: "任君雅" },
{ key: 82, label: "蔡小谷" },
{ key: 83, label: "孟忆之" },
{ key: 84, label: "姜闲丽" },
{ key: 85, label: "文忆香" },
{ key: 86, label: "戴运虹" },
{ key: 87, label: "王玄穆" },
{ key: 88, label: "刘绿柳" },
{ key: 89, label: "萧梦丝" },
{ key: 90, label: "谭忆山" },
{ key: 91, label: "方榕嫣" },
{ key: 92, label: "徐欣合" },
{ key: 93, label: "夏雨南" },
{ key: 94, label: "尹沙羽" },
{ key: 95, label: "万梦玉" },
{ key: 96, label: "谢灵枫" },
{ key: 97, label: "曾源源" },
{ key: 98, label: "赖谷枫" },
{ key: 99, label: "彭子童" },
],
};
},
created() {
this.createTableData();
},
methods: {
// 初始化、翻页、切换每页显示数量的时候触发
initTransfer({ keyword = "", currentPage = 1, pageSize = 10 } = {}) {
// 模拟接口调用----------------------------------------
let results = this.tableData_bk.filter((obj) =>
keyword
? Object.keys(obj).some((k) =>
obj[k]
.toString()
.toLocaleLowerCase()
.includes(keyword.toString().toLocaleLowerCase())
)
: true
);
this.transferData.startPage.total = results.length;
this.transferData.tableData = results.slice(
(currentPage - 1) * pageSize,
currentPage * pageSize
);
// ----------------------------------------
},
// 构建数据
createTableData(d) {
this.tableData_bk = this.userList.map((v) => {
let ID = this.$g.getRandomID();
return { ID, XM: v.label, YHM: `user${ID}` };
});
this.initTransfer();
},
},
};
</script>
到了这里,关于【sgTransfer】自定义组件:带有翻页、页码、分页器的穿梭框组件,支持大批量数据的穿梭显示。的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!