当前位置: 首页 > news >正文

draggable组件实现两层拖拽面板

遇见情况:现在的数据层层叠叠,有的要求不仅简单的单个盒子拖拽,而且要求:父盒子里面的子盒子也要能拖拽。

实现要求:拖拽父输入框只能与属于父输入框的交换位置;拖拽子输入框只能与子输入框交换位置

实现图片:

完整代码实现:

<template> <div class="custom no-select"> <el-form :model="formtwo" ref="formRef" label-width="auto" style="max-width: 475px" > <draggable v-model="formtwo.dimensionalInfoList" item-key="id" handle=".drag-handle" animation="300" @end="onEnd" > <template #item="{ element: group, index: groupIndex }"> <div class="group_card"> <!-- 父维度 --> <div class="father_box"> <span class="iconfont icon-hengxian drag-handle"></span> <el-form-item :prop="'dimensionalInfoList.' + groupIndex + '.content'" :rules="{ required: true, message: '父维度不能为空', trigger: 'blur', }" > <el-input v-model="group.content" placeholder="请输入父分析维度" class="desc__content" /> </el-form-item> <SisternodeOutlined class="icon_Share_css" :style="{ marginRight: formtwo.dimensionalInfoList.length === 1 ? '24px' : '10px', }" @click="addNextInput(groupIndex)" /> <el-icon class="icon_height_css" v-if="formtwo.dimensionalInfoList.length !== 1" > <CircleClose @click="delInput(groupIndex)" /> </el-icon> </div> <!-- 子维度 --> <draggable v-model="group.childInfo" item-key="id" handle=".drag-handle" animation="300" @end="onEnd" > <template #item="{ element: groupChild, index: groupIndexChild }"> <div class="groupChild_card"> <!-- 前方样式引导,用于连接父节点和子节点的连线--> <div style=" width: 30px; height: 50px; float: left; margin-top: -24px; " > <div style="display: flex"> <div :style="{ height: groupIndexChild !== group.childInfo.length - 1 ? '40px' : '35px', paddingLeft: '7px', borderRight: '1px solid #979797', }" ></div> <div style=" width: 20px; height: 6px; margin-top: 34px; border-left: 1px solid #979797; border-bottom: 1px solid #979797; border-radius: 0 0 0 5px; margin-left: -0.5px; " ></div> </div> <div style=" width: 0.5px; height: 10px; background-color: #979797; float: left; margin-left: 7px; " v-if="groupIndexChild !== group.childInfo.length - 1" ></div> </div> <span class="iconfont icon-hengxian drag-handle"></span> <el-form-item :prop=" 'dimensionalInfoList.' + groupIndex + '.childInfo.' + groupIndexChild + '.content' " :rules="{ required: true, message: '子维度不能为空', trigger: 'blur', }" > <el-input v-model="groupChild.content" placeholder="请输入子分析维度" class="desc__content desc__content_son" /> </el-form-item> <el-icon class="icon_height_css"> <CircleClose @click="delInputSon(child)" /> </el-icon> </div> </template> </draggable> </div> </template> </draggable> </el-form> </div> </template> <script setup> import { ref } from "vue"; import { CircleClose } from "@element-plus/icons-vue"; import { SisternodeOutlined } from "@ant-design/icons-vue"; import draggable from "vuedraggable"; let i = 1; //自定义id const formRef = ref(); //定义分析维度表单 // 分析维度,初始化就显示三个框 const formtwo = ref({ dimensionalInfoList: [ { content: "", dimId: ++i, childInfo: [] }, { content: "", dimId: ++i, childInfo: [] }, { content: "", dimId: ++i, childInfo: [] }, ], }); //拖拽结束事件,重新更新数据 const onEnd = () => { }; // 添加子联动输入框 const addNextInput = (index) => { // 获取当前维度对象 const currentItem = formtwo.value.dimensionalInfoList[index]; if (!currentItem.childInfo) { currentItem.childInfo = []; } // 向当前维度对象的 childInfo 数组中添加一个新的子维度对象 currentItem.childInfo.push({ content: "", }); }; // 删除维度输入框 const delInput = (index) => { formtwo.value.dimensionalInfoList.splice(index, 1); }; // 删除子维度输入框 const delInputSon = (child) => { // 找到当前子维度对应的父维度对象 const parentIndex = formtwo.value.dimensionalInfoList.findIndex((item) => item.childInfo.includes(child), ); const parentItem = formtwo.value.dimensionalInfoList[parentIndex]; // 从父维度对象的 childInfo 数组中删除当前子维度对象 parentItem.childInfo = parentItem.childInfo.filter((item) => item !== child); }; </script> <style lang="scss" scoped> .father_box { display: flex; justify-content: start; width: 100%; .icon_Share_css { text-align: center; margin-top: 15px; color: rgb(151, 151, 151); cursor: pointer; margin-right: 10px; } .icon_Share_css :hover { color: #1363df; } } .icon_height_css { text-align: center; line-height: 30px; margin-top: 15px; color: rgb(151, 151, 151) !important; cursor: pointer; } .icon_height_css :hover { color: red; } .desc__content { margin-left: 10px; margin-right: 10px; width: 100%; :deep .el-textarea__inner { background-color: rgba(246, 246, 246); min-height: 50px; max-height: 200px; } :deep .el-input__wrapper { background-color: rgba(246, 246, 246); } } .adddome { width: 100%; font-size: 12px; line-height: 12px; float: left; display: flex; justify-content: space-between; padding-bottom: 16px; .icon-gengxin { color: #979797; font-size: 15px; margin-right: 0; } .icon-gengxin:hover { color: #1363df; } } .icon-hengxian { font-size: 15px; color: #979797; text-align: center; line-height: 30px; cursor: move; } :deep .el-form-item__error { margin-left: 25px; } .son :deep .el-form-item__error { margin-left: 50px !important; } .prependInput { margin-bottom: 15px; } :deep .el-input-group--prepend > .el-input__wrapper, .el-input-group__append { background-color: rgba(246, 246, 246) !important; } :deep .el-input-group__prepend { background-color: rgba(246, 246, 246) !important; } .no-select { user-select: none; } .group_card { .groupChild_card { display: flex; width: 95%; } } .el-form-item { width: 100%; } </style>

