不要把你的input元素设置为“action”或“submit”

410 查看

大多数的浏览器都有一个严格意义上来说不能算作bug的bug。实际上,浏览器的本意是让你的工作变得更简单,但是如果你(或者其他人)恰好以某种方式(其实是错误的方式)来写HTML代码的话,就会完全触发该问题。特别的,如果你指定input标签的id或者name属性值为“action”或“submit”,你可能就会触发非常隐藏的bug。

关于该“Bug”的介绍

去年我通读了John Resig 和Bear Bibeault著作的《Secrets of the JavaScript Ninja》一书。顺便说一下,如果你想写高效、优雅的javascript代码,这绝对是一本非常棒的书。不管怎么样,在第11章,某些内容吸引了我的注意力。如果你在form表单里有一个拥有id和/或name属性的input元素,那么你可以直接通过form元素的某些属性获取到该input元素,该特性被作者称为是“贪婪的ID”(greedy IDs)。

这真是一个相当酷的想法,但是这并不是很有必要,因为通过元素的id或者name属性来获取元素也是很容易的。而且,要注意一个非常重要的事实:如果form元素的某个属性名和input元素的id/name值一样,那么该form的属性就会被input元素的属性值所覆盖。

如果你的input元素的id/name属性值被设置为了“action”或“submit”,然后你尝试使用javascript控制提交,那么此时就会变得极其悲剧。现在,如果你想知道form表单数据提交 (通过 form.action提交)的URL,或者你只是想通过写js代码的方式来提交(通过form.submit提交),那么你将会分别得到一个错误的值和直接报错。

解决方案

我从来没想过我会遇到这个问题,但是我还是碰到了。也许解决该问题的最简单的方法是改写你的input,但是不幸的是有时你可能拿不到HTML代码,而有时你根本不会去拿。而且其他的代码也可能依赖于id/name来做一些事情。因此,如果你没法去直接修改HTML代码,这里还有其他的解决方案。

这种解决方案只能解决form表单元素的属性值是函数的情形。任意值不是函数的属性都将不起作用,即使你尝试用javascript代码去动态修改input元素的id/name属性也毫无用处。不管怎么样,重写值是函数的属性(比如submit),从元素对象的原型获取函数,并将该函数以你想执行的form表单元素为运行环境来执行就能解决问题。

我并没有在老版本的浏览器做测试,但是它应该在对较老HTML4支持较好的浏览器上都能正常运行,因为HTMLFormElement最初是在DOM Level 1规范中被指定的。

结论

在书中没有给出解决方案我感到有些惊讶。他们只是多少提到了说我们要避免使用这些ids/names(指action、submit等):

“幸运的是,通过避免使用和标准的属性名冲突的较简单的id值,我们在自己的标记中可以避免这个问题,同时我们鼓励其他人也这么做。特别是id和name的值要避免用submit,这是一个导致让人费解的bug并令人沮丧的问题的常见来源。”

虽然这的确是一个合理的建议,正因如此我把它作为了文章的标题,但这种情况并不总是可以避免的,因此有一种简单的能解决一部分问题的方案总是好的。但无论如何,我希望你永远用不到这种解决方案。愿上帝保佑,祝你编程快乐!