闲话多提交按钮的HTML表单

标签: Web Development form HTML submit button | 发表时间:2011-10-05 20:57 | 作者:Justice 逸川
出处:http://lync.in
本文作者:Justice

在 Web 应用中,最常用的服务器端与客户端的数据交互是通过提交 HTML 表单实现的。以 HTML 4.01 为例,规定当表单提交时,会将 <form> 元素中的 Successful controls 的当前取值提交到服务器。所谓成功控件需要有以下几个条件(但不仅限于此):

  1. 必须有控件名字,即必须包含 name 属性
  2. 如果表单中有多个提交按钮,只有被点击的那个按钮可以是成功的
  3. 不能是禁用状态,即不含 disabled 属性
  4. 不是 Reset button

现在我们考虑一下这样的场景,在某个表单中我们需要用到多个提交按钮(Submit button),就如同 WordPress 后台写文章那样的表单,我们在编辑完文章内容后,可以选择保存草稿或是直接发布。下面图中所示是一个简化的发布页面,可以填写文章标题、内容之后选某一种提交形式:
Scenario

对应的 HTML 片段可以是这样:

HTML
1
2
3
4
5
6
<form action="http://localhost/blog/new-post" method="POST">
    <input type="text" name="title" id="title" /><br />
    <textarea name="content" id="content" cols="30" rows="10"></textarea><br />
    <input type="submit" id="save-post" value="Save Draft" />
    <input type="submit" id="publish" value="Publish" />
</form>

为了在提交时能区分是保存还是发布,需要通过 JavaScript 来为不同的按钮绑定不同的操作:

JavaScript
1
2
3
4
5
6
7
8
//using jQuery
$('#save-post').click(function() {
    //按保存草稿方式提交
});
 
$('#publish').click(function() {
    //按发布方式提交
});

那么提交的数据中如何来区分是保存草稿还是发布?通常我们会在 <form> 中添加一个隐藏的控件来保存这个状态,像这样:

HTML
<!-- value 可以是 publish 或 draft,默认为 publish -->
<input type="hidden" name="post-status" id="post-status" value="publish" />

这样在 JS 中就只需要为按保存方式提交作相应处理:

JavaScript
1
2
3
4
//using jQuery
$('#save-post').click(function() {
    $('#post-status').val('draft');
});

这样如果按 Save Draft,那么 POST 出去的数据就应该是:

title=blah&content=blahblah&post-status=draft

OK,这样的确已经可以正常工作了,但是总觉得让人有些不爽:这么简单的工作为什么还要通过脚本来实现?有没有想过为什么要这样实现呢?事实上,因为在文章开始的地方提到的 HTML 规范中定义了一个表单中有多个提交按钮的情况下,只有一个可以是成功控件从而提交自己的数据值,也就是说,我们给提交按钮加上相同的 name 属性,只有一个按钮会提交相应的数据。那何必还需要隐藏控件?应该只需要这样:

HTML
1
2
3
4
5
6
<form action="http://localhost/blog/post" method="POST">
    <input type="text" name="title" id="title" /><br />
    <textarea name="content" id="content" cols="30" rows="10"></textarea><br />
    <input type="submit" name="post-status" id="save-post" value="Save Draft" />
    <input type="submit" name="post-status" id="publish" value="Publish" />
</form>

像这样把两个提交按钮的 name 属性都设为 post-status,就可以像服务器发送唯一的 post-status 值了,但有一个问题:post-status 的值只能和按钮上的文字一样了,给 Web 应用的 i18n 带来了很大的不便。其实 HTML 规范也考虑到了这个问题,这就是为什么我们会有 <button> 元素。HTML 中的按钮共有三种类型:

  • submit buttons
  • reset buttons
  • push buttons

前两个不用说,第三种按钮没有默认的数据交互行为,需要依赖脚本才能起到作用。一般情况下我们使用的都是 type 属性分别为 submit / reset / button 的 <input> 元素,而 <button> 元素就是用来为这三类 <input> 提供更多渲染可能性的,<button> 中可以插入其他的 HTML 元素,比如可以加入 <img> 来给按钮增加一个图标,所以显然也可以使用任何你想使用的文本作为按钮上显示的文字。这个文字和按钮的取值 value 应当是分离的:

HTML
<button type="submit" name="post-type" id="save" value="draft">Save Draft</button>
<button type="submit" name="post-type" id="publish" value="publish">Publish</button>

看上去很不错,不是么?可是很不幸,我们又遇到麻烦了:在 IE6/7 下,这样的方法完全不能工作。在 IE6 下,用这样的方式按 Save Draft 按钮,POST 出的参数值为:

title=blah&content=blahblah&post-status=Save+Draft&post-status=Publish

在 IE7 下,则是:

title=blah&content=blahblah&post-status=Save+Draft

可以看到,IE6/7 错误地把 <button> 的 innerHTML 当作了 value 发送出去了,而 IE6 甚至把没有点击的按钮也看作成功。WTF!本来很优雅的代码在现实中却是无法完美工作的。有人写了个针对 IE6/7 的 hack 来解决这个问题,即在 <button> 的点击事件中,disable 同一表单内的其他 <button> 并且用其 value 替换 innerHTML,但这样在网速比较慢的情况下(就是大多数情况下)会出现下面这样的画面:
Awkward hack
这显然也是不能让人接受的。就是没有一个完美的方案,就是这样,所以又回到我们开头的地方了。用隐藏控件来 hold 住提交方式参数,用脚本来给它赋值,又变成了看起来最通用最简单的方案了。

