Обработка событий в IE - PullRequest
2 голосов
/ 06 июля 2010

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

Игра хорошо работает в браузерах модели событий W3C, но продолжает вызывать ошибку в IE6-8.Я получил код из другого вопроса и полагал, что он будет обрабатывать IE.Кто-нибудь видит, что я делаю не так?

    <script type="text/javascript">
    function setMouseEvent() {
        //Tel: 01 8279 400
        event = addEvent(document.getElementById('contactButton'), 'mouseover', changeText);
    }

    function changeText() {
        alert("worked!");
        removeEvent(document.getElementById('contactButton'), 'mouseover', changeText);
    }

    function addEvent(obj, type, fn) {
        if (typeof obj.addEventListener != undefined) {
            obj.addEventListener(type, fn, false);
        }
        else if (typeof obj.attachEvent != undefined) {
            obj.attachEvent("on" + type, fn);
        }
    }

    function removeEvent(obj, type, fn) {
        if (typeof obj.addEventListener != undefined) {
            obj.removeEventListener(type, fn, false);
        }
        else if (typeof obj.attachEvent != undefined) {
            obj.detachEvent("on" + type, obj[type + fn]);
            obj[type + fn] = null;
            obj["e" + type + fn] = null;
        }
    }

    window.onload = setMouseEvent;
</script>

Обновление: Я только что протестировал в последних версиях Chrome, Opera и FF без проблем, но Safari ничего не делает, когда я нахожу курсор мыши и IEвыдает ошибки как указано.

Ответы [ 2 ]

6 голосов
/ 06 июля 2010
event = addEvent(

addEvent ничего не возвращает; вы присваиваете undefined значение отсутствия возврата глобальной переменной event (так как вы не сказали var event в функции). Это вызовет исключение в IE, который использует глобальный event в качестве специального объекта для передачи деталей события обработчикам, и, следовательно, не позволяет вам назначить что-то еще для него.

if (typeof obj.addEventListener != undefined)

typeof всегда возвращает строку, которая никогда не будет проверяться равной undefined unvalue, поэтому IE всегда будет принимать ветвь не-IE и завершится ошибкой. Вы имели в виду if (typeof obj.addEventListener !== 'undefined') со строкой.

obj.detachEvent("on" + type, obj[type + fn]);

Поскольку вы не написали свойство с именами type и fn, слипшимися в функции addEvent, получить что-либо не удастся.

Как говорит Кресент, похоже, что вы используете функцию Resig removeEvent в сочетании с другой addEvent, которая не соответствует. Если вы используете его removeEvent, вам нужно будет использовать его addEvent, чтобы пойти с ним.

Однако я бы не стал использовать эти функции в любом случае: они довольно хитры. Я знаю, что это был 2005 год, когда этот непродуманный код выиграл конкурс addEvent в quirksmode, но даже тогда мы должны были знать намного лучше. Проблема в том, что он создает строку из имени события и текстовой сериализации кода функции (type+fn) и использует ее в качестве ключа для хранения обратного вызова. Этот ключ будет выглядеть примерно так: 'mouseoverfunction changeText() {...code...}'.

Но полагаться на сериализацию функций - ужасная идея. Формат не стандартизирован ECMAScript («Возвращается зависящее от реализации представление функции.»); Есть много браузерных причуд ; и что не менее важно, две разные функции могут легко возвращать одну и ту же строку для текущих методов сериализации браузеров:

var f1= function() {};
var f2= function() {};

f1 и f2 будут иметь одинаковую сериализацию строк, но это не один и тот же объект. Если вы сделали addEvent для f1 в IE, а затем еще одно для f2, второе свойство будет использовать ту же сериализованную строку и перезапишет первое свойство. Затем вызов removeEvent для f1 извлечет функцию для f2, попытается detachEvent и произойдет сбой, потому что это не та же функция. Этот пример может выглядеть надуманным, но на самом деле это очень легко сделать случайно, когда вы используете универсальные замыкания, поскольку современный JavaScript делает все больше и больше в наши дни. По этой причине я бы рекомендовал избегать Resig's addEvent при любых обстоятельствах .

(пользователи jQuery: не волнуйтесь, при всех своих проблемах jQuery не попадает в ловушку использования этого кода.)

Этот хак предназначен для сохранения значения this, когда IE вызывает функцию changeText, для которой attachEvent не устанавливает this. Но вы даже не используете значение this, так что вы могли бы обойтись гораздо более простой версией, такой как original addEvent , которая была создана для замены.

По крайней мере, недостатки в том, что addEvent хорошо известны и обнаруживаются сразу же, когда вы тестируете IE, используя this, вместо того, чтобы ошибаться только в конкретном случае, когда это влияет на вас, может быть очень запутанным и трудным для отладки.

Опять же, в настоящее время вы не используете даже несколько слушателей для одного и того же события, поэтому вы можете легко уйти со старомодным обработчиком событий DOM Level 0, что-то вроде:

window.onload= function() {
    var changed= false;
    document.getElementById('contactButton').onmouseover= function() {
        if (!changed) {
            alert('changing text');
        }
        changed= true;
    };
};
1 голос
/ 06 июля 2010

Перейти на Дин добавить событие , если вы хотите гибкое решение:

// written by Dean Edwards, 2005
// with input from Tino Zijdel, Matthias Miller, Diego Perini
// http://dean.edwards.name/weblog/2005/10/add-event/

function addEvent(element, type, handler) {
    if (element.addEventListener) {
        element.addEventListener(type, handler, false);
    } else {
        // assign each event handler a unique ID
        if (!handler.$$guid) handler.$$guid = addEvent.guid++;
        // create a hash table of event types for the element
        if (!element.events) element.events = {};
        // create a hash table of event handlers for each element/event pair
        var handlers = element.events[type];
        if (!handlers) {
            handlers = element.events[type] = {};
            // store the existing event handler (if there is one)
            if (element["on" + type]) {
                handlers[0] = element["on" + type];
            }
        }
        // store the event handler in the hash table
        handlers[handler.$$guid] = handler;
        // assign a global event handler to do all the work
        element["on" + type] = handleEvent;
    }
};
// a counter used to create unique IDs
addEvent.guid = 1;

function removeEvent(element, type, handler) {
    if (element.removeEventListener) {
        element.removeEventListener(type, handler, false);
    } else {
        // delete the event handler from the hash table
        if (element.events && element.events[type]) {
            delete element.events[type][handler.$$guid];
        }
    }
};

function handleEvent(event) {
    var returnValue = true;
    // grab the event object (IE uses a global event object)
    event = event || fixEvent(((this.ownerDocument || this.document || this).parentWindow || window).event);
    // get a reference to the hash table of event handlers
    var handlers = this.events[event.type];
    // execute each event handler
    for (var i in handlers) {
        this.$$handleEvent = handlers[i];
        if (this.$$handleEvent(event) === false) {
            returnValue = false;
        }
    }
    return returnValue;
};

function fixEvent(event) {
    // add W3C standard event methods
    event.preventDefault = fixEvent.preventDefault;
    event.stopPropagation = fixEvent.stopPropagation;
    return event;
};
fixEvent.preventDefault = function() {
    this.returnValue = false;
};
fixEvent.stopPropagation = function() {
    this.cancelBubble = true;
};
...