[Vue+Element UI] 实现树节点标签可编辑功能

需求和效果

在这里插入图片描述
需求:
1.可编辑:鼠标悬浮出现目录编辑图标,点击编辑图标,弹出树节点名称修改弹出框进行修改,同时弹出框具备校验功能。
2.可删除:点击删除图标,删除相对应节点。

代码

<template>
  <div class="editable-tree l-box-col">
    <div class="editable-tree-header l-mt-12 l-mb-12">
      <el-button
        class="market-standard-sidebar-btn"
        type="primary"
        @click="() => this.$emit('showDirectoryDialog', 'directory')"
        size="medium"
      >
        <i class="el-icon-folder"></i>
        新建目录
      </el-button>
      <el-button
        v-if="menuType == 'info'"
        class="market-standard-sidebar-btn"
        @click="() => this.$emit('showDirectoryDialog', 'specification')"
        size="medium"
      >
        <i class="el-icon-document"></i>
        新建规范集
      </el-button>
    </div>
    <div class="editable-tree-body l-flex" @click="cancleSelect">
      <el-tree
        :data="data"
        node-key="id"
        default-expand-all
        :expand-on-click-node="false"
        @node-click="handleNodeClick"
        ref="treeComp"
      >
        <div
          class="custom-tree-node"
          slot-scope="{ node, data }"
          @mouseenter="() => mouseenter(data)"
          @mouseleave="() => mouseout(data)"
        >
          <div class="custom-tree-node-label">
            <span v-show="data.directoryType == '00'" class="l-mr-10">
              <i class="el-icon-folder"></i>
            </span>
            <span v-show="data.directoryType == '01'" class="l-mr-10">
              <i class="el-icon-document"></i>
            </span>
            <div><title-tip :content="node.label" /></div>
            <!-- <span>{{ node.label }}</span> -->
          </div>

          <div class="custom-tree-node-operate">
            <i
              v-show="data.showEdit"
              @click="() => edit(node, data)"
              class="el-icon-edit l-mr-8"
            ></i>
            <i
              v-show="data.showDel"
              @click="() => remove(node, data)"
              class="el-icon-delete delete-icon"
            ></i>
          </div>
        </div>
      </el-tree>
    </div>
  </div>
</template>

<script>
import * as api from '@/api/tree'
let id = 10
export default {
  name: 'EditableTree',
  props: {
    data: {
      type: Array,
      default: () => [],
    },
    menuType: {
      type: String,
      default: '',
    },
    applicationType: {
      type: String,
      default: '',
    },
    defaultCheckTreeKeys: {
      type: Array,
      default: () => [],
    },
  },
  computed: {
    treeData() {
      return JSON.parse(JSON.stringify(this.data))
    },
  },
  data() {
    return {
      firstInit: true,
    }
  },
  methods: {
    remove(node, data) {
      const id = data.id
      const params = {
        id,
        applicationType: this.applicationType,
      }
      api.deleteDirectory(params).then((res) => {
        if (res.responseCode == 200) {
          this.removeTreeData(node, data)
          this.$message({
            showClose: true,
            message: '删除成功',
            type: 'success',
          })
          this.$emit('queryTreeData')
        } else {
          this.$message({
            message: res.message,
            type: 'warning',
          })
        }
      })
    },
    edit(node, data) {
      const nodeInfo = {
        id: data.id,
        directoryType: data.directoryType,
        directoryName: data.label,
      }
      this.$emit('editDirectoryDialog', nodeInfo)
    },
    removeTreeData(node, data) {
      const parent = node.parent
      const children = parent.data.children || parent.data
      const index = children.findIndex((d) => d.id === data.id)
      children.splice(index, 1)
    },
    mouseenter(data) {
      this.showEdit && this.$set(data, 'showEdit', true)
      if (data.children.length !== 0) return
      this.$set(data, 'showDel', true)
    },
    mouseout(data) {
      this.showEdit && this.$set(data, 'showEdit', false)
      if (data.children.length !== 0) return
      this.$set(data, 'showDel', false)
    },
    handleNodeClick(data) {
      this.$emit('getDirectoryId', data)
    },
    cancleSelect() {
      // this.$refs.treeComp.setCurrentKey(null)
      // this.$emit('clearDirectoryId')
    },
    // createDirectoryDialog(type) {
    //   this.dialogData.dialogVisible = true
    //   this.dialogData.width = '30%'
    //   this.dialogData.top = 'calc(50vh - 116px)'
    //   this.dialogData.title = type == 'directory' ? '新建目录' : '新建规范集'
    //   this.dialogData.component = 'MarketCreateDirectory'
    //   this.dialogData.transferData = { type }
    //   this.directoryDialogType = type
    //   this.dialogData.buttons = [
    //     {
    //       type: 'primary',
    //       size: 'medium',
    //       label: '确定',
    //       event: 'modifyTreeData',
    //     },
    //     {
    //       size: 'medium',
    //       label: '取消',
    //       event: 'close',
    //     },
    //   ]
    // },
  },
  watch: {
    defaultCheckTreeKeys: {
      handler: function (newVal, oldVal) {
        this.$nextTick(() => {
          this.$refs.treeComp.setCurrentKey(newVal[0])
        })
      },
    },
    $route: {
      handler: function (to, from) {
        // 只有当前页面为集市规范化-数据规范信息时
        const curPage = to.query.index.replace('/', '')
        this.showEdit = curPage == 'info'
      },
      immediate: true,
    },
  },
}
</script>

<style lang="less" scoped>
.editable-tree {
  &-body {
    overflow: scroll;

    ::v-deep {
      .el-button {
        color: #d2d2d2;
        border: none;
        margin-left: 20px;
        padding: 0;
        display: none;
      }
    }
  }

  ::v-deep .el-tree-node__content:hover {
    .el-button {
      display: inline-block;
    }
  }

  ::v-deep .custom-tree-node {
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding-right: 8px;
  }

  ::v-deep .custom-tree-node-label {
    display: flex;
    width: 180px;
  }

  // ::v-deep .custom-tree-node-operate {
  //   width: 40px;
  //   height: 15px;
  // }

  ::v-deep.el-tree-node.is-current > .el-tree-node__content {
    background: #f0f4ff;
    color: #358df6;
    font-weight: bold;
    i {
      color: #358df6;
      font-weight: bold;
    }
  }
  ::v-deep .el-tree-node__content {
    font-size: 14px;
  }
}
</style>

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值