商品服务-三级分类-拖拽修改

34 篇文章 0 订阅
32 篇文章 0 订阅

1.拖拽

在el-tree中加入draggable属性

<el-tree
     :data="menus"
     :props="defaultProps"
     :expand-on-click-node="false"
     node-key="catId"
     :default-expanded-keys="expandedKey"
     show-checkbox
     draggable
   >

在这里插入图片描述
问题:节点能拖动啦,但可形成四级分类(没有节点放置的判断)

2.拖拽时判定目标节点能否被放置

data中加入

 //最大层级
 maxLevel: 0,

方法中加上allowDrop和countNodeLevel

//拖拽时判定目标节点能否被放置。type 参数有三种情况:'prev'、'inner' 和 'next',
//分别表示放置在目标节点前、插入至目标节点和放置在目标节点后
 allowDrop(draggingNode, dropNode, type) {
   //1)、被拖动的当前节点总层数
   console.log("allowDrop:", draggingNode, dropNode, type);
   this.countNodeLevel(draggingNode);
   //当前正在拖动的节点+父节点所在的深度不大于3即可
   let deep = Math.abs(this.maxLevel - draggingNode.level) + 1;
   console.log("深度: ", deep);

   //   this.maxLevel
   if (type == "inner") {
     // console.log(
     //   `this.maxLevel:${this.maxLevel};draggingNode.data.catLevel:${draggingNode.data.catLevel};dropNode.level:${dropNode.level}`
     // );
     return deep + dropNode.level <= 3;
   } else {
     return deep + dropNode.parent.level <= 3;
   }
 },

 //层级
 countNodeLevel(node) {
   //找到所有子节点,求出最大深度
   if (node.childNodes != null && node.childNodes.length > 0) {
     for (let i = 0; i < node.childNodes.length; i++) {
       if (node.childNodes[i].level > this.maxLevel) {
         this.maxLevel = node.childNodes[i].level;
       }
       this.countNodeLevel(node.childNodes[i]);
     }
   }
 },

3.拖拽节点数据收集

在这里插入图片描述
在el-tree中绑定node-drop

<el-tree
     :data="menus"
     :props="defaultProps"
     :expand-on-click-node="false"
     node-key="catId"
     :default-expanded-keys="expandedKey"
     show-checkbox
     draggable
     :allow-drop="allowDrop"
     @node-drop="handleDrop"
   >

在data中加入

//要修改的节点
updateNodes: [],
//要展开的父节点
pCid: [],

拖拽成功后的处理与子节点的更新

 //拖拽成功后的处理
    handleDrop(draggingNode, dropNode, dropType, ev) {
    console.log("handleDrop: ", draggingNode, dropNode, dropType);
    //1、当前节点最新的父节点id
    let pCid = 0;
    //兄弟节点
    let siblings = null;
    if (dropType == "before" || dropType == "after") {
      pCid =
        dropNode.parent.data.catId == undefined
          ? 0
          : dropNode.parent.data.catId;
      siblings = dropNode.parent.childNodes;
    } else {
      pCid = dropNode.data.catId;
      siblings = dropNode.childNodes;
    }
    this.pCid.push(pCid);

    //2、当前拖拽节点的最新顺序,
    for (let i = 0; i < siblings.length; i++) {
      if (siblings[i].data.catId == draggingNode.data.catId) {
        //如果遍历的是当前正在拖拽的节点
        let catLevel = draggingNode.level;
        if (siblings[i].level != draggingNode.level) {
          //当前节点的层级发生变化
          catLevel = siblings[i].level;
          //修改他子节点的层级
          this.updateChildNodeLevel(siblings[i]);
        }
        this.updateNodes.push({
          catId: siblings[i].data.catId,
          sort: i,
          parentCid: pCid,
          catLevel: catLevel
        });
      } else {
        this.updateNodes.push({ catId: siblings[i].data.catId, sort: i });
      }
    }

    //3、当前拖拽节点的最新层级
    console.log("updateNodes", this.updateNodes);
   },

    //更新子节点层级
    updateChildNodeLevel(node) {
      if (node.childNodes.length > 0) {
        for (let i = 0; i < node.childNodes.length; i++) {
          var cNode = node.childNodes[i].data;
          this.updateNodes.push({
            catId: cNode.catId,
            catLevel: node.childNodes[i].level
          });
          this.updateChildNodeLevel(node.childNodes[i]);
        }
      }
    },

