踩坑复盘:为什么在输入框按个回车,页面就偷偷刷新了?

案发现场:按个回车,页面没了?

前几天在搞一个后台管理系统的搜索功能,测试小哥跑来找我,说:"你这搜索框怎么一按回车,整个页面就白屏刷新了?"

我当时心里一紧,心想不至于吧,我明明只写了触发搜索的请求逻辑,没写刷新页面的代码啊。自己上手一敲回车,好家伙,真刷新了,刚才填的表单数据全没了。

破案了:都是 <form> 惹的祸

排查了一圈业务代码,没发现哪里偷偷调了 location.reload() 或者路由跳转。后来打开 DevTools 仔细看了一眼 DOM 结构,发现这个输入框是被包在一个 <form> 标签里的。

这时候才恍然大悟:这根本不是 JS 代码的锅,而是 HTML 的"祖传手艺"。

在 <form> 表单中,如果你按下 Enter 键,浏览器会默认触发表单提交(Submit) 行为。特别是当表单里只有一个单行输入框,或者没有显式指定 action 属性时,它默认就会向当前 URL 发起提交,表现出来的结果就是------页面原地刷新。

怎么治?阻止它的"自作主张"

既然知道了是浏览器的默认行为在作祟,那解决思路就很清晰了:拦截它。

我们只需要在输入框上监听键盘事件,当用户按下 Enter 键时,手动调用 event.preventDefault() 把默认行为掐断就行了。

这里给一个 Vue3 Composition API 环境下的实操示例:

javascript 复制代码
import { onMounted, ref } from 'vue'

const baseCustomInputRef = ref(null)

// 封装键盘事件处理函数
const emitKeyDownEvent = (event) => {
  if (event.key === 'Enter') {
    // 核心:阻止表单默认的提交刷新行为
    event.preventDefault()
  }
  // 继续向外抛出事件,不影响其他业务逻辑
  emit('keydown', event)
}

onMounted(() => {
  // 绑定到真实的 DOM 节点上
  if (baseCustomInputRef.value) {
    baseCustomInputRef.value.addEventListener('keydown', emitKeyDownEvent)
  }
})

避坑指南:别只盯着原生 Input

如果你用的是原生 <input>,直接在模板里写 @keydown.enter.prevent 就能搞定。但在实际工程里,我们往往会用 Element Plus、Ant Design Vue 等组件库,这时候有几个细节需要特别注意:

  • 组件透传问题 :你拿到的往往是包装过的组件(比如 <el-input>),直接在外层绑 @keydown 有时不生效,因为组件内部可能没有把该事件透传给原生 input。
  • 获取真实 DOM :像上面的代码一样,通过 ref 拿到组件实例后,最好确保你绑定事件的目标是原生的 input 元素 ,或者是包裹该 input 的父级 DOM 节点。
  • 事件清理 :虽然 Vue 在组件卸载时会自动清理大部分事件,但如果是手动通过 addEventListener 绑定的原生事件,建议在 onBeforeUnmount 里顺手 removeEventListener 清理掉,防止内存泄漏。
javascript 复制代码
import { onBeforeUnmount } from 'vue'

onBeforeUnmount(() => {
  if (baseCustomInputRef.value) {
    baseCustomInputRef.value.removeEventListener('keydown', emitKeyDownEvent)
  }
})

写代码就是这样,很多时候bug并不在复杂的业务逻辑里,而是藏在这些基础标签的默认行为中。多留个心眼,下次再遇到"莫名其妙"的刷新,先看看它是不是住在 <form> 里。

📝 本文收录于《前端踩坑与实战复盘》系列,编号:No.042

相关推荐
u01110267510 小时前
JPG、PNG、WebP 怎么选?按透明度、体积和使用场景做判断
前端·javascript·vue.js·图像处理·ai作画
雪芽蓝域zzs15 小时前
第 7 节:多边形点击弹窗 + 清空绘制按钮
vue.js
溪语流沙15 小时前
【Web全栈进阶】Composition API与组件通信:props深入、emit、插槽
前端·css·vue.js
顽疲18 小时前
Java vue 养老系统源码详解:入住核算单 live-check 缴费入账与预交金收据实践
java·vue.js·python·java 养老·springboot 养老·vue养老
志尊宝19 小时前
Vue3 零基础每日笔记(088·完结):从零到一——一个完整 Vue3 项目的成长复盘
前端·javascript·vue.js·笔记·ecmascript·#vue.js
桔筐20 小时前
Vue中DOM的data-*自定义属性(dataset)与Vue data响应式变量区别详解
前端·javascript·vue.js
用户17335980753721 小时前
纯前端 PDF 按书签拆分避坑指南:拆分后章节对不上?
前端·javascript·vue.js
雪芽蓝域zzs1 天前
Webstorm打开uniapp uvue文件报红处理方案
vue.js
撸串-研究生1 天前
面向景区的综合服务管理平台设计——以稻城亚丁景区为例【附源码】
java·开发语言·vue.js·前后端分离·稻城亚丁景区
志尊宝1 天前
Vue3 零基础每日笔记(082):文件上传实战——el-upload 校验、自定义上传、头像预览
前端·javascript·vue.js·笔记·#javascript·#vue.js