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
    }

}
相关推荐
高级程序源6 小时前
django大学生创新创业项目管理系统94923-计算机课程设计、毕业设计
javascript·vue.js·spring boot·后端·python·django·课程设计
VXbishe9 小时前
【课程设计】基于SpringBoot的乡村政务服务系统的设计与实现-计算机毕设77011
javascript·vue.js·spring boot·python·php·课程设计·政务
志尊宝9 小时前
Vue3 零基础每日笔记(037):动手封装 useMouse 与 useWindowSize——事件监听的标准模板
前端·javascript·vue.js·笔记·html5
BillKu10 小时前
vue3双向邦定:使用defineModel替换defineProps+defineEmits
vue.js
志尊宝11 小时前
Vue3 零基础每日笔记(047):动态路由与路由参数——:id 传参、query 传参、props 解耦
前端·javascript·vue.js·笔记·html5
计算机毕设定制辅导-无忧学长12 小时前
《基于SpringBoot的中学教师数字胜任力测评网站的设计与实现》
java·vue.js·spring boot·mysql·中学教师数字胜任力测评网站
flash俊杰14 小时前
Vue 3 响应式陷阱与状态单例:从 TDZ 白屏到跨进程 Proxy 剥离
vue.js
志尊宝14 小时前
Vue3 零基础每日笔记(046):声明式导航与编程式导航——useRouter / useRoute 双子星
vue.js·笔记·#vue #前端 #前端开发·#javascript·#vue.js
你别说话了2 天前
Vue实现高效拖拽效果 vue-Draggable
前端·vue.js