4.前端代码

<template>
  <div>
    <el-tree
      :data="menus"
      :props="defaultProps"
      :expand-on-click-node="false"
      node-key="catId"
      :default-expanded-keys="expandedKey"
      show-checkbox
      draggable
      :allow-drop="allowDrop"
      @node-drop="handleDrop"
    >
      <span class="custom-tree-node" slot-scope="{ node, data }">
        <span>{{ node.label }}</span>
        <span>
          <el-button
            type="text"
            size="mini"
            v-if="node.level <= 2"
            @click="() => append(data)"
          >
            Append
          </el-button>
             <el-button
            type="text"
            size="mini"
            @click="() => edit(data)"
          >
            Edit
          </el-button>
          <el-button
            type="text"
            size="mini"
            v-if="node.childNodes.length == 0"
            @click="() => remove(node, data)"
          >
            Delete
          </el-button>
        </span>
      </span>
    </el-tree>

    <!-- 对话框 -->
    <el-dialog :title="title" :visible.sync="dialogVisible" width="30%"  :close-on-click-modal="false">
      <el-form :model="category">
        <el-form-item label="分类名称" >
          <el-input v-model="category.name" autocomplete="off"></el-input>
        </el-form-item>
       <el-form-item label="图标">
          <el-input v-model="category.icon" autocomplete="off"></el-input>
        </el-form-item>
        <el-form-item label="计量单位">
          <el-input v-model="category.productUnit" autocomplete="off"></el-input>
        </el-form-item>
      </el-form>
      <span slot="footer" class="dialog-footer">
        <el-button @click="dialogVisible = false">取 消</el-button>
        <el-button type="primary" @click="submitData"
          >确 定</el-button
        >
      </span>
    </el-dialog>
  </div>
</template>

