1、需求背景
用户需要在表格初始化的时候显示一些已经默认勾选数据(回显数据)和不可操作的数据(置灰数据: disable=true),在用户勾选完成时,保存当前勾选结果作为下次表格的回显数据(此应用在与弹窗相结合的场景中会遇到)
因此本文是在上文的逻辑上新增两个数组:
- 1、回显数组redisplayData
- 2、置灰数组setDisableData
2、思维导图
3、 相关代码
3.1 封装的table组件代码
// STable.vue
<template>
<div class="s-table">
<el-table
ref="innerTable"
class="table"
style="width: 100%"
:row-key="getRowKeys"
:data="tableData"
:total="total"
v-bind="$attrs"
@select="select"
@select-all="selectAll"
v-on="$listeners"
>
<el-table-column
v-if="selectable"
type="selection"
width="80"
:reserve-selection="true"
:selectable="selectableHandler"
></el-table-column>
<el-table-column
v-for="(item) in columns"
:key="item.prop"
:prop="item.prop"
:label="item.label"
:sortable="item.sortable"
:width="parseInt(item.width)"
>
</el-table-column>
</el-table>
</div>
</template>
<script>
export default {
name: 'STable',
props: {
// 默认列
columns: {
type: Array,
default: () => []
},
tableData: {
type: Array,
default: () => []
},
// 是否可选
selectable: {
type: Boolean,
default: false
},
// 是否跨页全选
isSelectedAll: {
type: Boolean,
default: false
},
// table表格的总数据条数
total: {
type: Number,
default: 0
},
// 回显数据
redisplayData: {
type: Array,
default: () => []
},
// 置灰数据
setDisableData: {
type: Array,
default: () => []
}
},
data() {
return {
uncheckedArr: [],
ifRedisplay: false,
redisplayArr: [], // 克隆接收到的redisplayData的值
disabledCheckedArr: [], // 被勾选的置灰数据
disabledUnCheckedArr: [] // 未被勾选的置灰数据(不可勾选)
}
},
watch: {
// 分页全选-监听数据变化
tableData: {
handler (value) {
this.isSelectedAll && this.chooseAllPages(this.isSelectedAll)
!this.isSelectedAll && this.checkedSelected()
this.ifRedisplay && this.redisplayHandler()
this.$nextTick(() => {
if (this.uncheckedArr.length === 0 && this.$refs.innerTable.selection.length === this.total - this.disabledUnCheckedArr.length) {
this.$emit('update:isSelectedAll', true)
}
})
},
deep: true
}
},
mounted() {
if (document) {
document.addEventListener('click', this.hideSettings)
}
this.redisplayData.length > 0 ? this.ifRedisplay = true : this.ifRedisplay = false
this.redisplayArr = JSON.parse(JSON.stringify(this.redisplayData))
this.ifRedisplay && this.redisplayHandler()
this.setDisableData.length > 0 && this.disabledArrHandler()
},
methods: {
getRowKeys(row) {
return row.id
},
// 全选所有页面
chooseAllPages(val) {
if (val) {
// 全选
this.$nextTick(() => {
let choosedArr = []
this.tableData.map(row => {
if (this.setDisableData.map(v => v.id).indexOf(row.id) < 0) {
choosedArr.push(row)
}
})
choosedArr.forEach(row => {
this.$refs.innerTable.toggleRowSelection(row, true)
})
})
} else {
// 取消全选
this.uncheckedArr = []
this.redisplayArr = []
this.$nextTick(() => {
this.$refs.innerTable.clearSelection()
this.$nextTick(() => {
this.tableData.forEach(row => {
if (this.disabledCheckedArr.map(v => v.id).indexOf(row.id) >= 0) {
this.$refs.innerTable.toggleRowSelection(row, true)
}
})
})
})
}
},
// 切换分页时选择之前选中
checkedSelected() {
if (this.isSelectedAll) {
// 全选状态
this.$nextTick(() => {
this.tableData.forEach(row => {
this.$refs.innerTable.toggleRowSelection(row, true)
})
})
} else {
// 非全选状态下
if (this.uncheckedArr.length > 0) {
this.$nextTick(() => {
this.tableData.forEach(row => {
if ((this.uncheckedArr.map(v => v.id).indexOf(row.id) < 0) && (this.disabledUnCheckedArr.map(v => v.id).indexOf(row.id) < 0)) {
this.$refs.innerTable.toggleRowSelection(row, true)
}
if (this.disabledCheckedArr.map(v => v.id).indexOf(row.id) >= 0) {
this.$refs.innerTable.toggleRowSelection(row, true)
}
})
})
}
this.$nextTick(() => {
this.tableData.forEach(row => {
if (this.disabledCheckedArr.map(v => v.id).indexOf(row.id) >= 0) {
this.$refs.innerTable.toggleRowSelection(row, true)
}
})
})
}
},
// 全选后取消单个选择事件,当用户手动勾选数据行的 Checkbox 时触发的事件
select(selection, row) {
this.selectExceptCardIds(selection, row)
this.$emit('select', [selection, row])
},
// 单个选择事件
selectExceptCardIds(selection, row) {
if (this.isSelectedAll) {
// 全选状态下,列表行数据都处于被选中状态,手动勾选只能触发取消选中
this.uncheckedArr.push(row)
if (this.ifRedisplay) {
this.redisplayArr.map((v, index) => {
if (row.id === v.id) {
this.redisplayArr.splice(index, 1)
}
})
}
this.$emit('update:isSelectedAll', false)
} else {
// false, 非全选状态下,列表行数据可能被 取消选中 或者 重新勾选
if (selection.indexOf(row) >= 0) {
// 勾选
selection.map(el => {
this.uncheckedArr.map((v, index) => {
if (el.id === v.id) {
this.uncheckedArr.splice(index, 1)
if (this.uncheckedArr.length === 0) {
this.$emit('update:isSelectedAll', true)
}
}
})
})
} else {
// 取消勾选
// 1、若是uncheckedArr.length > 0,取消勾选的数组加入uncheckedArr
if (this.uncheckedArr.length > 0) {
this.uncheckedArr.push(row)
}
// 有回显数的取消勾选
if (this.ifRedisplay) {
this.redisplayArr.map((v, index) => {
if (row.id === v.id) {
this.redisplayArr.splice(index, 1)
}
})
}
}
if (selection.length === this.total - this.disabledUnCheckedArr.length) {
this.$emit('update:isSelectedAll', true)
}
}
},
// 全选后取消单页选择事件,当用户手动勾选数据行的 Checkbox 时触发的事件
selectAll(selection) {
this.selectAllRows(selection)
this.$emit('selectAll', selection)
},
// 单页选择事件
selectAllRows(selection) {
if (this.isSelectedAll) {
// 全选状态下,列表行数据都处于被选中状态,手动勾选只能触发取消选中
this.tableData.map(row => {
this.uncheckedArr.push(row)
if (this.ifRedisplay) {
this.redisplayArr.map((v, index) => {
if (row.id === v.id) {
this.redisplayArr.splice(index, 1)
}
})
}
})
this.$emit('update:isSelectedAll', false)
} else {
// false,部分选中状态下
selection.map(row => {
// 勾选
this.uncheckedArr.map((v, index) => {
if (row.id === v.id) {
this.uncheckedArr.splice(index, 1)
}
if (this.uncheckedArr.length === 0) {
this.$emit('update:isSelectedAll', true)
}
})
// 取消勾选
if (this.uncheckedArr.length > 0 && this.tableData.map(v => v.id).indexOf(row.id) === -1) {
this.uncheckedArr.push(row)
}
// 有回显数据
if (this.ifRedisplay) {
this.redisplayArr.map((v, index) => {
if (row.id === v.id) {
this.redisplayArr.splice(index, 1)
}
})
}
})
if (selection.length === this.total - this.disabledUnCheckedArr.length) {
this.$emit('update:isSelectedAll', true)
}
}
},
// 回显数据
redisplayHandler() {
if (this.redisplayArr.length > 0) {
this.$nextTick(() => {
this.tableData.forEach(row => {
if (this.redisplayArr.map(v => v.id).indexOf(row.id) >= 0) {
this.$refs.innerTable.toggleRowSelection(row, true)
}
})
})
}
},
// 置灰数组处理
disabledArrHandler() {
if (this.redisplayData.length > 0) {
this.setDisableData.map(row => {
if (this.redisplayData.map(v => v.id).indexOf(row.id) > 0) {
this.disabledCheckedArr.push(row)
} else {
this.disabledUnCheckedArr.push(row)
}
})
}
},
// 置灰操作
selectableHandler(row, index) {
let flag = true
for (let i = 0; i < this.setDisableData.length; i++) {
if (row.id === this.setDisableData[i].id) {
flag = false
}
}
return flag
}
}
}
</script>
<style lang="scss">
</style>
3.2 示例代码
// example.vue
<template>
<el-card>
<el-checkbox
v-model="isSelectedAll"
@change="checkboxChange"
>全选所有</el-checkbox>
<s-table
ref="accessControlTable"
:table-data="tableData.slice((currentPage - 1) * pageSize, currentPage * pageSize)"
:redisplay-data="redisplayData"
:set-disable-data="setDisableData"
:columns="columns"
:selectable="true"
:total="tableData.length"
:is-selected-all.sync="isSelectedAll"
>
</s-table>
<el-pagination
class="s-pagination"
:currrent-page="currentPage"
:page-size="pageSize"
:page-sizes="[5,10,20,30]"
:total="tableData.length"
layout="total, prev, pager, next, sizes, jumper"
@current-change="handleCurrentChange"
@size-change="handleSizeChange"
>
</el-pagination>
</el-card>
</template>
<script>
import STable from '../components/STable.vue'
export default {
name: 'selectedAll',
components: {
STable
},
data() {
return {
tableData: [
{
id: 1,
date: '2016-05-02',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄'
},
{
id: 2,
date: '2016-05-03',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄'
},
{
id: 3,
date: '2016-05-04',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄'
},
{
id: 4,
date: '2016-05-05',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄'
},
{
id: 5,
date: '2016-05-06',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄'
},
{
id: 6,
date: '2016-05-07',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄'
},
{
id: 7,
date: '2016-05-08',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄'
},
{
id: 8,
date: '2016-05-09',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄'
},
{
id: 9,
date: '2016-05-10',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄'
},
{
id: 10,
date: '2016-05-11',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄'
},
{
id: 11,
date: '2016-05-12',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄'
}
],
redisplayData: [
{
id: 1,
date: '2016-05-02',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄'
},
{
id: 3,
date: '2016-05-04',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄'
},
{
id: 5,
date: '2016-05-06',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄'
},
{
id: 8,
date: '2016-05-09',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄'
},
{
id: 10,
date: '2016-05-09',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄'
},
{
id: 11,
date: '2016-05-12',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄'
}
],
setDisableData: [
{
id: 2,
date: '2016-05-03',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄'
},
{
id: 3,
date: '2016-05-04',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄'
},
{
id: 4,
date: '2016-05-05',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄'
},
{
id: 7,
date: '2016-05-08',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄'
},
{
id: 10,
date: '2016-05-11',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄'
}
],
columns: [
{
label: '日期',
prop: 'date',
width: 180
},
{
label: '姓名',
prop: 'name',
width: 180
},
{
label: '地址',
prop: 'address'
}
],
currentPage: 1, // 当前页码
pageSize: 5, // 每页的数据条数
total: 0,
isSelectedAll: false
}
},
methods: {
handleSizeChange(val) {
this.currentPage = 1
this.pageSize = val
},
handleCurrentChange(val) {
this.currentPage = val
},
// 手动点击改变全选/非全选状态触发的事件
checkboxChange(val) {
this.$refs.accessControlTable.chooseAllPages(val)
}
}
}
</script>
<style scoped>
.s-pagination {
text-align: right;
margin-top: 10px;
}
</style>
4、相关属性和方法
| 属性或者方法名 | 说明 | 类型 | 可选值 | 默认值 |
|---|---|---|---|---|
| columns | 默认列 | Array | -- | [] |
| tableData | 表格数据 | Array | -- | [] |
| selectable | 是否可选 | Boolean | true/false | false |
| isSelectedAll | 是否跨页全选 | Boolean | true/false | false |
| total | 表格数据的总条目数 | Number | -- | 0 |
| redisplayData | 回显数据 | Array | -- | [] |
| setDisableData | 置灰数据 | Array | -- | [] |
| chooseAllPages | 全选所有页面 | Function | -- | -- |
说明:
isSelectedAll表示表格数据是否全选,可用户传入对初始状态进行设置,设置为true表示初始默认设置全选;
chooseAllPages用户手动改变isSelectedAll的值时,需要调用触发chooseAllPages事件;
注意: 要实现跨页全选,传入的tableData数据中必须包含id属性;