求解:onBeforeRouteLeave 钩子影响输入框无法聚焦的原因?

新手上路,请多包涵

vue3 技术栈,A 页面组件销毁时,会执行 onBeforeRouteLeave 钩子函数:

onBeforeRouteLeave(() => {
  const confirmed = window.confirm('是否退出?')
  if (!confirmed) return false
})

弹出弹框,点击确认按钮,跳转 B 页面。B 页面有一按钮,点击按钮,弹出 ant-design-vue 的 modal 组件,弹窗内有一输入框,需做到输入框自动聚焦,我的代码如下:

// ...
await nextTick()
inputRef.value?.focus()
// ...
// inputRef 表示 input 输入框的 ref

实际情况是输入框无法自动聚焦,实际情况 B 页面刷新后是能聚焦的,说明 B 页面代码没问题。

而将 A 页面 onBeforeRouteLeave 钩子改写如下:

onBeforeRouteLeave((to, from, next) => {
  modal.confirm({
    centered: true,
    icon: '',
    content: '是否退出?',
    okText: '确认',
    cancelText: '取消',
    onOk() {
      next(true)
    },
    onCancel() {
      next(false)
    }
  })
})

从 A 页面跳转 B 页面,B 页面弹窗内输入框能正常聚焦,ant-design-vue 的 modal.confirm 本质是一个 promise 函数,所以想知道造成现象的原因,望大佬能解惑。B 页面究竟是哪阻塞了,因为我在 B 页面的

await nextTick()
console.log(inputRef.value)

是能打印出 inputRef.value 对象的。onBeforeRouteLeave 钩子下的同步代码为什么会阻塞目标页面的异步代码执行呢?

阅读 1.5k
2 个回答

这个问题是因为 window.confirm 是一个同步的方法,它会阻止浏览器的其他操作,包括输入框的聚焦。而使用 modal.confirm 是异步的,因此它不会阻止浏览器的其他操作。

当你使用 window.confirm 时,浏览器会在等待用户响应时阻塞执行。这意味着,在这个过程中,其他的操作(如输入框聚焦)无法执行。所以,当你从 A 页面跳转到 B 页面时,输入框无法自动聚焦。

而使用 modal.confirm 时,由于它是异步的,浏览器不会阻塞等待用户响应。这样,当你从 A 页面跳转到 B 页面时,输入框能够正常聚焦。

为了解决这个问题,你可以继续使用 modal.confirm,或者在 window.confirm 的情况下,尝试在 B 页面的 mounted 或 onMounted 钩子中添加一个异步的聚焦操作。例如:


// B 页面
onMounted(async () => {
  await nextTick()
  inputRef.value?.focus()
})

这样,在 A 页面跳转到 B 页面时,输入框应该能够自动聚焦。

inputRef.value 的确不存在,或者说,不在DOM 中存在。
所以 focus 就无效了。
可以写成
setTimeout 包一下

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题