<script>
export default {
  name: "",
  //import引入的组件需要注入到对象中才能使用
  components: {},
  props: {},
  data() {
    return {
      menus: [],
      //默认展开节点
      expandedKey: [],
      //对话框是否显示
      dialogVisible: false,
      //对话框类型  add/edit
      dialogType: "",
      //话框提示信息
      title: "",
      //最大层级
      maxLevel: 0,
      //要修改的节点
      // draggable: false,
      updateNodes: [],
      pCid: [],
      category: {
        name: "",
        parentCid: 0,
        catLevel: 0,
        showStatus: 1,
        sort: 0,
        productUnit: "",
        icon: "",
        catId: null
        },
      defaultProps: {
        children: "children",
        label: "name",
      },
    };
  },
  methods: {
    //获取菜单
    getMenus() {
      this.$http({
        url: this.$http.adornUrl("/product/category/list/tree"),
        method: "get",
      }).then(({ data }) => {
        console.log("获取菜单数据成功", data.data);
        this.menus = data.data;
      });
    },

    //添加
    append(data) {
      console.log("添加", data);
      //打开对话框
      this.dialogVisible = true;
      this.dialogType = "add";
      this.title = "添加分类";
      this.category.parentCid = data.catId;
      this.category.catLevel = data.catLevel * 1 + 1;
      //将修改的回显值还原为默认值
      this.category.catId = null;
      this.category.name = "";
      this.category.icon = "";
      this.category.productUnit = "";
      this.category.sort = 0;
      this.category.showStatus = 1;
    },

    //添加三级分类
    addCategory(){
      console.log("提交的三级分类数据", this.category);
      this.$http({
        url: this.$http.adornUrl("/product/category/save"),
        method: "post",
        data: this.$http.adornData(this.category, false)
      }).then(({ data }) => {
        this.$message({
          message: `${this.category.name}】菜单保存成功 `,
          type: "success"
        });
        //关闭对话框
        this.dialogVisible = false;
        //刷新出新的菜单
        this.getMenus();
        //设置需要默认展开的菜单
        this.expandedKey = [this.category.parentCid];
      });
    },

    //删除
    remove(node, data) {
      var ids = [data.catId];
      this.$confirm(`是否删除【${data.name}】菜单?`, "提示", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning",
      })
        .then(() => {
          this.$http({
            url: this.$http.adornUrl("/product/category/delete"),
            method: "post",
            data: this.$http.adornData(ids, false),
          }).then(({ data }) => {
            //console.log("6666:"+node.data.name);
            this.$message({
              message: `${node.data.name}】菜单删除成功`,
              type: "success",
            });
            //刷新出新的菜单
            this.getMenus();
            //设置需要默认展开的菜单(当前删除节点的父节点)
            this.expandedKey = [node.parent.data.catId];
          });
        })
        .catch(() => {});

      console.log("remove", node, data);
    },

    //修改
    edit(data){
     // console.log("要修改的数据:",data);
      //打开对话框
      this.dialogVisible = true;
      this.dialogType = "edit";
      this.title = "修改分类";
      //发送请求获取当前节点最新的数据
      this.$http({
        url: this.$http.adornUrl(`/product/category/info/${data.catId}`),
        method: "get",
      }).then(({ data }) => {
        console.log("修改回显的数据", data);
        this.category.name = data.data.name;
        this.category.catId = data.data.catId;
        this.category.icon = data.data.icon;
        this.category.productUnit = data.data.productUnit;
        this.category.parentCid = data.data.parentCid;
        this.category.catLevel = data.data.catLevel;
        this.category.sort = data.data.sort;
        this.category.showStatus = data.data.showStatus;
      });
    },

    //根据对话框类型提交数据
    submitData(){
      if (this.dialogType == "add") {
        this.addCategory();
      }
      if (this.dialogType == "edit") {
        this.editCategory();
      }
    },

     //修改三级分类数据
    editCategory() {
      //注意只提交要修改的数据和id , 不能提交其他数据, 否则数据库中会修改其他数据为默认值,导致数据丢失
      var { catId, name, icon, productUnit } = this.category;
      this.$http({
        url: this.$http.adornUrl("/product/category/update"),
        method: "post",
        data: this.$http.adornData({ catId, name, icon, productUnit }, false),
      }).then(({ data }) => {
        this.$message({
          message: `${this.category.name}】菜单修改成功`,
          type: "success",
        });
        //关闭对话框
        this.dialogVisible = false;
        //刷新出新的菜单
        this.getMenus();
        //设置需要默认展开的菜单
        this.expandedKey = [this.category.parentCid];
      });
    },

    
    //拖拽时判定目标节点能否被放置。type 参数有三种情况:'prev'、'inner' 和 'next',
    //分别表示放置在目标节点前、插入至目标节点和放置在目标节点后
    allowDrop(draggingNode, dropNode, type) {
      //1)、被拖动的当前节点总层数
      console.log("allowDrop:", draggingNode, dropNode, type);
      this.countNodeLevel(draggingNode);
      //当前正在拖动的节点+父节点所在的深度不大于3即可
      let deep = Math.abs(this.maxLevel - draggingNode.level) + 1;
      console.log("深度: ", deep);

      //   this.maxLevel
      if (type == "inner") {
        // console.log(
        //   `this.maxLevel:${this.maxLevel};draggingNode.data.catLevel:${draggingNode.data.catLevel};dropNode.level:${dropNode.level}`
        // );
        return deep + dropNode.level <= 3;
      } else {
        return deep + dropNode.parent.level <= 3;
      }
    },

    //层级
    countNodeLevel(node) {
      //找到所有子节点,求出最大深度
      if (node.childNodes != null && node.childNodes.length > 0) {
        for (let i = 0; i < node.childNodes.length; i++) {
          if (node.childNodes[i].level > this.maxLevel) {
            this.maxLevel = node.childNodes[i].level;
          }
          this.countNodeLevel(node.childNodes[i]);
        }
      }
    },


    //拖拽成功后的处理
    handleDrop(draggingNode, dropNode, dropType, ev) {
      console.log("handleDrop: ", draggingNode, dropNode, dropType);
    //1、当前节点最新的父节点id
    let pCid = 0;
    //兄弟节点
    let siblings = null;
    if (dropType == "before" || dropType == "after") {
      pCid =
        dropNode.parent.data.catId == undefined
          ? 0
          : dropNode.parent.data.catId;
      siblings = dropNode.parent.childNodes;
    } else {
      pCid = dropNode.data.catId;
      siblings = dropNode.childNodes;
    }
    this.pCid.push(pCid);

    //2、当前拖拽节点的最新顺序,
    for (let i = 0; i < siblings.length; i++) {
      if (siblings[i].data.catId == draggingNode.data.catId) {
        //如果遍历的是当前正在拖拽的节点
        let catLevel = draggingNode.level;
        if (siblings[i].level != draggingNode.level) {
          //当前节点的层级发生变化
          catLevel = siblings[i].level;
          //修改他子节点的层级
          this.updateChildNodeLevel(siblings[i]);
        }
        this.updateNodes.push({
          catId: siblings[i].data.catId,
          sort: i,
          parentCid: pCid,
          catLevel: catLevel
        });
      } else {
        this.updateNodes.push({ catId: siblings[i].data.catId, sort: i });
      }
    }

    //3、当前拖拽节点的最新层级
    console.log("updateNodes:", this.updateNodes);
   },

    //更新子节点层级
    updateChildNodeLevel(node) {
      if (node.childNodes.length > 0) {
        for (let i = 0; i < node.childNodes.length; i++) {
          var cNode = node.childNodes[i].data;
          this.updateNodes.push({
            catId: cNode.catId,
            catLevel: node.childNodes[i].level
          });
          this.updateChildNodeLevel(node.childNodes[i]);
        }
      }
    },

  },
  //计算属性 类似于data概念
  computed: {},
  //监控data中的数据变化
  watch: {},

  //生命周期 - 创建完成(可以访问当前this实例)
  created() {
    this.getMenus();
  },
  //生命周期 - 挂载完成(可以访问DOM元素)
  mounted() {},
  beforeCreate() {}, //生命周期 - 创建之前
  beforeMount() {}, //生命周期 - 挂载之前
  beforeUpdate() {}, //生命周期 - 更新之前
  updated() {}, //生命周期 - 更新之后
  beforeDestroy() {}, //生命周期 - 销毁之前
  destroyed() {}, //生命周期 - 销毁完成
  activated() {}, //如果页面有keep-alive缓存功能,这个函数会触发
};
</script>

