?文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-692945.html
特性:?文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-692945.html
- 表格寬度可以自定義
- 翻頁(yè)器顯示控件可以自定義
- 列配置項(xiàng)可以設(shè)置顯示字段列名稱(chēng)、寬度、字段名
- 可以配置搜索框提示文本,支持搜索過(guò)濾
- 穿梭框頂部標(biāo)題可以自定義
- 左右箭頭按鈕文本可以設(shè)置
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 || `請(qǐng)輸入搜索內(nèi)容...`"
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 || `請(qǐng)輸入搜索內(nèi)容...`"
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", //穿梭框?qū)挾? height: null, //穿梭框高度
style: {}, //全局穿梭框樣式
style_start: {}, //左側(cè)穿梭框樣式
style_end: {}, //右側(cè)穿梭框樣式
layout: `total, sizes, prev, pager, next, jumper`,
disabledForm: false,
inputSearchValue_start: "",
inputSearchValue_end: "",
tableItems_start: [], //表格列配置項(xiàng)
tableItems_end: [], //表格列配置項(xiàng)
tableData_start: [], //呈現(xiàn)的當(dāng)前頁(yè)數(shù)據(jù)
tableData_end: [], //呈現(xiàn)的當(dāng)前頁(yè)數(shù)據(jù)
tableData_end_bk: [], //最終選擇的數(shù)據(jù)
selection_start: [],
selection_end: [],
startPage: { currentPage: 1, pageSize: 10, total: 0 },
endPage: { currentPage: 1, pageSize: 10, total: 0 },
mainKey: null, //主鍵
filterKey_end: null, //右側(cè)穿梭表過(guò)濾關(guān)鍵詞字段
};
},
props: [
"value",
"data",
/*格式說(shuō)明
data: {
width: '400px',//表格寬度
layout: `total, sizes, prev, next, jumper`,//翻頁(yè)器顯示控件
// 列配置項(xiàng)
tableItems: [
{ prop: 'ID', label: '工號(hào)', minWidth: '50' },
{ prop: 'XM', label: '姓名', minWidth: '50' },
{ prop: 'YHM', label: '用戶(hù)名', minWidth: '50' },
],
tableData: [],//表格顯示內(nèi)容
startPage: { total: 0, },//實(shí)際總數(shù)
}, */
"titles",
"buttonTexts",
"filterPlaceholder",
],
computed: {
disabledLeftButton(d) {
return this.selection_end.length === 0;
},
disabledRightButton(d) {
// 在左邊表格選中項(xiàng)里面,遍歷每一項(xiàng),如果在右側(cè)表格中都能找到匹配項(xiàng)就true
return this.selection_start.every((row) =>
this.tableData_end_bk.some((v) => this.isSameItem(v, row))
);
},
},
watch: {
value: {
handler(d) {
// 避免重復(fù)循環(huán)執(zhí)行雙向綁定
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; //右側(cè)穿梭表過(guò)濾關(guān)鍵詞字段
this.startPage.total = (d.startPage || {}).total || 0;
this.$nextTick(() => {
this.refreshCheckStatus();
}); // 刷新勾選狀態(tài)
}
},
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: {
// 雙擊選中移動(dòng)到右側(cè)
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();
},
// 刷新勾選狀態(tài)
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();
}); // 刷新勾選狀態(tài)
},
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();
}); // 刷新勾選狀態(tài)
},
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="['所有用戶(hù)', '本組成員']"
:button-texts="['到左邊', '到右邊']"
:filter-placeholder="`請(qǐng)輸入工號(hào)、姓名…`"
@init="initTransfer"
/>
<hr />
<div>
<h1>勾選的數(shù)據(jù)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 {
// 穿梭框配置項(xiàng)
transferValue: [],
transferData: {
width: "400px", //表格寬度
height: "calc(100vh - 200px)", //表格高度
layout: `total, sizes, prev, next, jumper`, //翻頁(yè)器顯示控件
// 列配置項(xiàng)
tableItems: [
{ prop: "ID", label: "工號(hào)", minWidth: "50", mainKey: true }, //設(shè)置主鍵
{ prop: "XM", label: "姓名", minWidth: "50", filterKey_end: true },//設(shè)置右側(cè)穿梭表過(guò)濾關(guān)鍵詞字段
{ prop: "YHM", label: "用戶(hù)名", minWidth: "50" },
],
tableData: [], //表格顯示內(nèi)容
startPage: { total: 0 }, //實(shí)際總數(shù)
},
// 渲染數(shù)據(jù)
tableData: [],
tableData_bk: [],
userList: [
{ key: 1, label: "梁冰露" },
{ key: 2, label: "吳梵聽(tīng)" },
{ key: 3, label: "盧令美" },
{ key: 4, label: "韓宛曼" },
{ key: 5, label: "郝海冬" },
{ key: 6, label: "傅優(yōu)悅" },
{ 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: "鐘湛藍(lán)" },
{ 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: "文愛(ài)茹" },
{ key: 37, label: "王如曼" },
{ key: 38, label: "宋絲琪" },
{ key: 39, label: "王凝荷" },
{ key: 40, label: "鄭雨雪" },
{ key: 41, label: "梁映陽(yáng)" },
{ key: 42, label: "徐新雨" },
{ key: 43, label: "毛恬雅" },
{ key: 44, label: "侯若蕊" },
{ key: 45, label: "楊云蔚" },
{ key: 46, label: "史之卉" },
{ key: 47, label: "胡千束" },
{ key: 48, label: "馮冷荷" },
{ key: 49, label: "金語(yǔ)心" },
{ 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: "賴(lài)布凡" },
{ 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: "戴運(yùn)虹" },
{ key: 87, label: "王玄穆" },
{ key: 88, label: "劉綠柳" },
{ key: 89, label: "蕭夢(mèng)絲" },
{ key: 90, label: "譚憶山" },
{ key: 91, label: "方榕嫣" },
{ key: 92, label: "徐欣合" },
{ key: 93, label: "夏雨南" },
{ key: 94, label: "尹沙羽" },
{ key: 95, label: "萬(wàn)夢(mèng)玉" },
{ key: 96, label: "謝靈楓" },
{ key: 97, label: "曾源源" },
{ key: 98, label: "賴(lài)谷楓" },
{ key: 99, label: "彭子童" },
],
};
},
created() {
this.createTableData();
},
methods: {
// 初始化、翻頁(yè)、切換每頁(yè)顯示數(shù)量的時(shí)候觸發(fā)
initTransfer({ keyword = "", currentPage = 1, pageSize = 10 } = {}) {
// 模擬接口調(diào)用----------------------------------------
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
);
// ----------------------------------------
},
// 構(gòu)建數(shù)據(jù)
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>
到了這里,關(guān)于【sgTransfer】自定義組件:帶有翻頁(yè)、頁(yè)碼、分頁(yè)器的穿梭框組件,支持大批量數(shù)據(jù)的穿梭顯示。的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!