[转]prototype 源码解读 超强推荐第3/3页

 更新时间:2007年02月13日 00:00:00   作者:  

dom.js 代码:
复制代码 代码如下:

/**  
2  
3  * 根据 class attribute 的名字得到对象数组,支持 multiple class  
4  
5  *  
6  
7  */  
8   
9 document.getElementsByClassName = function(className) {   
10   
11   var children = document.getElementsByTagName('*') || document.all;   
12   
13   var elements = new Array();   
14   
15   
16   for (var i = 0; i < children.length; i++) {   
17   
18     var child = children[i];   
19   
20     var classNames = child.className.split(' ');   
21   
22     for (var j = 0; j < classNames.length; j++) {   
23   
24       if (classNames[j] == className) {   
25   
26         elements.push(child);   
27   
28         break;   
29   
30       }   
31   
32     }   
33   
34   }   
35   
36   
37   return elements;   
38   
39 }   
40   
41   
42 /*--------------------------------------------------------------------------*/  
43   
44   
45 /**  
46  
47  * Element 就象一个 java 的工具类,主要用来 隐藏/显示/销除 对象,  
48  
49  * 以及获取对象的简单属性。  
50  
51  *  
52  
53  */  
54   
55 var Element = {   
56   
57   toggle: function() {   
58   
59     for (var i = 0; i < arguments.length; i++) {   
60   
61       var element = $(arguments[i]);   
62   
63       element.style.display =   
64   
65         (element.style.display == 'none' ? '' : 'none');   
66   
67     }   
68   
69   },   
70   
71   
72   hide: function() {   
73   
74     for (var i = 0; i < arguments.length; i++) {   
75   
76       var element = $(arguments[i]);   
77   
78       element.style.display = 'none';   
79   
80     }   
81   
82   },   
83   
84   
85   show: function() {   
86   
87     for (var i = 0; i < arguments.length; i++) {   
88   
89       var element = $(arguments[i]);   
90   
91       element.style.display = '';   
92   
93     }   
94   
95   },   
96   
97   
98   remove: function(element) {   
99   
100     element = $(element);   
101   
102     element.parentNode.removeChild(element);   
103   
104   },   
105   
106   
107   getHeight: function(element) {   
108   
109     element = $(element);   
110   
111     return element.offsetHeight;   
112   
113   }   
114   
115 }   
116   
117   
118 /**  
119  
120  * 为 Element.toggle 做了一个符号连接,大概是兼容性的考虑  
121  
122  */  
123   
124 var Toggle = new Object();   
125   
126 Toggle.display = Element.toggle;   
127   
128   
129 /*--------------------------------------------------------------------------*/  
130   
131   
132 /**  
133  
134  * 动态插入内容的实现,MS的Jscript实现中对象有一个 insertAdjacentHTML 方法  
135  
136  * http://msdn.microsoft.com/workshop/  
137  
138  * author/dhtml/reference/methods/insertadjacenthtml.asp  
139  
140  * 这里算是一个对象形式的封装。  
141  
142  */  
143   
144 Abstract.Insertion = function(adjacency) {   
145   
146   this.adjacency = adjacency;   
147   
148 }   
149   
150   
151 Abstract.Insertion.prototype = {   
152   
153   initialize: function(element, content) {   
154   
155     this.element = $(element);   
156   
157     this.content = content;   
158   
159   
160     if (this.adjacency && this.element.insertAdjacentHTML) {   
161   
162       this.element.insertAdjacentHTML(this.adjacency, this.content);   
163   
164     } else {   
165   
166      /**  
167  
168       * gecko 不支持 insertAdjacentHTML 方法,但可以用如下代码代替  
169  
170       */  
171   
172       this.range = this.element.ownerDocument.createRange();   
173   
174      /**  
175  
176       * 如果定义了 initializeRange 方法,则实行,  
177  
178       * 这里相当与定义了一个抽象的 initializeRange 方法  
179  
180       */  
181   
182       if (this.initializeRange) this.initializeRange();   
183   
184       this.fragment = this.range.createContextualFragment(this.content);   
185   
186   
187      /**  
188  
189       * insertContent 也是一个抽象方法,子类必须实现  
190  
191       */  
192   
193       this.insertContent();   
194   
195     }   
196   
197   }   
198   
199 }   
200   
201   
202 /**  
203  
204  * prototype 加深了我的体会,就是写js 如何去遵循   
205  
206  * Don't Repeat Yourself (DRY) 原则  
207  
208  * 上文中 Abstract.Insertion 算是一个抽象类,  
209  
210  * 定义了名为 initializeRange 的一个抽象方法  
211  
212  * var Insertion = new Object() 建立一个命名空间  
213  
214  * Insertion.Before|Top|Bottom|After 就象是四个java中  
215  
216  * 的四个静态内部类,而它们分别继承于  
217  
218  * Abstract.Insertion,并实现了initializeRange方法。  
219  
220  */  
221   
222 var Insertion = new Object();   
223   
224   
225 Insertion.Before = Class.create();   
226   
227 Insertion.Before.prototype =   
228   
229   (new Abstract.Insertion('beforeBegin')).extend({   
230   
231   initializeRange: function() {   
232   
233     this.range.setStartBefore(this.element);   
234   
235   },   
236   
237   
238   /**  
239  
240    * 将内容插入到指定节点的前面, 与指定节点同级  
241  
242    */  
243   
244   insertContent: function() {   
245   
246     this.element.parentNode.insertBefore(this.fragment, this.element);   
247   
248   }   
249   
250 });   
251   
252   
253 Insertion.Top = Class.create();   
254   
255 Insertion.Top.prototype =   
256   
257   (new Abstract.Insertion('afterBegin')).extend({   
258   
259   initializeRange: function() {   
260   
261     this.range.selectNodeContents(this.element);   
262   
263     this.range.collapse(true);   
264   
265   },   
266   
267   
268   /**  
269  
270    * 将内容插入到指定节点的第一个子节点前,于是内容变为该节点的第一个子节点  
271  
272    */  
273   
274   insertContent: function() {   
275   
276     this.element.insertBefore(this.fragment, this.element.firstChild);   
277   
278   }   
279   
280 });   
281   
282   
283 Insertion.Bottom = Class.create();   
284   
285 Insertion.Bottom.prototype = (new Abstract.Insertion('beforeEnd')).extend({   
286   
287   initializeRange: function() {   
288   
289     this.range.selectNodeContents(this.element);   
290   
291     this.range.collapse(this.element);   
292   
293   },   
294   
295   
296   /**  
297  
298    * 将内容插入到指定节点的最后,于是内容变为该节点的最后一个子节点  
299  
300    */  
301   
302   insertContent: function() {   
303   
304     this.element.appendChild(this.fragment);   
305   
306   }   
307   
308 });   
309   
310   
311   
312 Insertion.After = Class.create();   
313   
314 Insertion.After.prototype = (new Abstract.Insertion('afterEnd')).extend({   
315   
316   initializeRange: function() {   
317   
318     this.range.setStartAfter(this.element);   
319   
320   },   
321   
322   
323   /**  
324  
325    * 将内容插入到指定节点的后面, 与指定节点同级  
326  
327    */  
328   
329   insertContent: function() {   
330   
331     this.element.parentNode.insertBefore(this.fragment,   
332   
333       this.element.nextSibling);   
334   
335   }   
336   
337 }); 