<style scoped>
</style>

5.批量拖拽

在CategoryController中updateSore

 /**
  * 批量修改排序
  */
 @RequestMapping("/update/sort")
 public R updateSort(@RequestBody CategoryEntity[] category){
     categoryService.updateBatchById(Arrays.asList(category));
     return R.ok();
 }

methods中批量修改保存

  //批量修改保存
  batchSave() {
    this.$http({
      url: this.$http.adornUrl("/product/category/update/sort"),
      method: "post",
      data: this.$http.adornData(this.updateNodes, false)
    }).then(({ data }) => {
      this.$message({
        message: "菜单顺序等修改成功",
        type: "success"
      });
      //刷新出新的菜单
      this.getMenus();
      //设置需要默认展开的菜单
      this.expandedKey = this.pCid;
      this.updateNodes = [];
      this.maxLevel = 0;
      // this.pCid = 0;
    });
  },

6.通过开关按钮控制拖拽功能的开启

在这里插入图片描述

 <el-switch
      style="display: block"
      v-model="draggable"
      active-color="#13ce66"
      inactive-color="#ff4949"
      active-text="开启拖拽"
      inactive-text="关闭拖拽"
    >
    </el-switch>
    <el-tree
      :data="menus"
      :props="defaultProps"
      :expand-on-click-node="false"
      node-key="catId"
      :default-expanded-keys="expandedKey"
      show-checkbox
      :draggable="draggable"
      :allow-drop="allowDrop"
      @node-drop="handleDrop"
    >

在data中新增draggable

 //是否开启拖拽
 draggable: false,

在这里插入图片描述

7.批量保存

 <el-button v-if="draggable" @click="batchSave">批量保存</el-button>

批量保存方法batchSave

//批量保存
batchSave() {
   this.$http({
     url: this.$http.adornUrl("/product/category/update/sort"),
     method: "post",
     data: this.$http.adornData(this.updateNodes, false),
   }).then(({ data }) => {
     this.$message({
       message: "菜单顺序等修改成功",
       type: "success",
     });
     //刷新出新的菜单
     this.getMenus();
     //设置需要默认展开的菜单
     this.expandedKey = this.pCid;
     this.updateNodes = [];
     this.maxLevel = 0;
   });
 },

在这里插入图片描述
在这里插入图片描述

8.完整代码

