Vue3中使用原生HTML5拖拽属性实现任务管理小功能

演示视频

使用HTML5拖放特性实现一个任务管理小功能

实现功能

  • 可以自己定义新增和配置任务面板
  • 可以在任务面板中添加多个任务
  • 不同面板中的任务可以拖放到其他面板中,并且拖放完成后自动请求后台修改接口

总体上我目前只需要上面的这些功能,方便自己在开发过程中清晰的知道自己需要做什么,以及完成了什么。

实现过程

整体使用的是原生HTML5中的拖放特性来实现的。废话不多说,直接上代码

<template>
    <div class="index">
        <div class="taskBox" @mouseup="handleMouseUp">
            <el-button v-if="taskTypeList.length == 0" @click="showPane = true; taskType = {}" type="primary" plain
                icon="Plus">增加面板</el-button>
            <div class="taskItem" v-for="item in taskTypeList" :key="item.id"  @dragover="allowDrop">
                <div class="taskItemHead" :style="'background-color:' + item.taskHeaderColor">
                    <div class="taskItemHeadLeft">{{ item.taskHeaderName }}</div>
                    <div class="taskItemHeadRight">
                        <el-button @click="delTaskType(item.id)" size="small" icon="Delete" circle></el-button>
                        <el-button @click="showPane = true; taskType = {}" size="small" icon="Plus" circle>
                        </el-button>
                    </div>
                </div>

                <div class="taskItemContent" @drop="drop" :data-tasktypeid="item.id" :id="'taskType'+item.id">
                    <div :id="'task'+task.id" draggable="true" @dragend="dragEnd" v-for="task in item.taskList" :key="task" class="card"
                        :style="'background-color:' + item.taskHeaderColor + '33'" :data-taskId="task.id" :data-tasktypeid="item.id">
                        <div class="cardHeader">
                            <div>{{ task.taskTitle }}</div>
                            <el-button @click="delTask(task.id)" round plain type="danger" size="small" icon="Delete">删除
                            </el-button>
                        </div>
                        <div class="cardContent">
                            {{ task.taskContent }}
                        </div>
                        <div class="cardFooter">
                            {{ task.createTime }}
                        </div>
                    </div>
                    <el-button @click="preAddTask(item.id)" icon="Plus" plain type="primary"
                        style="width:calc(100% - 20px); margin:10px;">添加任务</el-button>
                </div>
            </div>
        </div>
        <el-dialog title="面板信息" v-model="showPane">
            <el-form :model="taskType" label-width="120px">
                <el-form-item label="面板名称">
                    <el-input placeholder="输入面板名称" v-model="taskType.taskHeaderName"></el-input>
                </el-form-item>
                <el-form-item label="面板头部颜色">
                    <el-input placeholder="面板头部颜色" v-model="taskType.taskHeaderColor"></el-input>
                </el-form-item>
                <el-form-item>
                    <el-button type="info">取消</el-button>
                    <el-button @click="addTaskType" type="primary">确定</el-button>
                </el-form-item>
            </el-form>
        </el-dialog>
        <el-dialog title="任务信息" v-model="showTask">
            <el-form :model="task">
                <el-form-item label="任务标题">
                    <el-input placeholder="输入任务标题" v-model="task.taskTitle"></el-input>
                </el-form-item>
                <el-form-item label="任务内容">
                    <el-input type="textarea" placeholder="输入任务标题" v-model="task.taskContent"></el-input>
                </el-form-item>
                <el-form-item>
                    <el-button type="info">取消</el-button>
                    <el-button @click="addTask" type="primary">提交</el-button>
                </el-form-item>
            </el-form>
        </el-dialog>
    </div>
