About browser feature detection (2)-General event detection _jquery

Source: Internet
Author: User

Event detection, which detects whether an event exists (available) in a different browser, is also important in the process of writing JavaScript, such as the Mouseenter/mouseleave event is practical, but not all browsers provide standard support, So you need to simulate yourself manually, namely:

function addEvent(element, name, handler) { 
if (name == 'mouseenter' && !hasEvent(name, element)) { 
//通过其他手段模拟mouseenter事件 
} 
//正常的事件注册 
};

This article will focus on the above code in the specific implementation of hasevent.

Basic programme

The most basic way to detect an event requires starting with the registration method of the event.

Events usually have 3 ways of registering, one of which is inline, that is, declaring events in HTML in the form of attributes, such as:

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

The above code creates a button label and registers the Click event.

Another scenario is to register an event by assigning a value directly to the onclick:

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

From the above two types of registration events can be found, in fact, the onclick is a button tag of a property, by assigning value can complete the event registration.

Therefore, the most basic event detection scenario is to check whether the On[event name property exists in the DOM element, and therefore has 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 is important to note that the event is in the form of the on[event name as an attribute of the element, and therefore, in terms of generality, the event name is "on" when necessary. In addition, since it is a universal function to determine whether an event is available, the most widely used div element can be substituted when no specific element is given.

Partial label-specific events

Some events are specific to some elements, usually including the following:

    • Form Unique Event: Submit, reset
    • Input unique event: change, select
    • IMG Unique event: Load, error, abort

Given the existence of these events, the use of DIV elements sometimes results in errors, so when creating a generic alternative element, you can use a dictionary to maintain the element tag name you want to create:

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 closures to use tags as a static dictionary can reduce the overhead of object generation to some extent.

Dom pollution

Dom elements have properties that are similar to onclick because they have this attribute in the __proto__ of the DOM element object, and because of the JavaScript weak type mechanism, external code can affect the results of the Hasevent function by adding properties to the __proto__. The following code will produce the wrong result in Firefox and Chrome:

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

In the above example, while modifying the __proto__ property and calling Hasevent, a different div object is used, but because the essence of __proto__ is an object in the prototype chain, it affects all div objects.

In order to handle this situation, it is necessary to try to remove the corresponding property in the __proto__ property, because the native type's property with the dontdelete tag cannot be deleted with the DELETE keyword, so attaching the following logic to the Hasevent function can be more safely judged:

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

Logic is very simple, try to put the __proto__ may be attached to the deletion of a try again, of course, do not forget to change the original value back.

Firefox starts bugs

Unfortunately, the Hasevent function provided above does not work well in Firefox, and running the following code in Firefox will result in false results:

alert('onclick' in document.documentElement); //Firefox弹出false

Therefore, the Hasevent function needs to be rebuilt again to support Firefox. In most browsers, after an element has registered an event inline, you can get the function object registered on it by element.on[event name, 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); //弹出function 
alert(typoef button.ontest); //弹出string 
</script>

Therefore, you only need to mount a string representing the function through JavaScript to the on[event name attribute, and then get and determine whether you have a function object.

So the Hasevent function can add the following code to further determine whether an event exists when the method provided in the previous article returns false:

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

Firefox continue Bug

Up to now, events for individual DOM elements can be detected in a compatible majority of browsers, but there is no complete scenario for event detection for window objects.

For IE series, chrome, and Safari, you can use the simple on[event name in window to detect whether an event exists, so the original Hasevent function, which prevents DOM contamination, completes the task well.

Only Firefox, the following code will give the wrong result:

alert('onload' in window); //Firefox弹出false 
alert('onunload' in window); //Firefox弹出false 
alert('onerror' in window); //Firefox弹出false

Fortunately, it is also worth angry, Firefox is very strange to be in the div and other elements to detect the above 3 events, which directly results in the normal DOM elements to detect events errors, but also cause we can detect the events on the window. Fortunately, the general developer will not go to a div and other elements to detect whether there are unload events. So the Hasevent function is added, and the events on the window are directed to a Div object to detect some of the events:

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

At this point, a more complete hasevent function, although there are some problems in Firefox, such as the following code:

alert(hasEvent('unload', document.createElement('div')); //Firefox弹出true

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

Add cache

To further improve the efficiency of hasevent, you can detect the addition of caching mechanisms for common events (that is, element objects that do not specify instrumentation), given the limited number of events required by the DOM specification.

After the cache has been added, the final complete hasevent function is as follows:

var hasevent = (function () {var tags = {onsubmit: ' form ', onreset: ' Form ', onselect: ' Input ', onchange: ' Input ', on 

Error: ' 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; Handle the situation that is displayed on the __proto__ of the element if (supported && (temp = proto[name]) && Delete proto[name]) {supported = NA 
Me in element; 
Proto[name] = temp; }///processing Firefox//firefox the ' onunload ' in window is false, but the DIV has unload event (OTL) if (!supported) {if (!element.setattribu Te | | 
!element.removeattribute) {element = document.createelement (' div '); 
} element.setattribute (name, ' return; '); 
Supported = typeof Element[name] = = ' function '; 
Element.removeattribute (name); }//Add to cache cache[name] = SupporteD 
return supported; 
}; })();

Mutation Event

The Mutation event is a special kind of event created by DOM Level 2 that fires when a DOM tree structure with the root of an element changes, where you can see a specific list of events.

Unfortunately, the Hasevent function cannot detect the mutation event, so for this type of event, another more complex event detection scenario is needed.

As you can see from the list of mutation events, this type of event is only triggered when the DOM tree structure changes , so you can use the following set of logic to detect:

    1. Prepares a tag bit, which defaults to false.
    2. Creates a DOM tree structure.
    3. Register for a mutation Event.
    4. The DOM tree can be changed by some means to trigger the registered event.
    5. In the event handler function, set the tag bit to true.
    6. Returns the tag bit.

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开始支持addEventListener,因此只有IE6-8没有这个函数 
//但是IE6-8已经确定不支持Mutation Event,所以有这个判断 
if (!element.addEventListener) { 
return false; 
} 
element.addEventListener(name, handler, false); 
change(element); 
element.removeEventListener(name, handler, false); 
return supported; 
};

For example, to detect whether a domattrmodified event exists, you need to use the following code:

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

For other events, it is only necessary to create a specific change function.

domcontentloaded

This event fires when the document is loaded, but does not need to wait for resource downloads such as pictures, and most JavaScript framework Document.ready will attempt to use this event.

Neither the Hasevent function nor the Hasmutationevent function can detect this event, but the problem is not as follows:

    1. This event, like the onload, triggers only once in the page's lifecycle and is not used frequently.
    2. All browsers that support AddEventListener support this event (including IE9), so the judgment is simple.

So this event is excluded from the scope of this article to see how the Document.ready functions of each framework can be implemented.

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.

Who is bored to 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.