原生html vue3使用element plus 的树tree上移下移案例源码

上效果 

html源码

<!DOCTYPE html>
<html lang="en">
<!--
* @Name: mallSalesReports.html
* @Description:
* @Author Lani
* @date 2024-02-28 18:32:36
-->
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>商品类别</title>
  <script src="../js/vue3.3.8/vue.global.js"></script>
  <script src="../js/elementPlus/index.full.js"></script>
  <link rel="stylesheet" href="../js/elementPlus/index.css">
  <style>
    .el-header {
      height: 88px;
      background-color: #fff;
      z-index: 2;
    }

    #main-body .el-main {
      padding: 0;
      z-index: 1;
    }

    .el-aside {
      display: flex;
      justify-content: center;
      align-items: center;
    }

    .el-tree .el-tree-node__content {
      height: 50px !important;
      border-top: 1px solid #aaa;
    }

    .tree {
      border-bottom: 1px solid #aaa;
      border-left: 1px solid #aaa;
      border-right: 1px solid #aaa;
      /*width: 600px;*/
    }

    .custom-tree-node1 {
      display: flex;
      flex: 1;
      align-items: center;
      justify-content: space-between;
      font-size: 14px;
      padding: 8px;
      height: 50px;
    }


  </style>
</head>
<body>
<div id="app" class="common-layout" v-cloak>
  <el-affix :offset="0">
    <el-row :gutter="0" style="border-bottom: 0px solid #d0d0d0;margin:0 20px;padding: 15px 0;background-color: #fff;">
      <el-col :span="22">
        <div class="flex-r">
          <h4 class="menu-title-color fw7 fz22">商品销售报表</h4>
        </div>
      </el-col>
      <el-col :span="2" style="text-align: end">
        <el-button type="primary" size="large" @click="handleAddTopLevelNode">新增一级目录</el-button>
      </el-col>
    </el-row>
  </el-affix>
  <el-container>
    <el-main id="main-body">
      <el-tree
        ref="menutree"
        :allow-drop="allowDrop" :allow-drag="allowDrag"
        :data="treeData" draggable
        :expand-on-click-node="false"
        default-expand-all node-key="id"
        class="tree">
        <template #default="{ node, data }">
          <div class="custom-tree-node1">
            <div>
              <el-input v-if="data.isEdit" v-model="data.DICT_VALUE" maxlength="12" show-word-limit></el-input>
              <el-text v-else="!node.isEdit">{{ data.DICT_VALUE }}</el-text>
            </div>
            <div style="margin-left: 40px;">
              <el-button type="text" size="small" v-if="data.up"
                         @click="handleMoveUp(node, data, 'up')">上移<i class="el-icon-top"></i></el-button>
              <el-button
                type="text" size="small" v-if="data.down"
                @click="handleMoveDown(node, data, 'down')">下移
                <i class="el-icon-bottom"></i></el-button>
              <el-button @click="append(node,data)" type="primary" v-if="data.subNode"> 添加子级</el-button>
              <el-button style="margin-left: 18px" @click="edit(node, data)">
                {{ data.operateBtnText }}
              </el-button>
              <el-button style="margin-left: 18px" @click="remove(node, data)" v-if="data.delete"> 删除</el-button>
            </div>
          </div>
        </template>
      </el-tree>
    </el-main>
  </el-container>
