首页 前端知识 jQuery UI widget源码解析,想找工作的你还不看这份资料就晚了

jQuery UI widget源码解析,想找工作的你还不看这份资料就晚了

2024-08-23 20:08:29 前端知识 前端哥 198 226 我要收藏
  1. // Copy everything else by reference

  2. } else {

  3. target[key] = value;

  4. }

  5. }

  6. }

  7. }

  8. return target;

  9. };

  10. //bridge 是设计模式的一种,这里将对象转为插件调用

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

  12. var fullName = object.prototype.widgetFullName || name;

  13. //这里就是插件了

  14. //这部分的实现主要做了几个工作,也是制作一个优雅的插件的主要代码

  15. //1、初次实例化时将插件对象缓存在dom上,后续则可直接调用,避免在相同元素下widget的多实例化。简单的说,就是一个单例方法。

  16. //2、合并用户提供的默认设置选项options

  17. //3、可以通过调用插件时传递字符串来调用插件内的方法。如:$(‘#id’).menu(‘hide’) 实际就是实例插件并调用hide()方法。

  18. //4、同时限制外部调用“_”下划线的私有方法

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

  20. var isMethodCall = typeof options === “string”,

  21. args = widget_slice.call(arguments, 1),

  22. returnValue = this;

  23. // allow multiple hashes to be passed on init.

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

  25. options = !isMethodCall && args.length ? $.widget.extend.apply(null, [options].concat(args)) : options;

  26. //这里对字符串和对象分别作处理

  27. if (isMethodCall) {

  28. this.each(function() {

  29. var methodValue, instance = $.data(this, fullName);

  30. //如果传递的是instance则将this返回。

  31. if (options === “instance”) {

  32. returnValue = instance;

  33. return false;

  34. }

  35. if (!instance) {

  36. return $.error("cannot call methods on " + name + " prior to initialization; " + “attempted to call method '” + options + “'”);

  37. }

  38. //这里对私有方法的调用做了限制,直接调用会抛出异常事件

  39. if (!$.isFunction(instance[options]) || options.charAt(0) === “_”) {

  40. return $.error(“no such method '” + options + “’ for " + name + " widget instance”);

  41. }

  42. //这里是如果传递的是字符串,则调用字符串方法,并传递对应的参数.

  43. //比如插件有个方法hide(a,b); 有2个参数:a,b

  44. //则调用时$(‘#id’).menu(‘hide’,1,2);//1和2 分别就是参数a和b了。

  45. methodValue = instance[options].apply(instance, args);

  46. if (methodValue !== instance && methodValue !== undefined) {

  47. returnValue = methodValue && methodValue.jquery ? returnValue.pushStack(methodValue.get()) : methodValue;

  48. return false;

  49. }

  50. });

  51. } else {

  52. this.each(function() {

  53. var instance = $.data(this, fullName);

  54. if (instance) {

  55. instance.option(options || {});

  56. //这里每次都调用init方法

  57. if (instance._init) {

  58. instance._init();

  59. }

  60. } else {

  61. //缓存插件实例

  62. $.data(this, fullName, new object(options, this));

  63. }

  64. });

  65. }

  66. return returnValue;

  67. };

  68. };

  69. //这里是真正的widget基类

  70. $.Widget = function( /* options, element */ ) {};

  71. $.Widget._childConstructors = [];

  72. $.Widget.prototype = {

  73. widgetName: “widget”,

  74. //用来决定事件的名称和插件提供的callbacks的关联。

  75. // 比如dialog有一个close的callback,当close的callback被执行的时候,一个dialogclose的事件被触发。

  76. // 事件的名称和事件的prefix+callback的名称。widgetEventPrefix 默认就是控件的名称,但是如果事件需要不同的名称也可以被重写。

  77. // 比如一个用户开始拖拽一个元素,我们不想使用draggablestart作为事件的名称,我们想使用dragstart,所以我们可以重写事件的prefix。

  78. // 如果callback的名称和事件的prefix相同,事件的名称将不会是prefix。

  79. // 它阻止像dragdrag一样的事件名称。

  80. widgetEventPrefix: “”,

  81. defaultElement: “

    ”,

  82. //属性会在创建模块时被覆盖

  83. options: {

  84. disabled: false,

  85. // callbacks

  86. create: null

  87. },

  88. _createWidget: function(options, element) {

  89. element = $(element || this.defaultElement || this)[0];

  90. this.element = $(element);

  91. this.uuid = widget_uuid++;

  92. this.eventNamespace = “.” + this.widgetName + this.uuid;

  93. this.options = $.widget.extend({}, this.options, this._getCreateOptions(), options);

  94. this.bindings = $();

  95. this.hoverable = $();

  96. this.focusable = $();

  97. if (element !== this) {

  98. //            debugger

  99. $.data(element, this.widgetFullName, this);

  100. this._on(true, this.element, {

  101. remove: function(event) {

  102. if (event.target === element) {

  103. this.destroy();

  104. }

  105. }

  106. });

  107. this.document = $(element.style ?

  108. // element within the document

  109. element.ownerDocument :

  110. // element is window or document

  111. element.document || element);

  112. this.window = $(this.document[0].defaultView || this.document[0].parentWindow);

  113. }

  114. this._create();

  115. //创建插件时,有个create的回调

  116. this._trigger(“create”, null, this._getCreateEventData());

  117. this._init();

  118. },

  119. _getCreateOptions: $.noop,

  120. _getCreateEventData: $.noop,

  121. _create: $.noop,

  122. _init: $.noop,

  123. //销毁模块:去除绑定事件、去除数据、去除样式、属性

  124. destroy: function() {

  125. this._destroy();

  126. // we can probably remove the unbind calls in 2.0

  127. // all event bindings should go through this._on()

  128. this.element.unbind(this.eventNamespace).removeData(this.widgetFullName)

  129. // support: jquery <1.6.3

  130. // http://bugs.jquery.com/ticket/9413

  131. .removeData($.camelCase(this.widgetFullName));

  132. this.widget().unbind(this.eventNamespace).removeAttr(“aria-disabled”).removeClass(

  133. this.widgetFullName + "-disabled " + “ui-state-disabled”);

  134. // clean up events and states

  135. this.bindings.unbind(this.eventNamespace);

  136. this.hoverable.removeClass(“ui-state-hover”);

  137. this.focusable.removeClass(“ui-state-focus”);

  138. },

  139. _destroy: $.noop,

  140. widget: function() {

  141. return this.element;

  142. },

  143. //设置选项函数

  144. option: function(key, value) {

  145. var options = key,

  146. parts, curOption, i;

  147. if (arguments.length === 0) {

  148. // don’t return a reference to the internal hash

  149. //返回一个新的对象,不是内部数据的引用

  150. return $.widget.extend({}, this.options);

  151. }

  152. if (typeof key === “string”) {

  153. // handle nested keys, e.g., “foo.bar” => { foo: { bar: ___ } }

  154. options = {};

  155. parts = key.split(“.”);

  156. key = parts.shift();

  157. if (parts.length) {

  158. curOption = options[key] = $.widget.extend({}, this.options[key]);

  159. for (i = 0; i < parts.length - 1; i++) {

  160. curOption[parts[i]] = curOption[parts[i]] || {};

  161. curOption = curOption[parts[i]];

  162. }

  163. key = parts.pop();

  164. if (arguments.length === 1) {

  165. return curOption[key] === undefined ? null : curOption[key];

  166. }

  167. curOption[key] = value;

  168. } else {

  169. if (arguments.length === 1) {

  170. return this.options[key] === undefined ? null : this.options[key];

  171. }

  172. options[key] = value;

  173. }

  174. }

  175. this._setOptions(options);

  176. return this;

  177. },

  178. _setOptions: function(options) {

  179. var key;

  180. for (key in options) {

  181. this._setOption(key, options[key]);

  182. }

  183. return this;

  184. },

  185. _setOption: function(key, value) {

  186. this.options[key] = value;

  187. if (key === “disabled”) {

  188. this.widget().toggleClass(this.widgetFullName + “-disabled”, !! value);

  189. // If the widget is becoming disabled, then nothing is interactive

  190. if (value) {

  191. this.hoverable.removeClass(“ui-state-hover”);

  192. this.focusable.removeClass(“ui-state-focus”);

  193. }

  194. }

  195. return this;

  196. },

  197. enable: function() {

  198. return this._setOptions({

  199. disabled: false

  200. });

  201. },

  202. disable: function() {

  203. return this._setOptions({

  204. disabled: true

  205. });

  206. },

  207. _on: function(suppressDisabledCheck, element, handlers) {

  208. var delegateElement, instance = this;

  209. // no suppressDisabledCheck flag, shuffle arguments

  210. if (typeof suppressDisabledCheck !== “boolean”) {

  211. handlers = element;

  212. element = suppressDisabledCheck;

  213. suppressDisabledCheck = false;

  214. }

  215. // no element argument, shuffle and use this.element

  216. if (!handlers) {

  217. handlers = element;

  218. element = this.element;

  219. delegateElement = this.widget();

  220. } else {

  221. // accept selectors, DOM elements

  222. element = delegateElement = $(element);

  223. this.bindings = this.bindings.add(element);

  224. }

  225. $.each(handlers, function(event, handler) {

  226. function handlerProxy() {

  227. // allow widgets to customize the disabled handling

  228. // - disabled as an array instead of boolean

  229. // - disabled class as method for disabling individual parts

  230. if (!suppressDisabledCheck && (instance.options.disabled === true || $(this).hasClass(“ui-state-disabled”))) {

  231. return;

  232. }

  233. return (typeof handler === “string” ? instance[handler] : handler).apply(instance, arguments);

  234. }

  235. // copy the guid so direct unbinding works

  236. if (typeof handler !== “string”) {

  237. handlerProxy.guid = handler.guid = handler.guid || handlerProxy.guid || $.guid++;

  238. }

  239. var match = event.match(/^([\w:-]*)\s*(.*)$/),

  240. eventName = match[1] + instance.eventNamespace,

  241. selector = match[2];

  242. if (selector) {

  243. delegateElement.delegate(selector, eventName, handlerProxy);

  244. } else {

  245. element.bind(eventName, handlerProxy);

  246. }

  247. });

  248. },

  249. _off: function(element, eventName) {

  250. eventName = (eventName || “”).split(" ").join(this.eventNamespace + " ") + this.eventNamespace;

  251. element.unbind(eventName).undelegate(eventName);

  252. },

  253. _delay: function(handler, delay) {

  254. function handlerProxy() {

  255. return (typeof handler === “string” ? instance[handler] : handler).apply(instance, arguments);

  256. }

  257. var instance = this;

  258. return setTimeout(handlerProxy, delay || 0);

  259. },

  260. _hoverable: function(element) {

  261. this.hoverable = this.hoverable.add(element);

  262. this._on(element, {

  263. mouseenter: function(event) {

  264. $(event.currentTarget).addClass(“ui-state-hover”);

  265. },

  266. mouseleave: function(event) {

  267. $(event.currentTarget).removeClass(“ui-state-hover”);

  268. }

  269. });

  270. },

  271. _focusable: function(element) {

  272. this.focusable = this.focusable.add(element);

  273. this._on(element, {

  274. focusin: function(event) {

  275. $(event.currentTarget).addClass(“ui-state-focus”);

  276. },

  277. focusout: function(event) {

  278. $(event.currentTarget).removeClass(“ui-state-focus”);

  279. }

  280. });

  281. },

  282. _trigger: function(type, event, data) {

  283. var prop, orig, callback = this.options[type];

  284. data = data || {};

  285. event = $.Event(event);

  286. event.type = (type === this.widgetEventPrefix ? type : this.widgetEventPrefix + type).toLowerCase();

  287. // the original event may come from any element

  288. // so we need to reset the target on the new event

  289. event.target = this.element[0];

  290. // copy original event properties over to the new event

  291. orig = event.originalEvent;

  292. if (orig) {

  293. for (prop in orig) {

  294. if (!(prop in event)) {

  295. event[prop] = orig[prop];

  296. }

  297. }

  298. }

  299. this.element.trigger(event, data);

  300. return !($.isFunction(callback) && callback.apply(this.element[0], [event].concat(data)) === false || event.isDefaultPrevented());

  301. }

  302. };

  303. $.each({

  304. show: “fadeIn”,

  305. hide: “fadeOut”

  306. }, function(method, defaultEffect) {

  307. $.Widget.prototype[“_” + method] = function(element, options, callback) {

  308. if (typeof options === “string”) {

  309. options = {

  310. effect: options

  311. };

  312. }

  313. var hasOptions, effectName = !options ? method : options === true || typeof options === “number” ? defaultEffect : options.effect || defaultEffect;

  314. options = options || {};

  315. if (typeof options === “number”) {

  316. options = {

  317. duration: options

  318. };

  319. }

  320. hasOptions = !$.isEmptyObject(options);

  321. options.complete = callback;

  322. if (options.delay) {

  323. element.delay(options.delay);

  324. }

  325. if (hasOptions && KaTeX parse error: Expected 'EOF', got '&' at position 10: .effects &̲& .effects.effect[effectName]) {

  326. element[method](options);

  327. } else if (effectName !== method && element[effectName]) {

  328. element[effectName](options.duration, options.easing, callback);

  329. } else {

  330. element.queue(function(next) {

  331. $(this)[method]();

  332. if (callback) {

  333. callback.call(element[0]);

  334. }

  335. next();

  336. });

  337. }

  338. };

  339. });

  340. return $.widget;

  341. }));

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip1024c (备注前端)
img

