您的位置:首页 > Web前端 > HTML

闲话多提交按钮HTML表单

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

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

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



对应的 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
67
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,但这样在网速比较慢的情况下(就是大多数情况下)会出现下面这样的画面:



这显然也是不能让人接受的。就是没有一个完美的方案,就是这样,所以又回到我们开头的地方了。用隐藏控件来 hold 住提交方式参数,用脚本来给它赋值,又变成了看起来最通用最简单的方案了。

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



如果改成下面这样,就感觉十分别扭了:



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

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

Update: 欲了解更多关于按钮数据交互行为的浏览器差异可以阅读这篇文章
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: