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
相关产品推荐
相关产品推荐

