重命名我的函数后,代码停止工作。这个新名称似乎scrollIntoView
与element.scrollIntoView()
方法相冲突。
<div onmousedown="scrollIntoView('id001')"/>
function scrollIntoView(id) {
alert(id);
}
我创建了一个简单的测试用例 https://jsfiddle.net/mgtn215y/它表明我的函数被简单地忽略
了,甚至element.scrollIntoView()
- 它不是在元素上调用的
- 属性不匹配
解决方案很明显 - 使用不同的函数名称。由于此行为在主要浏览器中是一致的,因此我希望在某处指定此行为。但是,我找不到任何相关的内容,例如JavaScript词汇语法。这种行为有什么背景吗?
问题是从 HTML 源代码中声明的 HTML 元素属性值编译的函数的作用域链。窗体的属性on_eventName=functionBodyCode
表现出此行为。
由于历史原因(DOM 没有以当前的形式存在,document.getElementByID
尚未被发明......(,这些函数是使用一个作用域链编译的,该范围链包括提供事件处理程序属性的对象、元素所在的任何form
元素和document
对象。然而,不同的浏览器在模拟Netscape行为时采用了不同的方法。 一些浏览器包含提供事件处理程序属性的元素的任何和每个父对象,而其他浏览器则省略了一些相关对象,例如document
。
技术细节可以在"Javascript the definitive guide"O'Reilly,"19.1.6"一节中找到。事件处理程序的范围"。
主要建议是避免在 HTML 中提供事件处理程序 - 而是使用addEventListener
在 JavaScript 中添加它们。如果由于某种原因,函数调用必须在 HTML 属性值中编码,请避免使用作为 DOM 对象方法的函数名称。
请注意,事件处理程序的自定义作用域链仅适用于从 HTML 属性生成的函数。它不适用于在 JavaScript 中创建并使用addEventListener
或element.onEventName=aFunctionObject
添加到元素中的函数。
以下代码片段演示了在 HTML 中定义的事件处理程序的作用域链中查找外部元素的属性名称:
<form name="formName1" action="">
<p> Try to access the elements collection of the form:
<button type="button"
onclick="console.log( elements);">elements
</button>
</p>
</form>
<form name="formName2" action="" onsubmit="return false">
<p> Try to access form name as form.name:
<button type="button"
onclick="console.log( 'form.name: %s', form.name);">form.name
</button>
</p>
</form>
<form name="formName3" action="" onsubmit="return false">
<p>Access document.write as "write"
<button type="button"
onclick="console.log( 'write: %s', write);">write
</button>
</p>
</form>
-
在第一种形式中,
elements
是周围表单元素的属性。 -
在第二种形式中,
form
是 HTMLButtonElement 的属性。 -
在第三种形式中,
write
是一种document
的方法。 -
引用 2020 年,HTML5 将 HTML 属性处理程序的作用域链指定为内部原始未编译处理程序的编号列表项 3.9 中的">范围"下的"外部表单元素>文档"下的">元素"。
出于某种奇怪的原因,看起来内联处理程序在运行时隐式使用with(this)
,其中this
引用触发事件的元素。每当你尝试引用某物时,如果该某物作为this
的属性存在,那么该属性最终将被引用,而不是具有相同名称的外部变量:
console.log(typeof className); // Undefined in standard global scope
console.log(typeof scrollIntoView); // Undefined in standard global scope
.mydiv {
width: 100px;
height: 100px;
background-color: red;
cursor: pointer;
}
<div class="mydiv" onclick="
console.log(typeof className); // Defined inside inline handler
console.log(typeof scrollIntoView); // Defined inside inline handler
">
对于口译员来说,onclick
实际上看起来更像:
onclick="with(this) {
console.log(typeof className);
console.log(typeof scrollIntoView);
}"
这很奇怪。但无论如何,内联事件处理程序都是糟糕的做法,可能不应该使用;改为使用addEventListener
或onkeydown
正确分配处理程序:
document.querySelector('.mydiv').onmousedown = () => scrollIntoView("id001");
function scrollIntoView(id) {
console.log(id);
}
.mydiv {
width: 100px;
height: 100px;
background-color: red;
cursor: pointer;
}
<div class="mydiv"></div>
要覆盖,只需尝试:
Element.prototype.scrollIntoView = function(id) {
alert(id);
}
但请注意,它适用于addEventListener
:
var element = document.getElementById("element");
function scrollIntoView(id) {
alert(id);
}
element.addEventListener("mousedown", function() {
scrollIntoView("id001");
});
div {
width: 100px;
height: 100px;
background-color: red;
cursor: pointer;
}
<div id="element"></div>