el-tree实现类似windows文件列表,并支持折叠、展开和重命名

el-tree实现类似windows文件列表,并支持折叠、展开和重命名

1.需求:

后台管理系统的左侧导航菜单中文件管理下是个文件夹列表树,
UI给的设计稿是这样的
在这里插入图片描述
实现:左侧用了element的el-menu嵌套el-tree来实现,并且支持展开/折叠某个节点和重命名某个节点
实现效果:
在这里插入图片描述

2.代码实现:

<div id="treepage">
    <el-menu ref="menuRefs" default-active="" class="el-menu-vertical-demo" :collapse="isCollapse">
      <template v-for="item in menuData">
        <!-- 有子级菜单 -->
        <el-submenu v-if="item.children" :index="item.id">
          <template slot="title">
            <i :class="item.icon"></i>
            <span slot="title">{{item.title}}</span>
          </template>
          <template v-for="childItem in item.children">
            <!-- childItem.type === 'treeFile'给的是固定的类型来区分是menu-item还是文件tree -->
            <el-tree v-if="childItem.type === 'treeFile'" ref="treeNode" :highlight-current="true" :data="treeData"
              :default-expanded-keys="defaultTreeKey" :props="defaultProps" node-key="id" accordion
              @node-contextmenu="handleNodeRightMouse" @node-click="handleNodeClick">
              <span slot-scope="{node,data}" class="icon_name">
                <svg class="icon" aria-hidden="true" style="width:1.3rem;height:1.3rem">
                  <use xlink:href="#icon-wenjianjia" />
                </svg>
                <span v-if="!data.isRename" :ref="data.id" style="padding-left:4px">{{ node.label }}</span>
                <el-input v-else :ref="data.id" v-model.trim="cateNameInput" maxlength="20" placeholder="请输入"
                  @click.stop.native @blur="$event => editSave($event, data)"
                  @keyup.native.enter="$event.target.blur" />
              </span>
            </el-tree>
            <el-menu-item v-show="childItem.type !== 'treeFile'" :index="childItem.id">{{childItem.title}}
            </el-menu-item>
          </template>
        </el-submenu>
        <!-- 无子元素 -->
        <el-menu-item v-if="!item.children" :index="item.id">
          <i :class="item.icon"></i>
          <span slot="title">{{item.title}}</span>
        </el-menu-item>
      </template>
    </el-menu>
    <!--文件右击菜单 -->
    <div v-if="optionCardShow" id="option-button-group" :style="{left: optionCardX + 'px',
               top: optionCardY + 'px'
      }">
      <div @click="handleAllNode('open')" class="card-item">
        <img src="public/image/open.svg" alt="">全部展开
      </div>
      <div @click="handleAllNode('fold')" class="card-item">
        <img src="public/image/fold.svg" alt="">全部折叠
      </div>
      <div @click="renameFile" class="card-item" v-if="isNotRootNode">
        <img src="public/image/rename.svg" alt="">重命名
      </div>
    </div>
  </div>
