谷粒商城实战笔记-54-商品服务-API-三级分类-拖拽效果

avatar
作者
猴君
阅读量:0

文章目录

在这里插入图片描述

一,54-商品服务-API-三级分类-修改-拖拽效果

本节的主要内容是给三级分类树形结构加上拖拽功能,并且根据分类不能大于三级的规则判断是否能拖拽。

1,el-tree控件加上允许拖拽的属性

el-tree控件加上允许拖拽的属性draggable,此外还需要根据层级判断是否能拖动,通过给allow-drop绑定事件allowDrag实现这个需求。
在这里插入图片描述

	allowDrag(draggingNode, dropNode, dropPosition) {       console.log(draggingNode, dropNode, dropPosition);       return true     }, 

在 Element UI(El-UI)的树组件 el-tree 中,allow-drop 事件是一个自定义槽函数,用于控制是否允许将一个节点拖放到另一个节点上。这个函数接受三个参数,分别代表正在拖动的节点、可能的放置目标节点以及放置位置。这三个参数具体如下:

  1. draggingNode:
    这个参数是 TreeNode 类型的对象,表示当前正在被拖动的节点。它包含了关于拖动节点的所有信息,如节点的数据、状态等。

  2. dropNode:
    同样是 TreeNode 类型的对象,表示潜在的放置目标节点。这是你可能要将 draggingNode 放置到的节点。如果拖动过程中没有特定的放置目标(例如,拖动到树的空白区域),这个参数可能是 undefined 或者不适用。

  3. dropPosition:
    表示相对于 dropNode 的放置位置。这是一个字符串,可以是 'before''after''inner',分别表示拖动的节点将放置在目标节点之前、之后或内部。如果 dropNodeundefined,则这个参数可能表示放置在树的顶部或底部。

allow-drop 函数应该返回一个布尔值,指示是否允许进行拖放操作。如果返回 true,则允许拖放;如果返回 false,则阻止拖放操作。例如,在你的代码中:

接下来实现这个函数的逻辑。

原则是当前拖动的阶段到达要放置的位置后,层级数不能超过3,所以核心有3点:

  • ①计算出以拖动结点为根结点的子树的深度deep。
  • ②结合目标结点的深度及放置位置的类型,判断新位置的层级level。
  • ③deep + level <=3 时允许拖动。

关于第②点,新位置的类型可能有三种:

  • prev,目标节点的前面
  • inner,目标节点的子节点
  • next,目标节点的后面

2,是否允许拖拽

递归统计draggingNode子树的深度。

	// 递归计算draggingNode子树的深度     countDraggingNodeDeep(draggingNode) {       var deep = 0;       if (draggingNode.childNodes && draggingNode.childNodes.length > 0) {         debugger         draggingNode.childNodes.forEach(child => {           deep = Math.max(deep, this.countDraggingNodeDeep(child));         });       }       return deep + 1;     }, 

