[转]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.
最新评论