最近在使用vue antd admin做后台管理,由于vue2版本的antd vue表格组件没有拖拽功能,所以使用sortablejs实现一下,特此记录
点这里查看官网: sortablejs官网
1.npm install sortable.js --save
2.import Sortable from ‘sortablejs’
StandardTable.vue(表格组件封装)
<template>
<div class="standard-table">
<div class="alert">
<a-alert type="info" :show-icon="true" v-if="selectedRows">
<div class="message" slot="message">
已选择
<a>{{ selectedRows.length }}</a>
项
<a class="clear" @click="onClear">清空</a>
<template v-for="(item, index) in needTotalList">
<div v-if="item.needTotal" :key="index">
{{ item.title }}总计
<a>{{ item.customRender ? item.customRender(item.total) : item.total }}</a>
</div>
</template>
</div>
</a-alert>
</div>
<div ref="Scheduling">
<a-table
:bordered="bordered"
:loading="loading"
:columns="columns"
:dataSource="dataSource"
:rowKey="rowKey"
:pagination="pagination"
:expandedRowKeys="expandedRowKeys"
:expandedRowRender="expandedRowRender"
:customRow='customRow'
@change="onChange"
:rowSelection="selectedRows ? { selectedRowKeys: selectedRowKeys, onChange: updateSelect } : undefined"
>
<template slot-scope="text, record, index" :slot="slot" v-for="slot in Object.keys($scopedSlots).filter(key => key !== 'expandedRowRender')">
<slot :name="slot" v-bind="{ text, record, index }"></slot>
</template>
<template :slot="slot" v-for="slot in Object.keys($slots)">
<slot :name="slot"></slot>
</template>
<template slot-scope="record, index, indent, expanded" :slot="$scopedSlots.expandedRowRender ? 'expandedRowRender' : ''">
<slot v-bind="{ record, index, indent, expanded }" :name="$scopedSlots.expandedRowRender ? 'expandedRowRender' : ''"></slot>
</template>
</a-table>
</div>
</div>
</template>
<script>
import Sortable from 'sortablejs';
export default {
name: 'DragTable',
props: {
bordered: Boolean,
loading: [Boolean, Object],
columns: Array,
dataSource: Array,
rowKey: {
type: [String, Function],
default: 'key'
},
pagination: {
type: [Object, Boolean],
default: true
},
selectedRows: Array,
expandedRowKeys: Array,
expandedRowRender: Function,
customRow: Function
},
data() {
return {
needTotalList: []
};
},
mounted() {
this.$nextTick(() => {
this.rowDrop();
});
},
methods: {
rowDrop() {
const tbody = this.$refs.Scheduling.querySelectorAll('.ant-table-tbody'); // 元素选择器名称根据实际内容替换
Sortable.create(tbody[0], {
sort: true,
handle: '.dragSort', //指定哪个类名的可以拖动
// chosenClass: 'beforLine', //被选中项的css 类名
// dragClass: "sortableDrag", //被拖拽项的css 类名
group: { name: 'name', pull: true, put: true },
onEnd: ({ newIndex, oldIndex }) => {
if (newIndex == oldIndex) return;
const currRow = this.dataSource.splice(oldIndex, 1)[0];
this.dataSource.splice(newIndex, 0, currRow);
let ids = this.dataSource
.map(item => {
return item.id;
})
.join(',');
this.$emit('dragSort',ids)
}
});
},
updateSelect(selectedRowKeys, selectedRows) {
this.$emit('update:selectedRows', selectedRows);
this.$emit('selectedRowChange', selectedRowKeys, selectedRows);
},
initTotalList(columns) {
const totalList = columns
.filter(item => item.needTotal)
.map(item => {
return {
...item,
total: 0
};
});
return totalList;
},
onClear() {
this.updateSelect([], []);
this.$emit('clear');
},
onChange(pagination, filters, sorter, { currentDataSource }) {
this.$emit('change', pagination, filters, sorter, { currentDataSource });
}
},
created() {
this.needTotalList = this.initTotalList(this.columns);
},
watch: {
selectedRows(selectedRows) {
this.needTotalList = this.needTotalList.map(item => {
return {
...item,
total: selectedRows.reduce((sum, val) => {
return sum + val[item.dataIndex];
}, 0)
};
});
}
},
computed: {
selectedRowKeys() {
return this.selectedRows.map(record => {
return typeof this.rowKey === 'function' ? this.rowKey(record) : record[this.rowKey];
});
}
}
};
</script>
<style scoped lang="less">
.standard-table {
.alert {
margin-bottom: 16px;
.message {
a {
font-weight: 600;
}
}
.clear {
float: right;
}
}
}
/deep/.ant-table-row {
position: relative;
&.afterLine:after {
content: '';
display: block;
position: absolute;
width: 100%;
height: 0;
border-top: 1px dashed #ff528b;
bottom: 0;
left: 0;
z-index: 3;
}
&.sortableDrag:after {
content: '';
display: block;
position: absolute;
width: 100%;
height: 0;
border-top: 1px dashed #ff528b;
top: 0;
left: 0;
z-index: 3;
}
}
</style>
使用
<template>
<div class="stickyClassify">
<a-card>
<!-- 表格 -->
<standard-table
:columns="classifyColumns"
:data-source="tableData"
:pagination="pagination"
style="margin-top:20px"
@dragSort="dragSort"
:drag="true"
bordered
:rowKey="
record => {
return record.id;
}
"
>
<div slot="sort" slot-scope="{ record, index }" style="cursor:grab;" class="dragSort">
<a-icon type="flag" />
{{ index + 1 }}
</div>
<div slot="options" class="option"><a>编辑</a></div>
</standard-table>
</a-card>
</div>
</template>
<script>
import StandardTable from '@/components/table/StandardTable';
const classifyColumns = [
{
title: '序号',
scopedSlots: { customRender: 'sort' },
align: 'center'
},
{
title: '名称',
dataIndex: 'name',
align: 'center'
},
{
title: '操作',
scopedSlots: { customRender: 'options' },
align: 'center'
}
];
export default {
components: { StandardTable },
data() {
return {
pagination: {
current: 1,
total: 0
}, //分页数据
tableData: [],
classifyColumns
};
},
mounted() {
this.tableData = [
{
name: '示例1',
id: 1
},
{
name: '示例2',
id: 2
},
{
name: '示例3',
id: 3
},
{
name: '示例4',
id: 4
},
{
name: '示例5',
id: 5
}
];
},
methods:{
dragSort(){
//拖拽完成后做些什么
}
}
};
</script>
<style lang="less" scoped>
.option .option-btn {
color: #ff6396;
padding: 0px 10px;
&:nth-of-type(2) {
border-left: 1px solid #ff6396;
border-right: 1px solid #ff6396;
}
}
</style>
需要的朋友可以参考一下