sortablejs实现列表拖拽排序
2022-07-29 04:39:00
2025-01-10 14:22:57
引用方法
Vue3
shell
npm i -S sortablejs
shell
import Sortable from "sortablejs";
使用方法
js
<template>
<el-card class="box-card">
<template #header>
<div class="flex justify-between">
<span>友链列表</span>
<el-button type="primary" @click="addEditFriendLinks">添加友链</el-button>
</div>
</template>
<div class="table1">
<el-table
ref="dragTable"
:data="tableData"
style="width: 100%"
border
show-overflow-tooltip
stripe
class="t1"
row-key="id"
:row-class-name="tableRowClassName"
>
<el-table-column prop="orderId" label="排序" align="center" width="100" class="sorting">
<template #default="scope">
<el-button class="move" type="text" size="small">{{ scope.row.orderId }}</el-button>
</template>
</el-table-column>
<el-table-column prop="avatar" label="友链Logo" align="center" width="100">
<template #default="scope">
<a :href="scope.row.url" target="_blank">
<img :src="scope.row.avatar" class="avatar" />
</a>
</template>
</el-table-column>
<el-table-column prop="name" label="友链名称" align="center" width="150" />
<el-table-column
prop="status"
:formatter="formatterStatus"
label="状态"
width="120"
align="center"
/>
<el-table-column prop="desc" :formatter="formatterDesc" label="简介描述" align="center" />
<el-table-column prop="url" label="友链地址" align="center">
<template #default="scope">
<a :href="scope.row.url" target="_blank">{{ scope.row.url }}</a>
</template>
</el-table-column>
<el-table-column prop="createdAt" label="创建时间" align="center" width="120" />
<el-table-column prop="updatedAt" label="更新时间" align="center" width="120" />
<el-table-column prop="address" label="操作" align="center" width="220">
<template #default="scope">
<el-button @click="handleEdit(scope.row)">编辑</el-button>
<el-popconfirm
title="确定删除这个友链么?"
confirm-button-text="确定"
cancel-button-text="取消"
icon="el-icon-info"
icon-color="red"
@confirm="deleteType(scope.row.id)"
>
<template #reference>
<el-button type="danger">删除</el-button>
</template>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
</div>
<!-- dialog -->
<el-dialog v-model="visible" :title="titleMsg" width="400px">
<el-form ref="formRef" :model="formData" :rules="rules">
<el-form-item label="友链名称" prop="name" label-width="90px">
<el-input v-model="formData.name" placeholder="请填写友链名称" />
</el-form-item>
<el-form-item label="友链logo" prop="avatar" label-width="90px">
<el-input v-model="formData.avatar" placeholder="请填写友链logo图片地址" />
</el-form-item>
<el-form-item label="友链地址" prop="url" label-width="90px">
<el-input v-model="formData.url" placeholder="请填写友链地址链接" />
</el-form-item>
<el-form-item label="友链简述" prop="desc" label-width="90px">
<el-input
v-model="formData.desc"
:rows="3"
type="textarea"
placeholder="请填写友链简述说明"
/>
</el-form-item>
<el-form-item label="友链状态" prop="status" label-width="90px">
<el-select v-model="formData.status" placeholder="请选择友链状态">
<el-option
v-for="item in statusMap"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item label="排序定义" label-width="90px" prop="orderId">
<el-input v-model="formData.orderId" placeholder="填写排序数字[不填写系统自动赋予]" />
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="visible = false">取 消</el-button>
<el-button type="primary" @click="submit">确 定</el-button>
</span>
</template>
</el-dialog>
<!-- 分页 -->
<div class="flex justify-center mt-6">
<el-pagination
:current-page="params.page"
:page-size="params.pageSize"
:page-sizes="[10, 20, 30, 10000]"
:disabled="disabled"
:background="background"
layout="sizes, prev, pager, next, jumper"
:total="total"
@size-change="handleSizeChange"
@current-change="changePage"
/>
</div>
</el-card>
</template>
<script setup lang="ts">
import {
getFriendLinks,
createFriendLinks,
updateFriendLinks,
delFriendLinks,
} from '@/api/friend-links';
import { ElMessage } from 'element-plus';
import { formatTime } from '@/utils/tools';
import { statusMap } from './constant';
import Sortable from 'sortablejs';
const background = ref(false);
const disabled = ref(false);
const handleSizeChange = (val: number) => {
params.value.pageSize = val;
queryFriendLinks();
};
const formRef: any = ref(null);
const data: any = reactive({
tableData: [],
total: null,
params: {
page: 1,
pageSize: 10,
},
activeId: null,
formData: {
name: null,
status: 1,
orderId: null,
desc: null,
url: null,
avatar: null,
},
visible: false,
type: 1,
rules: {
name: [{ required: true, message: '请填写友链名称', trigger: 'blur' }],
desc: [{ required: true, message: '请填写友链描述', trigger: 'blur' }],
url: [{ required: true, message: '请填写友链地址', trigger: 'blur' }],
avatar: [{ required: true, message: '请填写友链logo地址', trigger: 'blur' }],
status: [{ required: true, message: '请选择友链状态', trigger: 'blur' }],
},
});
const { tableData, total, params, formData, visible, rules } = toRefs(data);
/* 查询友链列表 */
async function queryFriendLinks() {
const res: any = await getFriendLinks(data.params);
formatTime(res.rows);
data.tableData = res.rows;
data.total = res.count;
}
queryFriendLinks();
/* 添加或者修改友链 */
function addEditFriendLinks() {
data.type = 1;
data.visible = true;
}
const submit = async () => {
formRef.value.validate(async (valid) => {
if (valid) {
let param = JSON.parse(JSON.stringify(data.formData));
param.id && delete param.id;
data.type === 2 && (param.id = data.activeId);
if (data.type === 1) {
await createFriendLinks(param);
} else {
await updateFriendLinks(param);
}
ElMessage({ message: '操作成功', type: 'success' });
data.visible = false;
formRef.value.resetFields();
data.formData = resetForm();
queryFriendLinks();
}
});
};
function changePage(val) {
data.params.page = val;
queryFriendLinks();
}
function handleEdit(row) {
const { name, status, orderId, desc, url, avatar, id } = row;
data.activeId = id;
data.type = 2;
Object.assign(data.formData, { name, status, orderId, desc, url, avatar });
data.visible = true;
}
async function deleteType(id) {
await delFriendLinks({ id });
ElMessage({ message: '删除成功', type: 'success' });
queryFriendLinks();
}
const titleMsg = computed(() => {
return data.type === 1 ? '添加友链' : '修改友链';
});
const resetForm = () => {
return { name: null, status: 1, orderId: null };
};
function formatterStatus(row) {
return row.status == 1 ? '激活' : '禁止';
}
function formatterDesc(row) {
return row.desc.length > 16 ? row.desc.substr(0, 16) + '...' : row.desc;
}
// 创建sortable实例
function initSortable(className) {
// 获取表格row的父节点
const table = document.querySelector('.' + className + ' .el-table__body-wrapper tbody');
// 创建拖拽实例
let dragTable = Sortable.create(table, {
//动画
animation: 150,
// 拖拽不可用? false 启用(刚刚渲染表格的时候起作用,后面不起作用)
disabled: false,
//指定拖拽目标,点击此目标才可拖拽元素(此例中设置操作按钮拖拽)
handle: '.move',
//指定不可拖动的类名(el-table中可通过row-class-name设置行的class)
filter: '.disabled',
//设置拖拽样式类名
dragClass: 'dragClass',
//设置拖拽停靠样式类名
ghostClass: 'ghostClass',
//设置选中样式类名
chosenClass: 'chosenClass',
// 开始拖动事件
onStart: () => {
console.log('开始拖动');
},
// 结束拖动事件
onEnd: async ({ newIndex, oldIndex }) => {
console.log('结束拖动', `拖动前索引${oldIndex}---拖动后索引${newIndex}`);
const currRow = tableData.value.splice(oldIndex, 1)[0];
tableData.value.splice(newIndex, 0, currRow);
console.log('结束拖动', tableData.value);
let newTableData: any = [];
//更新排序
tableData.value.map(async (item, index) => {
item.orderId = index + 1 + (params.value.page - 1) * params.value.pageSize;
newTableData.push({
id: item.id,
orderId: item.orderId,
});
console.log(item.orderId);
});
await updateFriendLinks(newTableData);
},
});
console.log('dragTable', dragTable);
}
// 设置表格row的class
function tableRowClassName({ row }) {
if (row.disabled) {
return 'disabled';
}
return '';
}
onMounted(() => {
initSortable('t1');
});
</script>
<style lang="scss" scoped>
.el-select {
width: 100%;
}
.avatar {
width: 50px;
height: 50px;
border-radius: 50%;
margin: 0 auto;
}
</style>
常见问题
目录