写这篇文章的目的,一方面是介绍一下本身编写的模块化 DOM 库 domq.js,另外一方面是但愿你们对 jQuery 有一个正确的认识,即便 jQuery 已经逐渐退出历史舞台,可是它的 API 将会以另一种形式存在下去。html
GitHub:https://github.com/nzbin/domqjquery
jQuery 不会死去
从 GitHub 放弃 jQuery,再到 Bootstrap 5 宣布移除 jQuery,看来一个时代终究要落下帷幕。github
为何咱们会放弃 jQuery 呢?缘由无非这样几个:不须要再进行浏览器的兼容,原生 DOM 查找已经很方便,AJAX 请求有更好的替代方式等等。api
在我看来 jQuery 最大的弊端是没法分模块引入,直接引入整个库实在有些不妥,毕竟太多功能已经没有用武之地。可是 jQuery 的 DOM 操做依然颇有必要。不少人对个人这个观点有些疑问。其实在使用 MVVM 框架的时候,DOM 操做确实已经不多。可是咱们也不可能老是作一些 CRUD 的功能。对于复杂的业务需求仍然须要一些 DOM 操做。浏览器
假如 jQuery 能够把 DOM 操做相关的功能模块分离出来,或许还有很大的使用空间。框架
原生当道
在平时的项目中,愈来愈多的人选择用原生 JS 去操做对象,好比获取元素属性,宽高,定位等等。dom
早在几年前,github 上就有不少文章介绍如何用原生 JS 代替 jQuery,好比 YouDontNeedJQuery,YouMightNotNeedjQuery等。就我我的而言,纯 JS 操做确实很简单,可是并非很优雅,复杂一点的操做还要常常翻 MDN。ide
// jQuery $('.my #awesome selector'); // JS document.querySelectorAll('.my #awesome selector');
// jQuery $(el).hide(); // JS el.style.display = 'none';
// jQuery $(el).after(htmlString); // JS el.insertAdjacentHTML('afterend', htmlString);
以上是 jQuery 和原生 JS 对比的一个缩影,结果显而易见,jQuery 的 API 更加简洁。除此以外,jQuery API 的使用形式也很是统一。相反,原生 JS 的 API 使用方式就比较多样了,既有赋值,又有传参等。另外原生 JS 的 API 名称冗长,不方便记忆。这也是不少 JS 库诞生的意义。模块化
不少插件通常都会有一个 utils
的文件,基本会对原生方法作一个简单封装并提供一些工具方法。
Zepto 的优点与弱势
Zepto 是一个思想超前的库,为何我会有这样的结论?Zepto 对原生方法作了进一步的抽象,使用更简单。正如我在上文说过的,既然 jQuery 的 API 简洁易用,并且咱们也更加熟悉,那咱们为何不将 jQuery 和原生 JS 结合起来呢?使人惊讶的是,早在 2010 年,Zepto 的做者就已经这样去作了。用原生 JS 实现了 jQuery 的大部分 API,可替代率接近九成吧,至少在我编写的插件中,几乎能够替换掉全部的 jQuery API。并且 Zepto 也不是一味的使用 document.querySelector
方法,而是根据性能优劣,有选择的使用 document.getElementById
以及 document.querySelector
等。
可是 Zepto 也有一些显而易见的缺陷,毕竟仍是上个时代的产物,首先就是没法按需加载,如今咱们在写项目的时候更愿意根据本身的须要引入某些方法,而不是将整个库所有引入,虽然 Zepto 的体积不大,可是做为强迫症仍是有一些厌恶。另外就是 Zepto 自己也有一些 bug,好比 scrollTop
、scrollLeft
方法。其它不一样参见源码。
// Zepto scrollTop: function(value) { if (!this.length) return var hasScrollTop = 'scrollTop' in this[0] if (value === undefined) return hasScrollTop ? this[0].scrollTop : this[0].pageYOffset return this.each(hasScrollTop ? function() { this.scrollTop = value } : function() { this.scrollTo(this.scrollX, value) }) }
document
元素没法得到正确的值,我对这个问题提过 pr 可是没有回应,Zepto 目前基本已经中止维护。正确的方法以下:
// Domq function scrollTop(value) { if (!this.length) return var hasScrollTop = 'scrollTop' in this[0] if (value === undefined) return hasScrollTop ? this[0].scrollTop : isWindow(this[0]) ? this[0].pageYOffset : this[0].defaultView.pageYOffset; return this.each(hasScrollTop ? function () { this.scrollTop = value } : function () { this.scrollTo(this.scrollX, value) }) }
Domq 的使命
形如 jQuery 的 DOM 操做库有不少,好比 bonzo、$dom,可是在我重构 jQuery 插件时,我发现没有办法用这些库直接替换 jQuery,只有 Zepto 相对完美,可是我又不但愿引入额外的无用的方法。
最后我决定改造 Zepto,使之更符合如今的使用习惯。多说一点,我的以为 Zepto 的核心函数稍显凌乱,命名空间既有 zepto
、又有 $
、Z
,感受很是混乱,而 domq 的核心函数只有 D
这一个命名空间,形态及功能和 jQuery 的核心函数几乎同样,能够认为是一个 mini 版的 jQuery。
// Zepto 核心方法 var Zepto = (function() { var zepto = {}; ... zepto.Z = function(dom, selector) { return new Z(dom, selector) } ... $ = function(selector, context) { return zepto.init(selector, context) } ... })()
// Domq 核心方法 var D = function (selector, context) { return new D.fn.init(selector, context); } D.fn = D.prototype = { ... init: function(){ ... } ... }
固然, Domq 最关键的仍是按需加载,根据须要挂载方法,尽可能减小没必要要的代码。使用方式很简单,可是你须要建立一个独立文件,从新挂载须要的方法到 D
命名空间上,这在编写插件时很是有用。
import { D, isArray, addClass } from 'domq.js/src/domq.modular'; // 静态方法 const methods = { isArray } // 原型方法 const fnMethods = { addClass } D.extend(methods); D.fn.extend(fnMethods);
另外,在作项目时常常会用到一些工具方法,这时候用一个工具库暴露这些方法或许是最好的方式。Domq 也有一些经常使用的工具方法,不过还须要再迭代一下。
D.type() D.contains() D.camelCase() D.isFunction() D.isWindow() D.isEmptyObject() D.isPlainObject() D.isNumeric() D.isArray() D.inArray() ...
Domq 没有太多新的东西,因此也没有太多能够介绍的,它已经在插件 PhotoViewer 以及实际项目中得以运用,欢迎你们下载使用。
总结
这是一个好的时代,也是一个坏的时代,jQuery 的落幕确实让人感叹,可是咱们彻底不必由于 jQuery 的落幕而放弃 jQuery 的使用方式。正如前文所说,jQuery 的 DOM 操做在我看来依然是最好用的,因此,你不须要 jQuery,但你须要一个 DOM 库。
原文出处:https://www.cnblogs.com/nzbin/p/10230272.html