vue实现拖拽(vuedraggable)

2024-02-22 18:44

本文主要是介绍vue实现拖拽(vuedraggable),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

实现效果:

左侧往右侧拖动,右侧列表可以进行拖拽排序。

安装引用:

npm install vuedraggable
import draggable from 'vuedraggable'

使用:

data数据:

      componentList: [{groupName: '考试题型',children: [{componentType: 'danxuan',componentName: '单选题',componentIcon: 'icon-danxuan'},{componentType: 'duoxuan',componentName: '多选题',componentIcon: 'icon-duoxuan'},{componentType: 'panduan',componentName: '判断题',componentIcon: 'icon-panduan'}]},{groupName: '信息题',children: [{componentType: 'message',componentName: '姓名',componentIcon: 'icon-xingming'},{componentType: 'message',componentName: '手机',componentIcon: 'icon-shouji'},{componentType: 'message',componentName: '邮箱',componentIcon: 'icon-youxiang'}]}],
questionList:[],

html代码:

左侧代码:   
<el-tabs type="border-card" class="tabs"><el-tab-pane label="题型"><div v-for="(item, index) in componentList" :key="index"><b class="fs-14">{{item.groupName}}</b><draggable@end="end":clone="cloneElement"class="group"v-model="item.children":sort="false" //禁止排序:group="{name: 'component',pull: 'clone', put: false  //不允许其他元素拖拽进此空间}"><div @click="pushComponent(_item)" class="component" v-for="(_item, _index) in item.children" :key="_index"><i class="iconfont mr-8" :class="_item.componentIcon"></i><span>{{_item.componentName}}</span></div></draggable></div></el-tab-pane><el-tab-pane label="题库"><el-treeref="tree"highlight-current:data="treeList"node-key="id":current-node-key="currentNodekey"@node-click="handleNodeClick":load="loadNode":props="props"lazy><span slot-scope="{node}"><el-tooltip v-if="node.label.length>=8"  class="item" effect="dark" :content="node.label" placement="top"><div class="text-ellipsis width-150">{{ node.label }}</div></el-tooltip><div v-else>{{ node.label }}</div></span></el-tree></el-tab-pane></el-tabs>
右侧代码:<div class="content"><el-scrollbar ref="scrollbar" style="height: calc(100vh - 220px)">{{questionList}}<draggableclass="list"forceFallback:animation="200"ghostClass="ghost"handle=".el-icon-rank"v-model="questionList":group="{name: 'component'}"><transition-group class="height-percent-100 display-block"><divclass="item":class="{active: item.active, error: item.error}"v-for="(item, index) in questionList":key="item.uid"><divclass="display-flex ai-flex-start padding-20 pt-14"@click="clickQuestion(item)":id="item.uid"><div class="pt-6 width-40"><b>{{index + 1}}</b></div><div class="flex-1"><div class="display-flex ai-flex-start jc-space-between"><b @click="editTitle(item)" class="width-percent-80 pt-6" style="min-height: 26px" v-if="!item.editTitle">{{item.title}}</b><el-inputtype="textarea"autosize:ref="item.uid"v-elsesize="small"class="width-percent-80"@blur="item.editTitle = false"v-model="item.title"></el-input><span v-if="item.componentType !== 'message'" class="color-info pt-6">( {{item.score}}分 )</span></div><div class="mt-12"><el-inputv-if="item.componentType === 'message'"readonlyplaceholder="请输入"type="textarea"autosizev-model="item.answer"size="small"class="width-percent-80"></el-input><draggable v-model="item.options" handle=".el-icon-d-caret"><transition-group><div v-for="i in item.options" :key="i.value" class="display-flex ai-center jc-space-between pt-4 pb-4"><div class="flex-1 display-flex ai-center"><el-checkboxv-if="item.componentType === 'duoxuan'"v-model="item.answer" :label="i.value">{{  }}</el-checkbox><el-radiov-elsev-model="item.answer":label="i.value" class="mr-0">{{  }}</el-radio><p @click="editOption(i)" v-if="!i.edit" class="margin-0 fs-14 width-percent-80 display-flex ai-center" style="min-height: 32px">{{i.label}}</p><el-inputtype="textarea"autosize@blur="i.edit = false":ref="i.value"v-elsev-model="i.label"size="small"class="width-percent-80"></el-input></div><div class="display-flex ai-center fd-row-reverse color-info width-130"><i class="el-icon-d-caret ml-8 cursor-move"></i><i @click="delOption(item, i.value)" class="ml-10 el-icon-remove-outline cursor-pointer"></i><span class="color-success fs-14" v-if="item.answer.includes(i.value)">( 正确答案 )</span></div></div></transition-group></draggable><div v-if="['danxuan', 'duoxuan'].includes(item.componentType)"><el-button class="pb-0" @click="addOption(item)" type="text" icon="el-icon-plus">添加选项</el-button></div></div></div><div class="display-flex ai-center color-info mt-8"><i class="ml-14 el-icon-rank cursor-move"></i><i @click.stop="copyQuestion(item, index)" class="ml-14 el-icon-document-copy cursor-pointer"></i><i @click.stop="delQuestion(item)" class="ml-14 el-icon-delete cursor-pointer"></i></div></div><div class="errorMessage" v-if="item.error">{{item.errorMessage}}</div></div><div key="empty" v-if="!questionList.length" class="height-percent-100 fd-column display-flex ai-center jc-center"><el-empty description="请点击右侧或拖入题型进行添加题目"></el-empty></div></transition-group></draggable></el-scrollbar></div>

