Vue 實現(xiàn)高級穿梭框 Transfer 封裝過程
更新時間:2024年09月20日 10:40:22 作者:小晗同學
本文介紹了基于Vue2和Element-UI實現(xiàn)的高級穿梭框組件Transfer的設(shè)計與技術(shù)方案,組件支持多項選擇,并能實時同步已選擇項,包含豎版和橫版設(shè)計稿,并提供了組件的使用方法和源碼,此組件具備本地分頁和搜索功能,適用于需要在兩個列表間進行數(shù)據(jù)選擇和同步的場景
01 基礎(chǔ)信息
1.1. 技術(shù)棧
Element-UI
、Vue2
、lodash
1.2. 組件設(shè)計
需求描述:
【待選擇列表】 接收業(yè)務(wù)的表格數(shù)據(jù),支持選擇多項并將其添加到【已添加列表】 (勾選或刪除操作,兩邊的列表是同步的);
【已添加列表】支持本地分頁和本地簡易搜索功能(已添加的列表數(shù)據(jù)需要實時同步給業(yè)務(wù));
a. 豎版設(shè)計稿
b. 橫版設(shè)計稿
02 技術(shù)方案
(1)初定義數(shù)據(jù)
// 【待選擇列表】外部傳輸源數(shù)據(jù) // 【已添加列表】組件內(nèi)部控制數(shù)據(jù)的分頁、搜索和展示 const props = { sourceList: [], // 源數(shù)據(jù) columnList: [], // 表格列配置(注:字段類型均為字符串) searchList: [], // 【已添加列表】搜索項(注:與表頭對應) refreshTableData: (param)=>{}, // 回調(diào)函數(shù) total: 0, // 用于控制分頁器 } const state = { targetList: [], // 目標數(shù)據(jù) searchList: [], // 【已添加列表】搜索項 }
(2)注意事項
- 【待選擇列表】翻頁選擇時需要記錄并回顯已選擇的行
- 【已添加列表】刪除后需要繼續(xù)留在當前頁,即要判斷刪除的是否是最后一頁中只有一條的數(shù)據(jù)
- 【待選擇列表】更改選擇后,【已添加列表】的篩選項或是狀態(tài)項是否重置?或是維持不變?
(3)邏輯草圖
03 代碼示例
3.1. 組件使用
外部可通過 ref 調(diào)用的方法:
- clearSelection():清空所有選擇項;
- setPaginationParam({pageNum,pageSize},isFetch):設(shè)置源表格分頁器參數(shù),若 isFetch 為 true 則會自動調(diào)用 fetchSourceList( isFetch 默認為 false );
- initializeComponent(isFetch):初始化組件,若 isFetch 為 true 則初始化后自動請求源表格數(shù)據(jù)( isFetch 默認為 false );
- this.$refs['transferPlus'].selectList:若要初始化 selectList 可以使用 ref 設(shè)置(記得外面包裹 this.$nextTick);
注意事項:
- 使用插槽自定義表格列時,是同時應用到兩個列表中的;
- 組件會通過 selectionChange 事件告知您選擇的列表結(jié)果;
- 特別地,組件一開始不會默認請求源表格數(shù)據(jù),所以您需要在使用前自行調(diào)用 fetchSourceList 獲取 sourceList 等來渲染組件的數(shù)據(jù),組件只會在內(nèi)部的分頁狀態(tài)等有更改的情況下自動調(diào)用 fetchSourceList 為您刷新渲染數(shù)據(jù);
- 若 usePagination 為 true,則組件自動為您控制分頁器,但您必須設(shè)置好變量(sourceTotal)和源表格數(shù)據(jù)請求方法(fetchSourceList),并且為了防止您初始請求的分頁參數(shù)和組件內(nèi)部定義的默認初始分頁參數(shù)不同,您可以設(shè)置 initSourcePageNum 和 initSourcePageSize 來同步內(nèi)外初始化參數(shù);
<template> <TransferPlus ref="transferPlusRef" :sourceList="sourceList" :tableColumnList="tableColumnList" usePagination tableHeight="240" :sourceTotal="sourceTotal" :tableLoading="tableLoading" @fetchSourceList="fetchSourceList" > <!-- "table_"后拼接的是你定義該列的prop --> <template #table_tag="{ row, rowIndex }">{{ rowIndex + 1 }}{{row.tag}}</template> <!-- 自定義源表格的搜索區(qū)域 --> <template #source_search> <el-input placeholder="請輸入課程名稱" v-model="queryInfo.title" class="search-input" clearable> <el-button slot="append" icon="el-icon-search" @click="searchSourceList"></el-button> </el-input> </template> </TransferPlus> </template> <script> import TransferPlus from '@/components/TransferPlus' export default { components: { TransferPlus }, data() { sourceList: [], tableColumnList: [ { label: '課程id', prop: 'id' }, { label: '課程名稱', prop: 'title' }, { label: '課程類型', prop: 'tag' }, ], tableLoading: false, sourceTotal: 0, queryInfo: { pageNum: 1, pageSize: 10, title: '', tag: '', }, } method:{ async fetchSourceList (params={pageNum,pageSize}) { this.tableLoading = true const { pageNum, pageSize } = this.queryInfo this.queryInfo = { ...this.queryInfo, pageNum: params?.pageNum || pageNum, pageSize: params?.pageSize || pageSize, } const res = await getList(this.queryInfo) this.sourceList = res.data.list || [] this.sourceTotal = res.data.total || 0 this.tableLoading = false }, searchSourceList() { // 每次查詢時只需要重置穿梭框的頁碼到 1,并配置自動調(diào)用搜索函數(shù) this.$refs['transferPlusRef'].setPaginationParam({ pageNum: 1 }, true) }, } } </script> <style scoped> .search-input { margin-bottom: 12px; width: 100%; height: 32px; } </style>
實現(xiàn)效果圖:
3.2. 組件源碼
./TransferPlus/index.vue
<!-- 組件使用方式如下: <TransferPlus :sourceList="sourceList" :tableColumnList="tableColumnList" usePagination tableHeight="240" :sourceTotal="sourceTotal" :tableLoading="tableLoading" @fetchSourceList="fetchSourceList" > <template #table_你定義該列的prop="{ columnProps }">{{ columnProps.$index + 1 }}{{columnProps.row.xxx}}</template> </TransferPlus> method:{ async fetchSourceList (params={pageNum,pageSize}) { this.tableLoading = true const res = await getList({ ...this.queryInfo, ...params }) this.sourceList = res.data.list this.sourceTotal = res.data.total this.tableLoading = false } } 外部可通過 ref 調(diào)用的方法: 1. clearSelection():清空所有選擇項; 2. setPaginationParam({pageNum,pageSize},isFetch):設(shè)置源表格分頁器參數(shù),若 isFetch 為 true 則會自動調(diào)用 fetchSourceList( isFetch 默認為 false ); 3. initializeComponent(isFetch):初始化組件,若 isFetch 為 true 則初始化后自動請求源表格數(shù)據(jù)( isFetch 默認為 false ); 4. this.$refs['transferPlusRef'].selectList:若要初始化 selectList 可以使用 ref 設(shè)置(記得外面包裹 this.$nextTick); 注意事項: 1. 使用插槽自定義表格列時,是同時應用到兩個列表中的; 2. 組件會通過 selectionChange 事件告知您選擇的列表結(jié)果; 3. 特別地,組件一開始不會默認請求源表格數(shù)據(jù),所以您需要在使用前自行調(diào)用 fetchSourceList 獲取 sourceList 等來渲染組件的數(shù)據(jù),組件只會在內(nèi)部的分頁狀態(tài)等有更改的情況下自動調(diào)用 fetchSourceList 為您刷新渲染數(shù)據(jù); 4. 若 usePagination 為 true,則組件自動為您控制分頁器,但您必須設(shè)置好變量(sourceTotal)和源表格數(shù)據(jù)請求方法(fetchSourceList),并且為了防止您初始請求的分頁參數(shù)和組件內(nèi)部定義的默認初始分頁參數(shù)不同,您可以設(shè)置 initSourcePageNum 和 initSourcePageSize 來同步內(nèi)外初始化參數(shù); --> <template> <div :class="direction === 'horizontal' ? 'transfer-horizontal' : ''"> <!-- 【待選擇列表】 --> <div :class="['list-wrapping', { horizontal: direction === 'horizontal' }]"> <div class="wrapping-header"> <span>待選擇列表</span> <span>{{ selectLength }}/{{ sourceTotal || sourceList.length }}</span> </div> <div class="wrapping-content"> <!-- 自定義搜索 --> <slot name="source_search" /> <TransferTable ref="sourceTransferTableRef" v-model="selectList" :tableList="sourceList" :tableColumnList="tableColumnList" :tableHeight="tableHeight" :total="sourceTotal" :initPageNum="initSourcePageNum" :initPageSize="initSourcePageSize" :usePagination="usePagination" :tableLoading="tableLoading" :uniqueKey="uniqueKey" :selectable="selectable" :pagerCount="pagerCount" @fetchTableList="handleFetchTableList" > <!-- 使用穿梭表格的自定義列插槽 --> <template v-for="(item, index) in tableColumnList" :slot="`inner_table_${item.prop}`" slot-scope="slotData"> <span :key="index"> <!-- 設(shè)置新的插槽提供給消費端自定義列 --> <slot :name="`table_${item.prop}`" :columnProps="slotData.columnProps" :row="slotData.columnProps.row" :rowIndex="slotData.columnProps.$index"> {{ slotData.columnProps.row[item.prop] || '-' }} </slot> </span> </template> </TransferTable> </div> </div> <!-- 【已添加列表】 --> <div :class="['list-wrapping', { horizontal: direction === 'horizontal' }]"> <div class="wrapping-header"> <span>已添加列表</span> <span>{{ selectLength }}</span> </div> <div class="wrapping-content"> <template v-if="selectLength"> <el-input placeholder="請輸入內(nèi)容" v-model="searchStr" class="search-input" clearable> <el-select slot="prepend" v-model="searchKey" placeholder="請選擇" class="search-select" @change="handleSearchKeyChange" value-key="prop"> <el-option v-for="item in targetSearchList" :key="item.prop" :label="item.label" :value="item.prop"></el-option> </el-select> <el-button slot="append" icon="el-icon-search" @click="handleSearchStrChange"></el-button> </el-input> <TransferTable ref="targetTransferTableRef" :tableList="targetList" :tableColumnList="tableColumnList" :tableHeight="tableHeight" tableType="target" :uniqueKey="uniqueKey" :total="targetTotal" :usePagination="usePagination" :pagerCount="pagerCount" @removeSelectRow="handleRemoveSelectRow" @fetchTableList="getTargetTableList" > <!-- 使用穿梭表格的自定義列插槽 --> <template v-for="(item, index) in tableColumnList" :slot="`inner_table_${item.prop}`" slot-scope="slotData"> <span :key="index"> <!-- 設(shè)置新的插槽提供給消費端自定義列 --> <slot :name="`table_${item.prop}`" :columnProps="slotData.columnProps" :row="slotData.columnProps.row" :rowIndex="slotData.columnProps.$index"> {{ slotData.columnProps.row[item.prop] || '-' }} </slot> </span> </template> </TransferTable> </template> <div class="empty-box" v-else> <el-image class="empty-image" :src="require('@/assets/empty_images/data_empty.png')" /> </div> </div> </div> </div> </template> <script> import TransferTable from './TransferTable.vue' import { throttle, differenceBy, filter, isNil, noop } from 'lodash' export default { components: { TransferTable }, props: { // 源數(shù)據(jù) sourceList: { type: Array, default: () => [], }, // 表格列配置列表 tableColumnList: { type: Array, default: () => [], // {label,prop,align}[] }, // 表格數(shù)據(jù)是否加載中 tableLoading: { type: Boolean, default: false, }, // 表格高度 tableHeight: { type: String | Number, default: 240, }, // 【已添加列表】搜索項(注:與表格列配置對應,且僅能搜索字段類型為 String) searchList: { type: Array, default: () => [], // {label,prop}[] }, // 源表格總數(shù)據(jù)的條數(shù) sourceTotal: { type: Number, default: 0, }, // 源表格初始 pageNum(用于同步消費端初始化請求時的分頁參數(shù),進而幫助控制分頁器) initSourcePageNum: { type: Number, default: 1, }, // 源表格初始 pageSize(用于同步消費端初始化請求時的分頁參數(shù),進而幫助控制分頁器) initSourcePageSize: { type: Number, default: 10, }, // 使用分頁器 usePagination: { type: Boolean, default: false, }, // 唯一標識符(便于定位到某條數(shù)據(jù)進行添加和移除操作) uniqueKey: { type: String, default: 'id', }, // 穿梭框展示方式 direction: { type: String, default: 'vertical', // horizontal 左右布局, vertical 上下布局 }, selectable: { type: Function, default: noop(), }, // 頁碼按鈕的數(shù)量,當總頁數(shù)超過該值時會折疊(element規(guī)定:大于等于 5 且小于等于 21 的奇數(shù)) pagerCount: { type: Number, default: 7, }, }, data() { return { selectList: [], // 已選擇的列表 targetList: [], // 已添加列表的回顯數(shù)據(jù) searchKey: '', searchStr: '', targetPageNum: 1, targetPageSize: 10, targetTotal: 10, } }, computed: { targetSearchList() { return this.searchList.length ? this.searchList : this.tableColumnList }, selectLength() { return this.selectList?.length || 0 }, }, watch: { selectList(newVal) { this.getTargetTableList() this.$emit('selectionChange', newVal) }, }, mounted() { this.searchKey = this.targetSearchList[0].prop this.targetPageNum = 1 this.targetPageSize = 10 }, methods: { handleFetchTableList(params) { this.$emit('fetchSourceList', params) }, handleRemoveSelectRow(rowItem) { this.selectList = differenceBy(this.selectList, [rowItem], this.uniqueKey) }, handleSearchStrChange() { // 每次查詢時只需要重置穿梭框的頁碼到 1,并配置自動調(diào)用搜索函數(shù) this.$refs['targetTransferTableRef'].setPaginationParam({ pageNum: 1 }, true) }, handleSearchKeyChange() { // 更新搜索 Key 之后,需要清空搜索字符串 this.searchStr = '' this.$refs['targetTransferTableRef'].setPaginationParam({ pageNum: 1 }, true) }, getTargetTableList(params = null) { const targetTableList = filter(this.selectList, (item) => { if (this.searchStr) { const itemValueToString = isNil(item[this.searchKey]) ? '' : JSON.stringify(item[this.searchKey]) return itemValueToString.includes(this.searchStr) } else { return true } }) this.targetTotal = targetTableList.length if (params) { this.targetPageNum = params.pageNum this.targetPageSize = params.pageSize } // 前端分頁 const startIndex = (this.targetPageNum - 1) * this.targetPageSize const endIndex = this.targetPageNum * this.targetPageSize this.targetList = targetTableList.slice(startIndex, endIndex) }, clearSelection() { // 清空所有選擇項(用于消費端設(shè)置的 ref 調(diào)用) this.selectList = [] this.targetPageNum = 1 this.targetPageSize = 10 this.searchKey = this.targetSearchList[0].prop }, setPaginationParam({ pageNum, pageSize }, isFetch) { // 設(shè)置源表格分頁器參數(shù)(用于消費端設(shè)置的 ref 調(diào)用) // 若 isFetch 為 true,則自動調(diào)用消費端傳進來的回調(diào)搜索方法 this.$refs['sourceTransferTableRef'].setPaginationParam({ pageNum, pageSize }, isFetch) }, initializeComponent(isFetch) { // 初始化組件(用于消費端設(shè)置的 ref 調(diào)用) // 若 isFetch 為 true,則自動調(diào)用消費端傳進來的回調(diào)搜索方法 this.clearSelection() this.setPaginationParam({ pageNum: this.initSourcePageNum || 1, pageSize: this.initSourcePageSize || 10 }, isFetch) }, }, } </script> <style lang="scss" scoped> .transfer-horizontal { display: flex; } .list-wrapping { margin-bottom: 12px; border-radius: 2px; border: 1px solid #d9d9d9; background: #fff; overflow: hidden; } .horizontal { flex: 1; margin-right: 20px; margin-bottom: 0px; &:last-child { margin: 0px; } } .wrapping-header { width: 100%; padding: 10px 20px; height: 40px; display: flex; justify-content: space-between; align-items: center; border-bottom: 1px solid #d9d9d9; background: #f5f5f5; color: #333; font-size: 14px; line-height: 20px; } .wrapping-content { padding: 12px; width: 100%; } .search-input { margin-bottom: 12px; max-width: 500px; height: 32px; } .search-select { width: 120px; } .empty-box { display: flex; align-items: center; justify-content: center; width: 100%; height: 100%; margin: 40px 0px; } .empty-image { width: 150px; height: 150px; } :deep(.search-input .el-input-group__prepend) { background-color: #fff; } :deep(.el-select .el-input .el-select__caret) { color: #3564ff; } </style>
./TransferPlus/TransferTable.vue
<template> <div> <!-- 表格區(qū)域 --> <el-table ref="transferTable" v-loading="tableLoading" :border="true" :data="tableList" size="mini" :stripe="true" :height="tableHeight || 'auto'" :row-class-name="getTableRowClassName" :header-cell-style="{ background: '#F1F1F1', }" @select="handleSelect" @select-all="handleSelectAll" > <el-table-column type="index" align="center"></el-table-column> <el-table-column type="selection" width="50" v-if="tableType === 'source'" :selectable="selectable"></el-table-column> <el-table-column v-for="(item, index) in tableColumnList" :key="item.prop || index" :label="item.label" :prop="item.prop" :align="item.align || 'left'" :width="item.width || 'auto'" show-overflow-tooltip> <template #default="columnProps"> <slot :name="`inner_table_${item.prop}`" :columnProps="columnProps"> <span>{{ columnProps.row[item.prop] }}</span> </slot> </template> </el-table-column> <el-table-column fixed="right" label="操作" width="70" align="center" v-if="tableType === 'target'"> <template slot-scope="scope"> <el-button @click="handleRemoveRowItem(scope.row, scope.$index)" type="text" icon="el-icon-delete" size="medium"></el-button> </template> </el-table-column> </el-table> <!-- 分頁器區(qū)域 --> <div v-if="usePagination" class="pagination-box"> <!-- 實現(xiàn)兩側(cè)分布的分頁器布局:使用兩個分頁器組件 + 不同 layout 組成 --> <el-pagination background :current-page="pageNum" :layout="layoutLeft" :page-size="pageSize" :pager-count="pagerCount" :total="total" @current-change="handleCurrentChange" @size-change="handleSizeChange" /> <el-pagination background :current-page="pageNum" :layout="layoutRight" :page-size="pageSize" :pager-count="pagerCount" :total="total" @current-change="handleCurrentChange" @size-change="handleSizeChange" /> </div> </div> </template> <script> import { differenceBy, uniqBy, noop } from 'lodash' export default { props: { // 已勾選的數(shù)組 value: { type: Array, default: () => [], require: true, }, // 表格數(shù)據(jù) tableList: { type: Array, default: () => [], }, // 表格列配置列表 tableColumnList: { type: Array, default: () => [], // {label,prop,align}[] }, // 表格數(shù)據(jù)是否加載中 tableLoading: { type: Boolean, default: false, }, // 表格高度 tableHeight: { type: String | Number, default: 240, }, // 表格數(shù)據(jù)類型 tableType: { type: String, default: 'source', // source 源列表,target 目標列表 }, // 【已添加列表】搜索項(注:與表格列配置對應,且僅能字段類型為 String) searchList: { type: Array, default: () => [], // {label,prop,align}[] }, // 分頁后表格總數(shù)據(jù)的條數(shù) total: { type: Number, default: 0, }, // 初始 pageNum initPageNum: { type: Number, default: 1, }, // 初始 pageSize initPageSize: { type: Number, default: 10, }, // 使用分頁器 usePagination: { type: Boolean, default: false, }, // 唯一標識符(便于定位到某條數(shù)據(jù)進行添加和移除操作) uniqueKey: { type: String, default: 'id', }, // Function 的返回值用來決定這一行的 CheckBox 是否可以勾選 selectable: { type: Function, default: noop(), }, // 頁碼按鈕的數(shù)量,當總頁數(shù)超過該值時會折疊(element規(guī)定:大于等于 5 且小于等于 21 的奇數(shù)) pagerCount: { type: Number, default: 7, }, }, data() { return { layoutLeft: 'total', layoutRight: 'sizes, prev, pager, next', pageNum: 1, pageSize: 10, preSelectList: [], // 上一次選擇的數(shù)據(jù)(點擊分頁器就清空) stashSelectList: [], // 暫存數(shù)據(jù),便于點擊頁碼后,還能保存前一頁的數(shù)據(jù) isNeedToggle: true, // 是否需要勾選該頁已選擇項(用于換頁后的回顯選擇項) isTableChangeData: false, // 是否是當前表格造成選擇項的變化(用于同步【待選擇列表】的勾選項) } }, computed: { currentPageSelectList() { const currentSelectList = [] this.stashSelectList?.forEach((item) => { const currentRow = this.tableList?.find((row) => row[this.uniqueKey] === item[this.uniqueKey]) if (currentRow) { currentSelectList.push(currentRow) } }) return currentSelectList }, }, watch: { value(newVal) { this.stashSelectList = newVal || [] // 只有在其他地方修改了選擇表格數(shù)據(jù)后,才刷新覆蓋勾選項(當前表格修改選擇項是雙向綁定的,所以不需要刷新覆蓋勾選項),實現(xiàn)精準回顯和兩表格的聯(lián)動 if (!this.isTableChangeData) { this.handleToggleSelection() } // 當暫存的選擇列表為空時,需要同步更新 preSelect 為空數(shù)組,以便下次選擇時進行判斷是增加選擇項還是減少選擇項 if (!this.stashSelectList.length) { this.preSelectList = [] } this.isTableChangeData = false }, tableList() { if (this.isNeedToggle) { this.preSelectList = this.currentPageSelectList this.handleToggleSelection() this.isNeedToggle = false } }, }, mounted() { this.pageNum = this.initPageNum || 1 this.pageSize = this.initPageSize || 110 // 解決右側(cè)固定操作欄錯位問題 this.$nextTick(() => { this.$refs.transferTable.doLayout() }) this.$emit('selectionChange', []) }, methods: { getTableRowClassName({ rowIndex }) { if (rowIndex % 2 == 0) { return '' } else { return 'stripe-row' } }, fetchTableList(pageNum = 1) { if (this.usePagination) { // 若不是頁碼更改觸發(fā),則默認將 pageNum 重置為 1 this.pageNum = pageNum const params = { pageNum: this.pageNum, pageSize: this.pageSize, } this.$emit('fetchTableList', params) } else { this.$emit('fetchTableList') } }, setPaginationParam({ pageNum, pageSize }, isFetch = false) { // 設(shè)置分頁器參數(shù)(用于消費端設(shè)置的 ref 調(diào)用) this.pageNum = pageNum || this.pageNum this.pageSize = pageSize || this.pageSize this.isNeedToggle = true if (isFetch) { this.fetchTableList() } }, handleSizeChange(val) { this.pageSize = val this.isNeedToggle = true this.fetchTableList() }, handleCurrentChange(val) { this.isNeedToggle = true this.fetchTableList(val) }, handleStashSelectList(isAdd = true, list = []) { if (isAdd) { // 暫存數(shù)組中增加,并兜底去重 this.stashSelectList = uniqBy([...this.stashSelectList, ...list], this.uniqueKey) } else { // 暫存數(shù)組中移除 this.stashSelectList = differenceBy(this.stashSelectList, list, this.uniqueKey) } this.isTableChangeData = true this.$emit('input', this.stashSelectList) this.$emit('selectionChange', this.stashSelectList) }, handleSelect(selectList, row) { // 判斷是否是增加選擇項 const isAddRow = this.preSelectList.length < selectList.length this.handleStashSelectList(isAddRow, [row]) // 更新當前頁記錄的上次數(shù)據(jù) this.preSelectList = [...selectList] }, handleSelectAll(selectList) { // 判斷是否是全選(需要考慮兩個數(shù)組長度相等的情況) const isAddAll = this.preSelectList.length <= selectList.length // 更新當前頁記錄的上次數(shù)據(jù) this.handleStashSelectList(isAddAll, isAddAll ? selectList : this.preSelectList) this.preSelectList = [...selectList] }, handleRemoveRowItem(rowItem, rowIndex) { const remainderPage = this.total % this.pageSize ? 1 : 0 const pageNumTotal = parseInt(this.total / this.pageSize) + remainderPage const isLastPageOnlyOne = rowIndex === 0 && this.pageNum === pageNumTotal // 判斷刪除的是否是最后一頁中只有一條的數(shù)據(jù) if (isLastPageOnlyOne && this.pageNum > 1) { // 若是,則 pageNum 需要往前調(diào)整一頁,因為刪除后最后一頁不存在 this.handleCurrentChange(this.pageNum - 1) } this.$emit('removeSelectRow', rowItem) }, handleToggleSelection() { this.$nextTick(() => { // 先清除所有勾選狀態(tài) this.$refs.transferTable.clearSelection() if (this.currentPageSelectList.length) { // 再依次勾選當前頁存在的行 this.currentPageSelectList.forEach((item) => { this.$refs.transferTable.toggleRowSelection(item, true) }) } }) }, }, } </script> <style scoped> /* 表格斑馬自定義顏色 */ :deep(.el-table__row.stripe-row) { background: #f9f9f9; } /* 表格操作欄按鈕取消間距 */ :deep(.el-button) { padding: 0px; } /* 表格操作欄按鈕固定大小 */ :deep(.el-icon-delete::before) { font-size: 14px !important; } .pagination-box { display: flex; justify-content: space-between; } </style>
到此這篇關(guān)于Vue 實現(xiàn)高級穿梭框 Transfer 封裝的文章就介紹到這了,更多相關(guān)Vue 穿梭框 Transfer 內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
vue 監(jiān)聽input輸入事件(oninput)的示例代碼支持模糊查詢
這篇文章主要介紹了vue 監(jiān)聽input輸入事件(oninput)支持模糊查詢,比如說表格模糊查詢,實現(xiàn)一邊輸入,一邊過濾數(shù)據(jù),本文通過示例代碼給大家詳細講解,需要的朋友可以參考下2023-02-02van-uploader保存文件到后端回顯后端接口返回的數(shù)據(jù)
前端開發(fā)想省時間就是要找框架呀,下面這篇文章主要給大家介紹了關(guān)于van-uploader保存文件到后端回顯后端接口返回的數(shù)據(jù),文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下2023-06-06