<template>
  <div>
    <el-switch
      style="display: block"
      v-model="draggable"
      active-color="#13ce66"
      inactive-color="#ff4949"
      active-text="开启拖拽"
      inactive-text="关闭拖拽"
    >
    </el-switch>
    <el-button v-if="draggable" @click="batchSave">批量保存</el-button>
    <el-tree
      :data="menus"
      :props="defaultProps"
      :expand-on-click-node="false"
      node-key="catId"
      :default-expanded-keys="expandedKey"
      show-checkbox
      :draggable="draggable"
      :allow-drop="allowDrop"
      @node-drop="handleDrop"
    >
      <span class="custom-tree-node" slot-scope="{ node, data }">
        <span>{{ node.label }}</span>
        <span>
          <el-button
            type="text"
            size="mini"
            v-if="node.level <= 2"
            @click="() => append(data)"
          >
            Append
          </el-button>
          <el-button type="text" size="mini" @click="() => edit(data)">
            Edit
          </el-button>
          <el-button
            type="text"
            size="mini"
            v-if="node.childNodes.length == 0"
            @click="() => remove(node, data)"
          >
            Delete
          </el-button>
        </span>
      </span>
    </el-tree>

    <!-- 对话框 -->
    <el-dialog
      :title="title"
      :visible.sync="dialogVisible"
      width="30%"
      :close-on-click-modal="false"
    >
      <el-form :model="category">
        <el-form-item label="分类名称">
          <el-input v-model="category.name" autocomplete="off"></el-input>
        </el-form-item>
        <el-form-item label="图标">
          <el-input v-model="category.icon" autocomplete="off"></el-input>
        </el-form-item>
        <el-form-item label="计量单位">
          <el-input
            v-model="category.productUnit"
            autocomplete="off"
          ></el-input>
        </el-form-item>
      </el-form>
      <span slot="footer" class="dialog-footer">
        <el-button @click="dialogVisible = false">取 消</el-button>
        <el-button type="primary" @click="submitData">确 定</el-button>
      </span>
    </el-dialog>
  </div>
</template>