另外有一种观点认为,一个表单就不该有多个提交按钮,提交按钮不该携带任何参数值,完全可以换成单选框、下拉菜单等等等等方式来实现。但实际上多个提交按钮在很多时候可以减少用户的交互操作,并且更为直观,绝对是有其存在价值的。拿 WordPress 的文章发布方式来说,现在就是多提交按钮的:
WP Submit
如果改成下面这样,就感觉十分别扭了:
WP Submit Mod

总结一下:如果你可以抛弃 IE6/7,那么恭喜你,用最简单优雅的方式去实现吧!如果不能,那么,还是老老实实地用隐藏控件吧,慢慢等着 IE6/7 入土为安吧。

很久没写东西了,有点虎头蛇尾,其实没多少内容,发发牢骚而已。

Update: 欲了解更多关于按钮数据交互行为的浏览器差异可以阅读

Lync.in 是一个多人协作博客,欢迎您 查看原文 以获得更好的阅读体验。

相关 [闲话 按钮 html] 推荐:

闲话多提交按钮的HTML表单

- 逸川 - Lync.in
在 Web 应用中,最常用的服务器端与客户端的数据交互是通过提交 HTML 表单实现的. 以 HTML 4.01 为例,规定当表单提交时,会将
元素中的 Successful controls 的当前取值提交到服务器. 所谓成功控件需要有以下几个条件(但不仅限于此):. 必须有控件名字,即必须包含 name 属性.

HTML 安全列表

- 火锅土豆 - 酷壳 - CoolShell.cn
下面这个网站罗列了,几乎所有的关于HTML 5 在各种主流浏览器上的安全问题,这些安全问题很有可能将会是黑客攻击你的网上的敲门砖,他们几乎都和Javascript都有关系,你就要好好注意了. IE6,7,8,9,和Opera 8.x, 9.x, 10.x 都支持这样的语法. 这个问题会存在于所有的Firefox版本中,可以让用户进行XSS(跨站脚本)攻击.

HTML学习笔记

- - CSDN博客推荐文章
超文本标记语言( 英文:HyperText Markup Language,HTML)是为“ 网页创建和其它可在 网页浏览器中看到的信息”设计的一种 标记语言. HTML被用来结构化信息——例如标题、段落和列表等等  点击打开链接. w3schools  点击打开链接 {语法大全,超赞.

html嵌套规则

- - Web前端 - ITeye博客
转载: http://www.studyofnet.com/news/412.html. 一、HTML 标签包括 块级元素(block)、内嵌元素(inline). 一般用来搭建网站架构、布局、承载内容……它包括以下这些标签:. 一般用在网站内容之中的某些细节或部位,用以“强调、区分样式、上标、下标、锚点”等等,下面这些标签都属于内嵌元素:.

Html 转换成PDF

- - 编程语言 - ITeye博客
最近在搞一个关于html转换为pdf的需求,网上找了很多,但是如果批量处理就会出现问题,最后找到了PD4ML,解决了我的问题. String urlstring = "file:///D:/债权转让及受让协议--魏然2014-08-16.html";. 需要在src目录下创建fonts文件夹,并且在文件夹中建立pd4fonts.properties ,配置文件中的内容如下.

HTML+CSS小结 - jessies

- - 博客园_首页
   结构   HTML        .    样式   CSS      .    行为   JavaScript(交互行为).    .    网页标题.    标题.

HTML head 头标签

- - IT技术博客大学习
HTML head 头部分的标签、元素有很多,涉及到浏览器对网页的渲染,SEO 等等,而各个浏览器内核以及各个国内浏览器厂商都有些自己的标签元素,这就造成了很多差异性. 移动互联网时代,head 头部结构,移动端的 meta 元素,显得更为重要. 了解每个标签的意义,写出满足自己需求的 head 头标签,是本文的目的.

动态绑定HTML

- - 破狼 Blog
在Web前端开发中,我们经常会遇见需要动态的将一些来自后端或者是动态拼接的HTML字符串绑定到页面DOM显示,特别是在内容管理系统(CMS:是Content Management System的缩写),这样的需求,更是遍地皆是. 对于对angular的读者肯定首先会想到ngBindHtml,对,angular为我们提供了这个指令来动态绑定HTML,它会将计算出来的表达式结果用innerHTML绑定到DOM.

HTML编码规范

- - SegmentFault 最新的文章
这段时间在整理前端部分代码规范,初步想法是从HTML、CSS、Javascipt、项目文件目录四部分是整理. 之前已经整理完了 CSS编码规范,有兴趣可以了解下. [强制] 使用 4 个空格做为一个缩进层级,不允许使用 2 个空格 或 tab 字符. 对于非 HTML 标签之间的缩进,比如 script 或 style 标签内容缩进,与 script 或 style 标签的缩进同级.

这样去写你的 HTML

- Allen - 幸福收藏夹
昨天在 twitter 上说,怎么忍心把页面写得这么难用. 是的,这个世界还有一群人等着我们创建出来的东西,可以让他们的生活能过得更容易呢. 作为一个前端,我们又怎么会忍心呢. 之前就一直想写这样的一篇文章,分享一下如何去创造一个可访问性更好的页面. 今天的计划里有一条把 2HTML T2ag 和 WCAG标准结合起来.