vue2树节点刷新后定位到上一节点展开

需求:左侧树针对某一节点进行加锁、解锁处理,处理后的数据需要重新加载树接口,并展开到上一次展开的节点; 可作为有类似场景的代码参考

html 复制代码
  <el-tree
            ref="tree"
            :key="treeKey"
            highlight-current
            lazy
            node-key="node_id"
            :props="props"
            :load="loadNode"
            :default-expanded-keys="showList"
            :expand-on-click-node="false"
            @node-click="clicktree"
            @node-expand="afterNodeExpand"
          >
            <span slot-scope="{ data }" class="custom-tree-node">
              <span
                class="el-tree-node__label"
                :class="{ fnode: data.node_type === 'root' }"
              >
                <em
                  v-if="data.node_type === 'root'"
                  :title="data.name"
                  class="iconEpc icon-cangku mc"
                />
                <em v-else-if="data.node_type === 'dt_CraftRank_01'" class="iconEpc icon-gongsi1 mc" />
                <em v-else-if="data.node_type === 'dt_CraftRank_02'" class="iconEpc icon-chanpinxian mc" />
                <em v-else-if="data.node_type === 'dt_CraftRank_03'" class="iconEpc icon-gongyi mc" />
                <em v-else-if="data.node_type === 'dt_CraftRank_04'" class="iconEpc icon-chejianguanli mc" />
                <em v-else-if="data.node_type === 'dt_CraftRank_05'" class="iconEpc icon-piliangshengchan mc" />
                <em v-else-if="data.node_type === 'dt_CraftRank_06' && data.itemType === 'resource'" class="iconEpc icon-beijing mc" />
                <em v-else-if="data.node_type === 'dt_CraftRank_06'" class="iconEpc icon-server mc" />
                <em v-else-if="data.node_type === 'dt_CraftRank_08'" class="iconEpc icon-beijing mc" />
                &nbsp; &nbsp;&nbsp; &nbsp;{{ getNodeLabel(data) }} &nbsp;
                <span v-if="data.node_type === 'dt_CraftRank_08'" class="tree-btn-group">
                  <em v-if="data.lock == 1" class="el-icon-lock" style="color: #00b4e1;cursor: pointer;width:30px" @click.stop="handleClicklock(data)" /> &nbsp;
                  <em v-else-if="data.lock == 2" class="el-icon-lock" style="color: red;width:30px" @click.stop="handleClickUnlock(data)" />&nbsp;
                </span>
              </span>
            </span>
          </el-tree>
javascript 复制代码
   props: {
        label: 'title',
        isLeaf: 'leaf'
      },
      factoryId: '',
      mfgCenterCode: '',
      showList:[]
    treeKey: 0
