لماذا تفشل خاصية onclick المعينة باستخدام setAttribute في العمل في IE؟

StackOverflow https://stackoverflow.com/questions/95731

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

ولكنه سينقطع في IE في الوضع غير القياسي وفقًا لـscunliffe.

لا يمكنك فعل هذا على الإطلاق

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!تعمل هذه الطريقة إذا كنت بحاجة إلى أخذ سمة onclick الأصلية من HTML وإضافتها إلى حدث 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 الحالي على نظام التشغيل Windows؛Firefox و Epiphany على Ubuntu ؛لم يتم اختباره على أنظمة 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 لا يزال يعمل داخل المتصفحات الأخرى أيضًا، لذا إذا كنت تتذكر ممارسة البرمجة البسيطة هذه، فسيكون من الجيد اتباعها في معظم الحالات.

ومع ذلك، لن يعمل هذا الحل إذا كان عليك تغيير أي سمات بسرعة، حيث لا يمكن تغييرها في IE بمجرد إلحاق عنصر HTML الخاص بها بـ DOM؛في هذه الحالة، أتخيل أنه سيتعين على المرء حذف العنصر من 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، ولكنها ذات صلة أيضًا بما يلي:

بالنسبة لسمات html التي يتعارض اسمها مع كلمات جافا سكريبت المحجوزة، يتم اختيار اسم بديل، على سبيل المثال. <div class=''>, ، لكن div.className, ، أو <label for='...'>, ، لكن label.htmlFor.

في المتصفحات المعقولة، هذا لا يؤثر setAttribute.لذلك في أبو بريص وwebkit يمكنك الاتصال به div.setAttribute('class', 'foo'), ، ولكن في IE يجب عليك استخدام اسم خاصية جافا سكريبت بدلاً من ذلك 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 ()')} ؛

بالنسبة لي يعمل.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top