?實現效果:(可拉代碼下來看:vue-demo: vueDemo)
左側表格為點擊查詢調用接口查詢出來的數據,右側表格為左側表格所有選擇的數據,由前端實現分頁。
兩個el-table勾選數據聯動更新
實現邏輯:
el-table表格的selection-change方法(element組件的table表格)結合分頁組件,自定義一個用于存儲(左側表格)當前頁的已勾選數據;一個用于存儲所勾選的所有數據(右側表格所有數據);一個用于存儲(右側表格)當前頁的展示數據。
代碼實現:
?所有代碼:
<template><div><Search v-show="showSearch" label-width="100" :limit-height-param="false" @search="handleQuery" @clear="resetQuery"><div><span class="label">賬號名稱</span><el-selectv-model="queryParams.companyCodeList"placeholder="請選擇賬號名稱"clearablefilterabledefault-first-optionmultiplesize="small"><el-optionv-for="item in companyCodeOptions":key="item.dictValue":label="`${item.dictLabel} | ${item.dictValue}`":value="item.dictValue"></el-option></el-select></div><div><span class="label">賬戶類型</span><el-selectv-model="queryParams.accountType"placeholder="請選擇賬戶類型"clearablefilterabledefault-first-optionsize="small"><el-optionv-for="dict in accountTypeOptions":key="dict.dictValue":label="dict.dictLabel":value="dict.dictValue"></el-option></el-select></div><div><span class="label">銀行卡號</span><el-inputv-model="queryParams.cardNum"placeholder="請輸入銀行卡號"clearablesize="small"@keyup.enter.native="handleQuery"/></div></Search><el-row :gutter="20"><el-col :span="12"><el-tablev-loading="tableLoading"ref="multipleTable":data="tableData":stripe="true":row-key="getRowKeys":row-style="{height: '54px'}"@selection-change="handleSelectionChange"><el-table-column type="selection" align="center" width="55" fixed /><el-table-column label="序號" type="index" align="center" width="55" fixed /><el-table-column label="公司名稱" prop="companyCode" :formatter="tableFormat" align="center" min-width="120" show-overflow-tooltip /><el-table-column label="bankAccountId" prop="bankAccountId" align="center" min-width="130" show-overflow-tooltip /><el-table-column label="賬戶類型" prop="accountType" :formatter="tableFormat" align="center" min-width="100" show-overflow-tooltip /><el-table-column label="銀行卡號" prop="cardNum" align="center" min-width="220" show-overflow-tooltip /><template v-for="(column, columIndex) in tableColumnOption"><el-table-column:key="columIndex":prop="column.prop":label="column.label":min-width="column.width":fixed="column.fixed || false":align="column.align || 'center'":sortable="column.sortable || false":index="columIndex":show-overflow-tooltip="column.tooltip || true"><!-- v-for="(column, columIndex) in tableColumnOption" --><template slot-scope="scope"><span v-if="column.prop === 'status'"><el-tag v-if="scope.row.status == 0" type="danger">禁用</el-tag><el-tag v-else-if="scope.row.status == 1" type="success">啟用</el-tag></span><span v-else-if="column.prop === 'type'"><el-tag v-if="scope.row.type == 1">type1</el-tag><el-tag v-if="scope.row.type == 0" type="success">type0</el-tag></span><span v-else>{{ scope.row[column.prop] }}</span></template></el-table-column></template></el-table><paginationv-show="total > 0":total="total":page.sync="queryParams.pageNum":limit.sync="queryParams.pageSize":page-sizes="[3, 5, 10, 20, 30, 50]":pagerCount="5"@pagination="getList"/></el-col><el-col :span="12"><el-tablev-loading="tableLoading"ref="selectMultipleTable":data="selectTableData":row-style="{height: '54px'}"><el-table-column label="序號" type="index" align="center" width="55" fixed /><el-table-column label="賬戶名稱" prop="companyCode" :formatter="tableFormat" align="center" min-width="120" show-overflow-tooltip /><el-table-column label="bankAccountId" prop="bankAccountId" align="center" min-width="130" show-overflow-tooltip /><el-table-column label="賬戶類型" prop="accountType" :formatter="tableFormat" align="center" min-width="100" show-overflow-tooltip /><el-table-column label="銀行卡號" prop="cardNum" align="center" min-width="220" show-overflow-tooltip /><el-table-columnlabel="操作"align="center"fixed="right"width="100"><template slot-scope="scope"><el-buttonclass="delBtn"size="small"type="text"icon="el-icon-delete"@click="handleDelete(scope.row)">刪除</el-button></template></el-table-column></el-table><paginationv-show="selectTotal > 0":total="selectTotal":page.sync="pageNum":limit.sync="pageSize":page-sizes="[3, 5, 10, 20, 30, 50]":pagerCount="5"@pagination="getSelectList"/></el-col></el-row></div>
</template><script>
import Search from '@/components/Search/index'
import {deepClone,
} from '@/utils'
import {getDepartmentsList
} from '@/api/tableLinkage'
import {geBasicAccountType,geBasicCompany,
} from '@/api/selectList'export default {components: {Search,},data() {return {// 遮罩層// loading: false,tableLoading: false,// 顯示搜索條件showSearch: true,// 查詢參數queryParams: {pageNum: 1,pageSize: 10,companyCodeList: [],cardNum: null,accountType: null,},companyCodeOptions: [],accountTypeOptions: [],codeBsOptions: [],allDataScopeOptions: [{dictValue: '1',dictLabel: '是'},{dictValue: '0',dictLabel: '否'}],total: 0, // 搜索表格(左側)總條數selectTotal: 0, // 勾選表格(右側)總條數pageNum: 1, // 勾選表格(右側)當前頁碼pageSize: 10, // 勾選表格(右側)每頁數量tableData: [], // 搜索表格(左側)數據selectedData: [], // 所勾選的所有數據selectTableData: [], // 勾選表格(右側)當前頁展示的數據multipleSelection: [], // 當前頁選中的數據idKey: 'bankAccountId', // 標識列表數據中每一行的唯一鍵的名稱// idKey: 'id', // 標識列表數據中每一行的唯一鍵的名稱tableColumnOption: [{prop: 'preview',label: 'preview',width: '200',},{prop: 'status',label: 'status',width: '200',},{prop: 'jobType',label: 'jobType',width: '200',},{prop: 'type',label: 'type',width: '200',},],columnOption: [// { selection: true },// { type: 'index' },// {prop: 'name', label: '名稱', width: 160},// { slot: 'action', label: '操作' }],}},created () {// 若初始就有選中數據,需要對選中數據分頁// this.selectedData = [...]// this.handleSelectListPaging()this.geBasicAccountType()this.geBasicCompany()this.getList()},methods: {geBasicAccountType () {geBasicAccountType().then(res => {this.accountTypeOptions = res.data})},geBasicCompany () {geBasicCompany().then(res => {this.companyCodeOptions = res.data})},getList () {this.tableLoading = truegetDepartmentsList(this.queryParams).then(res => {console.log("🚀 ~ file: index.vue:24 ~ getDepartmentsList ~ res:", res)// console.log(res.data)this.tableData = res?.rows || []this.total = res?.total || 0// this.handleSelectListPaging()this.$nextTick(() => {// 設置選中this.setSelectRow()})this.tableLoading = false}).catch(() => { this.tableLoading = false })},/** 搜索按鈕操作 */handleQuery() {this.queryParams.pageNum = 1this.getList()},/** 重置按鈕操作 */resetQuery() {this.queryParams = this.$options.data().queryParamsthis.handleQuery()},tableFormat(row, { property }, value) {return this.selectDictLabel(this[`${property}Options`], value)},// 對表格數據分頁getSelectList() {const start = Math.ceil(((this.pageNum - 1) * this.pageSize).toFixed(0)),end = Math.ceil((start + this.pageSize).toFixed(2))this.selectTableData = this.selectedData.slice(start >= 0 ? start : 0, end)// this.$refs.selectMultipleTable.bodyWrapper.scrollTo(0, 0)},handleSelectListPaging() {// 前端分頁選中數據表格(左側表格)this.selectTotal = this.selectedData.length// 總頁數=(總數 - 1)/ 每頁數量 + 1// 總頁數=(總數 + 每頁數量 - 1)/ 每頁數量// 總頁數 = Math.ceil(總條數 / 每頁數量)// 使用Math.ceil()函數,返回大于或者等于指定表達式的最小整數,進1法取整const totalPage = Math.ceil(this.selectTotal / this.pageSize)// 原頁碼大于現數據的總頁數,頁碼取總頁數的值this.pageNum = this.pageNum > totalPage ? totalPage : this.pageNum// 頁碼最小值為1this.pageNum = this.pageNum < 1 ? 1 : this.pageNum// 對表格數據分頁this.getSelectList()},// 設置選擇表格行唯一標識getRowKeys(row) {return row[this.idKey]},// 設置選中的方法setSelectRow() {if (!this.selectedData || this.selectedData.length <= 0) {return}// 標識當前行的唯一鍵的名稱let idKey = this.idKey// 獲取所有選中數據的idconst selectAllIds = this.selectedData.map(row => row[idKey]) || []console.warn("🚀 ~ file: dataAuthenticationUpdateDetail.vue:558 ~ setSelectRow ~ selectAllIds:", selectAllIds)this.$refs.multipleTable.clearSelection() // 先清空原有選中數據this.tableData.forEach(item => {// 查找當前頁中是否包含所有選中數據中的id,存在則設置選中(觸發 handleSelectionChange ,進而觸發記憶選擇核心方法 changePageCoreRecordData)if (selectAllIds.indexOf(item[idKey]) >= 0) {this.$refs.multipleTable.toggleRowSelection(item, true)}})},// 多選框選中數據handleSelectionChange(selection) {this.multipleSelection = selectionthis.$nextTick(() => {this.changePageCoreRecordData()})},// 記憶選擇核心方法(操作搜索表格——左側,聯動改變勾選表格——右側)async changePageCoreRecordData() {// 標識當前行的唯一鍵的名稱let idKey = this.idKey// 如果總記憶中還沒有選擇的數據,那么就直接取當前頁選中的數據,不需要后面一系列計算if (this.selectedData.length <= 0) {this.selectedData = this.multipleSelection// 前端分頁this.handleSelectListPaging()return}// 總選擇里面的key集合const selectAllIds = this.selectedData.map(row => row[idKey]) || []// 獲取當前頁選中的idlet selectIds = []this.multipleSelection.forEach(row => {selectIds.push(row[idKey])// 如果總選擇里面不包含當前頁選中的數據,那么就加入到總選擇集合里// (左側表格勾選數據,加入到右側表格中)if (selectAllIds.indexOf(row[idKey]) < 0) {this.selectedData.push(row)}})// 得到當前頁沒有選中的idlet noSelectIds = []this.tableData.map(row => {if (selectIds.indexOf(row[idKey]) < 0) {noSelectIds.push(row[idKey])}})noSelectIds.map(id => {if (selectAllIds.indexOf(id) >= 0) {for (let i = 0; i < this.selectedData.length; i++) {if (this.selectedData[i][idKey] === id) {console.warn('總選擇中有未被選中的,那么就刪除這條:', id)// 如果總選擇中有未被選中的,那么就刪除這條// (左側表格取消勾選數據,從右側表格中刪除這條數據)this.selectedData.splice(i, 1)break}}}})// 前端分頁this.handleSelectListPaging()},// 刪除handleDelete(row) {// 標識當前行的唯一鍵的名稱let idKey = this.idKey// 過濾所有選中數據,將要刪除的這條數據過濾掉this.selectedData = this.selectedData.filter(item => {return item[idKey] !== row[idKey]})// 查找當前頁是否存在需要刪除的這條數據const findRow = this.tableData.find(item => { return row[idKey] === item[idKey] })if (findRow) {// 當前頁存在要刪除的這條數據,取消選中狀態// (觸發 handleSelectionChange ,進而觸發記憶選擇核心方法 changePageCoreRecordData)this.$refs.multipleTable.toggleRowSelection(findRow)} else {// 當前頁不存在需要刪除的這條數據,直接調用前端分頁方法,對所有選中數據(已剔除需要刪除的這條數據)重新進行分頁this.handleSelectListPaging()}},// 處理參數handleParams() {const param = deepClone(this.form)const bankAccountIdList = this.selectedData.map(item => item.bankAccountId)const params = {id: param.id,codeBs: param.codeBs,allDataScope: param.allDataScope,bankAccountIdList: bankAccountIdList}return params},}
}
</script><style>
</style>
關鍵步驟:
?
當點擊搜索查詢左側數據、或切換分頁、切換頁面大小,調用后端接口(this.getList())的時候,需要調用選中方法(this.setSelectRow()):
// 設置選中的方法setSelectRow() {if (!this.selectedData || this.selectedData.length <= 0) {return}// 標識當前行的唯一鍵的名稱let idKey = this.idKey// 獲取所有選中數據的idconst selectAllIds = this.selectedData.map(row => row[idKey]) || []console.warn("🚀 ~ file: dataAuthenticationUpdateDetail.vue:558 ~ setSelectRow ~ selectAllIds:", selectAllIds)this.$refs.multipleTable.clearSelection() // 先清空原有選中數據this.tableData.forEach(item => {// 查找當前頁中是否包含所有選中數據中的id,存在則設置選中// (觸發 handleSelectionChange ,進而觸發記憶選擇核心方法 changePageCoreRecordData)if (selectAllIds.indexOf(item[idKey]) >= 0) {this.$refs.multipleTable.toggleRowSelection(item, true)}})},
設置選中方法,先清空左側表格原有選中數據,然后根據右側表格所有選中數據的id(自己設定的key)來判斷右側表格當前頁是否存在選中數據,存在則調用el-table的toggleRowSelection方法,將數據勾選上。(toggleRowSelection方法會觸發el-table的selection-change【即觸發handleSelectionChange】進而觸發記憶選擇核心方法 changePageCoreRecordData)
// 多選框選中數據handleSelectionChange(selection) {this.multipleSelection = selectionthis.$nextTick(() => {this.changePageCoreRecordData()})},
勾選右側表格數據觸發記憶選擇核心方法 changePageCoreRecordData:
// 記憶選擇核心方法(操作搜索表格——左側,聯動改變勾選表格——右側)async changePageCoreRecordData() {// 標識當前行的唯一鍵的名稱let idKey = this.idKey// 如果總記憶中還沒有選擇的數據,那么就直接取當前頁選中的數據,不需要后面一系列計算if (this.selectedData.length <= 0) {this.selectedData = this.multipleSelection// 前端分頁this.handleSelectListPaging()return}// 總選擇里面的key集合const selectAllIds = this.selectedData.map(row => row[idKey]) || []// 獲取當前頁選中的idlet selectIds = []this.multipleSelection.forEach(row => {selectIds.push(row[idKey])// 如果總選擇里面不包含當前頁選中的數據,那么就加入到總選擇集合里// (左側表格勾選數據,加入到右側表格中)if (selectAllIds.indexOf(row[idKey]) < 0) {this.selectedData.push(row)}})// 得到當前頁沒有選中的idlet noSelectIds = []this.tableData.map(row => {if (selectIds.indexOf(row[idKey]) < 0) {noSelectIds.push(row[idKey])}})noSelectIds.map(id => {if (selectAllIds.indexOf(id) >= 0) {for (let i = 0; i < this.selectedData.length; i++) {if (this.selectedData[i][idKey] === id) {console.warn('總選擇中有未被選中的,那么就刪除這條:', id)// 如果總選擇中有未被選中的,那么就刪除這條// (左側表格取消勾選數據,從右側表格中刪除這條數據)this.selectedData.splice(i, 1)break}}}})// 前端分頁this.handleSelectListPaging()},
????????
????????如果總記憶中還沒有選擇的數據,那么就直接取當前頁選中的數據,不需要后面一系列計算。
????????如果已經有已選擇的數據了,則先獲取當前頁選中數據的值集,獲取當前頁沒有選中的數據的值集。如果總選擇里面不包含當前頁選中的數據,那么就將這些數據加入到總選擇集合里(左側表格勾選數據,加入到右側表格中)。如果總選擇中有未被選中的數據,那么就從總選擇表格中刪除這些數據(左側表格取消勾選數據,從右側表格中刪除這條數據)。
? ? ? ? 這里經過上述計算后,得到最新的右側表格全部數據,這時就需要對右側表格重新分頁:
(涉及到總頁面數的計算,看這里Javascript 前端分頁——根據頁面大小(pageSize)和總行數(total)計算總頁面數(totalPage)-CSDN博客)
// 對表格數據分頁getSelectList() {const start = Math.ceil(((this.pageNum - 1) * this.pageSize).toFixed(0)),end = Math.ceil((start + this.pageSize).toFixed(2))this.selectTableData = this.selectedData.slice(start >= 0 ? start : 0, end)// this.$refs.selectMultipleTable.bodyWrapper.scrollTo(0, 0)},handleSelectListPaging() {// 前端分頁選中數據表格(左側表格)this.selectTotal = this.selectedData.length// 總頁數=(總數 - 1)/ 每頁數量 + 1// 總頁數=(總數 + 每頁數量 - 1)/ 每頁數量// 總頁數 = Math.ceil(總條數 / 每頁數量)// 使用Math.ceil()函數,返回大于或者等于指定表達式的最小整數,進1法取整const totalPage = Math.ceil(this.selectTotal / this.pageSize)// 原頁碼大于現數據的總頁數,頁碼取總頁數的值this.pageNum = this.pageNum > totalPage ? totalPage : this.pageNum// 頁碼最小值為1this.pageNum = this.pageNum < 1 ? 1 : this.pageNum// 對表格數據分頁this.getSelectList()},
????????前面已經講了左側表格勾選,取消勾選時,對右側表格的聯動改變。下面來講,右側表格刪除一條數據,如何讓左側表格取消勾選。其實也很簡單,就是從右側表格全部數據中,將要刪除的數據去掉,若這條數據在左側表格當前頁存在,則觸發el-table的toggleRowSelection(row,false)方法,取消勾選。若這條數據左側表格在當前頁不存在,則直接對右側表格重新分頁就好了。因為下次當左側表格重新調用getList()方法(觸發記憶選擇核心方法 changePageCoreRecordData)的時候,右側表格內已經沒有要刪除的數據了。
// 刪除handleDelete(row) {// 標識當前行的唯一鍵的名稱let idKey = this.idKey// 過濾所有選中數據,將要刪除的這條數據過濾掉this.selectedData = this.selectedData.filter(item => {return item[idKey] !== row[idKey]})// 查找當前頁是否存在需要刪除的這條數據const findRow = this.tableData.find(item => { return row[idKey] === item[idKey] })if (findRow) {// 當前頁存在要刪除的這條數據,取消選中狀態// (觸發 handleSelectionChange ,進而觸發記憶選擇核心方法 changePageCoreRecordData)this.$refs.multipleTable.toggleRowSelection(findRow)} else {// 當前頁不存在需要刪除的這條數據,直接調用前端分頁方法,對所有選中數據(已剔除需要刪除的這條數據)重新進行分頁this.handleSelectListPaging()}},
參考文章:
element的table表格多選結合分頁實現已選中的記憶功能和實現表格數據和已選數據動態同步更新_element table分頁多選-CSDN博客