</template>
<script>
import { addTaskType, taskTypeList, delTaskType, addTask, setTask, delTask } from '../js/api.js'
import { ElMessage, ElMessageBox } from 'element-plus'
import draggable from "vuedraggable"
export default {
    components: {
        draggable
    },
    data() {
        return {
            showPane: false,
            showTask: false,
            taskType: {},
            taskTypeList: [],
            task: {},
            list: [],
            tempTaskTypeId: null,
        }
    },
    methods: {
        addTaskType() {
            addTaskType(this.taskType).then(res => {
                ElMessage({ type: res.status ? 'success' : 'error', message: res.msg })
                this.showPane = false;
                this.getTaskTypeList();
            })
        },
        getTaskTypeList() {
            taskTypeList().then(res => {
                this.taskTypeList = res.data;
            })
        },
        delTaskType(id) {
            ElMessageBox.confirm('该操作将删除该面板以及里面的所有任务,是否继续?', '提示', { confirmButtonText: '确定', cancelButtonText: '取消' }).then(() => {
                delTaskType([id]).then(res => {
                    ElMessage({ type: res.status ? 'success' : 'error', message: res.msg });
                    this.getTaskTypeList();
                })
            })
        },
        delTask(id) {
            ElMessageBox.confirm('该操作将删除该任务,是否继续?', '提示', { confirmButtonText: '确定', cancelButtonText: '取消' }).then(() => {
                delTask([id]).then(res => {
                    ElMessage({ type: res.status ? 'success' : 'error', message: res.msg });
                    this.getTaskTypeList();
                })
            })
        },
        preAddTask(taskTypeId) {
            this.task.taskTypeId = taskTypeId;
            this.showTask = true;
        },
        addTask() {
            addTask(this.task).then(res => {
                ElMessage({ type: res.status ? 'success' : 'error', message: res.msg });
                this.showTask = false;
                this.getTaskTypeList();
            })
        },
        allowDrop(event){
            event.preventDefault();
        },
        drop(event){
            console.log('097907097097',document.getElementById(event.target.id).dataset)
            this.tempTaskTypeId = document.getElementById(event.target.id).dataset.tasktypeid;
            console.log(event.target.id)
            event.preventDefault();
            // var data=event.dataTransfer.getData("Text");
            // event.target.appendChild(document.getElementById(data));
        },
        dragEnd(event){
            let taskId = document.getElementById(event.target.id).dataset.taskid;
            console.log(taskId)
            let oldTask = null;
            for(let i=0; i<this.taskTypeList.length; i++){
                let tempTaskList = this.taskTypeList[i].taskList;
                for(let j=0; j<tempTaskList.length; j++){
                    if(taskId==tempTaskList[j].id){
                        oldTask = tempTaskList[j];
                        break;
                    }
                }
            }
            oldTask.taskTypeId = this.tempTaskTypeId;
            setTask(oldTask).then(res=>{
                ElMessage({ type: res.status ? 'success' : 'error', message: res.msg });
                this.getTaskTypeList();
            })
            console.log(oldTask);
        }

    },
    mounted() {
        this.getTaskTypeList();
    }
}
</script>
<style lang="scss">
.index {
    height: calc(100vh - 50px);
    display: flex;
    flex-direction: column;
    justify-content: center;
}

.taskBox {
    display: flex;
    justify-content: center;
}

.taskItem {
    width: 300px;
    height: calc(100vh - 200px);
    border: 1px solid gainsboro;
    border-radius: 5px;
    margin: 0 10px;
    box-shadow: 2px 3px 10px gainsboro;
}

.taskItemHead {
    width: 100%;
    height: 40px;
    font-weight: bold;
    display: flex;
    align-items: center;
    font-size: 13px;
    color: white;
    justify-content: space-between;
}

.taskItemHeadLeft {
    padding-left: 10px;
    display: flex;
    justify-content: center;
}

.taskItemHeadRight {
    display: flex;
    align-items: center;
    padding-right: 10px;
    cursor: pointer;
}

.taskItemContent {
    height: calc(100vh - 240px);
    overflow-y: auto;
}

.card {
    margin: 10px;
    cursor: pointer;
    box-shadow: 2px 3px 10px gainsboro;
    text-align: left;
    padding: 5px;
    border-radius: 4px;
}

.cardHeader {
    display: flex;
    justify-content: space-between;
    align-items: center;
    font-weight: bold;
    font-size: 16px;

}

.cardContent {
    padding: 10px 0;
}

.cardFooter {
    padding-top: 5px;
    font-size: 14px;
}
</style>

上面是实现此功能的所有代码,当然其中的请求接口需要自己实现,后台的具体代码就不往出贴了,这里只贴出用到的表结构,相信大家很容易实现上面那些接口

任务类型表(也就是面板表)
在这里插入图片描述

任务表
在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

@胡海龙

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值