//文件夹树数据结构
 let treeData = [
      {
        label: "团队文件",
        id: 0,
        isRename: false,
        children: [
          {
            label: "一级 1",
            id: 1,
            isRename: false,
            children: [
              {
                label: "二级 1-1",
                id: 4,
                isRename: false,
                children: [
                  {
                    label: "三级 1-1-1",
                    isRename: false,
                    id: 5,
                  },
                ],
              },
            ],
          },
          {
            id: 2,
            label: "一级 2",
            isRename: false,
            children: [
              {
                label: "二级 2-1",
                isRename: false,
                id: 6,
                children: [
                  {
                    label: "三级 2-1-1",
                    isRename: false,
                    id: 7,
                  },
                ],
              },
              {
                label: "二级 2-2",
                isRename: false,
                id: 8,
                children: [
                  {
                    label: "三级 2-2-1",
                    isRename: false,
                    id: 9,
                  },
                ],
              },
            ],
          },
          {
            id: 3,
            label: "一级 3",
            isRename: false,
            children: [
              {
                label: "二级 3-1",
                isRename: false,
                id: 10,
                children: [
                  {
                    label: "三级 3-1-1",
                    isRename: false,
                    id: 11,
                  },
                ],
              },
              {
                label: "二级 3-2",
                id: 12,
                children: [
                  {
                    label: "三级 3-2-1",
                    id: 13,
                  },
                ],
              },
            ],
          },

        ]
      },
    ]
    //menu菜单数据结构
    let menuData = [
      {
        id: '1',
        title: '文件管理',
        icon: 'el-icon-document',
        type: 'menu',
        children: [{
          id: '1-1',
          title: '团队文件',
          icon: 'icon-wenjianjia',
          type: 'treeFile',
        },
        {
          id: '1-2',
          title: '分享管理',
          icon: '',
          type: 'menu',
        }
        ]
      }, {
        id: '2',
        title: '设置',
        icon: 'el-icon-setting',
        type: 'menu',
      }
    ]
   
	data () {
        return {
          treeData: treeData,//文件树数据
          menuData: menuData,//menu菜单数据
          defaultProps: {
            children: "children",
            label: "label",
          },
          isCollapse: false,//菜单折叠
          cateNameInput: "", // 当前修改文件名
          optionCardShow: false, // 文件夹节点操作卡是否显示
          optionCardX: "", // 文件夹节点操作卡位置
          optionCardY: "",
          optionData: "", // 右键选中的节点
          node: null, // 右键当前选中的节点
          isNotRootNode: true,//是否是根目录
          defaultTreeKey: [],//设置默认选中当前文件夹树node

        }
      },
    methods: {
        // 设置默认节点 (这个是选择某一个文件夹层级后,刷新页面默认选中)
        handleExpend () {
          this.defaultTreeKey = []
          // 5给的是测试数据,某一层级的ID
          this.defaultTreeKey.push(5)
          this.$nextTick(() => {
            this.$refs.treeNode[0].setCurrentKey(5);
          });
        },

        // 点击菜单tree形文件节点,隐藏右键菜单
        handleNodeClick (data, node, self) {
          this.optionCardShow = false;
        },

        // 右击文件夹tree
        handleNodeRightMouse (e, data, n, t) {
          this.optionCardShow = false;
          this.optionCardX = e.x; // 让右键菜单出现在鼠标右键的位置
          this.optionCardY = e.y;
          this.optionData = data;
          this.node = n; // 将当前节点保存
          this.tree = t;
          this.isNotRootNode = !!n.parent.parent
          this.optionCardShow = true; // 展示右键菜单
        },

        // 失去焦点后保存
        editSave (val, data) {
          console.log(this.optionData);
          data.isRename = !data.isRename;
          data.label = this.cateNameInput || data.label;
          this.optionCardShow = false;
          // 修改名称成功
        },

        // 重命名节点
        renameFile () {
          this.cateNameInput = this.optionData.label;
          this.optionData.isRename = !this.optionData.isRename;
          this.optionCardShow = false;
          this.$nextTick(() => {
            this.$refs[this.optionData.id][0] &&
              this.$refs[this.optionData.id][0].focus(); // 获取输入框,自动获取焦点
          });
        },

        // 展开或者折叠node点击事件
        handleAllNode (type) {
          if (!this.optionData) {
            return
          }
          let _data = [this.optionData]
          _data.length && this.handleNowNodeData(_data, type == 'open')
          this.optionCardShow = false;
        },

        // 展开or折叠当前父节点
        handleNowNodeData (data, bool) {
          let _this = this
          data.forEach((el) => {
            _this.$refs.treeNode[0].store.nodesMap[el.id].expanded = bool;
            el.children && el.children.length > 0
              ? _this.handleNowNodeData(el.children, bool)
              : ""; // 子级递归
          });
        },

      }
#treepage {
  width: 13vw;
}

.el-tree {
  padding: 0;
  overflow-y: auto;
}