<script>
export default {
  name: "",
  //import引入的组件需要注入到对象中才能使用
  components: {},
  props: {},
  data() {
    return {
      menus: [],
      //默认展开节点
      expandedKey: [],
      //对话框是否显示
      dialogVisible: false,
      //对话框类型  add/edit
      dialogType: "",
      //话框提示信息
      title: "",
      //最大层级
      maxLevel: 0,
      //要修改的节点
      updateNodes: [],
      //是否开启拖拽
      draggable: false,
      //要展开的父节点
      pCid: [],
      category: {
        name: "",
        parentCid: 0,
        catLevel: 0,
        showStatus: 1,
        sort: 0,
        productUnit: "",
        icon: "",
        catId: null,
      },
      defaultProps: {
        children: "children",
        label: "name",
      },
    };
  },
  methods: {
    //获取菜单
    getMenus() {
      this.$http({
        url: this.$http.adornUrl("/product/category/list/tree"),
        method: "get",
      }).then(({ data }) => {
        console.log("获取菜单数据成功", data.data);
        this.menus = data.data;
      });
    },

    //添加
    append(data) {
      console.log("添加", data);
      //打开对话框
      this.dialogVisible = true;
      this.dialogType = "add";
      this.title = "添加分类";
      this.category.parentCid = data.catId;
      this.category.catLevel = data.catLevel * 1 + 1;
      //将修改的回显值还原为默认值
      this.category.catId = null;
      this.category.name = "";
      this.category.icon = "";
      this.category.productUnit = "";
      this.category.sort = 0;
      this.category.showStatus = 1;
    },

    //添加三级分类
    addCategory() {
      console.log("提交的三级分类数据", this.category);
      this.$http({
        url: this.$http.adornUrl("/product/category/save"),
        method: "post",
        data: this.$http.adornData(this.category, false),
      }).then(({ data }) => {
        this.$message({
          message: `${this.category.name}】菜单保存成功 `,
          type: "success",
        });
        //关闭对话框
        this.dialogVisible = false;
        //刷新出新的菜单
        this.getMenus();
        //设置需要默认展开的菜单
        this.expandedKey = [this.category.parentCid];
      });
    },

    //删除
    remove(node, data) {
      var ids = [data.catId];
      this.$confirm(`是否删除【${data.name}】菜单?`, "提示", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning",
      })
        .then(() => {
          this.$http({
            url: this.$http.adornUrl("/product/category/delete"),
            method: "post",
            data: this.$http.adornData(ids, false),
          }).then(({ data }) => {
            //console.log("6666:"+node.data.name);
            this.$message({
              message: `${node.data.name}】菜单删除成功`,
              type: "success",
            });
            //刷新出新的菜单
            this.getMenus();
            //设置需要默认展开的菜单(当前删除节点的父节点)
            this.expandedKey = [node.parent.data.catId];
          });
        })
        .catch(() => {});

      console.log("remove", node, data);
    },

    //修改
    edit(data) {
      // console.log("要修改的数据:",data);
      //打开对话框
      this.dialogVisible = true;
      this.dialogType = "edit";
      this.title = "修改分类";
      //发送请求获取当前节点最新的数据
      this.$http({
        url: this.$http.adornUrl(`/product/category/info/${data.catId}`),
        method: "get",
      }).then(({ data }) => {
        console.log("修改回显的数据", data);
        this.category.name = data.data.name;
        this.category.catId = data.data.catId;
        this.category.icon = data.data.icon;
        this.category.productUnit = data.data.productUnit;
        this.category.parentCid = data.data.parentCid;
        this.category.catLevel = data.data.catLevel;
        this.category.sort = data.data.sort;
        this.category.showStatus = data.data.showStatus;
      });
    },

    //根据对话框类型提交数据
    submitData() {
      if (this.dialogType == "add") {
        this.addCategory();
      }
      if (this.dialogType == "edit") {
        this.editCategory();
      }
    },

    //修改三级分类数据
    editCategory() {
      //注意只提交要修改的数据和id , 不能提交其他数据, 否则数据库中会修改其他数据为默认值,导致数据丢失
      var { catId, name, icon, productUnit } = this.category;
      this.$http({
        url: this.$http.adornUrl("/product/category/update"),
        method: "post",
        data: this.$http.adornData({ catId, name, icon, productUnit }, false),
      }).then(({ data }) => {
        this.$message({
          message: `${this.category.name}】菜单修改成功`,
          type: "success",
        });
        //关闭对话框
        this.dialogVisible = false;
        //刷新出新的菜单
        this.getMenus();
        //设置需要默认展开的菜单
        this.expandedKey = [this.category.parentCid];
      });
    },

    //拖拽时判定目标节点能否被放置。type 参数有三种情况:'prev'、'inner' 和 'next',
    //分别表示放置在目标节点前、插入至目标节点和放置在目标节点后
    allowDrop(draggingNode, dropNode, type) {
      //1)、被拖动的当前节点总层数
      console.log("allowDrop:", draggingNode, dropNode, type);
      this.countNodeLevel(draggingNode);
      //当前正在拖动的节点+父节点所在的深度不大于3即可
      let deep = Math.abs(this.maxLevel - draggingNode.level) + 1;
      console.log("深度: ", deep);

      //   this.maxLevel
      if (type == "inner") {
        // console.log(
        //   `this.maxLevel:${this.maxLevel};draggingNode.data.catLevel:${draggingNode.data.catLevel};dropNode.level:${dropNode.level}`
        // );
        return deep + dropNode.level <= 3;
      } else {
        return deep + dropNode.parent.level <= 3;
      }
    },

    //层级
    countNodeLevel(node) {
      //找到所有子节点,求出最大深度
      if (node.childNodes != null && node.childNodes.length > 0) {
        for (let i = 0; i < node.childNodes.length; i++) {
          if (node.childNodes[i].level > this.maxLevel) {
            this.maxLevel = node.childNodes[i].level;
          }
          this.countNodeLevel(node.childNodes[i]);
        }
      }
    },

    //拖拽成功后的处理
    handleDrop(draggingNode, dropNode, dropType, ev) {
      console.log("handleDrop: ", draggingNode, dropNode, dropType);
      //1、当前节点最新的父节点id
      let pCid = 0;
      //兄弟节点
      let siblings = null;
      if (dropType == "before" || dropType == "after") {
        pCid =
          dropNode.parent.data.catId == undefined
            ? 0
            : dropNode.parent.data.catId;
        siblings = dropNode.parent.childNodes;
      } else {
        pCid = dropNode.data.catId;
        siblings = dropNode.childNodes;
      }
      this.pCid.push(pCid);

      //2、当前拖拽节点的最新顺序,
      for (let i = 0; i < siblings.length; i++) {
        if (siblings[i].data.catId == draggingNode.data.catId) {
          //如果遍历的是当前正在拖拽的节点
          let catLevel = draggingNode.level;
          if (siblings[i].level != draggingNode.level) {
            //当前节点的层级发生变化
            catLevel = siblings[i].level;
            //修改他子节点的层级
            this.updateChildNodeLevel(siblings[i]);
          }
          this.updateNodes.push({
            catId: siblings[i].data.catId,
            sort: i,
            parentCid: pCid,
            catLevel: catLevel,
          });
        } else {
          this.updateNodes.push({ catId: siblings[i].data.catId, sort: i });
        }
      }

      //3、当前拖拽节点的最新层级
      console.log("updateNodes:", this.updateNodes);
    },

    //更新子节点层级
    updateChildNodeLevel(node) {
      if (node.childNodes.length > 0) {
        for (let i = 0; i < node.childNodes.length; i++) {
          var cNode = node.childNodes[i].data;
          this.updateNodes.push({
            catId: cNode.catId,
            catLevel: node.childNodes[i].level,
          });
          this.updateChildNodeLevel(node.childNodes[i]);
        }
      }
    },

    //批量保存
    batchSave() {
      this.$http({
        url: this.$http.adornUrl("/product/category/update/sort"),
        method: "post",
        data: this.$http.adornData(this.updateNodes, false),
      }).then(({ data }) => {
        this.$message({
          message: "菜单顺序等修改成功",
          type: "success",
        });
        //刷新出新的菜单
        this.getMenus();
        //设置需要默认展开的菜单
        this.expandedKey = this.pCid;
        this.updateNodes = [];
        this.maxLevel = 0;
      });
    },
  },
  //计算属性 类似于data概念
  computed: {},
  //监控data中的数据变化
  watch: {},

  //生命周期 - 创建完成(可以访问当前this实例)
  created() {
    this.getMenus();
  },
  //生命周期 - 挂载完成(可以访问DOM元素)
  mounted() {},
  beforeCreate() {}, //生命周期 - 创建之前
  beforeMount() {}, //生命周期 - 挂载之前
  beforeUpdate() {}, //生命周期 - 更新之前
  updated() {}, //生命周期 - 更新之后
  beforeDestroy() {}, //生命周期 - 销毁之前
  destroyed() {}, //生命周期 - 销毁完成
  activated() {}, //如果页面有keep-alive缓存功能,这个函数会触发
};
</script>