方法:

     /*** 点击组件进行push* @param data* @param type*/pushComponent (data, type = 0) {console.log(data)//type=1:后端给的题库项导入  0:题型项导入this.questionList.push(type ? data : this.cloneElement(data))const newDraggableIndex = this.questionList.length - 1const e = {to: {className: 'pushComponent'},newDraggableIndex}this.end(e)},/*** 拖拽结束* @param e*/end (e) {console.log(e)if (e.to.className !== 'group') {for (const item of this.questionList) {item.active = false}this.questionList[e.newDraggableIndex].active = truethis.$nextTick(() => {document.getElementById(this.questionList[e.newDraggableIndex].uid).scrollIntoView();})}},/*** 拖拽clone* @param item* @returns {any}*/cloneElement (item) {const data = JSON.parse(JSON.stringify(item));console.log(data)data.uid = `${data.componentType}-${Math.floor(Math.random() * 1000000)}`data.title = data.componentNamedata.answer = ''data.active = falsedata.editTitle = falsedata.error = falsedata.errorMessage = ''switch (data.componentType) {case 'danxuan':data.scoreMethod = '1' // 得分方式data.options = [{edit: false,label: '选项1',value: `${data.componentType}-${Math.floor(Math.random() * 1000000)}`},{edit: false,label: '选项2',value: `${data.componentType}-${Math.floor(Math.random() * 1000000)}`}] // 选项data.answer = data.options[0].value // 答案data.score = 10 // 分数data.description = '' // 解析breakcase 'duoxuan':data.scoreMethod = '1'data.options = [{edit: false,label: '选项1',value: `${data.componentType}-${Math.floor(Math.random() * 1000000)}`},{edit: false,label: '选项2',value: `${data.componentType}-${Math.floor(Math.random() * 1000000)}`}]data.answer = [data.options[0].value]data.score = 10data.description = ''breakcase 'panduan':data.scoreMethod = '1'data.options = [{edit: false,label: '是',value: `${data.componentType}-true`},{edit: false,label: '否',value: `${data.componentType}-false`}]data.answer = data.options[0].valuedata.score = 10data.description = ''break}return data},

css:

.tabs {width: 240px;box-shadow: none;border: none;height: 100%;.group {display: grid;grid-gap: 12px;grid-template-columns: repeat(2, 1fr);font-size: 14px;padding: 12px 0;}.component {color: #666666;border-radius: 4px;border: 1px solid #D8D8D8;display: flex;align-items: center;justify-content: center;padding: 8px 0;cursor: pointer;&:hover {color: #1774FF;border-color: #1774FF;}}
}
.content {flex: 1;background-color: #EFF2F4;border-left: 1px solid #DCDFE6;border-right: 1px solid #DCDFE6;padding: 20px 4px 0 20px;.list {height: 100%;margin-right: 16px;.item {padding: 0;border: 1px solid transparent;border-radius: 4px;box-shadow: 0 2px 4px 0 rgba(0,0,0,0.1);background-color: #fff;margin-bottom: 20px;.el-icon-delete,.el-icon-remove-outline {&:hover {color: #F56C6C;}}.el-icon-document-copy {&:hover {color: #3377FF;}}}.errorMessage {color: #FFFFFF;background-color: #F56C6C;padding: 10px 20px;font-size: 14px;border-radius: 0 0 4px 4px;}.active {border-color: #2A5EFF;}.error {border-color: #F56C6C;}}.ghost {background-color: #499BFF;border-radius: 4px;padding: 20px;margin-bottom: 20px;.iconfont {display: none;}span {color: #FFFFFF;}}
}

扩展:

点击题库中的题进行导入:

代码:

<el-tab-pane label="题库"><el-treeref="tree"highlight-current:data="treeList"node-key="id":current-node-key="currentNodekey"@node-click="handleNodeClick":load="loadNode":props=" {label: 'name',value: 'id',isLeaf: 'isLeaf'},"lazy><span slot-scope="{node}"><el-tooltip v-if="node.label.length>=8"  class="item" effect="dark" :content="node.label" placement="top"><div class="text-ellipsis width-150">{{ node.label }}</div></el-tooltip><div v-else>{{ node.label }}</div></span></el-tree>
</el-tab-pane>

方法:

handleNodeClick (node) {if (node.level === 2) {//点击子节点(叶子节点)this.$nextTick(() => {this.$refs.tree.setCurrentKey(node.id)})const data = JSON.parse(JSON.stringify(node))data.answer = JSON.parse(node.answer)data.uid = `${data.componentType}-${Math.floor(Math.random() * 1000000)}`this.pushComponent(data, 1)} else {this.$nextTick(() => {this.$refs.tree.setCurrentKey()})}
},
loadNode (node, resolve) {if (node.level === 0) {this.$api.pxExam.getExamSetList({ name: this.fuzzy }).then(res => {this.treeList = res.map(res => {return {name: res.name,id: res.id,isLeaf: false,level: 1}})return resolve(this.treeList)})}
pushComponent方法通用的(传参不同),上面写的有。

这篇关于vue实现拖拽(vuedraggable)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/736165

相关文章

SpringBoot集成redisson实现延时队列教程

《SpringBoot集成redisson实现延时队列教程》文章介绍了使用Redisson实现延迟队列的完整步骤,包括依赖导入、Redis配置、工具类封装、业务枚举定义、执行器实现、Bean创建、消费... 目录1、先给项目导入Redisson依赖2、配置redis3、创建 RedissonConfig 配

Python的Darts库实现时间序列预测

《Python的Darts库实现时间序列预测》Darts一个集统计、机器学习与深度学习模型于一体的Python时间序列预测库,本文主要介绍了Python的Darts库实现时间序列预测,感兴趣的可以了解... 目录目录一、什么是 Darts?二、安装与基本配置安装 Darts导入基础模块三、时间序列数据结构与

Python使用FastAPI实现大文件分片上传与断点续传功能

《Python使用FastAPI实现大文件分片上传与断点续传功能》大文件直传常遇到超时、网络抖动失败、失败后只能重传的问题,分片上传+断点续传可以把大文件拆成若干小块逐个上传,并在中断后从已完成分片继... 目录一、接口设计二、服务端实现(FastAPI)2.1 运行环境2.2 目录结构建议2.3 serv

C#实现千万数据秒级导入的代码

《C#实现千万数据秒级导入的代码》在实际开发中excel导入很常见,现代社会中很容易遇到大数据处理业务,所以本文我就给大家分享一下千万数据秒级导入怎么实现,文中有详细的代码示例供大家参考,需要的朋友可... 目录前言一、数据存储二、处理逻辑优化前代码处理逻辑优化后的代码总结前言在实际开发中excel导入很

SpringBoot+RustFS 实现文件切片极速上传的实例代码

《SpringBoot+RustFS实现文件切片极速上传的实例代码》本文介绍利用SpringBoot和RustFS构建高性能文件切片上传系统,实现大文件秒传、断点续传和分片上传等功能,具有一定的参考... 目录一、为什么选择 RustFS + SpringBoot?二、环境准备与部署2.1 安装 RustF

Nginx部署HTTP/3的实现步骤

《Nginx部署HTTP/3的实现步骤》本文介绍了在Nginx中部署HTTP/3的详细步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学... 目录前提条件第一步:安装必要的依赖库第二步:获取并构建 BoringSSL第三步:获取 Nginx

MyBatis Plus实现时间字段自动填充的完整方案

《MyBatisPlus实现时间字段自动填充的完整方案》在日常开发中,我们经常需要记录数据的创建时间和更新时间,传统的做法是在每次插入或更新操作时手动设置这些时间字段,这种方式不仅繁琐,还容易遗漏,... 目录前言解决目标技术栈实现步骤1. 实体类注解配置2. 创建元数据处理器3. 服务层代码优化填充机制详

Python实现Excel批量样式修改器(附完整代码)

《Python实现Excel批量样式修改器(附完整代码)》这篇文章主要为大家详细介绍了如何使用Python实现一个Excel批量样式修改器,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一... 目录前言功能特性核心功能界面特性系统要求安装说明使用指南基本操作流程高级功能技术实现核心技术栈关键函

Java实现字节字符转bcd编码

《Java实现字节字符转bcd编码》BCD是一种将十进制数字编码为二进制的表示方式,常用于数字显示和存储,本文将介绍如何在Java中实现字节字符转BCD码的过程,需要的小伙伴可以了解下... 目录前言BCD码是什么Java实现字节转bcd编码方法补充总结前言BCD码(Binary-Coded Decima

Vue和React受控组件的区别小结

《Vue和React受控组件的区别小结》本文主要介绍了Vue和React受控组件的区别小结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学... 目录背景React 的实现vue3 的实现写法一:直接修改事件参数写法二:通过ref引用 DOMVu