下面是我在学习HTML和CSS的时候整理的一些笔记,有兴趣的可以看下:

HTML、CSS部分截图

进阶阶段

进阶阶段,开始攻 JS,对于刚接触 JS 的初学者,确实比学习 HTML 和 CSS 有难度,但是只要肯下功夫,这部分对于你来说,也不是什么大问题。

JS 内容涉及到的知识点较多,看到网上有很多人建议你从头到尾抱着那本《JavaScript高级程序设计》学,我是不建议的,毕竟刚接触 JS 谁能看得下去,当时我也不能,也没那样做。

我这部分的学习技巧是,增加次数,减少单次看的内容。就是说,第一遍学习 JS 走马观花的看,看个大概,去找视频以及网站学习,不建议直接看书。因为看书看不下去的时候很打击你学下去的信心。

然后通过一些网站的小例子,开始动手敲代码,一定要去实践、实践、实践,这一遍是为了更好的去熟悉 JS 的语法。别只顾着来回的看知识点,眼高手低可不是个好习惯,我在这吃过亏,你懂的。

1、JavaScript 和 ES6

在这个过程你会发现,有很多 JS 知识点你并不能更好的理解为什么这么设计,以及这样设计的好处是什么,这就逼着让你去学习这单个知识点的来龙去脉,去哪学?第一,书籍,我知道你不喜欢看,我最近通过刷大厂面试题整理了一份前端核心知识笔记,比较书籍更精简,一句废话都没有,这份笔记也让我通过跳槽从8k涨成20k。

