分页勾选记忆

553 阅读1分钟

表格分页.gif

我们常见的分页勾选可以分为表格分页、非表格类分页, 其中要实现的就是 来回切换分页, 记住每一页选中的数据, 我看很多同学用了各种手段, 这里讲讲我认为比较简单的方案

表格分页勾选

实现表格类勾选记忆主要两种方案

方案一

利用表格插件自带记忆功能, 这里以 el-table 举例

<el-table :data="tableData" row-key="id" border ref="multipleTable" @selection-change="handleSelectionChange">
    <el-table-column type="selection" :reserve-selection="true" width="55" />
    <el-table-column label="通知标题" prop="messageName" />
    <el-table-column label="发布时间" :formatter="formatTime" prop="publishTime" />
    <el-table-column label="发布状态" prop="postStatus" />
    <el-table-column label="操作" :width="200">...</el-table-column>
</el-table>

主要就是加这行代码 :reserve-selection="true" 然后在触发选中时赋值就OK了

handleSelectionChange(val) {
    this.multipleSelection = val
}

这也是最简单的情况, 但是有些项目里用的表格插件不支持分页记忆, 但是它有其它功能需要用到那个插件不能换, 这个时候就需要我们手写表格分页记忆

方案二
<template>
    <Table ref="multipleTable" :columns="columns" :data="data"></Table>
    <Page :total="total" @on-change="onSearch"/>
</template>

<script>
    //创建对象, 保存每一页勾选数据
    const checkData = {}
    export default {
        methods: {
           //分页时触发
           onSearch(page) {
               this.pageNo = page
               checkData[page] = '当前页选中的数据'
               //一般表格都能拿到, 实在不行自己在复选框选中时加个checked字段, 然后在这里过滤
               
               this.getTableData()
           },
           
           getTableData() {
               axios.get({
                   pageNo: this.pageNo,
                   pageSize: this.pageSize,
                   param: {
                       ....
                   }
               }).then(res => {
                   this.tableData = res.data
                   ...
               })
           }
        }
    }
</script>

数据我们是保存了, 接下来就是取数据环节, 比如我们勾选之后,点击了导出数据按钮

<script>
    export default {
        ...
        methods: {
           download() {
               const ids = Object.values(checkData).flat()
               //Object.values处理后=[Array(3), Array(2), Array(6)]   
               //需要flat扁平化下
               
               httpRequest({ids})
           }
        }
    }
</script>

分页数据是完成了, 但是表格勾选回显还要做下

<script>
    export default {
        ...
        methods: {
           getTableData() {
               axios.get({
                   pageNo: this.pageNo,
                   pageSize: this.pageSize,
                   param: {
                       ....
                   }
               }).then(res => {
                   this.tableData = res.data
                   //设置默认选中状态
                   const cureentPageSelectIds = checkData[this.pageNo]
                   this.tableData.map(row => {
                       cureentPageSelectIds.map(id => {
                           if (row.id === id) {
                               //说明之前勾选了, 重新选中它
                               this.$refs.multipleTable.selection(row)
                           }
                       })
                   })
               })
           }
        }
    }
</script>

就这样一个简单版的手写的分页记忆功能实现了  O(∩_∩)O     ^_^

但是! 但是来了, 它还有个小问题就是当你分页过程中改变了每页数据量pageSize, 就得做一些特殊处理了, 想知道怎么处理吗, V me 50 肯德基   ^_^

卡片式分页记忆

除了上面的表格类比较常见的分页记忆还有如下图卡片类的, 这种就是手写 ul > li 做的

image.png

<template>
    <div>
         <ul>
            <li v-for="item in cardList" :key="item.id">
                <div class="card-top">
                    <el-checkbox v-model="item.checked" 
                                :true-label="item.id"
                                :false-label="'false='+item.id"
                                @change="checkChange">
                    </el-checkbox>
                    <!-- true-label: 选中改的值,  false-label: 没有选中的值-->
                    <span>{{ status }}</span>
                </div>
                <div class="card-content">...</div>
            <li>
        </ul>
        <el-pagination :current-page="pageNo"
                       :page-size="pageSize"
                       @current-change="onSearch"
                       layout="prev, pager, next"
                       :total="total">
        </el-pagination>
    </div>
</template>

<script>
    export default {
        data() {
            return {
                pageNo: 1,
                pageSize: 9,
                total: 0,
                cardList: [
                    //demo
                    // {
                    //     id: 1,
                    //     name: '西游记-1',
                    //     url: '',
                    //     checked: false,
                    // }
                ],
                multipleSelection: [], //保存勾选数据
            }
        },
        methods: {
           checkChange(value) {
               //没有选中时, 用false=区分, 可以自定义, 主要是为了区分取消勾选
               if (value.startsWith('false=')) {
                    const ID = value.split('false=')[1]
                    this.multipleSelection.map((item, index, arr) => {
                        if (item.id === ID) {
                            //剔除取消勾选项
                            arr.splice(index, 1)
                        }
                    })
                } else {
                    //选中时,追加勾选项
                    this.cardList.map(card => {
                        if (card.id === value) {
                            this.multipleSelection.push(card)
                        }
                    })
                }
            },
            
            //以上就把勾选当前页完成了, 接下来搞下分页勾选记忆
            async getCardList() {
                this.cardList = ( await axios.get('url') ).data || []
                this.cardList.forEach(card => {
                    this.multipleSelection.map(select => {
                        card.checked = (card.id === select.id)  //增加选中字段
                    })
                })
            }
        }
    }
</script>

这样就完成卡片分页勾选记忆功能啦   (^▽^)
正如上面的截图, 还有个全选功能,我这里也写下

<template>
    <el-checkbox v-model="checkAll" @change="handleCheckAll">全选</el-checkbox>
    <Card />
    <Page />
</template>

<script>
    export default {
        data() {
            return {
                ...
               checkAll: false 
            }
        },
        methods: {
            handleCheckAll(value) {
                if(value) { //全选
                    //所有选中的id 数组
                    const ids = this.multipleSelection.map(select => select.id)
                    
                    //设置卡片数据checked 
                    this.cardList.forEach(card => {
                        this.$set(card, 'checked', true)         
                        //再更新下选中数组
                        if ( !ids.includes(card.id) ) {
                            //全选也只添加之前不存在的
                            this.multipleSelection.push(card)
                        }
                    })
                } else { //全不选
                    this.cardList.forEach(card => {
                        this.$set(card, 'checked', false)  
                        //把取消选中的剔除
                        this.multipleSelection.forEach((select, index, arr) => {
                            if(select.id === card.id) {
                                arr.splice(index, 1)
                            }
                        })
                    })
                }
            },
           
            async getCardList() {
                this.cardList = ( await axios.get('url') ).data || []
                const CheckedIds = this.multipleSelection.map(item => item.id)
                //这个方案比上面比上面双循环性能应该要好些
                this.cardList.forEach(card => {
                    card.checked = CheckedIds.includes(card.id)  
                })
                
                //增加了全选状态判断
                this.checkAll = this.cardList.every(item => item.checked)
            }
        }
    }
</script>

问题:

  1. 这里卡片分页为什么不用上面的表格分页手写记忆方案, 用对象保存每页勾选数据呢? 因为表格可以很轻松拿到当前页勾选数据, 而卡片的checkBox是我们手写的, 还不如用一个数组存全部勾选数据方便

  2. 为啥不直接监听cardList, 当前页可以, 分页了就不行了