`

jquery(自己看的)

    博客分类:
  • java
阅读更多

jQuery UI Widget(1.8.1)工作原理 2010年05月24日

类归于: jQuery , javascript — admin @ 7:43 上午

先看下代码的相关注释:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
/*!
 * jQuery UI Widget 1.8.1
 *
 * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
 * Dual licensed under the MIT (MIT-LICENSE.txt)
 * and GPL (GPL-LICENSE.txt) licenses.
 *
 * http://docs.jquery.com/UI/Widget
 */

(
function
(
 $ )
 {

 
var
 _remove =
 $.fn
.remove
;

 
$.fn
.remove
 =
 function
(
 selector,
 keepData )
 {

	return
 this
.each
(
function
(
)
 {

		if
 (
 !
keepData )
 {

			if
 (
 !
selector ||
 $.filter
(
 selector,
 [
 this
 ]
 )
.length
 )
 {

				$(
 "*"
,
 this
 )
.add
(
 this
 )
.each
(
function
(
)
 {

					$(
 this
 )
.triggerHandler
(
 "remove"
 )
;

				}
)
;

			}

		}

		//dom元素在被删除前,触发一下remove事件,jquery框架本身没有对元素删除绑定事件

		return
 _remove.call
(
 $(
this
)
,
 selector,
 keepData )
;

	}
)
;

}
;

 
$.widget
 =
 function
(
 name
,
 base,
 prototype )
 {

	var
 namespace
 =
 name
.split
(
 "."
 )
[
 0
 ]
,

		fullName;

	name
 =
 name
.split
(
 "."
 )
[
 1
 ]
;

	fullName =
 namespace
 +
 "-"
 +
 name
;

	//比如ui.tab,上面的name='tab';fullName='ui-tab';

 
	if
 (
 !
prototype )
 {

		prototype =
 base;

		base =
 $.Widget
;

	}

	//如果没有prototype,那么prototype就是base参数,实际base默认为$.Widget

 
	// create selector for plugin

	$.expr
[
 ":"
 ]
[
 fullName ]
 =
 function
(
 elem )
 {

		return
 !!
$.data
(
 elem,
 name
 )
;

	}
;

 
	$[
 namespace
 ]
 =
 $[
 namespace
 ]
 ||
 {
}
;
//是否有命名空间

	$[
 namespace
 ]
[
 name
 ]
 =
 function
(
 options,
 element )
 {
//根据上面的例子,即初始化了$.ui.tab=func

		// allow instantiation without initializing for simple inheritance

		if
 (
 arguments.length
 )
 {

			this
._createWidget(
 options,
 element )
;

		}

	}
;

 
	var
 basePrototype =
 new
 base(
)
;
//初始化,一般都是调用了new $.Widget()

	// we need to make the options hash a property directly on the new instance

	// otherwise we'll modify the options hash on the prototype that we're

	// inheriting from

//	$.each( basePrototype, function( key, val ) {

//		if ( $.isPlainObject(val) ) {

//			basePrototype[ key ] = $.extend( {}, val );

//		}

//	});

	basePrototype.options
 =
 $.extend
(
 {
}
,
 basePrototype.options
 )
;
//初始化options值,注意不需要深度拷贝

	$[
 namespace
 ]
[
 name
 ]
.prototype
 =
 $.extend
(
 true
,
 basePrototype,
 {

		namespace
:
 namespace
,

		widgetName:
 name
,

		widgetEventPrefix:
 $[
 namespace
 ]
[
 name
 ]
.prototype
.widgetEventPrefix
 ||
 name
,

		widgetBaseClass:
 fullName
	}
,
 prototype )
;

	//为新的ui模块创建原型,使用深度拷贝,在basePrototype上扩展一些模块基本信息,在扩展prototype,比如ui.tabs.js中就是tab的拥有各种方法的大对象

 
	$.widget
.bridge
(
 name
,
 $[
 namespace
 ]
[
 name
 ]
 )
;
//将此方法挂在jQuery对象上

}
;

 
$.widget
.bridge
 =
 function
(
 name
,
 object )
 {

	$.fn
[
 name
 ]
 =
 function
(
 options )
 {

		var
 isMethodCall =
 typeof
 options ===
 "string"
,

			args =
 Array.prototype
.slice
.call
(
 arguments,
 1
 )
,

			returnValue =
 this
;

		//如果第一个参数是string类型,就认为是调用模块方法

		//剩下的参数作为方法的参数,后面会用到

 
		// allow multiple hashes to be passed on init

		options =
 !
isMethodCall &&
 args.length
 ?

			$.extend
.apply
(
 null
,
 [
 true
,
 options ]
.concat
(
args)
 )
 :

			options;

		//可以简单认为是$.extend(true,options,args[0],...),args可以是一个参数或是数组

 
		// prevent calls to internal methods

		if
 (
 isMethodCall &&
 options.substring
(
 0
,
 1
 )
 ===
 "_"
 )
 {

			return
 returnValue;

		}

		//开头带下划线的方法都是私有方法,不让调用

 
		if
 (
 isMethodCall )
 {
//如果是调用函数

			this
.each
(
function
(
)
 {

				var
 instance =
 $.data
(
 this
,
 name
 )
,
//得到实例,实例作为一个数据和元素关联上

					methodValue =
 instance &&
 $.isFunction
(
 instance[
options]
 )
 ?

						instance[
 options ]
.apply
(
 instance,
 args )
 :
//如果实例和方法均存在,调用方法,把args作为参数传进去

						instance;
//否则返回undefined

				if
 (
 methodValue !==
 instance &&
 methodValue !==
 undefined )
 {
//如果methodValue不是jquery对象也不是undefined

					returnValue =
 methodValue;

					return
 false
;
//跳出each,一般获取options的值会走这个分支

				}

			}
)
;

		}
 else
 {
//不是函数调用的话

			this
.each
(
function
(
)
 {

				var
 instance =
 $.data
(
 this
,
 name
 )
;

				if
 (
 instance )
 {
//实例存在

					if
 (
 options )
 {
//有参数

						instance.option
(
 options )
;
//调用option函数,一般是设置状态之类的操作

					}

					instance._init(
)
;
//再次调用此函数,根据options调整

				}
 else
 {

					$.data
(
 this
,
 name
,
 new
 object(
 options,
 this
 )
 )
;

					//没有实例的话,给元素绑定一个实例。注意这里的this是dom,object是模块类

				}

			}
)
;

		}

 
		return
 returnValue;
//返回,有可能是jquery对象,有可能是其他值

	}
;

}
;

 
$.Widget
 =
 function
(
 options,
 element )
 {
//所有模块的基类

	// allow instantiation without initializing for simple inheritance

	if
 (
 arguments.length
 )
 {
//如果有参数,调用初始化函数

		this
._createWidget(
 options,
 element )
;

	}

}
;

 
$.Widget
.prototype
 =
 {

	widgetName:
 "widget"
,

	widgetEventPrefix:
 ""
,

	options:
 {

		disabled:
 false

	}
,
//上面的属性会在创建模块时被覆盖

	_createWidget:
 function
(
 options,
 element )
 {

		// $.widget.bridge stores the plugin instance, but we do it anyway

		// so that it's stored even before the _create function runs

		this
.element
 =
 $(
 element )
.data
(
 this
.widgetName
,
 this
 )
;
//缓存实例,保存jquery对象

		this
.options
 =
 $.extend
(
 true
,
 {
}
,

			this
.options
,

			$.metadata
 &&
 $.metadata
.get
(
 element )
[
 this
.widgetName
 ]
,

			options )
;
//参数处理

 
		var
 self =
 this
;

		this
.element
.bind
(
 "remove."
 +
 this
.widgetName
,
 function
(
)
 {

			self.destroy
(
)
;

		}
)
;
//注册销毁事件

 
		this
._create(
)
;
//创建

		this
._init(
)
;
//初始化

	}
,

	_create:
 function
(
)
 {
}
,

	_init:
 function
(
)
 {
}
,

 
	destroy:
 function
(
)
 {
//销毁模块:去除绑定事件、去除数据、去除样式、属性

		this
.element

			.unbind
(
 "."
 +
 this
.widgetName
 )

			.removeData
(
 this
.widgetName
 )
;

		this
.widget
(
)

			.unbind
(
 "."
 +
 this
.widgetName
 )

			.removeAttr
(
 "aria-disabled"
 )

			.removeClass
(

				this
.widgetBaseClass
 +
 "-disabled "
 +

				"ui-state-disabled"
 )
;

	}
,

 
	widget:
 function
(
)
 {
//返回jquery对象

		return
 this
.element
;

	}
,

 
	option:
 function
(
 key,
 value )
 {
//设置选项函数

		var
 options =
 key,

			self =
 this
;

 
		if
 (
 arguments.length
 ===
 0
 )
 {

			// don't return a reference to the internal hash

			return
 $.extend
(
 {
}
,
 self.options
 )
;
//返回一个新的对象,不是内部数据的引用

		}

 
		if
  (
typeof
 key ===
 "string"
 )
 {

			if
 (
 value ===
 undefined )
 {

				return
 this
.options
[
 key ]
;
//取值

			}

			options =
 {
}
;

			options[
 key ]
 =
 value;
//设置值

		}

 
		$.each
(
 options,
 function
(
 key,
 value )
 {

			self._setOption(
 key,
 value )
;
//调用内部的_setOption

		}
)
;

 
		return
 self;

	}
,

	_setOption:
 function
(
 key,
 value )
 {

		this
.options
[
 key ]
 =
 value;

 
		if
 (
 key ===
 "disabled"
 )
 {
//增加或是去除className

			this
.widget
(
)

				[
 value ?
 "addClass"
 :
 "removeClass"
]
(

					this
.widgetBaseClass
 +
 "-disabled"
 +
 " "
 +

					"ui-state-disabled"
 )

				.attr
(
 "aria-disabled"
,
 value )
;

		}

 
		return
 this
;

	}
,

 
	enable:
 function
(
)
 {

		return
 this
._setOption(
 "disabled"
,
 false
 )
;

	}
,

	disable:
 function
(
)
 {

		return
 this
._setOption(
 "disabled"
,
 true
 )
;

	}
,

 
	_trigger:
 function
(
 type,
 event,
 data )
 {

		var
 callback =
 this
.options
[
 type ]
;

 
		event =
 $.Event
(
 event )
;

		event.type
 =
 (
 type ===
 this
.widgetEventPrefix
 ?

			type :

			this
.widgetEventPrefix
 +
 type )
.toLowerCase
(
)
;

		data =
 data ||
 {
}
;

 
		// copy original event properties over to the new event

		// this would happen if we could call $.event.fix instead of $.Event

		// but we don't have a way to force an event to be fixed multiple times

		if
 (
 event.originalEvent
 )
 {
//把原始的event属性重新赋到event变量上

			for
 (
 var
 i =
 $.event
.props
.length
,
 prop;
 i;
 )
 {

				prop =
 $.event
.props
[
 --
i ]
;

				event[
 prop ]
 =
 event.originalEvent
[
 prop ]
;

			}

		}

 
		this
.element
.trigger
(
 event,
 data )
;

 
		return
 !
(
 $.isFunction
(
callback)
 &&

			callback.call
(
 this
.element
[
0
]
,
 event,
 data )
 ===
 false
 ||

			event.isDefaultPrevented
(
)
 )
;

	}

}
;

 
}
)
(
 jQuery )
;

上面是jquery.ui.widget.js的源码,jquery ui的所有模块都是基于其中的widget方法进行扩展,使用统一的命名规范和编码风格。
先来说一下原理:
$.widget此函数完成了对jQuery本身的扩展,根据第一个参数来确定模块的命名空间和函数名;第二个参数确定模块的基类(默认是$.Widget);第三个参数实现模块本身的方法。比如标签切换插件jquery.ui.tabs.js中开始:
$.widget(“ui.tabs”, {…});//这里只有两个参数,那么基类就默认是$.Widget
第一个参数:”ui.tabs”用来表示在jQuery上选择(或增加)一个命名空间,即如果jQuery.ui不存在,则定义jQuery.ui = {},然后在jQuery.ui上增加一个函数,名称为tabs.最后调用$.widget.bridge将tabs方法挂在jQuery对象上。这样, 所有的jquery对象将拥有tabs方法。

注意:jquery ui有严格的命名规范,每个控件对外只暴露一个借口。控件所有方法或属性通过向此借口传递不同参数来调用和获取。

jquery ui的大部分控件是基于$.Widget基类实现的。所以一般我们做控件是都要重写$.Widget类中的一些方法。一般来说,一个ui控件需要实现下列的方法或属性:
属性
options 用来缓存控件各项参数
私有方法 ,使用“$(xx).tabs(私有方法)”这种方式来调用私有方法时会立刻返回,调用不能成功:
_create 控件初始化调用,多次调用$(xx).tabs()这样不带参数的方法只会执行一次
_init 一般不用实现,默认为空函数,每次“$(xx).tabs()”这样调用时会调用此方法
_setOption “$(xx).tabs(‘option’,xxx)”这种调用方式会调用此方法
公开方法
destroy 销毁模块
option 设置或获取参数
enable 启用模块功能
disable 禁用功能

几乎所有的jquery ui控件都会重写这些接口,同时增加控件相关的私有或公有方法。

记住,jquery ui的实例是和元素关联起来的,作为数据保存起来了。暴露给用户使用的只是jquery对象上增加的方法。一般我们不需要获取ui的实例。

分享到:
评论

相关推荐

    [精华]网站论坛源码C# Jquery,完全自制,有很多jquery自己写的插件

    【标题】中的“[精华]网站论坛源码C# Jquery”揭示了这是一个关于网站论坛开发的项目,采用的核心技术是C#后端语言和Jquery前端库。C#是微软开发的一种面向对象的编程语言,广泛应用于构建Web应用程序,而Jquery则是...

    Jquery下載,Jquery-3.5.1

    **jQuery 下载与详解** jQuery 是一个广泛使用的 JavaScript 库,它极大地简化了网页上的 JavaScript 编程。...通过下载并学习 jQuery-3.5.1,你可以提升自己的前端开发技能,并更好地理解和利用这个经典的工具。

    jquery例子大全 jquery demo

    **jQuery 是一个高效、简洁且功能丰富的 JavaScript 库,它极大地简化了JavaScript代码的编写,使得网页交互变得更加简单。...所以,无论是初学者还是有一定经验的开发者,都应该好好利用这些示例来提升自己的技能。

    自己写的一个Jquery

    【标题】"自己写的一个Jquery" 描述了一个个人开发的基于Jquery的项目,它采用了Win8风格的用户界面设计,旨在为用户提供一个现代化、直观的交互体验。这个项目可能是一个轻量级的库或者插件,利用Jquery的强大功能...

    jquery1.7中文手册CHM文档(附jquery1.82chm手册)

    资源名称:jquery1.7 中文手册 CHM文档(附jquery1.82 chm手册)内容简介:因国内jquery中文手册更新太慢了,等了一段时间实在等不下去了,干脆自己动手做一个丰衣足食,时刻更新. 最后感谢Shawphy提供1.4.1版,jehn提供...

    jquery-migrate: 迁移旧的jQuery代码至jQuery1.9以上的版本

    通过观察和分析这个示例,你可以更深入地理解`jQuery Migrate`如何工作,并学习如何在自己的项目中应用。 **5. 逐步更新和最佳实践** 虽然`jQuery Migrate`可以帮助你过渡到新版本,但长期依赖它是不可取的。最好...

    jquery 源码初探,一步步实现自己的jquery(四)

    在本篇《jquery 源码初探,一步步实现自己的jquery(四)》中,我们将深入探讨jQuery库的核心概念,并尝试逐步构建一个简易版的jQuery,以帮助理解其内部机制。jQuery是一个广泛使用的JavaScript库,它简化了DOM操作...

    jquery-ui.css、jquery-ui.js下载

    此外,jQuery UI支持Themeroller工具,允许开发者轻松创建和定制自己的主题。 接着,`jquery-ui.js`是jQuery UI的核心JavaScript库,它包含了所有UI组件的实现。这个文件包含了实现交互性和动态效果的代码,如拖放...

    制作属于自己的jQuery参考文档

    《制作属于自己的jQuery参考文档》 在IT行业中,jQuery是一个广泛使用的JavaScript库,它极大地简化了JavaScript代码,尤其是处理DOM操作、事件处理和Ajax请求。本文将指导你如何利用提供的资源,如`jQueryAPI.en_...

    jquery, 就是 jquery, 自己保存下。 以后都是vue了

    jquery, 就是 jquery, 自己保存下。 以后都是vue了

    jQuery各类炫酷效果demo

    jQuery是一款广泛应用于网页交互与动态效果开发的JavaScript库,它简化了HTML文档遍历、事件处理、动画设计和Ajax交互。本压缩包“jQuery各类炫酷...开发者可以通过查看和学习这些示例,进一步提升自己的网页开发能力。

    jquery多选框

    在网页开发中,jQuery是一个非常流行的JavaScript库,它极大地简化了DOM操作、事件处理和动画效果。...结合提供的文件,开发者可以快速地在自己的项目中实现这一功能,同时也能为用户提供更丰富的选择和控制。

    jQuery Starterkit

    **jQuery Starterkit** jQuery 是一个广泛使用的JavaScript库,它极大地简化了HTML文档遍历、事件处理、动画制作以及...通过阅读教程、查阅API文档、实践代码示例,用户可以深入理解jQuery,提升自己的前端开发技能。

    jquery alert 提示框、动态加载提示框、jquery插件

    对于提示框,开发者可以创建自己的插件,定义提示框的样式、行为和功能,以满足项目特定的需求。开发插件时,我们需要考虑兼容性、性能优化和易于使用等因素。 在实际应用中,创建一个jQuery提示框插件可能包括以下...

    李炎恢jQuery讲义代码.rar

    《李炎恢jQuery讲义代码》是一份专为学习jQuery设计的配套资源,它与李炎恢老师的66集jQuery视频教程紧密关联。...无论你是初学者还是有经验的开发者,都可以通过这份讲义代码进一步提升自己的jQuery技能。

    教你如何做一个自己的jQuery插件,jQuery扩展笔记

    这篇文章将指导你如何构建一个自己的jQuery插件,理解jQuery扩展的核心原理。 首先,我们要明白jQuery插件的本质是一个包装在jQuery对象上的函数。在jQuery中,我们经常看到这样的匿名函数结构: ```javascript ...

    jquery纸牌消消看.zip

    《jQuery纸牌消消看游戏实现详解》 在IT领域,开发一款互动性强、趣味性高的小游戏总能吸引用户的眼球。"jQuery纸牌消消看"就是这样一款简单易上手,却又充满挑战性的益智休闲游戏。它利用了jQuery库的高效特性,将...

    jquery开发必备jquery开发包

    jQuery的`$.fn.extend()`允许开发者创建自己的插件,便于组织和维护代码。同时,jQuery的兼容性和良好的文档让开发者在不同浏览器环境下进行调试工作更为轻松。 最后,为了保证项目的质量和一致性,遵循jQuery的...

    JQuery desktop 基本JQuery 的虚拟桌面

    通过阅读代码和官方文档,了解其架构和API,结合示例进行实践,逐渐掌握如何在自己的项目中集成和定制jQuery Desktop。 总之,jQuery Desktop是一个创新的前端解决方案,它利用JavaScript和jQuery的力量,为Web应用...

    用JQuery 自己写的一个锁屏

    这个"用jQuery自己写的一个锁屏"项目提供了三种不同的锁屏类型,以满足不同场景下的需求。这可能包括基础的全屏遮罩、带有输入密码功能的锁屏以及更复杂的交互设计。 实现锁屏功能通常涉及以下步骤: 1. **创建...

Global site tag (gtag.js) - Google Analytics