为什么使用 setAttribute 设置的 onclick 属性在 IE 中不起作用?
-
01-07-2019 - |
题
今天遇到这个问题,发帖以防其他人也有同样的问题。
var execBtn = document.createElement('input');
execBtn.setAttribute("type", "button");
execBtn.setAttribute("id", "execBtn");
execBtn.setAttribute("value", "Execute");
execBtn.setAttribute("onclick", "runCommand();");
结果是让 IE 在动态生成的元素上运行 onclick,我们不能使用 setAttribute。相反,我们需要使用包装我们要运行的代码的匿名函数来设置对象的 onclick 属性。
execBtn.onclick = function() { runCommand() };
坏主意:
你可以做
execBtn.setAttribute("onclick", function() { runCommand() });
但根据 @sunliffe 的说法,它会在非标准模式下的 IE 中崩溃。
你根本不能这样做
execBtn.setAttribute("onclick", runCommand() );
因为它会立即执行,并将runCommand()的结果设置为onClick属性值,你也不能这样做
execBtn.setAttribute("onclick", runCommand);
解决方案
要使此功能在 FF 和 IE 中都有效,您必须以两种方式编写:
button_element.setAttribute('onclick','doSomething();'); // for FF
button_element.onclick = function() {doSomething();}; // for IE
谢谢 这个帖子.
更新: :这是为了证明有时 是 必须使用setAttribute!如果您需要从 HTML 中获取原始 onclick 属性并将其添加到 onclick 事件中,这样它就不会被覆盖,则此方法有效:
// get old onclick attribute
var onclick = button_element.getAttribute("onclick");
// if onclick is not a function, it's not IE7, so use setAttribute
if(typeof(onclick) != "function") {
button_element.setAttribute('onclick','doSomething();' + onclick); // for FF,IE8,Chrome
// if onclick is a function, use the IE7 method and call onclick() in the anonymous function
} else {
button_element.onclick = function() {
doSomething();
onclick();
}; // for IE7
}
其他提示
有一个 大的 你的属性集合 IE中无法设置 使用 .setAttribute() 其中包括每个内联事件处理程序。
详细信息请参见此处:
http://webbugtrack.blogspot.com/2007/08/bug-242-setattribute-doesnt-always-work.html
效果很好!
现在似乎没有必要使用这两种方式:
execBtn.onclick = function() { runCommand() };
显然适用于当前的每个浏览器。
在 Windows 上当前的 Firefox、IE、Safari、Opera、Chrome 中进行了测试;Ubuntu上的Firefox和Epiphany;未在 Mac 或移动系统上进行测试。
- 克雷格:我会尝试“document.getElementById(ID).type='password';
- 有没有人检查过不同引擎的“AddEventListener”方法?
对于跨浏览器兼容的事件绑定来说,这是一个令人惊奇的功能。
从那里得到的 http://js.isite.net.au/snippets/addevent
有了它你就可以做 Events.addEvent(element, event, function);
无忧无虑!
例如:(http://jsfiddle.net/Zxeka/)
function hello() {
alert('Hello');
}
var button = document.createElement('input');
button.value = "Hello";
button.type = "button";
Events.addEvent(input_0, "click", hello);
document.body.appendChild(button);
这是函数:
// We create a function which is called immediately,
// returning the actual function object. This allows us to
// work in a separate scope and only return the functions
// we require.
var Events = (function() {
// For DOM2-compliant browsers.
function addEventW3C(el, ev, f) {
// Since IE only supports bubbling, for
// compatibility we can't use capturing here.
return el.addEventListener(ev, f, false);
}
function removeEventW3C(el, ev, f) {
el.removeEventListener(ev, f, false);
}
// The function as required by IE.
function addEventIE(el, ev, f) {
// This is to work around a bug in IE whereby the
// current element doesn't get passed as context.
// We pass it via closure instead and set it as the
// context using call().
// This needs to be stored for removeEvent().
// We also store the original wrapped function as a
// property, _w.
((el._evts = el._evts || [])[el._evts.length]
= function(e) { return f.call(el, e); })._w = f;
// We prepend "on" to the event name.
return el.attachEvent("on" + ev,
el._evts[el._evts.length - 1]);
}
function removeEventIE(el, ev, f) {
for (var evts = el._evts || [], i = evts.length; i--; )
if (evts[i]._w === f)
el.detachEvent("on" + ev, evts.splice(i, 1)[0]);
}
// A handler to call all events we've registered
// on an element for legacy browsers.
function addEventLegacyHandler(e) {
var evts = this._evts[e.type];
for (var i = 0; i < evts.length; ++i)
if (!evts[i].call(this, e || event))
return false;
}
// For older browsers. We basically reimplement
// attachEvent().
function addEventLegacy(el, ev, f) {
if (!el._evts)
el._evts = {};
if (!el._evts[ev])
el._evts[ev] = [];
el._evts[ev].push(f);
return true;
}
function removeEventLegacy(el, ev, f) {
// Loop through the handlers for this event type
// and remove them if they match f.
for (var evts = el._evts[ev] || [], i = evts.length; i--; )
if (evts[i] === f)
evts.splice(i, 1);
}
// Select the appropriate functions based on what's
// available on the window object and return them.
return window.addEventListener
? {addEvent: addEventW3C, removeEvent: removeEventW3C}
: window.attachEvent
? {addEvent: addEventIE, removeEvent: removeEventIE}
: {addEvent: addEventLegacy, removeEvent: removeEventLegacy};
})();
如果你不想使用这么大的功能,这应该适用于几乎所有浏览器,包括 IE:
if (el.addEventListener) {
el.addEventListener('click', function, false);
} else if (el.attachEvent) {
el.attachEvent('onclick', function);
}
回答克雷格的问题。您将必须创建一个新元素并复制旧元素的属性。这个函数应该完成以下工作:(来源)
function changeInputType(oldObject, oType) {
var newObject = document.createElement('input');
newObject.type = oType;
if(oldObject.size) newObject.size = oldObject.size;
if(oldObject.value) newObject.value = oldObject.value;
if(oldObject.name) newObject.name = oldObject.name;
if(oldObject.id) newObject.id = oldObject.id;
if(oldObject.className) newObject.className = oldObject.className;
oldObject.parentNode.replaceChild(newObject,oldObject);
return newObject;
}
或者你可以使用 jQuery 并避免所有这些问题:
var execBtn = $("<input>", {
type: "button",
id: "execBtn",
value: "Execute"
})
.click(runCommand);
jQuery 还将解决所有跨浏览器问题。
实际上,据我所知,动态创建的内联事件处理程序在使用 Internet Explorer 8 创建时可以完美地工作 x.setAttribute()
命令;你只需要将它们正确地放置在 JavaScript 代码中即可。我偶然发现了你的问题(和我的)的解决方案 这里.
当我移动所有包含以下内容的语句时 x.appendChild()
到它们的正确位置(即,紧随其组中的最后一个 setAttribute 命令之后),我发现每个 setAttribute 在 IE8 中都按预期工作,包括所有表单输入属性(包括“名称”和“类型”属性,如以及我的“onclick”事件处理程序)。
我发现这非常了不起,因为在我这样做之前,我在 IE 中遇到的只是屏幕上呈现的垃圾,以及一个又一个错误。此外,我发现每个 setAttribute 仍然可以在其他浏览器中工作,因此,如果您只记住这个简单的编码实践,那么在大多数情况下您就可以很好地进行操作。
但是,如果您必须即时更改任何属性,则此解决方案将不起作用,因为一旦将 HTML 元素附加到 DOM,就无法在 IE 中更改它们;在这种情况下,我想象必须从 DOM 中删除该元素,然后重新创建它及其属性(当然,以正确的顺序!),以便它们正常工作,并且不会抛出任何错误。
内联编写函数,解释器足够聪明,知道您正在编写函数。这样做,它假设它只是一个字符串(技术上是这样)。
function CheckBrowser(){
if(navigator.userAgent.match(/Android/i)!=null||
navigator.userAgent.match(/BlackBerry/i)!=null||
navigator.userAgent.match(/iPhone|iPad|iPod/i)!=null||
navigator.userAgent.match(/Nokia/i)!=null||
navigator.userAgent.match(/Opera M/i)!=null||
navigator.userAgent.match(/Chrome/i)!=null)
{
return 'OTHER';
}else{
return 'IE';
}
}
function AddButt(i){
var new_butt = document.createElement('input');
new_butt.setAttribute('type','button');
new_butt.setAttribute('value','Delete Item');
new_butt.setAttribute('id', 'answer_del_'+i);
if(CheckBrowser()=='IE'){
new_butt.setAttribute("onclick", function() { DelElemAnswer(i) });
}else{
new_butt.setAttribute('onclick','javascript:DelElemAnswer('+i+');');
}
}
你试过了吗:
execBtn.setAttribute("onclick", function() { runCommand() });
在某些情况下,此处列出的示例在 Internet Explorer 中不适合我。
因为您必须使用这样的方法设置属性(不带括号)
HtmlElement.onclick = myMethod;
如果您必须传递对象名称甚至参数,它将不起作用。对于 Internet Explorer,您应该在运行时创建一个新对象:
HtmlElement.onclick = new Function('myMethod(' + someParameter + ')');
也适用于其他浏览器。
与 onclick 问题无关,但也相关:
对于名称与 javascript 保留字冲突的 html 属性,会选择一个备用名称,例如。 <div class=''>
, , 但 div.className
, , 或者 <label for='...'>
, , 但 label.htmlFor
.
在合理的浏览器中,这不会影响 setAttribute
. 。所以在 gecko 和 webkit 中你会调用 div.setAttribute('class', 'foo')
, ,但在 IE 中你必须使用 javascript 属性名称,所以 div.setAttribute('className', 'foo')
.
您是否考虑过使用事件侦听器而不是设置属性?除此之外,它还允许您传递参数,这是我在尝试执行此操作时遇到的一个问题。对于 IE 和 Mozilla,您仍然需要执行两次:
function makeEvent(element, callback, param, event) {
function local() {
return callback(param);
}
if (element.addEventListener) {
//Mozilla
element.addEventListener(event,local,false);
} else if (element.attachEvent) {
//IE
element.attachEvent("on"+event,local);
}
}
makeEvent(execBtn, alert, "hey buddy, what's up?", "click");
只需将事件命名为“单击”或“鼠标悬停”即可。
我这样做是为了绕过它并继续前进,在我的例子中,我没有使用“输入”元素,而是使用图像,当我尝试为此图像设置“onclick”属性时,我遇到了同样的问题,所以我尝试用“a”元素包装图像,并将引用指向像这样的函数。
var rowIndex = 1;
var linkDeleter = document.createElement('a');
linkDeleter.setAttribute('href', "javascript:function(" + rowIndex + ");");
var imgDeleter = document.createElement('img');
imgDeleter.setAttribute('alt', "Delete");
imgDeleter.setAttribute('src', "Imagenes/DeleteHS.png");
imgDeleter.setAttribute('border', "0");
linkDeleter.appendChild(imgDeleter);
尝试使用此ExecBtn.OnClick = function(){eval('runCommand()')};
对我来说它有效。