前言
ant design + HTML原生表格 + draggable + vue-scroll 实现给表格数据排序并计算开始时间和结束时间且表格可滚动,效果图如下
一、html
<!-- 数字输入框 -->
<a-input-number id="inputNumber" v-model="form.topicTime" style="width: 40%;" :min="1" :max="10" @change="getTopicTime()" />分钟
<!-- 表格 -->
<table>
<td style="border: 0px;">
<tr>
<td class="titleClass" style="width:60px;background: #fafafa;">
<a-checkbox v-model="checkState" :indeterminate="indeterminate" @click="onCheckAllChange()" />
</td>
<td v-for="(item, index) in titleList" :key="index" class="titleClass" style="background: #fafafa;" :style="getTableWidth(index)">{{ item }}</td>
</tr>
<vue-scroll :ops="ops" :style="getStyle1()">
<draggable v-model="dataSource" animation="500" force-fallback="true" :move="checkMove" @start="onStart" @end="onEnd" @change="getTopicTime()">
<tr v-for="(item, index) in dataSource" :key="item.id" :class="rowClassName(index)">
<td class="titleClass" style="width:60px">
<a-checkbox v-model="item.isTrusted" @change="onChange(item)" />
</td>
<td class="titleClass" style="width:60px">{{ index +1 }}</td>
<td class="titleClass" style="width:200px">{{ item.topicName }}</td>
<td class="titleClass" style="width:100px">{{ item.partNumber }}</td>
<td class="titleClass" style="width:100px">{{ item.topicType }}</td>
<td class="titleClass" style="width:100px">{{ item.specialGroup }}</td>
<td class="titleClass" style="width:100px">{{ item.meetingPurpose }}</td>
<td class="titleClass" style="width:100px">{{ item.fsPrincipal }}</td>
<td class="titleClass" style="width:100px">{{ item.ppPrincipal }}</td>
<td class="titleClass" style="width:100px">{{ item.materialGroup }}</td>
<td class="titleClass" style="width:100px">{{ item.startTime }}</td>
<td class="titleClass" style="width:100px">{{ item.endTime }</td>
</tr>
</draggable>
</vue-scroll>
</td>
</table>
<a-space style="float: right;margin: 15px;" size="large">
<a-button class="save" @click="topIndex()">置顶</a-button>
<a-button @click="bottomIndex()">置底</a-button>
</a-space>
二、data
data() {
return {
drag: false,
titleList: ['序号', '议题名称', '零件编号', '议题类型', '专业组', '上会目的', 'FS负责人', 'PP负责人', '材料组', '起始时间', '结束时间'],
checkedList: [], // 选中的数据
checkState: false, // 全选check选中状态
indeterminate: false, // 非全选check选中状态
ops: {
vuescroll: {},
scrollPanel: {},
rail: {
keepShow: true
},
bar: {
hoverStyle: true,
onlyShowBarOnScroll: false, // 是否只有滚动的时候才显示滚动条
background: '#00519B', // 滚动条颜色
opacity: 1, // 滚动条透明度
'overflow-x': 'hidden'
}
},
dataSource: [{ topicId: 1, topicName: '议题1', isTrusted: false },
{ topicId: 2, topicName: '议题2', startTime: '', endTime: '', isTrusted: false },
{ topicId: 3, topicName: '议题3', startTime: '', endTime: '', isTrusted: false },
{ topicId: 4, topicName: '议题4', startTime: '', endTime: '', isTrusted: false },
{ topicId: 5, topicName: '议题5', startTime: '', endTime: '', isTrusted: false },
{ topicId: 6, topicName: '议题6', startTime: '', endTime: '', isTrusted: false }],
form: {
topicTime: 3
},
}
},
三、methods
// 根据选中数据数量来改变 全选check样式
onChange(e) {
console.log(e)
let m = 0 // m 为选中的数据数量
for (let n = 0; n < this.dataSource.length; n++) {
if (this.dataSource[n].isTrusted === true) {
m++
}
}
// m = 0 时 显示空白
// 0 < m < 全部数量 显示方块
// m = 全部数量 显示对号
if (m < this.dataSource.length && m > 0) {
this.checkState = false
this.indeterminate = true
} else if (m === 0) {
this.checkState = false
this.indeterminate = false
} else if (m === this.dataSource.length) {
this.checkState = true
this.indeterminate = false
}
},
// 全选方法
onCheckAllChange() {
if (this.checkedList.length < this.dataSource.length) {
for (let n = 0; n < this.dataSource.length; n++) {
this.dataSource[n].isTrusted = true
// 这里是深复制,如果直接等于,在下面清空时会清空原数据
this.checkedList = JSON.parse(JSON.stringify(this.dataSource))
}
} else {
for (let n = 0; n < this.dataSource.length; n++) {
this.dataSource[n].isTrusted = false
this.checkedList = []
}
}
},
// 不同列不同宽度
getTableWidth(index) {
if (index === 0) {
return 'width: 60px;'
} else if (index === 1) {
return 'width: 200px;'
} else {
return 'width: 100px;'
}
},
// 根据页面分辨率自适应表格高度
getStyle1() {
const fullWidth = document.documentElement.clientWidth
if (fullWidth >= 1680) {
return 'width:100%;height:300px;'
} else if (window.screen.width < 1680) {
return 'width:100%;height:200px;'
}
},
// 表格斑马线
rowClassName(index) {
let className = 'light-row'
if (index % 2 === 1) className = 'dark-row'
return className
},
// 开始拖拽事件
onStart() {
this.drag = true
},
// 拖拽结束事件
onEnd() {
this.drag = false
console.log('end..............')
},
// 设置拖动放置规则
checkMove(evt) {
console.log(evt)
return true
},
// 置顶
topIndex() {
var that = this
// 将所有 isTrusted 为 true 的数据存入 checkedList 中,并删除
this.dataSource.forEach(function (item){
if (item.isTrusted === true) {
item.isTrusted = false
that.checkedList.push(item)
}
})
// 将checkedList中的数据从dataSource中删除
let diff = [...this.dataSource]
for (let i = 0, len = this.dataSource.length; i < len; i++ ) {
let flag = false
for (let j = 0, length = this.checkedList.length; j < length; j++) {
if (this.dataSource[i].topicId === this.checkedList[j].topicId) {
flag = true
}
}
if (flag) {
diff.splice(diff.findIndex(item => item.topicId === this.dataSource[i].topicId), 1)
}
}
this.dataSource = diff
// 将checkedList中的数据插入dataSource前面
for (let i = this.checkedList.length -1; i >= 0; i--) {
this.dataSource.unshift(this.checkedList[i])
}
this.checkedList = []
this.getTopicTime()
},
// 置地
bottomIndex(arr,index) {
var that = this
// 将所有 isTrusted 为 true 的数据存入 checkedList 中,并删除
this.dataSource.forEach(function (item){
if (item.isTrusted === true) {
item.isTrusted = false
that.checkedList.push(item)
}
})
// 将checkedList中的数据从dataSource中删除
let diff = [...this.dataSource]
for (let i = 0, len = this.dataSource.length; i < len; i++ ) {
let flag = false
for (let j = 0, length = this.checkedList.length; j < length; j++) {
if (this.dataSource[i].topicId === this.checkedList[j].topicId) {
flag = true
}
}
if (flag) {
diff.splice(diff.findIndex(item => item.topicId === this.dataSource[i].topicId), 1)
}
}
this.dataSource = diff
// 将checkedList中的数据插入dataSource后面
for (let i = 0; i < this.checkedList.length; i++) {
this.dataSource.push(this.checkedList[i])
}
this.checkedList = []
this.getTopicTime()
},
// 计算议题开始结束时间
getTopicTime() {
var that = this
let date = new Date(2021, 6, 25, 8, 0, 0) // 传入的会议开始日期,时间
let startDate = '' // 议题开始的时间
let endDate = '' // 议题结束的时间
let hour = '' // 议题所在小时
let startMinute = '' // 议题开始分钟
let endMinute = '' // 议题结束分钟
this.dataSource.forEach(function (item, index){
startDate = new Date(date.setMinutes(date.getMinutes()))
endDate = new Date(date.setMinutes(date.getMinutes() + that.form.topicTime))
hour = date.getHours() < 10 ? '0' + date.getHours() : date.getHours()
// console.log('hour:' + hour)
startMinute = startDate.getMinutes() < 10 ? '0' + startDate.getMinutes() : startDate.getMinutes()
endMinute = endDate.getMinutes() < 10 ? '0' + endDate.getMinutes() : endDate.getMinutes()
// console.log('startMinute:' + startMinute)
// console.log('endMinute:' + endMinute)
item.startTime = hour + ':' + startMinute
item.endTime = hour + ':' + endMinute
// console.log(item.startTime)
// console.log(item.endTime)
})
},
大功告成!剩下的样式什么的不用看也行,就是还原ant表格的样式
四、CSS
<style scoped>
/*选中样式*/
.chosen {
border: solid 1px #3089dc !important;
}
/*定义要拖拽元素的样式*/
.titleClass {
padding: 16px 16px;
border: 0px solid #fff;
font-size: 12px;
font-weight: 500;
}
.chackClass {
position: relative;
top: 0;
left: 0;
display: block;
width: 16px;
height: 16px;
background-color: #fff;
border: 1px solid #ddd;
border-radius: 2px;
border-collapse: separate;
}
.light-row {
background-color: #fff;
}
.dark-row {
background-color: #F8FBFE;
}
table.itxst {
border-collapse: collapse;
margin-bottom: -6px;
padding-bottom: 0px;
min-width: 6px;
background: #fafafa;
}
table.itxst th {
border: #ddd solid 1px;
padding: 8px;
background-color: #dedede;
}
table.itxst td {
border: #ddd solid 1px;
padding: 8px;
background-color: #ffffff;
}
table.itxst tr {
cursor: pointer;
}
table.itxst td.move:hover {
cursor: move;
}
</style>
总结
记得下载引入组件
npm install vuedraggable --save
npm install vue-scroll --save
main.js中:
import vuescroll from "vuescroll";//引入vuescroll
import "vuescroll/dist/vuescroll.css";//引入vuescroll样式
Vue.use(vuescroll);
。。。大概吧,记不住了