You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vue路由切换后$refs为undefined 键盘导航功能异常问题求助

问题根因

该错误的核心原因是事件总线的监听没有在组件销毁时解绑:

  • 每次进入页面mounted钩子执行时,都会新增一个navegarSetasPedidos事件的监听回调
  • 切换路由离开页面时,组件实例已销毁但绑定的回调没有被移除,事件触发时旧的回调仍会执行,旧组件的$refs已经被回收所以返回undefined
  • 新进入页面时新增的回调也会同时执行,所以会出现先打印空值、再打印有效值的情况,功能看似正常但会抛出大量错误
解决方案

按以下步骤修改即可完全解决问题:

步骤1:组件销毁时解绑事件监听

首先要把绑定的匿名回调改为具名方法引用,才能在销毁时准确解绑,修改组件生命周期逻辑:

mounted() {
    // 直接绑定方法引用,不要用匿名箭头函数
    Event.$on('navegarSetasPedidos', this.navegarSetas)
},
// 新增销毁前解绑逻辑
beforeDestroy() {
    // 解绑对应事件的回调
    Event.$off('navegarSetasPedidos', this.navegarSetas)
    // 可选:切走页面时重置导航状态,避免下次进入复用旧的索引值
    this.navegacaoSetasAtiva = false
    this.navegacaoAtual = 0
}

步骤2:给$refs访问增加判空防护

不管任何场景,访问$refs前都要做存在性判断,避免极端场景(比如异步数据还没渲染完成、列表数据为空)下的报错,修改navegarSetas方法中的元素获取逻辑:

navegarSetas(key) {
   if (this.navegacaoSetasAtiva == false) {
      this.navegacaoSetasAtiva = true
      this.navegacaoAtual = 0
   } else if (this.modalAtivado == false && this.navegacaoSetasAtiva == true) {
     if (key == 'ArrowDown' && this.navegacaoAtual < this.pedidos.length - 1) {
        this.navegacaoAtual++
        // 新增判空逻辑
        const refKey = 'pedido' + this.navegacaoAtual
        const refItem = this.$refs[refKey]
        if (!refItem || !refItem[0] || !refItem[0].$el) return
        let elementoSelecionado = refItem[0].$el
        let boundaries = elementoSelecionado.getBoundingClientRect()
        if (boundaries.top < 0 || boundaries.top > (window.innerHeight || document.documentElement.clientHeight)){
          elementoSelecionado.scrollIntoView({behavior: 'smooth'}) 
        }
     } else if (key == 'ArrowUp' && this.navegacaoAtual <= this.pedidos.length && this.navegacaoAtual > 0) {
       this.navegacaoAtual--
       // 同上述判空逻辑
       const refKey = 'pedido' + this.navegacaoAtual
       const refItem = this.$refs[refKey]
       if (!refItem || !refItem[0] || !refItem[0].$el) return
       let elementoSelecionado = refItem[0].$el
       let boundaries = elementoSelecionado.getBoundingClientRect()
       if (boundaries.top < 0 || boundaries.top > (window.innerHeight || document.documentElement.clientHeight)){
          elementoSelecionado.scrollIntoView({behavior: 'smooth'}) 
       }
     } else if (key == 'Enter') {
       // 可选:判断索引对应数据存在再执行
       if (!this.pedidos[this.navegacaoAtual]) return
       let pedidoSelecionado = this.pedidos[this.navegacaoAtual].id
       Event.$emit('changeShow', pedidoSelecionado)
     }
  }
}

可选优化(针对异步加载列表的场景)

如果你的pedidos列表是通过接口异步请求获取的,可以在导航函数最开始加一个数据加载完成的判断,避免数据还没返回、DOM没渲染时触发导航逻辑:

navegarSetas(key) {
  // 新增判断,isPedidosLoaded在接口请求完成后赋值为true即可
  if (!this.isPedidosLoaded || !this.pedidos.length) return
  // 原有逻辑...
}

内容的提问来源于stack exchange,提问作者Mirino97

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 04:39:02