背景
在一个悠闲的午后,旁边的同事突然一脸严肃地问我:"为什么在 form 表单中点击一个按钮会导致我的 Web 页面刷新?"我一时愣住了,因为这样的问题我从未遇到过,涉及到了我的知识盲区。当我观察他的操作时,确实发现页面刷新了。然后我尝试将他的业务代码全部删除,只保留 form 标签和 button,结果点击仍然刷新了页面。
css
<form>
<button>保存设置</button>
<button>取消</button>
</form>
http://localhost:3000
变成了http://localhost:3000/?
,页面也刷新了。百思不得其解
分析
接着,我尝试使用 antd 组件库
进行测试,发现一切正常。点击按钮并没有触发页面的刷新,令人费解
javascript
import { Button, Form } from 'antd';
function App() {
return (
<Form>
<Button>Submit</Button>
</Form>
);
}
我开始思考,这和原生的编写方式有什么不同吗?于是我开始检查页面元素,看看是否有什么不同。灵机一动,我发现 antd 组件库编译之后的 button 多了一个 type="button"
的设置,难道这就是答案吗?
验证
于是我在原生标签的 button 上添加了 type="button",发现问题得到了解决,点击按钮后,页面不再刷新!同事直呼 牛啊~。但作为一名具有工匠精神的程序员,我带着问题和答案,想进一步探究这个问题的根源。
一番努力,偶然在 MDN Web 文档 - <button>
上找到了相关的介绍
如果你的按钮不是用于向服务器提交数据,请确保这些按钮的
type
属性设置成button
。否则它们被按下后将会向服务器发送数据并加载(可能并不存在的)响应内容,因而可能会破坏当前文档的状态。
有点意思,翻译成大白话就是:当一个按钮位于 <form>
标签内且没有指定 type
属性时,它的默认行为是提交表单。当表单提交时,浏览器会进行以下操作:
- 收集表单内所有输入字段的值。
- 根据
<form>
标签的method
属性(默认为GET
)和action
属性(默认为当前页面URL)来确定提交的方式和目标。 - 提交表单数据,并根据
method
属性将数据添加到URL(如果是GET
方法)或请求体(如果是POST
方法)。
真相大白
在一个标准的 HTML 表单中,如果你没有指定 action
属性,表单提交后的目标 URL 将会是当前页面的 URL。同时,如果你没有指定 method
属性默认就是 GET
方法,浏览器会将表单数据以 查询字符串 的形式添加到 URL 中。
查询字符串 是 URL 中 ?
后面的部分,用于传递额外的参数。http://localhost:3000/?
中的 ?
就是查询字符串的开始。如果表单中没有任何数据,或者数据都为空,查询字符串 就只有?
,没有任何参数。
所以,当你点击 type
属性为 submit
(或未指定 type
属性)的按钮提交表单时,如果表单未指定 method
属性,并且未指定 action
属性,浏览器就会将表单数据以 查询字符串 的形式添加到当前页面 URL 中,从而导致 URL 变为 http://localhost:3000/?
解决方法
要解决这个问题,可以采取以下两种措施:
方法1:将按钮类型设置为 button
将按钮的 type
属性设置为 button
,这样它就不会触发表单提交,从而避免修改浏览器URL。
jsx
<form>
<Button type="button">保存设置</Button>
<Button type="button">取消</Button>
</form>
方法2:阻止表单提交
在表单的onSubmit
事件处理函数中调用preventDefault()
方法,阻止表单提交。这样,即使按钮的类型是submit
,也不会触发表单提交。
jsx
import React from 'react';
const MyForm = () => {
const handleSubmit = (event) => {
event.preventDefault(); // 阻止表单提交
// 处理表单提交的逻辑
};
return (
<form onSubmit={handleSubmit}>
<Button>保存设置</Button>
<Button type="button">取消</Button>
</form>
);
};
export default MyForm;
这两种方法都可以防止点击按钮时修改浏览器URL。通过使用这些方法,你可以确保按钮不会触发表单提交,从而避免修改浏览器URL和页面刷新。
结论
原本同事直接使用 antd 组件库
就很好,偏偏要自己敲代码。作为一条咸鱼,我们不应该总是想着自己造轮子,直接使用第三方组件库能避免很多问题,既省时又省力,避免了不必要的麻烦。另外,长时间使用 Ctrl C + Ctrl V 之后,我们还是需要不时地复习基础知识。如果大家也遇到了类似的问题,可以参考我的解决方法。