.el-tree {
  background: #fff !important;
  color: #000 !important;
  padding: 0 10px 10px 30px;
  font-size: 14px;
}

.el-tree-node__content {
  display: flex;
  align-items: center;
  height: 35px;
}

.el-tree-node__children {
  overflow: visible;
}

.el-tree-node__content:hover,
.el-tree-node:focus>.el-tree-node__content {
  background-color: #ffffff !important;
  color: #6bafed !important;
}

.el-tree-node.is-current>.el-tree-node__content {
  background: transparent !important;
  color: #6bafed !important;
}

.icon_name {
  display: flex;
  align-items: center;
}

.el-input__inner {
  height: 25px;
  margin-left: 5%;
  font-size: 14px;
  padding-left: 8px;
}

.el-input.is-active .el-input__inner,
.el-input__inner:focus {
  border-color: #1890ff;
}

.right_table {
  width: 70%;
  border: 1px solid rgba(0, 0, 0, 0.1);
}

#option-button-group {
  padding: 0 10px 10px 10px;
  font-size: 12px;
  color: #000000;
  z-index: 9999;
  position: fixed;
  background: #ffffff;
  box-shadow: 0px 9px 28px 8px rgba(0, 0, 0, 0.05),
    0px 6px 16px 0px rgba(0, 0, 0, 0.08), 0px 3px 6px -4px rgba(0, 0, 0, 0.12);
  border-radius: 2px 2px 2px 2px;
}

#option-button-group .card-item {
  margin-top: 10px;
  display: flex;
  align-content: center;
  cursor: pointer;
}

.card-item img {
  margin-top: 3px;
  margin-right: 5px
}

.iconfont {
  font-size: 12px;
  margin-right: 10px;
}

.el-empty {
  margin-top: 20%;
}

.noMenuTile .el-submenu__title {
  height: 0;
}

.noMenuTile .el-icon-arrow-down:before {
  content: '';
}
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
实现右键菜单重命名功能,你可以使用el-tree组件的contextmenu事件和自定义右键菜单来实现。 首先,在el-tree组件上添加contextmenu事件监听器,可以使用@contextmenu指令或v-contextmenu指令。例如: ```html <el-tree @contextmenu="showContextMenu"> <!-- 树节点内容 --> </el-tree> ``` 接下来,在你的Vue实例中定义showContextMenu方法来处理右键菜单的显示和点击事件。在该方法中,你可以使用event对象的clientX和clientY属性来获取鼠标点击的位置,然后显示自定义的右键菜单。例如: ```javascript methods: { showContextMenu(event) { event.preventDefault(); // 阻止默认右键菜单弹出 const menu = document.getElementById('custom-menu'); // 获取自定义右键菜单元素 menu.style.left = event.clientX + 'px'; // 设置菜单的水平位置 menu.style.top = event.clientY + 'px'; // 设置菜单的垂直位置 menu.style.display = 'block'; // 显示菜单 // 其他逻辑... } } ``` 注意,上述代码中获取自定义右键菜单元素的方式使用了getElementById,所以需要在页面中定义一个id为custom-menu的元素作为自定义右键菜单的容器,并设置其样式为隐藏。例如: ```html <div id="custom-menu" style="display: none;"> <!-- 自定义右键菜单内容 --> </div> ``` 最后,你还需要在自定义右键菜单的内容中添加一个重命名选项,并为其添加点击事件监听器。在点击事件处理函数中,你可以通过获取当前选中的树节点,进行相应的重命名操作。例如: ```html <div id="custom-menu" style="display: none;"> <div @click="renameNode">重命名</div> </div> ``` ```javascript methods: { renameNode() { // 获取当前选中的树节点 const selectedNode = this.$refs.tree.getCurrentNode(); // 执行重命名逻辑... } } ``` 这样,当用户右键点击el-tree的节点时,会触发showContextMenu方法显示自定义右键菜单,点击重命名选项会执行renameNode方法进行重命名操作。你可以根据具体的业务需求,在renameNode方法中实现对节点的重命名逻辑。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值