【问题标题】:Element.animate() in HTML4HTML4 中的 Element.animate()
【发布时间】:2014-09-12 07:27:30
【问题描述】:

Chrome 的人似乎有自己的 appropriated Element.animate(),使用类似于 onclick="animate();" 的东西有效地破坏了所有现有的 HTML 页面。

这对于 HTML 4/Transitional 规范下的浏览器是否合法?这是 W3C 正式授权的事情吗?

小型网站所有者可以采取什么措施来防止进一步的此类违规行为?

编辑: 测试用例:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" 
    "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
    <title>test</title>
    <script type="text/javascript">
        function animate() {
            alert('this should work');
        }
    </script>
</head>
<body>
    <input type="button" onclick="animate();" value="push me!">
</body>
</html>

在 Chrome 上的结果为 Uncaught TypeError: Failed to execute 'animate' on 'Element': 1 argument required, but only 0 present.,但在 FireFox 中有效。

【问题讨论】:

  • 我敢肯定,没有人能阻止 Google 做任何事情。
  • .animate() 方法由 W3C 托管的 currently-in-draft specification 定义(链接在文章的第 3 段)。它不仅适用于 Chrome,而且很有可能被其他浏览器采用。避免冲突的一种选择是 avoid depending on obtrusive/embedded JavaScriptonevent 属性使用的隐含 with (this) {} 块。
  • 我不确定他们是否“挪用”了任何东西。他们为 DOM 中的元素原型添加了一种方法,可能是根据与其他浏览器供应商合作的一些标准草案。我什至不确定您的示例是否受到影响,因为animate() 肯定会寻找window.animate() 而新方法将是this.animate()
  • 正确附加事件监听器,你会没事的。
  • 看来我错了,如果设置了this.animate。但是,您始终可以明确限定函数名称以运行全局函数。请参阅此示例:jsfiddle.net/bKB8E/4

标签: javascript html google-chrome dom chromium


【解决方案1】:

您所指的更改不是 Google 的单方面举措,而是 draft W3C standard called Web Animations 1.0 的一部分。您遇到问题的具体修改是the extension to the DOM Element interface,它添加了三个新方法,包括animate()

由于 DOM Elements 可能是动画的目标,因此 Element 接口 [DOM4] 扩展如下:Element implements Animatable;

这允许以下类型的使用。 elem.animate({ color: 'red' }, 2000);

这里的 DOM 代表“文档对象模型”,即another standard, separate from HTML,它定义了 JavaScript 和其他语言应如何公开 HTML、XML 或类似文档并与之交互。该标准多年来进行了多次扩展,因此将这种新方法添加到Element 对象中绝不是前所未有的,也不会引起争议。


您的具体问题是命名空间冲突之一。 JavaScript 的作用域规则在任何情况下都比较复杂,当您在 HTML 属性中嵌入事件处理程序时,会有一些特殊的逻辑,如 this MDN article about "event attributes" 中所述。

结果是,当您编写 onclick="animate();" 时,animate 会被查找为多个范围或命名空间中的属性,包括:

  • 作为被点击元素的属性,已经绑定到this;如果找到,animate() 的行为将与 this.animate() 相同
  • 作为全局window 对象的属性,在任何情况下它始终是最后检查的范围;因此,如果没有找到其他内容,animate() 将等同于 window.animate()

你的问题是你依赖于从全局命名空间调用的东西,但是对 DOM 的更改意味着它现在也在 this 上定义(具体来说,它在 @ 的所有后代的原型中987654344@)。由于新功能优先于您现有的功能,因此会发生意外的行为变化。

因此,最简单的代码修复方法是更具体地限定您的事件,例如 onclick="window.animate();"。您不仅应该对您知道现在有冲突的方法和变量执行此操作,还应该对所有这些方法和变量执行此操作,这样它们将来就不会受到 DOM 的其他更改的影响。 (Here is a demo of that approach.)


但是,如果您想让您的代码更健壮,您应该进行更广泛的更改以使其符合最新的编码实践:

  • 不要使用诸如onclick 之类的“事件属性”,而是以编程方式添加事件侦听器。用于此的现代 API 是 addEventListener,尽管许多人更喜欢像 jQuery 这样的库,它可以更轻松地使用不同的浏览器,并简化常见任务(在这种情况下,您将使用 the .on() method)。李>
  • 与其将函数置于全局范围内,不如让它们成为某个对象的属性,这样您就可以跟踪自己的命名空间。更好的是,如果您将它们与 HTML 分开(使用类似 addEventListener 或 jQuery 的 .on),您可以通过使用 @ 使它们成为 private 变量,甚至无法从全局范围访问987654329@(仅用于创建新变量范围的封闭函数)。

【讨论】:

  • 很棒的答案,值得一提的是 IIFE 方法应该与 .addEventListener() 或 jQuery 的 .on() 一起使用,以免让任何人想知道如何从孤立的范围内附加 DOM 侦听器。
  • @FabrícioMatté 是的,我试图暗示第二个最佳实践建议依赖于第一个,但为了避免任何混淆,我已经更明确了。
  • 哦,太好了。 =] 这对我来说已经足够清楚了,但是假设未来可能的读者只使用过内联事件属性,那么孤立地阅读这一点似乎还不清楚。感谢您的编辑。 =]
猜你喜欢
  • 2012-06-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-17
相关资源
最近更新 更多