为什么使用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在动态生成的元素上运行onclick,我们不能使用setAttribute。相反,我们需要使用包装要运行的代码的匿名函数在对象上设置onclick属性。
execBtn.onclick = function() { runCommand() };
错误提示:
你可以做
execBtn.setAttribute("onclick", function() { runCommand() });
但根据@scunliffe,它将以非标准模式在IE中中断。
你根本做不到
execBtn.setAttribute("onclick", runCommand() );
因为它会立即执行,并将runCommand()的结果设置为onClick属性值,所以我们也无法执行
execBtn.setAttribute("onclick", runCommand);
解决方案
你试过了吗:
execBtn.setAttribute("onclick", function() { runCommand() });
内联编写函数,解释器足够聪明,可以知道我们正在编写函数。这样做,并假设它只是一个字符串(从技术上讲是这样)。
与onclick问题无关,但也与以下内容有关:
对于其名称与javascript保留字冲突的html属性,请选择一个备用名称,例如。 <div class =''>>,但
div.className,或者
<label for ='...'>,但
label.htmlFor`。
在合理的浏览器中,这不会影响" setAttribute"。因此,在壁虎和Webkit中,我们将调用div.setAttribute('class','foo')
,但在IE中,我们必须改用javascript属性名称,因此,div.setAttribute('className','foo' )
。
我们无法使用.setAttribute()在IE中设置大量的属性,其中包括每个内联事件处理程序。
详细信息请参见此处:
http://webbugtrack.blogspot.com/2007/08/bug-242-setattribute-doesnt-always-work.html
要使此功能在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和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");
只需让event为" click"或者" mouseover"之类的名称即可。
我这样做是为了解决它并继续前进,在我的情况下,我不使用'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);
或者我们可以使用jQuery并避免所有这些问题:
var execBtn = $("<input>", { type: "button", id: "execBtn", value: "Execute" }) .click(runCommand);
jQuery还将解决所有跨浏览器的问题。
在某些情况下,这里列出的示例在Internet Explorer中对我而言不可行。
由于我们必须使用这样的方法设置属性(不带方括号)
HtmlElement.onclick = myMethod;
如果我们必须传递对象名称或者什至参数,它将无法正常工作。对于Internet Explorer,我们应该在运行时中创建一个新对象:
HtmlElement.onclick = new Function('myMethod(' + someParameter + ')');
在其他浏览器上也可以使用。
对于跨浏览器兼容的事件绑定,这是一个了不起的功能。
从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; }