注意点:

1、拖拽的id必须要有,要不然不能进行拖拽

2、handle=".drag-handle"为draggable组件的拖拽盒子的css,所以要在导入的icon图标上添加上该className

3、且template下方必须只有一个item的slot——必须只有一个子节点

4、子维度在父维度内部,

5、关于图片上父节点与子节点的连线是html手动调整实现,所以你们要写的时候需要根据实际情况进行调整

<!-- 前方样式引导,用于连接父节点和子节点的连线--> <div style=" width: 30px; height: 50px; float: left; margin-top: -24px; " > <div style="display: flex"> <div :style="{ height: groupIndexChild !== group.childInfo.length - 1 ? '40px' : '35px', paddingLeft: '7px', borderRight: '1px solid #979797', }" ></div> <div style=" width: 20px; height: 6px; margin-top: 34px; border-left: 1px solid #979797; border-bottom: 1px solid #979797; border-radius: 0 0 0 5px; margin-left: -0.5px; " ></div> </div> <div style=" width: 0.5px; height: 10px; background-color: #979797; float: left; margin-left: 7px; " v-if="groupIndexChild !== group.childInfo.length - 1" ></div> </div>
http://www.jsqmd.com/news/166717/

相关文章:

  • 从零开始:用Miniconda-Python3.9跑通PyTorch GPU模型
  • 麒麟操作系统认证全解析:国产操作系统专家成长指南
  • 【收藏级干货】AI智能体革命:Agentic AI的核心架构、技术实现与行业应用全景
  • Linux find命令查找Miniconda环境中的大文件
  • Jupyter Themes美化Notebook界面
  • 深入解析字符串:从基础到高效应用
  • Jupyter Notebook密码保护设置:Miniconda安全指南
  • GitHub Projects管理Miniconda相关开发任务
  • Miniconda-Python3.9镜像跨平台兼容性测试报告
  • 自动化数据清洗流程:Miniconda-Python3.9+Pandas脚本
  • AI开发者必藏!AIGC、Agent与MCP三大技术概念全解析,一篇就够
  • Linux df命令检查Miniconda磁盘使用情况
  • 软件信创测评机构推荐:山东本土检测机构中承信安
  • 第 1 章 Docker 实战:MySQL 主从集群部署与运维 —— 基于 Volumes 持久化与 EnvFile 配置管理
  • 时间序列分析库:Miniconda中安装statsmodels
  • 普通二本程序员除了外包还有别的路吗?
  • Java线程优先级的真相:你知道它真的起作用吗?
  • 自然语言处理Pipeline:SpaCy在Miniconda中安装
  • HTML viewport设置:适配移动端Miniconda报告
  • SSH代理转发:Miniconda服务器跳板机应用场景
  • GitHub Pages发布技术博客:Markdown转静态网站
  • 收藏!让AI从“废话生成器“变神级辅助的3个量化指标,99%的人不知道的提示词优化秘诀
  • 智能掌控温度,安全预见未来:ATE800无线测温装置,为工业安全保驾护航
  • Docker logs查看Miniconda容器运行日志
  • Docker prune清理无用Miniconda镜像节省存储
  • 大模型输出去重策略:Miniconda环境实现算法优化
  • HTML SEO优化:提升Miniconda技术文章搜索排名
  • Markdown嵌入视频链接:技术分享更直观
  • 【必藏干货】LLM智能体完全指南:60+图表详解记忆、工具、规划与多智能体协同
  • Jupyter Notebook内核选项管理