How Prototype extends the DOM

來源:互聯網
上載者:User
原文出自:http://prototypejs.org/learn/extensions

The biggest part of the Prototype framework are its DOM extensions. Prototype adds many convenience methods to elements returned by the $() function: for instance, you can write $('comments').addClassName('active').show() to get the element with the ID 'comments', add a class name to it and show it (if it was previously hidden). The 'comments' element didn't have those methods in native JavaScript; how is this possible? This document reveals some clever hacks found in Prototype.

The Element.extend() method

Most of the DOM methods are encapsulated by the Element.Methods object and then copied over to the Element object (for convenience). As referring to  source code (ProtoType 1.5),  you can see that:

1 Object.extend(Element, Element.Methods);

They all receive the element to operate with as the first parameter:

1 Element.hide('comments');
2 var div_height = Element.getHeight(my_div);
3 Element.addClassName('contactform', 'pending');

These examples are concise and readable, but we can do better. If you have an element to work with, you can pass it through Element.extend() and it will copy all those methods directly to the element. Example, to create an element and manipulate it:

1 var my_div = document.createElement('div');

3 Element.extend(my_div);
4 my_div.addClassName('pending').hide();

6 // insert it in the document
7 document.body.appendChild(my_div);

Our method calls just got shorter and more intuitive! As mentioned before, Element.extend() copies all the methods from Element.Methods to our element which automatically becomes the first argument for all those functions. The extend() method is smart enough not to try to operate twice on the same element. What's even better, **the dollar function $() extends every element passed through it** with this mechanism.

In addition, Element.extend() also applies Form.Methods to FORM elements and Form.Element.Methods to INPUT, TEXTAREA and SELECT elements:

1 var contact_data = $('contactform').serialize();
2 var search_terms = $('search_input').getValue();

 

Note that not only the dollar function automatically extends elements! Element.extend() is also called in document.getElementsByClassName, Form.getElements, on elements returned from the $$() function (elements matching a CSS selector) and other places - in the end, chances are you will rarely need to explicitly call Element.extend() at all.

Adding your own methods with Element.addMethods()

If you have some DOM methods of your own that you'd like to add to those of Prototype, no problem! Prototype provides a mechanism for this, too. Suppose you have a bunch of functions encapsulated in an object, just pass the object over to Element.addMethods():

 1 var MyUtils = {
 2     truncate: function(element, length){
 3         element = $(element);
 4         return element.update(element.innerHTML.truncate(length));
 5     },
 6     updateAndMark: function(element, html){
 7         return $(element).update(html).addClassName('updated');
 8     }
 9 }
10 
11 Element.addMethods(MyUtils);
12 
13 // now you can:
14 $('explanation').truncate(100);

 

The only thing to watch out here is to make sure the first argument of these methods is the element itself. In your methods, you can also return the element in the end to allow for chainability (or, as practiced in the example, any method which itself returns the element).

Native extensions

There is a secret behind all this.

In browsers that support adding methods to prototype of native objects such as HTMLElement all DOM extensions on the element are available by default without ever having to call Element.extend(), dollar function or anything! As referring to  source code (ProtoType 1.5),  you can see that:

 1 Element.addMethods = function(methods) {
 2   
 3 
 4   if (typeof HTMLElement != 'undefined') {
 5     copy(Element.Methods, HTMLElement.prototype);
 6     copy(Element.Methods.Simulated, HTMLElement.prototype, true);
 7     copy(Form.Methods, HTMLFormElement.prototype);
 8     [HTMLInputElement, HTMLTextAreaElement, HTMLSelectElement].each(function(klass) {
 9       copy(Form.Element.Methods, klass.prototype);
10     });
11     _nativeExtensions = true;
12   }
13 }

This will then work in those browsers:

1 var my_div = document.createElement('div');
2 my_div.addClassName('pending').hide();
3 document.body.appendChild(my_div);

Because the prototype of the native browser object is extended, all DOM elements have Prototype extension methods built-in. This, however, isn't true for IE which doesn't let anyone touch HTMLElement.prototype. To make the previous example work in IE you would have to extend the element with Element.extend(). Don't worry, the method is smart enough not to extend an element more than once.

Because of browsers that don't support this you must take care to use DOM extensions only on elements that have been extended. For instance, the example above works in Firefox and Opera, but add Element.extend(my_div) after creating the element to make the script really solid. You can use the dollar function as a shortcut like in the following example:

1 // this will error out in IE: 
2 $('someElement').parentNode.hide()
3 // to make it cross-browser:
4 $($('someElement').parentNode).hide()

 

Don't forget about this! Always test in all the browsers you plan to support.

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

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.