HTML4中的Element.animate()

Dex*_*ter 2 html javascript dom google-chrome chromium

似乎Chrome上的人们已经为自己挪用了Element.animate(),有效地打破了所有现有的HTML页面onclick="animate();".

这对于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>
Run Code Online (Sandbox Code Playgroud)

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

IMS*_*SoP 9

您所指的更改不是Google的单方面行动,而是W3C标准草案的一部分,称为Web Animations 1.0.您遇到麻烦的具体修改是DOM Element接口的扩展,它增加了三种新方法,包括animate():

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

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

这里的DOM代表"文档对象模型",它是另一个标准,与HTML分开,它定义了JavaScript和其他语言应该如何公开HTML,XML或类似文档并与之交互.这个标准多年来已经进行了很多扩展,因此将这种新方法添加到Element对象中绝不是前所未有的或可能引起争议的.


您的具体问题是名称空间冲突.JavaScript的作用域规则在任何情况下都相对复杂,当您在HTML属性中嵌入事件处理程序时,会有一些特殊的逻辑,如本MDN文章中关于"事件属性"所述.

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

  • 作为已被绑定的被点击元素的属性this; 如果找到,animate()将表现得一样this.animate()
  • 作为全局window对象的属性,它始终是在任何情况下检查的最后一个范围; 因此,如果没有找到其他任何东西,animate()将相当于window.animate()

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

因此,对代码的最简单修复就是更具体地限定您的事件onclick="window.animate();".你应该这样做不只是你知道现在有冲突的方法和变量,而是所有这些方法和变量,这样它们将来不会受到对DOM的其他更改的影响.(这是该方法的演示.)


但是,如果您希望使代码更加健壮,那么您应该进行更广泛的更改,以使其与更新的编码实践保持一致:

  • 而不是使用"事件属性",例如,以onclick编程方式添加事件侦听器.现代API就是这样addEventListener,虽然很多人更喜欢像jQuery这样的库,它可以更容易地使用不同的浏览器,并简化了常见的任务(在这种情况下,你可以使用这个.on()方法).
  • 而不是将函数放入全局范围,使它们成为某个对象的属性,以便您可以跟踪自己的命名空间.更妙的是,如果你让他们从HTML代码中分离(使用类似addEventListener或jQuery的.on),你可以让他们私有变量,甚至没有从全球范围访问,通过使用IIFE(只存在一个封闭的函数来创建一个新的变量范围).