其他代码:

prototype 还有两个源码文件 effects.js compat.js 就不贴出来了。两者并不常用,effects.js 看example 做花哨的效果还不错,不过代码中没有太多新鲜的东西。 

需要指出的就是 
compat.js 中 Funcation.prototype.apply 的实现有两个错误(应该是拼写错误), 我分别贴出来,大家比较一下就清楚了。
复制代码 代码如下:

/* 这是包含错误的原版本  
2  
3 if (!Function.prototype.apply) {  
4  
5 // Based on code from http://www.youngpup.net/  
6  
7 Function.prototype.apply = function(object, parameters) {  
8  
9 var parameterStrings = new Array();  
10  
11 if (!object) object = window;  
12  
13 if (!parameters) parameters = new Array();  
14  
15  
16 for (var i = 0; i < parameters.length; i++)  
17  
18 parameterStrings[i] = 'x[' + i + ']'; //Error 1  
19  
20  
21 object.__apply__ = this;  
22  
23 var result = eval('obj.__apply__(' + //Error 2  
24  
25 parameterStrings[i].join(', ') + ')');  
26  
27 object.__apply__ = null;  
28  
29  
30 return result;  
31  
32 }  
33  
34 }  
35  
36 */  
37   
38   
39 if (!Function.prototype.apply) {   
40   
41   Function.prototype.apply = function(object, parameters) {   
42   
43     var parameterStrings = new Array();   
44   
45     if (!object) object = window;   
46   
47     if (!parameters) parameters = new Array();   
48   
49   
50     for (var i = 0; i < parameters.length; i++)   
51   
52       parameterStrings[i] = 'parameters[' + i + ']';   
53   
54   
55     object.__apply__ = this;   
56   
57     var result = eval('object.__apply__(' + parameterStrings.join(', ') + ')');   
58   
59     object.__apply__ = null;   
60   
61   
62     return result;   
63   
64   }   
65   
66 }  

接下来是我模仿着编写的一个 Effect 的一个子类,用来实现闪烁的效果。
复制代码 代码如下:

Effect.Blink = Class.create();   
2   
3 Effect.Blink.prototype = {   
4   
5   initialize: function(element, frequency) {   
6   
7     this.element = $(element);   
8   
9     this.frequency = frequency?frequency:1000;   
10   
11     this.element.effect_blink = this;   
12   
13     this.blink();   
14   
15   },   
16   
17   
18   blink: function() {   
19   
20     if (this.timer) clearTimeout(this.timer);   
21   
22     try {   
23   
24       this.element.style.visibility =   
25   
26           this.element.style.visibility == 'hidden'?'visible':'hidden';   
27   
28     } catch (e) {}   
29   
30     this.timer = setTimeout(this.blink.bind(this), this.frequency);   
31   
32    }   
33   
34 };  

使用也很简单, 调用 new Effect.Blink(elementId) 就好了。 

通过对 prototype 源码的研究,我想我对javascript又有了一点新的体会,而最大的体会就是 《Ajax : A New Approach to Web Applications》文章最后作者对设计人员的建议: to forget what we think we know about the limitations of the Web, and begin to imagine a wider, richer range of possibilities. 

相关文章

最新评论