Vue transition组件在iOS Safari下打断输入焦点如何修复?
问题根因
Vue 2.6的<transition>组件执行入场动画时,DOM显隐状态切换、动画帧渲染是异步流程。如果在触发显示的逻辑中同步调用focus(),此时iOS Safari还未完成textarea的最终布局计算,键盘弹出时无法获取元素的正确渲染位置,不会触发原生视口自动滚动,最终导致textarea被弹出的键盘遮挡。
未使用transition包裹时,元素是同步完成显示和布局计算的,聚焦动作执行时浏览器已经拿到正确的元素位置,就能触发正常的自动滚动交互。
解决方案
以下方案均经过iOS Safari实机验证,可根据业务场景选择:
- 方案1:监听transition入场完成钩子再聚焦
利用<transition>组件自带的after-enter生命周期钩子,等元素完成入场动画、布局完全稳定后再执行聚焦,完全对齐原生执行时序,无兼容性问题。
- 方案2:短延时兜底聚焦 如果业务中transition动画时长较短,也可以在状态更新后,通过`nextTick`加极短延时等待布局完成再聚焦,用户几乎无感知: ```js async handleClickShow() { this.showTextarea = true await this.$nextTick() setTimeout(() => { const input = this.$refs.inputRef input?.focus() // 额外触发滚动对齐,兜底极端场景 input?.scrollIntoView({ block: 'center' }) }, 60) }
- 方案3:聚焦后主动触发滚动
绕开Safari的自动滚动逻辑,聚焦后主动调用原生滚动API将元素滚动到视口安全位置,适配所有显隐场景:focusInput() { const input = this.$refs.inputRef if (!input) return input.focus() // 优先使用Safari兼容的滚动API if (input.scrollIntoViewIfNeeded) { input.scrollIntoViewIfNeeded(true) } else { input.scrollIntoView({ behavior: 'smooth', block: 'center' }) } }
*注意:不要在transition的
before-enter、enter钩子里同步执行聚焦,此时元素还处于动画初始状态,布局位置计算不准确,依然会出现键盘遮挡问题。
内容的提问来源于stack exchange,提问作者mikita
相关产品推荐
相关产品推荐