javascript 复制代码
methods: {
    // 请求树的接口  写自己的逻辑即可
   loadNode(node, resolve) {
      const craftType = (this.$route.meta && this.$route.meta.craftType) || 'ZZ'
      if (node.level === 0) {
        querytree({ craftType, modelCode: this.selectedModel, jphVersion: this.currentJphVersionType, versionNo: this.currentVersion ? this.currentVersion.versionNo : '' }).then(res => {
          if (res.data.rows.length > 0) {
            this.showList.push(res.data.rows[0].node_id)
            if (res.data.rows[0].isParent === 'true' || res.data.rows[0].isParent === true) {
              res.data.rows[0].leaf = false
            } else {
              res.data.rows[0].leaf = true
            }
            const n = node
            n.data = res.data.rows[0]
            this.rootNode = n
            resolve(res.data.rows)

            this.$nextTick(() => {
              if (this.autoExpandFinished) return
            })
          } else {
            resolve([])
          }
        }).catch(e => {
          console.error('加载树节点失败:', e)
          resolve([])
        })
        return
      }
      if (node.level > 0) {
        querytree({
          'nodeId': node.data.node_id,
          craftType,
          modelCode: this.selectedModel,
          jphVersion: this.currentJphVersionType,
          versionNo: this.currentVersion ? this.currentVersion.versionNo : ''
        }).then(res => {
          if (res.data.rows.length > 0) {
            res.data.rows.forEach(i => {
              if (i.isParent === 'true' || i.isParent === true) {
                this.$set(i, 'leaf', false)
              } else {
                this.$set(i, 'leaf', true)
              }
            })
          }
          return resolve(res.data.rows)
        }).catch(e => {
          console.error('加载树节点失败:', e)
          resolve([])
        })
      }
    },

 
    // 加锁
    handleClicklock(data) {
      this.handleLockToggle(data, 'lock', '加锁')
    },

    // 解锁
    handleClickUnlock(data) {
      this.handleLockToggle(data, 'unlock', '解锁')
    },

    // 加锁/解锁
    handleLockToggle(data, action, actionName) {
      this.$confirm(`确定对此数据${actionName}吗?`, '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {
        const api = action === 'lock' ? lockZZPrBOP : unlockZZPrBOP
        api({ recordIds: data.id }).then((res) => {
          if (res.data.result == '1') {
            this.$message.success(`${actionName}成功!`)

            // 保存当前路径(用于刷新后定位)
            const savedPath = this.getCurrentPath()

            this._restorePath = [...savedPath]
            this.showList = [...savedPath]

            // 刷新树
            this.$nextTick(() => {
              this.treeKey++
            })

            this.$nextTick(() => {
              setTimeout(() => {
                this.locateToNode(savedPath)
              }, 600)
            })
          }
        })
      }).catch(() => {})
    },

    // 定位到目标节点(带重试)
    locateToNode(path, retries = 5) {
      if (!path || path.length === 0) return
      const tree = this.$refs.tree
      if (!tree) return

      const targetId = path[path.length - 1]
      const targetNode = tree.getNode(targetId)

      if (targetNode && targetNode.data) {
        // 找到了,设置高亮并触发点击
        tree.setCurrentKey(targetId, true)
        this.clicktree(targetNode.data, targetNode, null)
        this._restorePath = null
      } else if (retries > 0) {
        // 节点还未加载,延迟重试
        setTimeout(() => {
          this.locateToNode(path, retries - 1)
        }, 400)
      } else {
        console.log('定位失败,目标节点未加载:', targetId)
      }
    },
    getCurrentPath() {
      const savedPath = []
      let current = this.clicknode
      while (current && current.data && current.data.node_id) {
        // 排除 root 节点
        if (current.data.node_type !== 'root') {
          savedPath.push(current.data.node_id)
        }
        // 遇到 root 直接跳出,避免死循环
        if (current.data.node_type === 'root') {
          break
        }
        current = current.parent
      }
      savedPath.reverse()
      console.log('保存的路径:', savedPath)
      return savedPath
    }

}
相关推荐
志尊宝10 小时前
Vue3 零基础每日笔记(073):keep-alive 页面缓存实战——列表页返回不丢状态
vue.js·笔记·缓存·#vue #前端 #前端开发·#javascript·#vue.js
Southern Wind21 小时前
AIAgent——第一章:本地 Agent 与 Vue 3 流式全栈实战
前端·javascript·vue.js
ym hyd 1111 天前
生鲜超市库存管理信息系统源码 Java+SpringBoot+Vue3 前后分离
java·开发语言·vue.js·spring boot·毕设
FYKJ_20101 天前
express绿叶横店短剧推荐与影评分享平台34219-计算机课程设计、毕业设计
java·javascript·vue.js·spring boot·后端·课程设计·express
Eric.461 天前
毕设实战|SpringBoot+Vue 实现多个系统项目
vue.js·spring boot·课程设计
一颗小芹菜的日常1 天前
vue-crack插件是干什么的
前端·javascript·vue.js
peter67681 天前
vue学习小结
前端·vue.js·学习
web3d5202 天前
Vue3 地图白屏排查清单:容器、弹窗与 ol-viewport 重复创建
vue.js·gis
hai_android2 天前
一个公式看懂动态跨表查找:P8 + VLOOKUP
前端·javascript·vue.js
wdssmq2 天前
「折腾」Vue 简单的状态管理实践
vue.js