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

相关文章

C++使用栈实现括号匹配的代码详解

《C++使用栈实现括号匹配的代码详解》在编程中,括号匹配是一个常见问题,尤其是在处理数学表达式、编译器解析等任务时,栈是一种非常适合处理此类问题的数据结构,能够精确地管理括号的匹配问题,本文将通过C+... 目录引言问题描述代码讲解代码解析栈的状态表示测试总结引言在编程中,括号匹配是一个常见问题,尤其是在

Java实现检查多个时间段是否有重合

《Java实现检查多个时间段是否有重合》这篇文章主要为大家详细介绍了如何使用Java实现检查多个时间段是否有重合,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录流程概述步骤详解China编程步骤1:定义时间段类步骤2:添加时间段步骤3:检查时间段是否有重合步骤4:输出结果示例代码结语作

使用C++实现链表元素的反转

《使用C++实现链表元素的反转》反转链表是链表操作中一个经典的问题,也是面试中常见的考题,本文将从思路到实现一步步地讲解如何实现链表的反转,帮助初学者理解这一操作,我们将使用C++代码演示具体实现,同... 目录问题定义思路分析代码实现带头节点的链表代码讲解其他实现方式时间和空间复杂度分析总结问题定义给定

Java覆盖第三方jar包中的某一个类的实现方法

《Java覆盖第三方jar包中的某一个类的实现方法》在我们日常的开发中,经常需要使用第三方的jar包,有时候我们会发现第三方的jar包中的某一个类有问题,或者我们需要定制化修改其中的逻辑,那么应该如何... 目录一、需求描述二、示例描述三、操作步骤四、验证结果五、实现原理一、需求描述需求描述如下:需要在

部署Vue项目到服务器后404错误的原因及解决方案

《部署Vue项目到服务器后404错误的原因及解决方案》文章介绍了Vue项目部署步骤以及404错误的解决方案,部署步骤包括构建项目、上传文件、配置Web服务器、重启Nginx和访问域名,404错误通常是... 目录一、vue项目部署步骤二、404错误原因及解决方案错误场景原因分析解决方案一、Vue项目部署步骤

如何使用Java实现请求deepseek

《如何使用Java实现请求deepseek》这篇文章主要为大家详细介绍了如何使用Java实现请求deepseek功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1.deepseek的api创建2.Java实现请求deepseek2.1 pom文件2.2 json转化文件2.2

python使用fastapi实现多语言国际化的操作指南

《python使用fastapi实现多语言国际化的操作指南》本文介绍了使用Python和FastAPI实现多语言国际化的操作指南,包括多语言架构技术栈、翻译管理、前端本地化、语言切换机制以及常见陷阱和... 目录多语言国际化实现指南项目多语言架构技术栈目录结构翻译工作流1. 翻译数据存储2. 翻译生成脚本

如何通过Python实现一个消息队列

《如何通过Python实现一个消息队列》这篇文章主要为大家详细介绍了如何通过Python实现一个简单的消息队列,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录如何通过 python 实现消息队列如何把 http 请求放在队列中执行1. 使用 queue.Queue 和 reque

Python如何实现PDF隐私信息检测

《Python如何实现PDF隐私信息检测》随着越来越多的个人信息以电子形式存储和传输,确保这些信息的安全至关重要,本文将介绍如何使用Python检测PDF文件中的隐私信息,需要的可以参考下... 目录项目背景技术栈代码解析功能说明运行结php果在当今,数据隐私保护变得尤为重要。随着越来越多的个人信息以电子形

使用 sql-research-assistant进行 SQL 数据库研究的实战指南(代码实现演示)

《使用sql-research-assistant进行SQL数据库研究的实战指南(代码实现演示)》本文介绍了sql-research-assistant工具,该工具基于LangChain框架,集... 目录技术背景介绍核心原理解析代码实现演示安装和配置项目集成LangSmith 配置(可选)启动服务应用场景