Vue使用el-table實現(xiàn)表格跨頁多選
前言
在我們?nèi)粘m椖块_發(fā)中,經(jīng)常會有 表格跨頁多選
的需求,接下來讓我們用 el-table
示例一步步來實現(xiàn)這個需求。
動手開發(fā)
在線體驗
priceless-mcclintock-4cp7x3 - CodeSandbox
常規(guī)版本
本部分只寫了一些重點代碼,心急的彥祖可以直接看 性能進階版
- 首先我們需要初始化一個選中的數(shù)組
checkedRows
this.checkedRows = []
- 在觸發(fā)選中的時候,我們就需要把當前行數(shù)據(jù)
push
到checkedRows
,否則就需要剔除對應(yīng)行
<el-table ref="multipleTable" @select="handleSelectChange"> handleSelectChange (val, row) { const checkedIndex = this.checkedRows.findIndex(_row => _row.id === row.id) if (checkedIndex > -1) { // 選中剔除 this.checkedRows.splice(checkedIndex, 1) } else { // 未選中壓入 this.checkedRows.push(row) } }
- 實現(xiàn)換頁的時候的回顯邏輯
this.data.forEach(row=>{ const checkedIndex = this.checkedRows.findIndex(_row => _row.id === row.id) if(checkedIndex>-1) this.$refs.multipleTable.toggleRowSelection(row,true) })
效果預(yù)覽
讓我們看下此時的效果
完整代碼
<template> <div> <el-table ref="multipleTable" :data="tableData" tooltip-effect="dark" style="width: 100%" @select="handleSelectChange" @select-all="handleSelectAllChange" > <el-table-column type="selection" width="55" /> <el-table-column label="日期" width="120" prop="date" /> <el-table-column prop="name" label="姓名" width="120" /> </el-table> <el-pagination background :current-page.sync="currentPage" layout="prev, pager, next" :total="1000" @current-change="currentChange" /> </div> </template> <script> export default { data () { return { currentPage: 1, checkedRows: [], pageSize: 10, totalData: Array.from({ length: 1000 }, (_, index) => { return { date: '2016-05-03', id: index, name: '王小虎' + index } }) } }, computed: { tableData () { const { currentPage, totalData, pageSize } = this return totalData.slice((currentPage - 1) * pageSize, currentPage * pageSize) } }, methods: { currentChange (page) { this.currentPage = page this.tableData.forEach(row => { const checkedIndex = this.checkedRows.findIndex(_row => _row.id === row.id) if (checkedIndex > -1) this.$refs.multipleTable.toggleRowSelection(row, true) }) }, handleSelectChange (val, row) { const checkedIndex = this.checkedRows.findIndex(_row => _row.id === row.id) if (checkedIndex > -1) { this.checkedRows.splice(checkedIndex, 1) } else { this.checkedRows.push(row) } }, handleSelectAllChange (val) { this.tableData.forEach(row => { this.handleSelectChange(null, row) }) } } } </script>
性能進階版
性能缺陷分析
優(yōu)秀的彥祖?zhèn)?應(yīng)該發(fā)現(xiàn)以上代碼的性能缺陷了
1. handleSelectChange
需要執(zhí)行一個 O(n)
復(fù)雜度的循環(huán)
2. currentChange
的回顯邏輯內(nèi)部, 有一個 O(n^2)
復(fù)雜度的循環(huán)
想象一下 如果場景中勾選的行數(shù)達到了 10000
行, 每頁顯示 100
條
那么我們每次點擊換頁 最壞情況就要執(zhí)行 10000 * 100
次循環(huán),這是件可怕的事...
重新設(shè)計數(shù)據(jù)結(jié)構(gòu)
其實我們沒必要把 checkedRows
設(shè)計成一個數(shù)組, 我們可以設(shè)計成一個 map
,這樣讀取值就只需要 O(1)
復(fù)雜度
1.改造 checkedRows
this.crossPageMap = new Map()
2.修改選中邏輯( 核心代碼
)
handleSelectChange (val, row) { // 實現(xiàn)了 O(n) 到 O(1) 的提升 const checked = this.crossPageMap.has(row.id) if (checked) { this.crossPageMap.delete(row.id) } else { this.crossPageMap.set(row.id, row) } }
3.修改換頁回顯邏輯
currentChange (page) { this.currentPage = page // 實現(xiàn)了 O(n^2) 到 O(n) 的提升 this.tableData.forEach(row => { const checked = this.crossPageMap.has(row.id) if (checked) this.$refs.multipleTable.toggleRowSelection(row, true) }) }
完整代碼
<template> <div> <el-table ref="multipleTable" :data="tableData" tooltip-effect="dark" style="width: 100%;height:500px" @select="handleSelectChange" @select-all="handleSelectAllChange" > <el-table-column type="selection" width="55" /> <el-table-column label="日期" width="120" prop="date" /> <el-table-column prop="name" label="姓名" width="120" /> </el-table> <el-pagination background :current-page.sync="currentPage" layout="prev, pager, next" :total="1000" @current-change="currentChange" /> </div> </template> <script> export default { data () { return { currentPage: 1, crossPageMap: new Map(), pageSize: 10, totalData: Array.from({ length: 1000 }, (_, index) => { return { date: '2016-05-03', id: index, name: '王小虎' + index } }) } }, computed: { tableData () { const { currentPage, totalData, pageSize } = this return totalData.slice((currentPage - 1) * pageSize, currentPage * pageSize) } }, methods: { currentChange (page) { this.currentPage = page this.tableData.forEach(row => { const checked = this.crossPageMap.has(row.id) if (checked) this.$refs.multipleTable.toggleRowSelection(row, true) }) }, handleSelectChange (val, row) { const checked = this.crossPageMap.has(row.id) if (checked) { this.crossPageMap.delete(row.id) } else { this.crossPageMap.set(row.id, row) } }, handleSelectAllChange (val) { this.tableData.forEach(row => { this.handleSelectChange(null, row) }) } } } </script>
抽象業(yè)務(wù)邏輯
以上就是完整的業(yè)務(wù)代碼部分,但是為了復(fù)用性。
我們考慮可以把其中的邏輯抽象成一個 CrossPage
類
設(shè)計 CrossPage 類
接收以下參數(shù)
`data` - 行數(shù)據(jù) `key` - 行數(shù)據(jù)唯一值 `max` - 最大選中行數(shù) `toggleRowSelection` - 切換行數(shù)據(jù)選中/取消選中的方法
提供以下方法
`onRowSelectChange` - 外部點行數(shù)據(jù)點擊的時候調(diào)用此方法 `onDataChange` - 外部數(shù)據(jù)變化的時候調(diào)用此方法 `clear` - 清空所有選中行
構(gòu)造器大致代碼 如下
constructor (options={}) { this.crossPageMap = new Map() this.key = options.key || 'id' this.data = options.data || [] this.max = options.max || Number.MAX_SAFE_INTEGER this.toggleRowSelection = options.toggleRowSelection if(typeof this.toggleRowSelection !== 'function') throw new Error('toggleRowSelection is not function') }
設(shè)置私有crossPageMap
彥祖?zhèn)?問題來了,我們把 crossPageMap
掛載到實例上,那么外部就可以直接訪問修改這個變量。
這可能導致我們內(nèi)部的數(shù)據(jù)邏輯錯亂,所以必須禁止外部訪問。
我們可以使用 #
修飾符來實現(xiàn)私有屬性,具體參考
類私有域 - JavaScript | MDN (mozilla.org)
完整代碼
- CrossPage.js
/** * @description 跨頁選擇 * @param {Object} options * @param {String} options.key 行數(shù)據(jù)唯一標識 * @param {Array} options.data 行數(shù)據(jù) * @param {Number} options.max 最大勾選行數(shù) * @param {Function} options.toggleRowSelection 設(shè)置行數(shù)據(jù)選中/取消選中的方法,必傳 */ export const CrossPage = class { #crossPageMap = new Map(); constructor (options={}) { this.key = options.key || 'id' this.data = options.data || [] this.max = options.max || Number.MAX_SAFE_INTEGER this.toggleRowSelection = options.toggleRowSelection if(typeof this.toggleRowSelection !== 'function') throw new Error('toggleRowSelection is not function') } get keys(){ return Array.from(this.#crossPageMap.keys()) } get values(){ return Array.from(this.#crossPageMap.values()) } get size(){ return this.#crossPageMap.size } clear(){ this.#crossPageMap.clear() this.updateViews() } onRowSelectChange (row) { if(typeof row !== 'object') return console.error('row is not object') const {key,toggleRowSelection} = this const checked = this.#crossPageMap.has(row[key]) if(checked) this.#crossPageMap.delete(row[key]) else { this.#crossPageMap.set(row[key],row) if(this.size>this.max){ this.#crossPageMap.delete(row[key]) toggleRowSelection(row,false) } } } onDataChange(list){ this.data = list this.updateViews() } updateViews(){ const {data,toggleRowSelection,key} = this data.forEach(row=>{ toggleRowSelection(row,this.#crossPageMap.has(row[key])) }) } }
- crossPage.vue
<template> <div> <el-table ref="multipleTable" :data="tableData" tooltip-effect="dark" style="width: 100%" @select="handleSelectChange" @select-all="handleSelectAllChange" > <el-table-column type="selection" width="55" /> <el-table-column label="日期" width="120" prop="date" /> <el-table-column prop="name" label="姓名" width="120" /> </el-table> <el-button @click="clear"> 清空 </el-button> <el-button @click="keys"> 獲取 keys </el-button> <el-button @click="values"> 獲取 values </el-button> <el-pagination background :current-page.sync="currentPage" layout="prev, pager, next" :total="1000" @current-change="currentChange" /> </div> </template> <script> import { CrossPage } from './CrossPage' export default { data () { return { currentPage: 1, pageSize: 10, totalData: Array.from({ length: 1000 }, (_, index) => { return { date: '2016-05-03', id: index, name: '王小虎' + index } }), multipleSelection: [] } }, computed: { tableData () { const { currentPage, totalData, pageSize } = this return totalData.slice((currentPage - 1) * pageSize, currentPage * pageSize) } }, mounted () { this.crossPageIns = new CrossPage({ key: 'id', max: 2, data: this.tableData, toggleRowSelection: this.$refs.multipleTable.toggleRowSelection }) }, methods: { clear () { this.crossPageIns.clear() }, keys () { console.log('keys:', this.crossPageIns.keys) }, values () { console.log('values:', this.crossPageIns.values) }, currentChange (page) { this.currentPage = page // 調(diào)用實例 onDataChange 方法 this.crossPageIns.onDataChange(this.tableData) }, handleSelectChange (val, row) { // 調(diào)用實例 onRowSelectChange 方法 this.crossPageIns.onRowSelectChange(row) }, handleSelectAllChange (val) { this.tableData.forEach(row => { this.crossPageIns.onRowSelectChange(row) }) } } } </script>
寫在最后
未來想做的還有很多
- 利用
requestIdleCallback
提升單頁大量數(shù)據(jù)的toggleRowSelection
渲染效率 - 提供默認選中項的配置
- ...
以上就是Vue使用el-table實現(xiàn)表格跨頁多選的詳細內(nèi)容,更多關(guān)于Vue el-table表格跨頁多選的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
vue實現(xiàn)樹形結(jié)構(gòu)增刪改查的示例代碼
其實很多公司都會有類似于用戶權(quán)限樹的增刪改查功能,本文主要介紹了vue實現(xiàn)樹形結(jié)構(gòu)增刪改查,具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-09-09詳解如何在Vue中快速實現(xiàn)數(shù)據(jù)可視化大屏展示
在現(xiàn)代數(shù)據(jù)驅(qū)動的應(yīng)用程序中,數(shù)據(jù)可視化大屏已經(jīng)成為了非常重要的一環(huán),通過對海量數(shù)據(jù)進行可視化展示,可以幫助用戶更好地理解和分析數(shù)據(jù),從而做出更加明智的決策,在Vue中進行數(shù)據(jù)可視化大屏展示也變得越來越流行,本文將介紹如何在Vue中快速實現(xiàn)數(shù)據(jù)可視化大屏展示2023-10-10vue使用原生js實現(xiàn)滾動頁面跟蹤導航高亮的示例代碼
這篇文章主要介紹了vue使用原生js實現(xiàn)滾動頁面跟蹤導航高亮的示例代碼,滾動頁面指定區(qū)域?qū)Ш礁吡?。小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-10-10vue配置electron使用electron-builder進行打包的操作方法
這篇文章主要介紹了vue配置electron使用electron-builder進行打包的操作方法,本文通過實例代碼給大家介紹的非常詳細,感興趣的朋友跟隨小編一起看看吧2024-08-08