prototype学习笔记(Element篇一)

转自: http://tianmoboping.blog.163.com/blog/

Element,哈哈哈。遇到正主了,到现在为止才遇到让我高兴的玩意。当初Ext.Element可是花三千余行代码专门来封装啊。我倒要看一看它的代码了。事实上prototype中我最想研究的只有两个内容:Element、Selector。这两个东西是精华。

先说一下Element对DOM扩展的技术思路,我也是看了一天的代码,这才有了点心得。

使用prototype,我们最常用的莫过于$('div1')之类的代码。从而获得扩展后的element对象,然后,我们就可以用它的各种扩展出来的方法了,如:

$('div1').addClassName('loading').show();

所以,我们研究Element的扩展正应当以此为入口。

  1. function $(element) {
  2.     if (arguments.length > 1) {
  3.     for (var i = 0, elements = [], length = arguments.length; i < length; i++)
  4.         elements.push($(arguments[i]));
  5.         return elements;
  6.     }
  7.     if (Object.isString(element))
  8.         element = document.getElementById(element);
  9.     return Element.extend(element);
  10. }
这个函数一个巧妙的递归就可以处理多个参数的情况,实在令我赞叹啊。代码中的关键是:Element.extend(element),在extend之前,element还仅仅是一个普通的DOM对象,extend之后就被扩展了,可见,秘密就在extend之中。

既然是Element.extend(element),那么,我们当然不能单独去研究extend,还是得先了解一下Element是何物。

  1. (function() {
  2.    var element = this.Element;
  3.    this.Element = function(tagName, attributes) { 
  4.      attributes = attributes || { }; 
  5.      tagName = tagName.toLowerCase(); 
  6.      var cache = Element.cache; 
  7.      if (Prototype.Browser.IE && attributes.name) {
  8.        tagName = ' <' + tagName + ' name="' + attributes.name + '">';
  9.        delete attributes.name; 
  10.        return Element.writeAttribute(document.createElement(tagName), attributes); 
  11.      } 
  12.      if (!cache[tagName]) cache[tagName] = Element.extend(document.createElement(tagName)); 
  13.      return Element.writeAttribute(cache[tagName].cloneNode(false), attributes); 
  14.    }; 
  15.    Object.extend(this.Element, element || { }); 
  16. }).call(window);
这种代码比较有个性,基本结构是:(function(){……}).call(window);所以,看到这个结构,就要晓得,省略号部分出现的this都是指向window的。

var element=this.Element;这行不难理解,但是,关键是this.Element这时还没有被定义。后面则是定义一个类:window.Element类,它有两个参数:tagName、attributes。它的作用就是创建一个元素,并把一个纯洁的指定标签对应的DOM对象放入缓存。创建元素后,并且写入指定的属性值。这儿要提醒一下:

writeAttribute、readAttribute这两个函数功能显然,读、写属性,但是,它的代码并不简单啊,它的复杂性主要源于不同的浏览器中,读、写属性的方法的不同。

这是Element类的构造函数的定义,它之后的Element.cache = { };缓存,什么的缓存,不大好描述,各种标签的纯洁版DOM元素对象的缓存?这话说得太恶心了。后面紧跟着就是一个:Element.Methods={……},在这里,几乎定义了所有的扩展方法。这里的扩展方法都有一个特征,代码中没有一个用this的,都是老老实实传进去一个element引用。这是一个伏笔,为什么要定义成这样,是有原因的。且容后交待。

现在Element大概说了一下,就得讲一讲Element.extend了。

  1. Element.extend = (function() {
  2.    if (Prototype.BrowserFeatures.SpecificElementExtensions)
  3.      return Prototype.K; 
  4.   var Methods = { }, ByTag = Element.Methods.ByTag;
  5.   var extend = Object.extend(function(element) {
  6.      if (!element || element._extendedByPrototype ||
  7.      element.nodeType != 1 || element == window) return element; 
  8.     var methods = Object.clone(Methods),
  9.      tagName = element.tagName, property, value;
  10.     // extend methods for specific tags
  11.      if (ByTag[tagName]) Object.extend(methods, ByTag[tagName]);
  12.     for (property in methods) {
  13.        value = methods[property];
  14.        if (Object.isFunction(value) && !(property in element))
  15.          element[property] = value.methodize(); 
  16.      } 
  17.     element._extendedByPrototype = Prototype.emptyFunction;
  18.      return element;
  19.   }, {
  20.       refresh: function() {
  21.        // extend methods for all tags (Safari doesn't need this) 
  22.        if (!Prototype.BrowserFeatures.ElementExtensions) { 
  23.          Object.extend(Methods, Element.Methods); 
  24.          Object.extend(Methods, Element.Methods.Simulated); 
  25.        } 
  26.      } 
  27.    }); 
  28.   extend.refresh();
  29.    return extend;
  30. })();
第一行的原理我不大肯定,不说,下面的代码看似复杂,待我抽出它的大概结构来:

var extend=Object.extend(function(element){……},{refresh:function(){……}});

extend内,第一个函数作用是从XXXX.Methods中获取方法,并复制到本element中。这儿主要基于这样的考虑:

一、元素如果是一个Form,就得从Form.Methods取方法

二、元素如果是表单内的可输入元素,就得从Form.Element中取方法

三、所有元素都应当从Element.Methods中取得通用方法(后面的refresh所考虑的)。

也就是说,这儿要考虑多种情况,本来应当是个if语句的事,但是,这儿巧妙地设计了一个Element.Methods.ByTag。从而解决了这个问题。

if (Object.isFunction(value) && !(property in element))
element[property] = value.methodize();

如果Methods中的成员不是函数或者函数在element中已存在,则不会覆盖。这儿到了关键了,那个value.methodize(),这时,前面的伏笔生效了,methodize的作用就是把当前调用者传递进方法。且作为第一个参数传入。它的使用方法一般是:

obj.methodname=functionname.methodize();

这样,调用时,obj对象就会作为第一个参数传入functionsname这个函数。

到此为止,这个extend函数中的大概思路应当清晰了,现在还有一个问题没有清楚:根据元素的tagName来获得应当从哪个Methods获得扩展,那么,我们有必要了解一下ByTag的详情,查找一下,找到了:

Object.extend(Element.Methods.ByTag, {
"FORM": Object.clone(Form.Methods),
"INPUT": Object.clone(Form.Element.Methods),
"SELECT": Object.clone(Form.Element.Methods),
"TEXTAREA": Object.clone(Form.Element.Methods)
});

ok,差不多就这样了。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值