<style scoped>
</style>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
vue-draggable-resizable-gorkys是一个Vue组件,用于实现可拖拽和可缩放的元素。如果要实现拖拽互换,可以使用该组件提供的事件和方法。 首先,在使用该组件时,需要给每个元素设置一个唯一的id,以便后续操作。可以在组件的v-for中,使用item的索引值作为id,如下所示: ``` <draggable-resizable v-for="(item, index) in items" :key="item.id" :id="index"> <!-- 元素内容 --> </draggable-resizable> ``` 接下来,可以使用组件提供的事件和方法来实现拖拽互换。具体步骤如下: 1. 监听组件的dragging事件,该事件在拖拽过程中触发: ``` <draggable-resizable @dragging="onDragging"> <!-- 元素内容 --> </draggable-resizable> ``` 2. 在事件处理函数中,使用组件提供的getOverlappingItems方法,获取与当前拖拽元素重叠的元素列表: ``` methods: { onDragging (event) { const overlappingItems = this.$refs.draggable.getOverlappingItems(event) // 处理重叠元素列表 } } ``` 3. 处理重叠元素列表,可以通过判断元素位置和拖拽方向,来决定是否进行互换。如果需要互换,可以使用组件提供的swapItems方法: ``` methods: { onDragging (event) { const overlappingItems = this.$refs.draggable.getOverlappingItems(event) overlappingItems.forEach(item => { // 判断位置和拖拽方向 if (/* 需要互换 */) { this.$refs.draggable.swapItems(event, item.id) } }) } } ``` 4. 在组件的props中,可以设置拖拽和缩放的边界。如果需要互换时,可以通过设置边界来限制互换的范围: ``` <draggable-resizable :boundary="boundary"> <!-- 元素内容 --> </draggable-resizable> data () { return { boundary: { top: 0, left: 0, right: 1000, bottom: 1000 } } } ``` 以上就是使用vue-draggable-resizable-gorkys实现拖拽互换的基本步骤。具体实现方式可以根据需求进行调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值