setAttribute, onClick и кросс-браузерная совместимость - PullRequest
5 голосов
/ 14 апреля 2009

Я прочитал несколько постов по этому поводу, но ни один из них не дал однозначного ответа. Вот мой код:

// button creation
onew = document.createElement('input');
onew.setAttribute("type", "button");
onew.setAttribute("value", "hosts");
onew.onclick = function(){fnDisplay_Computers("'" + alines[i] + "'"); }; // ie
onew.setAttribute("onclick", "fnDisplay_Computers('" + alines[i] + "')"); // mozilla
odiv.appendChild(onew);

Теперь метод setAttribute () (с комментарием mozilla) прекрасно работает в mozilla, но только если он появляется ПОСЛЕ строки над ним. Другими словами, кажется, что по умолчанию используется только то, что установлено в последнюю очередь. Метод .onclick (с комментарием ie) не работает ни в одном случае, я использую его неправильно?

В любом случае я не могу найти способ заставить эту работу вообще работать в IE, не говоря уже об обоих. Я изменил вызов функции при использовании метода .onclick, и он работал нормально, используя простой вызов функции оповещения, поэтому я считаю, что мой синтаксис неверен.

Короче говоря, я не могу заставить параметр onclick работать последовательно между IE / Mozilla.

- Николай

Ответы [ 4 ]

15 голосов
/ 15 апреля 2009

onew.setAttribute («тип», «кнопка»);

Никогда не используйте setAttribute в документах HTML. Во многих случаях IE ошибается, а свойства DOM-HTML короче, быстрее и проще для чтения:

onew.type= 'button';

onew.onclick = function () {fnDisplay_Computers ("'" + alines [i] + "'"); }; // т.е.

Что такое "алины"? Почему вы конвертируете его в строку и заключаете в одинарные кавычки? Похоже, вы пытаетесь сделать что-то отвратительное, включая оценку кода в строке (это то, что вы делаете ниже в версии «onew.setAttribute»). Оценка кода JavaScript в строках почти всегда является неправильной вещью; избегайте этого, как чумы. В приведенном выше случае IE должен делать то же самое, что и Firefox: он не должен работать.

Если «alines [i]» является строкой, я думаю, что вы пытаетесь сделать так, чтобы она запомнила эту строку, создав строку кода, которая в JavaScript будет преобразована в исходную строку. Но:

"'" + alines[i] + "'"

недостаточно. Что произойдет, если у «alines [i]» есть апостроф или обратный слеш?

'O'Reilly'

у вас есть синтаксическая ошибка и возможная дыра в безопасности. Теперь вы можете сделать что-то кропотливое и раздражающее, например:

"'" + alines[i].split('\\').join('\\\\').split("'").join("\\'") + "'"

, чтобы попытаться избежать строки, но это уродливо и не будет работать для других типов данных. Вы даже можете попросить JavaScript сделать это для вас:

uneval(alines[i])

Но не все объекты можно даже преобразовать в оцениваемые исходные строки JavaScript; в основном весь подход обречен на провал.

Обычная вещь, которую нужно сделать, если вы просто хотите, чтобы функция обратного вызова onclick вызывала функцию с параметром, - это написать код простым способом:

onew.onclick= function() {
    fnDisplay_Computers(alines[i]);
};

Как правило, это будет работать, и это то, что вы хотите. Однако есть небольшая складка, которую вы, возможно, наткнулись здесь, что может сбить вас с толку при рассмотрении дурацкого подхода со строками.

А именно, если в этом случае «i» является переменной окружающего цикла «for», ссылка на «alines [i]» не будет делать то, что вы думаете, что она делает. Когда произойдет щелчок, к функции «i» будет обращаться функция обратного вызова, которая равна после , когда цикл завершен. На этом этапе переменная 'i' останется с любым значением, которое у нее было в конце цикла, поэтому 'alines [i]' всегда будет последним элементом 'alines', независимо от того, на каком элементе нажата кнопка 'onew'.

(См., Например, Как исправить проблему с замыканием в ActionScript 3 (AS3) для некоторого обсуждения этого. Это одна из главных причин путаницы с замыканиями в JavaScript и Python, и она действительно должна быть исправлено на уровне языка когда-нибудь.)

Вы можете обойти проблему с циклом, заключив замыкание в его собственную функцию, например:

function callbackWithArgs(f, args) {
    return function() { f.apply(window, args); }
}

// ...

onew.onclick= callbackWithArgs(fnDisplay_Computers, [alines[i]]);

А в более поздней версии JavaScript вы сможете просто сказать:

onew.onclick= fnDisplay_Computers.bind(window, alines[i]);

Если вы хотите использовать функцию Function.bind () в современных браузерах, вы можете получить реализацию из Prototype framework или просто использовать:

if (!('bind' in Function.prototype)) {
    Function.prototype.bind= function(owner) {
        var that= this;
        var args= Array.prototype.slice.call(arguments, 1);
        return function() {
            return that.apply(owner,
                args.length===0? arguments : arguments.length===0? args :
                args.concat(Array.prototype.slice.call(arguments, 0))
            );
        };
    };
}
6 голосов
/ 14 апреля 2009

Я обычно использую что-то вроде:

onew.onclick = new Function("fnDisplay_Computers('" + alines[i] + "')");

это должно работать как в IE, так и в Firefox.

1 голос
/ 14 апреля 2009

Используйте функцию addEventListener() с "click" для аргумента type для браузеров на базе Mozilla и функцию attachEvent() с "onclick" в качестве аргумента sEvent для IE; Я считаю, что лучше всего использовать оператор try / catch, например:

try {
  onew.attachEvent("onclick", //For IE
                   function(){fnDisplay_Computers("'" + alines[i] + "'"); });
}
catch(e) {
  onew.addEventListener("click", //For Mozilla-based browsers
                   function(){fnDisplay_Computers("'" + alines[i] + "'"); },
                   false);
}
0 голосов
/ 24 апреля 2010

Я думаю, что # 3 слишком много протестует. Во многих ситуациях я строю таблицу динамически и мне нужно передать параметры в функцию обратного вызова. Это не типобезопасная проблема, так как моя переменная parm является целочисленным индексом для рассматриваемой строки таблицы. Вот код с переменным и фиксированным параметром, который кажется совместимым с браузером:

for (i = 0; i < arrTableData.length; i++) {
    eleTR = objTable.insertRow(i + 1);
    cell = eleTR.insertCell(0);
    cell.width = "21";
    var myElement = document.createElement('img');
    myElement.setAttribute('src', 'images/button_down.gif');
    myElement.setAttribute('alt', 'Move item down');
    myElement.onclick = new Function('moveItem(' + i + ',0)');
    cell.appendChild(myElement);
}
...