Browser Feature Detection (2)-General event detection

Source: Internet
Author: User
Document directory
  • Basic Solution
  • Some tag-specific events
  • DOM pollution
  • Firefox BUG
  • Firefox BUG persists
  • Add Cache
  • Mutation Event
  • DOMContentLoaded
  • Related Resources

Event detection is used to detect whether an event exists (available) in different browsers. This is also very important during Javascript writing. For example, the mouseenter/mouseleave event is practical, but not all browsers provide standard support, so you need to manually simulate it yourself, that is:

Function addEvent (element, name, handler) {if (name = 'mouseenter '&&! HasEvent (name, element) {// simulate a mouseenter event by other means} // normal event registration };

This article focuses on the specific implementation of hasEvent in the above Code.

Basic Solution

The most basic event detection method must begin with the event registration method.

There are usually three registration methods for events, one of which is inline, that is, declaring events in HTML through attributes, such:

<button onclick="alert('CLICKED!');">CLICK ME</button>

The code above creates a button tag and registers a click event.

Another solution is to register an event by directly assigning values to onclick:

document.getElementById('myButton').onclick = function() { alert('CLICKED!'); };

From the above two event registration methods, we can find that onclick is an attribute of the button tag, and event registration can be completed by assigning values to it.

Therefore, the most basic event detection solution is to check whether the on [event name] attribute exists in the DOM element. Therefore, there is the simplest version:

function hasEvent(name, element) { name = name.indexOf('on') ? 'on' + name : name; element = element || document.createElement('div'); var supported = name in element; };

It should be noted that an event exists in the form of on [event name] as an element attribute. Therefore, in terms of universality, add 'on' to the event name when necessary. In addition, it is a common function to determine whether an event is available. When no specific element is specified, the most widely used div element can be used as an alternative.

Some tag-specific events

Some events are unique to some elements and generally include the following:

  • Unique form events: submit, reset
  • Unique input events: change, select
  • Unique img events: load, error, abort

Considering the existence of these events, using div elements may sometimes produce incorrect results. Therefore, when creating a common replacement element, you can use a dictionary to maintain the element tag name to be created:

var hasEvent = (function() { var tags = { onsubmit: 'form', onreset: 'form', onselect: 'input', onchange: 'input', onerror: 'img', onload: 'img', onabort: 'img' }; return function(name, element) { name = name.indexOf('on') ? 'on' + name : name; element = element || document.createElement(tags[name] || 'div'); supported = name in element; } })();

Using the closure to use tags as a static dictionary can reduce the overhead of object generation to a certain extent.

DOM pollution

The reason why DOM elements have an attribute similar to onclick is that this attribute exists in the _ proto _ of DOM element objects. Due to the weak type mechanism of Javascript, external code can affect the result of the hasEvent function by adding properties to _ proto _. For example, the following code produces incorrect results in Firefox and Chrome:

document.createElement('div').__proto__.ontest = function() {}; var supported = hasEvent('test', document.createElement('div')); //true

In the above example, although the _ proto _ attribute is modified and hasEvent is called, different div objects are used, however, because _ proto _ is essentially an object in the prototype chain, it affects all div objects.

In order to deal with this situation, you need to try to delete the corresponding attribute in the _ proto _ attribute. Because the native type attribute has the DontDelete tag, you cannot use the delete keyword to delete it, therefore, the following logic can be appended to the hasEvent function for more secure judgment:

var temp; if (supported && (temp = proto[name]) && delete proto[name]) { supported = name in element; proto[name] = temp; }

The logic is very simple. Try to append _ proto _ and try again. Of course, don't forget to change the original value back.

Firefox BUG

Unfortunately, the hasEvent function provided previously does not work perfectly in Firefox. Running the following code in Firefox will result in false:

Alert ('onclick' in document.doc umentElement); // Firefox pops up with false

Therefore, you need to rebuild the hasEvent function to support Firefox. In most browsers, after an element registers an event in inline mode, you can use element. on [event name] to obtain the registered function object. For example:

<Button id = "test" onclick = "alert ('clicked! '); "Ontest =" alert ('test! '); "> Click me </button> <script type =" text/javascript "> var button = document. getElementById ('test'); alert (typeof button. onclick); // The function alert (typoef button. ontest); // pop-up string </script>

Therefore, you only need to mount a string representing the function to the on [event name] attribute through Javascript, and then obtain and determine whether a function object is obtained.

Therefore, when the hasEvent function returns false, you can add the following code to determine whether the event exists:

if (!supported) { element.setAttribute(name, 'return;'); supported = typeof element[name] == 'function'; }
Firefox BUG persists

So far, we have been able to detect events of various DOM elements with compatibility with most browsers, but there is no complete solution for event detection of window objects.

For IE series, Chrome, and Safari, you can use a simple on [event name] in window to check whether an event exists, therefore, the original hasEvent function provided to prevent DOM contamination can well complete the task.

Only on Firefox, the following code will give incorrect results:

Alert ('onload' in window); // false alert ('onload' in window) is displayed in Firefox; // false alert ('onerror' in window) is displayed in Firefox ); // Firefox Pop-up false

Fortunately, Firefox can detect the above three events on elements such as div, which directly leads to errors in common DOM element detection events, this also allows us to detect events on the window. Fortunately, developers generally do not check for unload events on elements such as a div. Therefore, the hasEvent function is added to direct the event on the window to a div object to detect some events:

if (!supported) { if (!element.setAttribute || !element.removeAttribute) { element = document.createElement('div'); } element.setAttribute(name, 'return;'); supported = typeof element[name] == 'function'; element.removeAttribute(name); }

So far, a complete hasEvent function has been completed, although there are still some problems in Firefox, such as the following code:

Alert (hasEvent ('unload', document. createElement ('div '); // Firefox pops up true

However, in 99% of applications, this function can work correctly.

Add Cache

To further improve hasEvent efficiency, considering that the DOM specification specifies a small number of events, you can add a cache mechanism for detecting common events (that is, elements that do not specify detection objects.

After the cache is added, the complete hasEvent function is as follows:

Var hasEvent = (function () {var tags = {onsubmit: 'form', onreset: 'form', onselect: 'input', onchange: 'input', onerror: 'img ', onload: 'img', onabort: 'img '}, cache = {}; return function (name, element) {name = name. indexOf ('on ')? 'On' + name: name; // hit cache if (! Element & name in cache) {return cache [name];} element = element | document. createElement (tags [name] | 'div '); var proto = element. _ proto _ | {}, supported = name in element, temp; // process if (supported & (temp = proto [name]) where an attribute is added to _ proto _ of the element. & delete proto [name]) {supported = name in element; proto [name] = temp;} // handle cases where Firefox is not powerful. // 'onunload' in window in Firefox is false, however, div has an unload event (OT L) if (! Supported) {if (! Element. setAttribute |! Element. removeAttribute) {element = document. createElement ('div ');} element. setAttribute (name, 'Return; '); supported = typeof element [name] = 'function'; element. removeAttribute (name) ;}// add to cache [name] = supported; return supported ;};})();
Mutation Event

Mutation events are a special type of events formulated by DOM Level 2. These events are triggered when the DOM tree structure with the root element changes. The specific Event list is displayed here.

Unfortunately, the hasEvent function cannot detect Mutation events. Therefore, another complicated Event detection solution is required for such events.

From the Mutation Event list, we can find that this type of Event is characterized by the DOM tree structure.ChangedSo you can use the following logic to detect:

  1. Prepare a flag. The default value is false.
  2. Creates a DOM tree structure.
  3. Register a Mutation Event.
  4. This DOM tree is changed by some means to trigger registration events.
  5. In the event processing function, set the flag bit to true.
  6. The flag bit is returned.

The specific implementation code can be as follows:

Function hasMutationEvent (name, tag, change) {var element = document. createElement (tag), supported = false; function handler () {supported = true ;}; // IE9 starts to support addEventListener, so only the IE6-8 does not have this function // but the IE6-8 has been determined that Mutation Event is not supported, so there is this judgment if (! Element. addEventListener) {return false;} element. addEventListener (name, handler, false); change (element); element. removeEventListener (name, handler, false); return supported ;};

For example, to check whether the DOMAttrModified event exists, you only need to use the following code:

var isDOMAttrModifiedSupported = hasMutationEvent('DOMAttrModified', 'div', function (div) { div.id = 'new'; });

To detect other events, you only need to create a specific change function.

DOMContentLoaded

This event is triggered when the file is loaded, but does not need to wait for resources such as images to be downloaded. Most document. ready Javascript frameworks attempt to use this event.

Either the hasEvent function or the hasMutationEvent function cannot detect this event, but it is not a problem because:

  1. Like onload, this event is only triggered once in the lifecycle of a page and is not frequently used.
  2. All browsers that support addEventListener support this event (including IE9), so it is easy to judge.

Therefore, this event is excluded from the scope discussed in this article. For details, you can view the implementation methods of the document. ready function of each framework.

Related Resources
  • Detecting event support without browser sniffing provides a lot of ideas for this article.
  • Diego Perini's NWMatcher provides the idea of Mutation Event detection.
  • Click here to view the source code of hasEvent and hasMutationEvent.

If anyone is bored, write out all the Mutation Event detection functions ......

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.