乐趣区

关于vue.js:通过改造elementUI的eltree非源码实现类文档编辑器右键菜单删除文件功能

最近做我的项目遇到了一个需要,之前没写过,且对本人来说感觉实现起来有些难度,所以记录一下过程以作备忘。
我的项目现页面左侧是应用 el-tree 实现的一个文档构造,在该文档的某个节点鼠标右键弹出菜单,能够删除对应的文件,而 el-tree 通过鼠标左键点击节点默认只有单选高亮。当初须要减少一个性能,通过 ctrl+ 鼠标左键点击节点实现多选高亮,再通过鼠标右键弹出菜单时能够批量删除。交互如下图所示:

接到需要,必定就要想好这个交互怎么搞,有一些脉络,然而也不是很清晰,放心细节考虑不周,所以就去钻研了一下 vscode 这个性能是怎么实现的,钻研一下竞品的交互设计(偷师)是一个必修课嘛。

捣鼓了一阵就得出了大抵的交互细节。如:

  1. ctrl+ 左键点击节点实现多选高亮。
  2. 鼠标右键显示的菜单是依据所右键的节点的内容决定的。
  3. 不是所有的节点都有删除性能,也就是不是所有文件都是能够删除的,因为我的项目的某些后盾文件删除会导致整个我的项目跑不起来。然而 crtl+ 左键多选是所有节点都能够抉择的,所以删除时须要排除掉不可删除的节点
  4. 右键时其节点可能并没有被左键选中高亮,所以须要加一个判断,右键时,节点若不在高亮节点中,删除时只删除以后右键节点,反之,则批量删除高亮节点内可被删除的节点。

从技术上实现的话,须要留神的是以下几点:

  1. 实现树的多选须要应用 show-checkboxnode-key字段来显示复选框才可多选,因为 UI 设计里无复选框,所以还须要笼罩款式暗藏复选框,该字段的应用会多出类名为 el-checkbox 的节点, 通过 css 来暗藏,而节点的高亮则通过高亮时新增的类名 .is-checked 来实现的,所以能够依据这个类名对 el-tree-node__content 减少背景色彩来实现高亮。
  2. 因为多选高亮时父子节点的关联高亮是不合乎设计和习惯的,所以应用 :check-strictly="true" 严格的遵循父子不相互关联。
  3. 依据 @node-contextmenu="handleNodeContextMenu 函数获取右键的节点,和通过树的 getCheckedNodes 函数获取全副已选节点的数组,通过 findIndex 判断右键节点是否在其中。
  4. 节点的 data 数据内会蕴含是否能够删除的信息

最初实现的代码局部内容如下:

//html 局部
<el-tree
        :data="projectShowPanel"
        :props="treeProps"
        :default-expanded-keys="expandedArr"
        @node-click="handleNodeClick" // 关键点
        :expand-on-click-node="false"
        @node-contextmenu="handleNodeContextMenu" // 关键点
        @node-expand="nodeExpand"
        @node-collapse="nodeCollapse"
        show-checkbox // 关键点
        node-key="path" // 关键点
        :filter-node-method="searchNode"
        :indent="nodeIndent"
        :check-strictly="true"// 关键点
        ref="serverTree"
  ></el-tree>
<mouse-menu
      :menuList="menuList"
      @handleContext="handleContext"
      ref="mouseContext"
></mouse-menu>// 通过 vue-context 插件来实现右键菜单
//css 局部
/deep/ .el-tree-node{
    .is-checked > .el-tree-node__content {
      background-color: #07B6B5 !important;
      color: #fff !important;
    }
     > .el-tree-node__content {
       .el-checkbox{display: none;}
    }
  }
//JavaScript 局部
// 解决 tree-item 被右键单击
    handleNodeContextMenu(event, data, node, nodeSelf) {let datas = this.$refs.serverTree.getCheckedNodes();// 获取已选节点的数据
      let nodes = datas.map(data => {return this.$refs.serverTree.getNode(data.path)// 获取已选节点
      });
      //datas 和 nodes 还须要通过是否可删除的字段来过滤掉不可删除节点
      // 以下判断右键节点是否在已选节点内
      let index = datas.findIndex(item => {return item.path === data.path});
      // 依据是否存在,通过 getContextList 函数生成对应菜单数组 menuList 
      if(index > -1){// 若在
        this.menuList = this.getContextList(data, node, datas, nodes);
      }
      else{// 若不在
        this.menuList = this.getContextList(data, node);
      }
      if (this.menuList.length > 0) {this.$refs.mouseContext.openContext(event, node);// 若菜单数组不为空,显示右键菜单内容
      }
    }

以上代码可获取到节点的具体数据,最初再依据理论业务代码来决定具体的删除代码函数

退出移动版