为什么用setAttribute设置的onclick属性在IE中失败?

今天就遇到这个问题,张贴以防别人有同样的问题。

var execBtn = document.createElement('input'); execBtn.setAttribute("type", "button"); execBtn.setAttribute("id", "execBtn"); execBtn.setAttribute("value", "Execute"); execBtn.setAttribute("onclick", "runCommand();"); 

原来让IE在dynamic生成的元素上运行onclick,我们不能使用setAttribute。 相反,我们需要用包装我们想要运行的代码的匿名函数来设置对象上的onclick属性。

 execBtn.onclick = function() { runCommand() }; 

不好的想法:

你可以做

 execBtn.setAttribute("onclick", function() { runCommand() }); 

但根据@scunliffe,它将在非标准模式下在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() }; 

显然在每个当前的浏览器中都有效。

在当前的Firefox,IE,Safari,Opera,Chrome上进行testing; Ubuntu上的Firefox和Epiphany; 未在Mac或移动系统上testing。

  • 克雷格:我会尝试“document.getElementById(ID).type ='密码';
  • 有没有人用不同的引擎检查“AddEventListener”方法?

这对跨浏览器兼容的事件绑定来说是一个了不起的function。

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); 

这个function:

 // 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}; })(); 

如果你不想使用这样一个大function,这应该适用于几乎所有的浏览器,包括IE浏览器:

 if (el.addEventListener) { el.addEventListener('click', function, false); } else if (el.attachEvent) { el.attachEvent('onclick', function); } 

回答克雷格的问题。 你将不得不做一个新的元素,并复制旧的元素的属性。 这个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也会照顾所有的跨浏览器问题。

实际上,就我所知,当使用x.setAttribute()命令创build时,dynamic创build的内联事件处理程序DO在Internet Explorer 8中完美工作; 你只需要把它们放在你的JavaScript代码中。 我在这里偶然发现了你的问题(和我的)的解决scheme。

当我将包含x.appendChild()所有语句移动到正确的位置(即紧跟其组中的最后一个setAttribute命令)后,我发现每个单独的setAttribute都在IE8中工作,包括所有的表单input属性(包括“name”和“type”属性,以及我的“onclick”事件处理程序)。

我发现这是非常了不起的,因为我之前在IE浏览器中的所有内容都是在屏幕上呈现垃圾,一个又一个错误。 另外,我发现每个setAttribute在其他浏览器中都还在工作,所以如果你只记得这个简单的编码实践,那么在大多数情况下你都会很好用。

但是,如果您必须即时更改任何属性,则此解决scheme将无法工作,因为一旦将其HTML元素添加到DOM后,便无法在IE中对其进行更改; 在这种情况下,我会想象,必须从DOM中删除该元素,然后重新创build它的属性(当然是正确的顺序),以使它们正常工作,而不是抛出任何错误。

写内联函数,解释器足够聪明,知道你正在写一个函数。 这样做,它假定它只是一个string(它在技术上)。

 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,您应该在运行时创build一个新的对象:

 HtmlElement.onclick = new Function('myMethod(' + someParameter + ')'); 

也适用于其他浏览器。

与onclick问题无关,还涉及到:

对于名称与javascript保留字相冲突的html属性,select一个替代名称,例如。 <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"); 

只要让事件成为“点击”或“鼠标hover”这样的名称即可。

我这样做是为了绕过它,继续前进,在我的情况下,我没有使用“input”元素,而是使用图像,当我试图设置这个图像的“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()')};

对我来说,它的作品。