JavaScript部分截图

2、前端框架

前端框架太多了,真的学不动了,别慌,其实对于前端的三大马车,Angular、React、Vue 只要把其中一种框架学明白,底层原理实现,其他两个学起来不会很吃力,这也取决于你以后就职的公司要求你会哪一个框架了,当然,会的越多越好,但是往往每个人的时间是有限的,对于自学的学生,或者即将面试找工作的人,当然要选择一门框架深挖原理。

以 Vue 为例,我整理了如下的面试题。

Vue部分截图

能看得下去,当时我也不能,也没那样做。

我这部分的学习技巧是,增加次数,减少单次看的内容。就是说,第一遍学习 JS 走马观花的看,看个大概,去找视频以及网站学习,不建议直接看书。因为看书看不下去的时候很打击你学下去的信心。

然后通过一些网站的小例子,开始动手敲代码,一定要去实践、实践、实践,这一遍是为了更好的去熟悉 JS 的语法。别只顾着来回的看知识点,眼高手低可不是个好习惯,我在这吃过亏,你懂的。

1、JavaScript 和 ES6

在这个过程你会发现,有很多 JS 知识点你并不能更好的理解为什么这么设计,以及这样设计的好处是什么,这就逼着让你去学习这单个知识点的来龙去脉,去哪学?第一,书籍,我知道你不喜欢看,我最近通过刷大厂面试题整理了一份前端核心知识笔记,比较书籍更精简,一句废话都没有,这份笔记也让我通过跳槽从8k涨成20k。

JavaScript部分截图

2、前端框架

前端框架太多了,真的学不动了,别慌,其实对于前端的三大马车,Angular、React、Vue 只要把其中一种框架学明白,底层原理实现,其他两个学起来不会很吃力,这也取决于你以后就职的公司要求你会哪一个框架了,当然,会的越多越好,但是往往每个人的时间是有限的,对于自学的学生,或者即将面试找工作的人,当然要选择一门框架深挖原理。

以 Vue 为例,我整理了如下的面试题。

Vue部分截图

转载请注明出处或者链接地址:https://www.qianduange.cn//article/16680.html
标签
评论
发布的文章

HTML5 基本框架

2024-09-01 23:09:50

HTML5取消边框的方法

2024-09-01 23:09:50

大家推荐的文章
会员中心 联系我 留言建议 回顶部
复制成功!