这个widget是jquery ui的核心部分,实用它能实现一致的API,创建有状态的插件,而无需关心插件的内部转换。
$.widget( name, base, prototype )
widget一共有2或3个参数。base为可选。
这里之所以把base放在第二个参数里,主要是因为这样写代码更直观一些。(因为后面的prototype 是个代码非常长的大对象)。
name:第一个参数是一个包含一个命名空间和组件名称的字符串,通过”.”来分割。
命名空间必须有,它指向widget prototype存储的全局jQuery对象。
如果命名空间没有,widget factory将会为你生成。widget name是插件函数和原型的真实名称,
比如: jQuery.widget( “demo.multi”, {…} ) 将会生成 jQuery.demo , jQuery.demo.multi , and jQuery.demo.multi.prototype .
base:第二个参数(可选)是 widget prototype继承于什么对象。
例如jQuery UI有一个“mouse”的插件,它可以作为其他的插件提供的基础。
为了实现这个所有的基于mouse的插件比如draggable,
droppable可以这么做: jQuery.widget( "ui.draggable", $.ui.mouse, {...} );
如果没有这个参数,widget默认继承自“base widget” jQuery.Widget(注意jQuery.widget 和 jQuery.Widget不同) 。
prototype:最后一个参数是一个对象文字,它会转化为所有widget实例的prototype。widget factory会生成属性链,连接到她继承的widget的prototype。一直到最基本的 jQuery.Widget。
一旦你调用jQuery.widget
,它会在jQuery prototype ( jQuery.fn )
上生成一个新的可用方法对应于widget的名字,比如我们这个例子jQuery.fn.multi。 .fn方法是包含Dom元素的jquery对象和你生成的 widget prototyp实例的接口,为每一个jQuery对象生成一个新的widget的实例。
1 /*! 2 * jQuery UI Widget @VERSION 3 * http://jqueryui.com 4 * 5 * Copyright 2014 jQuery Foundation and other contributors 6 * Released under the MIT license. 7 * http://jquery.org/license 8 * 9 * http://api.jqueryui.com/jQuery.widget/ 10 */ 11 12 //这里判定是否支持amd or cmd 模式 13 (function(factory) { 14 if (typeof define === "function" && define.amd) { 15 16 // AMD. Register as an anonymous module. 17 define(["jquery"], factory); 18 } else { 19 20 // Browser globals 21 factory(jQuery); 22 } 23 }(function($) { 24 25 var widget_uuid = 0, 26 //插件的实例化数量 27 widget_slice = Array.prototype.slice; //数组的slice方法,这里的作用是将参赛arguments 转为真正的数组 28 29 //清除插件的数据及缓存 30 $.cleanData = (function(orig) { 31 return function(elems) { 32 for (var i = 0, elem; 33 (elem = elems[i]) != null; i++) { 34 try { 35 // 重写cleanData方法,调用后触发每个元素的remove事件 36 $(elem).triggerHandler("remove"); 37 // http://bugs.jquery.com/ticket/8235 38 } catch (e) {} 39 } 40 orig(elems); 41 }; 42 })($.cleanData); 43 44 /** 45 * widget工厂方法,用于创建插件 46 * @param name 包含命名空间的插件名称,格式 xx.xxx 47 * @param base 需要继承的ui组件 48 * @param prototype 插件的实际代码 49 * @returns {Function} 50 */ 51 $.widget = function(name, base, prototype) { 52 var fullName, //插件全称 53 existingConstructor, //原有的构造函数 54 constructor, //当前构造函数 55 basePrototype, //父类的Prototype 56 // proxiedPrototype allows the provided prototype to remain unmodified 57 // so that it can be used as a mixin for multiple widgets (#8876) 58 proxiedPrototype = {}, 59 //可调用父类方法_spuer的prototype对象,扩展于prototype 60 namespace = name.split(".")[0]; 61 62 name = name.split(".")[1]; 63 fullName = namespace + "-" + name; 64 //如果只有2个参数 base默认为Widget类,组件默认会继承base类的所有方法 65 if (!prototype) { 66 prototype = base; 67 base = $.Widget; 68 } 69 70 // console.log(base, $.Widget) 71 72 // create selector for plugin 73 //创建一个自定义的伪类选择器 74 //如 $(':ui-menu') 则表示选择定义了ui-menu插件的元素 75 $.expr[":"][fullName.toLowerCase()] = function(elem) { 76 return !!$.data(elem, fullName); 77 }; 78 79 // 判定命名空间对象是否存在,没有的话 则创建一个空对象 80 $[namespace] = $[namespace] || {}; 81 //这里存一份旧版的插件,如果这个插件已经被使用或者定义了 82 existingConstructor = $[namespace][name]; 83 //这个是插件实例化的主要部分 84 //constructor存储了插件的实例,同时也创建了基于命名空间的对象 85 //如$.ui.menu 86 constructor = $[namespace][name] = function(options, element) { 87 // allow instantiation without "new" keyword 88 //允许直接调用命名空间上的方法来创建组件 89 //比如:$.ui.menu({},'#id') 这种方式创建的话,默认没有new 实例化。因为_createWidget是prototype上的方法,需要new关键字来实例化 90 //通过 调用 $.ui.menu 来实例化插件 91 if (!this._createWidget) { 92 console.info(this) 93 return new constructor(options, element); 94 } 95 96 // allow instantiation without initializing for simple inheritance 97 // must use "new" keyword (the code above always passes args) 98 //如果存在参数,则说明是正常调用插件 99 //_createWidget是创建插件的核心方法 100 if (arguments.length) { 101 this._createWidget(options, element); 102 } 103 }; 104 // extend with the existing constructor to carry over any static properties 105 //合并对象,将旧插件实例,及版本号、prototype合并到constructor 106 $.extend(constructor, existingConstructor, { 107 108 version: prototype.version, 109 // copy the object used to create the prototype in case we need to 110 // redefine the widget later 111 //创建一个新的插件对象 112 //将插件实例暴露给外部,可用户修改及覆盖 113 _proto: $.extend({}, prototype), 114 // track widgets that inherit from this widget in case this widget is 115 // redefined after a widget inherits from it 116 _childConstructors: [] 117 }); 118 119 //