199 lines
5.1 KiB
Vue
199 lines
5.1 KiB
Vue
<template>
|
||
<a-table
|
||
ref="tableRef"
|
||
class="custom-table"
|
||
:class="['custom-table', canSelect && multiple && mouseMoveSelect ? 'mouse-move-select' : '']"
|
||
v-bind="$attrs"
|
||
:data-source="list"
|
||
:columns="columns"
|
||
:size="size"
|
||
:row-key="rowKey"
|
||
:loading="loading"
|
||
:pagination="pagination"
|
||
:customRow="multiple && mouseMoveSelect ? customMouseMoveSelectRow : customRow"
|
||
:rowClassName="() => (canSelect ? 'custom-table-row' : '')"
|
||
@change="handleTableChange"
|
||
>
|
||
<!-- 处理 scopedSlots -->
|
||
<template v-for="slotName of scopedSlotsKeys" :slot="slotName" slot-scope="text, record, index">
|
||
<slot :name="slotName" :text="text" :record="record" :index="index"></slot>
|
||
</template>
|
||
</a-table>
|
||
</template>
|
||
<script>
|
||
export default {
|
||
props: {
|
||
list: {
|
||
type: Array,
|
||
default: () => [],
|
||
},
|
||
columns: {
|
||
type: Array,
|
||
default: () => [],
|
||
},
|
||
size: {
|
||
type: String,
|
||
default: 'middle',
|
||
},
|
||
rowKey: {
|
||
type: String,
|
||
default: 'id',
|
||
},
|
||
loading: {
|
||
type: Boolean,
|
||
},
|
||
pagination: {
|
||
type: [Object, Boolean],
|
||
},
|
||
selectedRowKeys: {
|
||
type: Array,
|
||
},
|
||
selectionRows: {
|
||
type: Array,
|
||
},
|
||
canSelect: {
|
||
type: Boolean,
|
||
default: true,
|
||
},
|
||
canDeselect: {
|
||
type: Boolean,
|
||
default: true,
|
||
},
|
||
// 多选
|
||
multiple: {
|
||
type: Boolean,
|
||
default: false,
|
||
},
|
||
// 鼠标移动选择
|
||
mouseMoveSelect: {
|
||
type: Boolean,
|
||
default: true,
|
||
},
|
||
},
|
||
data() {
|
||
return {
|
||
innerSelectedRowKeys: [],
|
||
innerSelectedRows: [],
|
||
}
|
||
},
|
||
mounted() {
|
||
if (this.canSelect && this.multiple && this.mouseMoveSelect) {
|
||
const tbody = this.$el.querySelector('.ant-table-tbody')
|
||
tbody.addEventListener('mouseleave', () => {
|
||
this.mouseMoveStartIndex = undefined
|
||
})
|
||
}
|
||
},
|
||
methods: {
|
||
// 实现单击选中/反选功能
|
||
customRow(record, index) {
|
||
const key = record[this.rowKey]
|
||
return {
|
||
class: this.innerSelectedRowKeys.includes(key) ? 'ant-table-row-selected' : '',
|
||
on: {
|
||
click: () => {
|
||
if (!this.canSelect) {
|
||
return
|
||
}
|
||
// 反选
|
||
if (this.innerSelectedRowKeys.includes(key)) {
|
||
if (this.multiple || this.canDeselect) {
|
||
const findIndex = this.innerSelectedRowKeys.findIndex((k) => k == key)
|
||
this.innerSelectedRowKeys.splice(findIndex, 1)
|
||
}
|
||
}
|
||
// 选中
|
||
else {
|
||
if (this.multiple) {
|
||
this.innerSelectedRowKeys.push(key)
|
||
} else {
|
||
this.innerSelectedRowKeys = [key]
|
||
}
|
||
}
|
||
this.$emit('detail', record)
|
||
|
||
this.$emit('rowClick', record, index)
|
||
},
|
||
dblclick: () => {
|
||
this.$emit('rowDblClick', record, index)
|
||
},
|
||
},
|
||
}
|
||
},
|
||
|
||
// 实现鼠标拖移动多选功能
|
||
customMouseMoveSelectRow(record, index) {
|
||
const key = record[this.rowKey]
|
||
return {
|
||
class: this.innerSelectedRowKeys.includes(key) ? 'ant-table-row-selected' : '',
|
||
on: {
|
||
mousedown: () => {
|
||
this.innerSelectedRowKeys = []
|
||
this.mouseMoveStartIndex = index
|
||
},
|
||
mouseenter: () => {
|
||
if (this.mouseMoveStartIndex !== undefined) {
|
||
const indexes = [this.mouseMoveStartIndex, index].sort((a, b) => a - b)
|
||
this.innerSelectedRowKeys = this.list.slice(indexes[0], indexes[1] + 1).map((item) => item[this.rowKey])
|
||
}
|
||
},
|
||
mouseup: () => {
|
||
// 开始和结束在同一个,相当于click
|
||
if (this.mouseMoveStartIndex == index) {
|
||
this.innerSelectedRowKeys = [key]
|
||
}
|
||
this.mouseMoveStartIndex = undefined
|
||
},
|
||
},
|
||
}
|
||
},
|
||
|
||
handleTableChange(pagination, filters, sorter) {
|
||
this.$emit('change', pagination, filters, sorter)
|
||
},
|
||
|
||
// 让第index行滚动到视野范围
|
||
scrollIntoView(index) {
|
||
const tableEle = this.$refs.tableRef.$el
|
||
const tableBodyEle = tableEle.querySelector('.ant-table-body')
|
||
const prevEle = tableBodyEle.querySelector(`.ant-table-row:nth-child(${index + 1})`)
|
||
tableBodyEle.scrollTop = prevEle.offsetTop
|
||
},
|
||
},
|
||
watch: {
|
||
selectedRowKeys(val) {
|
||
this.innerSelectedRowKeys = val
|
||
},
|
||
innerSelectedRowKeys() {
|
||
this.$emit('update:selectedRowKeys', this.innerSelectedRowKeys)
|
||
this.innerSelectedRows = this.innerSelectedRowKeys.map((key) => {
|
||
return this.list.find((item) => item[this.rowKey] === key)
|
||
})
|
||
this.$emit('update:selectionRows', this.innerSelectedRows)
|
||
},
|
||
},
|
||
computed: {
|
||
scopedSlotsKeys() {
|
||
return Object.keys(this.$scopedSlots)
|
||
},
|
||
},
|
||
}
|
||
</script>
|
||
<style lang="less" scoped>
|
||
::v-deep {
|
||
.custom-table-row {
|
||
cursor: pointer;
|
||
}
|
||
}
|
||
|
||
.mouse-move-select {
|
||
user-select: none;
|
||
|
||
::v-deep {
|
||
td {
|
||
transition: none !important;
|
||
}
|
||
}
|
||
}
|
||
</style>
|