</div>
</body>
<script type="module">
  import zhCn from "../js/elementPlus/locale/zh-cn.mjs";

  const {createApp, ref, reactive, watch, toRaw, toRefs, shallowRef} = Vue
  const _app = createApp({
    setup() {
      const categoryInfo = reactive({
          maxLevel: 2,//类别层级最大2
          treeData: [
            { //默认保留第一个节点数不能为空
              label: '全部商品',
              DICT_VALUE: '全部商品',
              up: false, down: true, subNode: true, delete: false, operateBtnText: '修改',
              id: 1,
              children: [
                {
                  label: 'Level two 1-1',
                  DICT_VALUE: 'Level two 1-1',
                  id: 2,
                  up: false, down: true, subNode: true, delete: true, operateBtnText: '修改',
                },
              ],
            },
            { //默认保留第一个节点数不能为空
              label: '花吃了那女孩',
              DICT_VALUE: '花吃了那女孩',
              up: false, down: true, subNode: true, delete: false, operateBtnText: '修改',
              id: 1,
              children: [
                {
                  label: 'Level two 1-1',
                  DICT_VALUE: 'Level two 1-1',
                  id: 2,
                  up: false, down: true, subNode: true, delete: true, operateBtnText: '修改',
                },
              ],
            },
          ],
          id: 1
        }
      )

      const payStatus = ref('')
      const num = ref(20)
      const timer = ref(null);
      const clickCount = ref(0);
      const locale = ref('')
      const searchKeywords = ref('')

      /*
      * 判断结点拖拽
      * */
      const allowDrop = (draggingNode, dropNode, type) => {
        // console.log('|--正在拖拽draggingNode,type', draggingNode, type)
        // console.log('|--dropNode', dropNode)
        if (type == 'inner') return false //只能同级拖拽
        if (draggingNode.level > categoryInfo.maxLevel) return false
        return true//允许拖拽
      }
      const allowDrag = (draggingNode) => {
        return !draggingNode.data.label.includes('Level three 3-1-1')
      }

      const toast = (message, type = 'warning', fn = null) => {
        ElementPlus.ElMessage({
          message,
          type, fn
        })
      }
      /*
      * 插入:$refs.menutree.insertBefore
      * 删除:$refs.menutree.remove
      * */
      const handleMoveUp = (node) => {  // 上移的原理就是现在选中节点上方复制一个一模一样的节点,然后删掉原来那个
        const {$treeNodeId, ...newData} = node.data
        console.log('|--选中结点', node.data, vm.$refs.menutree, $treeNodeId, newData, node.previousSibling.data.$treeNodeId)
        if (vm.$refs.menutree) vm.$refs.menutree.insertBefore(newData, node.previousSibling)
        // if (vm.$refs.menutree) vm.$refs.menutree.insertBefore(newData, node.previousSibling.data.$treeNodeId)
        if (vm.$refs.menutree) vm.$refs.menutree.remove(node)
        saveCategoryRequest()
      }
      const handleMoveDown = (node) => {  // 下移的原理就是现在选中节点下方复制一个一模一样的节点,然后删掉原来那个
        const {$treeNodeId, ...newData} = node.data
        if (vm.$refs.menutree) vm.$refs.menutree.insertAfter(newData, node.nextSibling)
        // if (vm.$refs.menutree) vm.$refs.menutree.insertAfter(newData, node.nextSibling.data.$treeNodeId)
        if (vm.$refs.menutree) vm.$refs.menutree.remove(node)
        saveCategoryRequest()
      }
      /*
      * node: 当前节点,
      * data: 当前节点
      * */
      const append = (node, data) => {//给当前节点,添加一个子节点
        console.log('|--添加', node, data)
        if (node.level >= categoryInfo.maxLevel) {
          toast(`级别最大只能为${categoryInfo.maxLevel}`)
          return
        }
        categoryInfo.id = categoryInfo.id + 1

        const newChild = {
          label: '二级类别 ',
          id: categoryInfo.id,

          children: [],
          up: data.children.length > 0 ? true : false,
          down: false,
          subNode: false,
          delete: true,
          isEdit: true,
          operateBtnText: '保存',
          /*API字段*/
          "DICT_SEQ": 0,
          DICT_VALUE: '二级类别 ',
        }
        if (!data.children) {
          data.children = []
        }
        data.children.push(newChild)
        data.items = JSON.parse(JSON.stringify(data.children))
        if (data.children.length > 1) {
          data.children[data.children.length - 2].down = true
        }
      }
      const handleAddTopLevelNode = () => { //添加一级类别
        categoryInfo.id = categoryInfo.id + 1
        let newTopLevelNode = {
          id: categoryInfo.id,
          label: '一级类别 ',
          up: true, down: false, subNode: true, delete: true, isEdit: true, operateBtnText: '保存',
          children: [],

          items: [],
          "DICT_SEQ": 0,
          DICT_VALUE: '一级类别 ',
        }
        categoryInfo.treeData.push(newTopLevelNode)
        if (categoryInfo.treeData.length > 1) {
          categoryInfo.treeData[categoryInfo.treeData.length - 2].down = true
        }
      }
      /*
      * isAPI: true:用于请求掊口,删除不用字段, false 用于ui渲染增加一些字段
      * */
      const refreshTree = (data, isAPI = false) => {
        for (let i = 0; i < data.length; i++) {
          // data[i].id = data[i].DICT_SEQ
          if (isAPI && data[i]) { // 上传修改
            try {
              delete data[i].label
              delete data[i].up
              delete data[i].down
              delete data[i].subNode
              delete data[i].delete
              delete data[i].isEdit
              delete data[i].operateBtnText
              data[i].items = JSON.parse(JSON.stringify(data[i].children))  //同步items

              if ((!data[i].children) || (data[i].children.length <= 0)) continue
              data[i].items = refreshTree(data[i].items, isAPI)
              delete data[i].children
            } catch (e) {
            }
            continue
          }
          //渲染ui
          data[i].label = data[i].DICT_VALUE
          data[i].up = (i != 0)
          data[i].down = (i != (data.length - 1))
          data[i].subNode = true
          data[i].delete = true
          data[i].isEdit = false
          categoryInfo.id = categoryInfo.id + 1
          data[i].id = categoryInfo.id

          data[i].operateBtnText = '修改'
          data[i].children = []
          if ((!data[i].items) || (data[i].items.length <= 0)) continue
          data[i].children = refreshTree(data[i].items, isAPI)
          // console.log(data[i].children)
        }
        return data
      }

      const saveCategoryRequest = async () => {
        console.log('|-http 请求-')
        toast('Http请求')
      }

      return {
        ...toRefs(categoryInfo),
        num,
        locale, searchKeywords,
        clickCount, timer,
        headerCellStyle: {borderTop: '2px solid #d0d0d0', background: '#f5f5f5', color: '#333', fontWeight: 500},
        // 方法
        allowDrag, allowDrop,
        toast, append, handleMoveDown, handleMoveUp,

        //移除节点
        remove: (node, data) => {
          console.log("|--del", node, data, node.data.$treeNodeId)
          const {$treeNodeId} = node.data
          console.log('|--', $treeNodeId, vm.$refs.menutree)
          // return
          if (categoryInfo.treeData.length <= 1) {
            toast('至少保留一个结点')
            return;
          }
          if (!vm.$refs.menutree) return
          console.log('|--remove')
          // vm.$refs.menutree.remove($treeNodeId)
          vm.$refs.menutree.remove(node) //OK
          // vm.$refs.menutree.remove(data)
          saveCategoryRequest()

          /* const parent = node.parent;
           const children = parent.data.children || parent.data;
           const index = children.findIndex((d) => d.id === data.id);
           children.splice(index, 1);*/
        }, //移除节点
        edit: (node, data) => {
          let btnText = '保存'
          if (data.isEdit) {
            saveCategoryRequest()
            btnText = '修改'
          }
          data.isEdit = !data.isEdit
          data.operateBtnText = btnText
        },
        handleAddTopLevelNode,
        payStatusItemSelectedEvent: (item, index) => {
          payStatus.value = item.item
        },
         refreshTree, saveCategoryRequest,

        menuMoveF: (node, data, type) => { //上移,下移 结点,指针
          console.log('|--node', node)
          // 将变动之前的node备份
          let copyNode = {...node};
          console.log(copyNode)
          copyNode.previousSibling = {...node.previousSibling};
          copyNode.nextSibling = {...node.nextSibling};
          console.log('|--copyNode 复制节点--|', copyNode)
          let nodeData = {};
          if (node.previousSibling) { //上移
            vm.$refs.menutree.remove(node.data);// 删除原先的node
            // 拿到copy的node   // nodeData = CircularJSON.parse(
            nodeData = copyNode
            // 复制该node到指定位置(参数:1. 要增加的节点的 data 2. 要增加的节点的后一个节点的 data、key 或者 node)
            /*  vm.$refs.menutree.insertBefore(
                nodeData.data,
                nodeData.previousSibling.data
              );  */
            vm.$refs.menutree.insertBefore(
              nodeData.data,
              nodeData.previousSibling.data
            );
            window.sessionStorage.removeItem("menuNode");
          } else {
            toast("该菜单已经是当前层最上级");
          }
          return


          if (type === "up") {  // 上移
            if (node.previousSibling) {
              vm.$refs.menutree.remove(node.data);// 删除原先的node
              // 拿到copy的node   // nodeData = CircularJSON.parse(
              nodeData = copyNode
              // 复制该node到指定位置(参数:1. 要增加的节点的 data 2. 要增加的节点的后一个节点的 data、key 或者 node)
              vm.$refs.menutree.insertBefore(
                nodeData.data,
                nodeData.previousSibling.data
              );
              window.sessionStorage.removeItem("menuNode");
            } else {
              toast("该菜单已经是当前层最上级");
            }
          } else {  // 下移
            if (node.nextSibling) {
              vm.$refs.menutree.remove(node.data);
              nodeData = CircularJSON.parse(
                window.sessionStorage.getItem("menuNode")
              );
              // 参数:1. 要增加的节点的 data 2. 要增加的节点的前一个节点的 data、key 或者 node
              vm.$refs.menutree.insertAfter(
                nodeData.data,
                nodeData.nextSibling.data
              );
              window.sessionStorage.removeItem("menuNode");
            } else {
              toast("该菜单已经是当前层最下级");
            }
          }
        }

      }
    },
    async mounted() {
    },
  })
  _app.use(ElementPlus, {locale: zhCn})
  const vm = _app.mount('#app')