结合draggingNode子树的深度和位置判断是否能拖动。

	allowDrag(draggingNode, dropNode, dropPosition) {       console.log(draggingNode, dropNode, dropPosition);       var deep = this.countDraggingNodeDeep(draggingNode);        console.log(deep,  dropNode.data.catLevel + deep);        // 根据dropPosition结合dropNode.catLevel来判断draggingNode新位置的位置是否合法       if (dropPosition === "prev" || dropPosition === "next") {         return dropNode.data.catLevel + deep - 1 <= 3;       } else if (dropPosition === "inner" ) {         return dropNode.data.catLevel + deep <= 3;       }     }, 

3,完整代码

<template>   <div>     <el-tree       node-key="catId"       :data="menus"       :props="defaultProps"       :expand-on-click-node="false"       show-checkbox       :default-expanded-keys="expandedKeys"       :allow-drop="allowDrag"       draggable     >       <span class="custom-tree-node" slot-scope="{ node, data }">         <span>{{ node.label }}</span>         <span>           <el-button             v-if="node.level <= 2"             size="mini"             @click="() => append(data)"           >             Append           </el-button>           <el-button             size="mini"             @click="() => edit(data)"           >             Edit           </el-button>           <el-button             v-if="node.childNodes.length == 0"             type="text"             size="mini"             @click="() => remove(node, data)"           >             Delete           </el-button>         </span>       </span>     </el-tree>      <el-dialog :title="dialogTitle" :visible.sync="dialogFormVisible" :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>       <div slot="footer" class="dialog-footer">         <el-button @click="dialogFormVisible = false">取 消</el-button>         <el-button type="primary" @click="submitCategory">确 定</el-button         >       </div>     </el-dialog>   </div> </template>  <script> export default {   components: {},   props: {},   data() {     return {       dialogTitle: "", // 编辑窗口标题,新增分类,修改分类       dialogType: "", // 编辑窗口类型,create表示append,edit表示edit       dialogFormVisible: false,       menus: [],       category: {name: "", parentCid: 0, catLevel: 0, sort: 0, showStatus: 1, icon: "", productUnit: "", catId: null},       expandedKeys: [],       defaultProps: {         children: "children",         label: "name",       },     };   },    methods: {     allowDrag(draggingNode, dropNode, dropPosition) {       console.log(draggingNode, dropNode, dropPosition);       var deep = this.countDraggingNodeDeep(draggingNode);        console.log(deep,  dropNode.data.catLevel + deep);        // 根据dropPosition结合dropNode.catLevel来判断draggingNode新位置的位置是否合法       if (dropPosition === "prev" || dropPosition === "next") {         return dropNode.data.catLevel + deep - 1 <= 3;       } else if (dropPosition === "inner" ) {         return dropNode.data.catLevel + deep <= 3;       }     },      // 递归计算draggingNode子树的深度     countDraggingNodeDeep(draggingNode) {       var deep = 0;       if (draggingNode.childNodes && draggingNode.childNodes.length > 0) {         debugger         draggingNode.childNodes.forEach(child => {           deep = Math.max(deep, this.countDraggingNodeDeep(child));         });       }       return deep + 1;     },     append(data) {       console.log(data);       this.dialogType = "create";       this.dialogTitle = "新增分类";       this.dialogFormVisible = true;       this.category = {         name: "",         parentCid: data.catId,         catLevel: data.level + 1,         sort: 0,         showStatus: 1       };     },     edit(data) {       console.log(data);       this.dialogType = "edit";       this.dialogTitle = "修改分类";       this.dialogFormVisible = true;              // 根据catId查询最新数据       this.$http({         url: this.$http.adornUrl(`/product/category/info/${data.catId}`),         method: "get",         data: this.$http.adornData({ catId: data.catId }, false),       }).then(({ data }) => {         if (data && data.code === 0) {           this.category = {...data.data };         } else {           this.$message.error(data.msg);         }       });     },     submitCategory() {       if (this.dialogType === "create") {         this.addCategory();       } else if (this.dialogType === "edit") {         this.updateCategory();       }     },     updateCategory() {       var {catId, name, icon, productUnit } = this.category       console.log( this.category);       this.$http({         url: this.$http.adornUrl("/product/category/update"),         method: "post",         data: this.$http.adornData({catId, name, icon, productUnit }, false),       }).then(({ data }) => {         if (data && data.code === 0) {           this.$message({             message: "修改成功",             type: "success",             duration: 1500,             onClose: () => {               console.log("修改成功,关闭消息提示");               this.dialogFormVisible = false;               this.getMenus(); // 重新获取数据               this.expandedKeys =[ this.category.parentCid == 0 ? this.category.catId : this.category.parentCid ]; // 重置展开节点               console.log(this.expandedKeys);             },           });         } else {           this.$message.error(data.msg);         }       });     },     addCategory() {       this.$http({         url: this.$http.adornUrl("/product/category/save"),         method: "post",         data: this.$http.adornData(this.category, false),       }).then(({ data }) => {         if (data && data.code === 0) {           this.$message({             message: "添加成功",             type: "success",             duration: 1500,             onClose: () => {               console.log("添加成功,关闭消息提示");               this.dialogFormVisible = false;               this.getMenus(); // 重新获取数据               this.expandedKeys =[ this.category.parentCid ]; // 重置展开节点             },           });         } else {           this.$message.error(data.msg);         }       });     },     remove(node, data) {       console.log(node, data);       var ids = [node.data.catId];        this.$confirm(         `确定对[id=${ids.join(",")}]进行[${           ids.length == 1 ? "删除" : "批量删除"         }]操作?`,         "提示",         {           confirmButtonText: "确定",           cancelButtonText: "取消",           type: "warning",         }       )         .then(() => {           this.$http({             url: this.$http.adornUrl("/product/category/delete"),             method: "post",             data: this.$http.adornData(ids, false),           }).then(({ data }) => {             if (data && data.code === 0) {               this.$message({                 message: "操作成功",                 type: "success",                 duration: 1500,                 onClose: () => {                   console.log("删除成功,关闭消息提示");                   this.getMenus(); // 重新获取数据                   this.expandedKeys = [ node.parent.data.catId ]; // 重置展开节点                 },               });             } else {               this.$message.error(data.msg);             }           });         })         .catch(() => {});     },     // 获取分类数据     getMenus() {       this.dataListLoading = true;       this.$http({         url: this.$http.adornUrl("/product/category/list/tree"),         method: "get",       }).then(({ data }) => {         console.log(data);         this.dataListLoading = false;         this.menus = data.data;       });     },   },   created() {     this.getMenus(); // 获取分类数据   }, }; </script> <style scoped> </style> 

广告一刻

为您即时展示最新活动产品广告消息,让您随时掌握产品活动新动态!