</script>


</html>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/470851.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【蓝桥杯选拔赛真题41】C++操作字符串 第十四届蓝桥杯青少年创意编程大赛 算法思维 C++编程选拔赛真题解析

目录 C操作字符 一、题目要求 1、编程实现 2、输入输出 二、算法分析 三、程序编写 四、程序说明 五、运行结果 六、考点分析 七、推荐资料 C操作字符 第十四届蓝桥杯青少年创意编程大赛C选拔赛真题 一、题目要求 1、编程实现 给定两个字符串S1和S2(1<S1长度&…

JS精度计算的几种解决方法,1、转换成整数计算后再转换成小数,2、toFixed,3、math.js,4、bignumber.js,5、big.js

提示&#xff1a;学习express&#xff0c;搭建管理系统 文章目录 前言一、转换成整数计算后再转换成小数二、toFixed三、math.js四、bignumber.js五、big.js总结 前言 原始计算 let aNum 6.6 0.3;let bNum 6.6 - 0.2;let cNum 6.6 * 0.3;let dNum 6.6 / 0.2;console.log(…

界面组件DevExpress WinForms v23.2 - 数据可视化功能升级

DevExpress WinForms拥有180组件和UI库&#xff0c;能为Windows Forms平台创建具有影响力的业务解决方案。DevExpress WinForms能完美构建流畅、美观且易于使用的应用程序&#xff0c;无论是Office风格的界面&#xff0c;还是分析处理大批量的业务数据&#xff0c;它都能轻松胜…

Android14 - AMS之Activity启动过程(3)

Android14 - AMS之Activity启动过程&#xff08;1&#xff09;-CSDN博客 Android14 - AMS之Activity启动过程&#xff08;2&#xff09;-CSDN博客 上篇中我们梳理完ActivityStarter的startActivityInner&#xff0c;本篇从这里开始&#xff1a; platform/frameworks/base/servi…

c++类和对象(三)

c类和对象&#xff08;三&#xff09; 再谈构造函数 Static成员 友元 内部 匿名对象 拷贝对象时的一些编译器优化 再次理解封装 1.再谈构造函数 1.1构造函数体赋值 在创建对象时&#xff0c;编译器通过调用构造函数&#xff0c;给对象中各个成员变量一个合适的初始值。…

YOLOv9有效改进|加入RT-DETR中的AIFI结构。

专栏介绍&#xff1a;YOLOv9改进系列 | 包含深度学习最新创新&#xff0c;助力高效涨点&#xff01;&#xff01;&#xff01; 一、改进点介绍 AIFI是RT-DETR中使用的尺度内特征交互模块。 二、AIFI模块详解 2.1 模块简介 AIFI的主要思想&#xff1a; 与Transformer的Encoder类…

【leetcode热题】二叉搜索树迭代器

实现一个二叉搜索树迭代器类BSTIterator &#xff0c;表示一个按中序遍历二叉搜索树&#xff08;BST&#xff09;的迭代器&#xff1a; BSTIterator(TreeNode root) 初始化 BSTIterator 类的一个对象。BST 的根节点 root 会作为构造函数的一部分给出。指针应初始化为一个不存在…

【2024最新版,redis7】redis底层的10种数据结构

前言&#xff1a;本文redis版本&#xff1a;7.2.4 本文语雀原文地址&#xff08;首发更新&#xff09;&#xff1a;https://www.yuque.com/wzzz/redis/xg2cp37kx1s4726y 本文CSDN转载地址&#xff1a; https://blog.csdn.net/u013625306/article/details/136842107 1. 常见的数…

【JavaScript】JavaScript 程序流程控制 ① ( 顺序流程控制 | 分支流程控制 )

文章目录 一、JavaScript 程序流程控制简介1、顺序流程控制2、分支流程控制3、分支流程控制 - 代码示例 一、JavaScript 程序流程控制简介 JavaScript 程序 执行过程中 , 不同的代码执行顺序 , 得到的结果是不同的 , 在编程中 经常 需要 根据 不同的条件 执行不同的代码块 , 或…

Redis数据结构对象中的对象共享、对象的空转时长

对象共享 概述 除了用于实现引用计数内存回收机制之外&#xff0c;对象的引用计数属性还带有对象共享的作用。 在Redis中&#xff0c;让多个键共享同一个值对象需要执行以下两个步骤: 1.将数据库键的值指针指向一个现有的值对象2.将被共享的值对象的引用计数增一 目前来说…

实验03-OSPF高级实验

1.实验拓扑 2.实验需求 3.配置思路 根据所给的IP地址配置完成后进行OSPF的配置&#xff1a; #R1 [r1]ospf 1 router-id 10.0.1.1 [r1-ospf-1]a 0 [r1-ospf-1-area-0.0.0.0]network 10.0.1.1 0.0.0.0 [r1-ospf-1-area-0.0.0.0]network 10.0.12.1 0.0.0.0 [r1-ospf-1-area-0.0.…

图书馆管理系统 1.架构项目以及加搭建项目

项目架构图 技术栈 后端 开发语言&#xff1a;java 开发环境&#xff1a;jdk11.0.12 开发工具&#xff1a;IntelliJ IDEA 2022.2.4 项目管理工具&#xff1a;maven 集成框架&#xff1a;springboot 权限控制框架&#xff1a;springSecurity 数据库&#xff1a;mysql 数据库框架…

QT-绘制动态曲线

QT-绘制动态曲线 pro文件中添加chart 在串口工程中添加控件 将控件功能提升为QChartView 点击添加 添加相关的头文件和变量

Selenium不同版本配置自动下载驱动及打包细节

Selenium配置浏览器驱动 自动下载浏览器驱动的方法 selenium4.7.0自动下载浏览器驱动的方法 selenium4.11.0 或4.11.1手动设置浏览器驱动路径的方法pyinstaller打包程序时同时打包ChromeDriverchromedriver路径需要sys._MEIPASS的路径进行引用方法一&#xff1a;通过–add-data…

【目标检测】图解 YOLOv3 的网络结构(Darknet-53 作为 backbone)

到了 YOLOv3&#xff0c;backbone 从 YOLOv2 的 Darknet-19 升级到了 Darknet-53。 下面一张完整的结构示意图来一起理解一下 YOLOv3 的网络结构。 我们怎么理解最后输出的 3 个特征图&#xff08;feature map&#xff09;的这个 255&#xff1f; 同 YOLOv2 一样&#xff0c;…

【蓝桥杯-单片机】基于定时器的倒计时程序设计

基于定时器的倒计时程序 题目如下所示&#xff1a; 实现过程中遇到的一些问题 01 如何改变Seg_Buf数组的值数码管总是一致地显示0 1 2 3 4 5 首先这个问题不是在main.c中关于数码管显示部分的逻辑错误&#xff0c;就是发生在数码管的底层错误。 检查了逻辑部分&#xff…

玩转C语言——深入理解指针

一、指针概念 1.1 内存和地址 在开始学习指针前&#xff0c;我们先来讲一个例子&#xff0c;假如你身处一栋楼中&#xff0c;你点了一份外卖&#xff0c;那么&#xff0c;外卖员如何能找到你&#xff1f;有两种方法。法一&#xff1a;直接一间一间找&#xff0c;这样做不仅消耗…

线程和进程的区别和联系

一、什么是进程 进程(Process), 是一个具有独立功能的程序关于某个数据集合的一次运行活动&#xff0c;是系统进行 【资源分配和调度】 的一个独立单位。 进程是【程序】的【一次执行】(是计算机中程序的执行过程&#xff0c;而不是计算机中的程序)进程是系统进行【资源分配和…

十二 超级数据查看器 讲解稿 详情7 其他功能

十二 超级数据查看器 讲解稿 详情7 其他功能 点击此处 以新页面 打开B站 播放当前教学视频 点击访问app下载页面 百度手机助手 下载地址 ​ 讲解稿全文&#xff1a; 其他操作&#xff0c;主要用来完成替换和批量修改&#xff0c; 这里&#xff0c;我们想给成语字段增…

YOLOv9改进策略:卷积魔改 | 分布移位卷积(DSConv),提高卷积层的内存效率和速度

&#x1f4a1;&#x1f4a1;&#x1f4a1;本文改进内容&#xff1a; YOLOv9如何魔改卷积进一步提升检测精度&#xff1f;提出了一种卷积的变体&#xff0c;称为DSConv&#xff08;分布偏移卷积&#xff09;&#xff0c;其可以容易地替换进标准神经网络体系结构并且实现较低的存…