传统的 jQuery
使用十分方便友好,但随着 ES6
、HTML5/CSS3
的逐步成熟,我们可以编写一个轻量级的类 jQuery
工具,这就是 tQuery
。它采用 ES6
语法编写,仅包含 jQuery
中有关 DOM
、CSS
和 Event
的部分,即省略了 Ajax
、Deferred
和 Effect
等,因为这些部分可由 ES6/HTML5
中原生的 Fetch
、Promise
和 CSS3
来支持。
tQuery
名称里的 t
来源于 Tpb
里的 Template
,但也可以认为是 tiny
。
注:
本设计的接口虽然大部分与jQuery
相似,但并不兼容,同名的接口只是在功能上相似而已。
可以打开test.html
在浏览器控制台执行console.dir($)
或console.dir($().__proto__)
简单地查看接口分布情况。
jQuery
中对检索结果集的操作,在这里都有一个单元素的版本,如:$.next(el, slr)
、$.hasClass(el, names)
,以及相应的集合版本:$('xx').next(...)
、$('xx').hasClass(...)
。单元素版如果没有值需要返回,通常返回 $
自身,集合版会返回一个值集合或一个新的 Collector
实例。与 jQuery
中类似,集合版的 Collector
返回值可以链式调用。
与 jQuery
相比,大多数同名接口的行为相似,但不少地方依然区别明显。如对元素集的属性取值,jQuery
中仅是对集合内首个成员取值,如 $('a').attr('href')
取首个 <a>
元素的 href
属性值,而 tQuery
中则会返回集合里全部元素的属性值(一个数组)。
又如 $.html
方法,jQuery
中它既可以处理文本,也处理节点元素,效果与连续的 $.empty().append()
调用相似。但在 tQuery
中该接口只负责文本的逻辑:设置元素内容时接收HTML文本或提取来源元素的 outerHTML
值,获取源码时提取元素的 innerHTML
值。另外也支持插入位置和HTML编码功能。
在实现上,代码不对浏览器的原生事件对象产生侵入,元素上也不存储任何数据(因此没有 .data()
方法)。设计上尽量精简,只要有可能就把任务交给原生的 ES6
、HTML5/CSS3
去处理。
下面接口的名称中,前置 $.
的指 $
的成员,前置 .
表示 $(...)
检索结果(Collector
实例)的成员。
-
.contains()
- jQuery: 仅针对内部子孙元素,不含容器元素自身测试。
- tQuery: 包含容器元素自身测试,与DOM同名接口行为相同。
-
.hasClass()
- jQuery: 对空格分隔的名称序列视为一个整体。
- tQuery: 空格分隔的名称序列被视为多个名称,逐个判断,因此
class="A B"
与class="B A"
是一样的。
-
.is()
- jQuery: 只要集合中有一个匹配即为true,且可接受多种类型的参数。
- tQuery: 对集合中每一个元素判断,返回一个true和false值混合的集合(数组),参数类型较为简单。
-
.first()/.last()
- jQuery: 简单返回集合中首个或最后一个成员。
- tQuery: 返回集合中首个或最后一个匹配的成员。接受一个可选的选择器匹配参数,无实参调用时与jQuery相同。
-
.next()/.prev()
- jQuery: 简单返回下一个或前一个兄弟元素,可以传递一个选择器测试是否匹配,不匹配则返回
null
。 - tQuery: 返回下一个或前一个匹配的兄弟元素,如果未传入匹配测试条件,则无条件匹配(同jQuery)。匹配测试支持函数(函数支持迭代计数)。
- jQuery: 简单返回下一个或前一个兄弟元素,可以传递一个选择器测试是否匹配,不匹配则返回
-
$.data()/.data()
- jQuery: 存储与目标元素关联的任意数据,或者返回集合中匹配首个元素的存储的值。
- tQuery: 没有该接口。元素的data-xx系属性融入在
attr
和prop
接口中,支持名称简写(-xx
表示data-xx
)。
-
$.get()/.get()
- jQuery:
$.get
为用Ajax
方式通过GET
方法获取目标网站的内容。.get
为获取集合内的某个成员。 - tQuery:
$.get
为获取文档中单个元素的版本,如通过id
定位或querySelector
检索。.get
为集合版的同功能接口,获取集合内某个成员采用.item
接口。
- jQuery:
-
$.wrap()/.wrap()/$.wrapInner()/.wrapInner()
- jQuery: 传递包含子元素的包裹容器时,会递进到最深层子元素为实际包裹容器,整个容器为复制方式。支持选择器选择目标元素。返回原始被包裹元素的集合。
- tQuery: 与jQuery相同,包含子元素的包裹容器会递进到最深层子元素为包裹元素,但容器元素的克隆是可选的,并且返回的是包裹容器(根)本身,同时也支持被包裹内容为文本。如果包裹元素是既有的元素,可以指定是否同时克隆元素(及其子孙元素)上绑定的事件处理器。另外,集合版支持包裹元素的数组式指定(与被包裹数据一一对应)和前值默认的功能。
-
.wrapAll()
- jQuery: 用目标容器元素包裹集合内的全部成员,与
$.wrap()
等接口类似,容器元素会递进到首个最深层子元素(也为克隆方式),返回原始被包裹内容的集合。 - tQuery: 用目标容器元素包裹集合内的全部成员,也与本库的
$.wrap()
等接口类似,支持包裹元素的克隆选项,返回包裹容器本身(Collector
封装),因此可以简单的链式调用(如.appendTo()
等)。
- jQuery: 用目标容器元素包裹集合内的全部成员,与
-
$.html()/.html()
- jQuery: 接收节点参数时,是执行简单的复制和移动,实参节点会从原来的地方脱离DOM树。数组实参会被合并为单一的值,然后拷贝赋值到各个目标。
- tQuery: 接收节点参数时,会提取元素的
outerHTML
或文本节点的textContent
,这里是纯粹的文本逻辑,不会影响原节点,同时也可以指定插入的位置。集合版版中数组实参是一一对应的逻辑。
-
$.text()/.text()
- jQuery: 接收节点参数时,只是简单地将节点转换为字符串,因此一个元素实际上会被转换为
[object HTMLElement]
之类的值。数组实参会被转换为数组的字符串表示,然后赋值。 - tQuery: 接收节点参数时,会取节点的
textContent
值,不论这个节点是元素、文本节点还是注释节点。同样地,也可以指定插入的位置。集合版数组实参的说明参考.html
接口说明。
- jQuery: 接收节点参数时,只是简单地将节点转换为字符串,因此一个元素实际上会被转换为
-
$.val()/.val()
- jQuery: 获取或设置表单控件
value
属性的值,不论该表单控件是否已disabled
,效果与.prop('value', '...')
相同。 - tQuery: 严格遵循表单逻辑:取值时返回
value
属性的值,设置时部分控件为对比目标值并改变控件状态(如单/复选按钮、选单等),而非修改value
属性本身。例如不能对<option>
控件直接取值或设置,因为它们由<select>
管理。另外,如果控件已disabled
,则取值返回null
,设置不起作用。(注:这是一个与 jQuery 版差异较大的接口)
- jQuery: 获取或设置表单控件
-
$.scroll()/.scroll()
- jQuery: 是绑定滚动事件处理器的便捷方法。
- tQuery: 窗口/元素滚动条位置的获取或滚动到目标位置的执行(会触发事件)。注:绑定事件处理器仅采用
$.on()
方法实施。
注: tQuery 只涉及 jQuery 中与 DOM 相关的部分,因此差异对比也仅限于这一子集。
-
元素和节点创建。
- jQuery: 通过
$( html )
方式创建元素,但仅能创建元素(Element
)而无法创建单纯的文本节点(Text
)。 - tQuery: 通过
$.Element( tag, data, conf )
创建元素,通过$.Text( data )
创建文本节点。另外还有 SVG 和 Table 的特定接口。
- jQuery: 通过
-
数据集合对元素集合的赋值。
- jQuery: 当数据赋值到jQuery检索的结果集时,数据被视为一个单元执行拷贝赋值。如:
$('p').text([1, 3, 5])
,数组被转化为一个字符串:1,3,5
,然后拷贝赋值到集合中每一个段落元素。 - tQuery: 当目标元素是集合时(
Collector
),部分接口中数据源的类型被区别对待:如果是一个数组,则是各自一一对应。如上述例子,集合中的前3个段落被分别填充为1
、2
、3
等值。
- jQuery: 当数据赋值到jQuery检索的结果集时,数据被视为一个单元执行拷贝赋值。如:
-
before/after/append/prepend/html/text 等接口的功能限定。
- jQuery: 全部方法既支持节点/元素、也支持HTML字符串即时创建元素。
- tQuery:
before/after/append/prepend/replace/fill
六个方法被限定为仅支持节点/元素,因此也就支持节点/元素的克隆,以及元素上绑定的事件处理器的克隆。html/text
被严格限定为文本类操作,且支持插入位置参数和源码编解码的简单功能,条理更清晰一些。
-
事件委托绑定(
delegate
)的触发区别。- jQuery: 事件处理器的绑定可以用一个选择器限定事件触发的目标。从事件的触发起始元素(
target
)开始到委托绑定的元素,如果有多个目标元素匹配,就会触发多次事件处理器的调用。 - tQuery: 委托绑定的规则与jQuery相同,但事件的触发仅有一次,触发的目标是从起始元素(
target
)开始(含target
),向上第一个匹配的元素。注:从事件处理器接口(function(event, elo): Any
)的第二个实参elo
上取当前匹配元素(elo.current
)。
- jQuery: 事件处理器的绑定可以用一个选择器限定事件触发的目标。从事件的触发起始元素(
-
节点变化事件(
varyevent, bindevent
)。为了跟踪DOM节点的变化,设计加入了如下定制事件:
attrvary, attrdone
元素特性设置:之前/完成
事件。由.attr|.attribute|.removeAttr|.toggleAttr
接口触发。propvary, propdone
元素属性设置:之前/完成
事件。由.prop|.property|.val
接口触发。stylevary, styledone
元素内联样式设置:之前/完成
事件。由.css|.cssSets
接口触发。classvary, classdone
元素类名设置:之前/完成
事件。由.addClass|.removeClass|.toggleClass
接口触发。nodein, nodeok, nodesdone
节点插入DOM:之前/完成/全部完成
事件。由5个接口.prepend|.append|.before|.after|.replace
触发。也可能由复合类操作如fill, wrap, wrapInner, html, text
等触发。detach, detached
节点脱离DOM:之前/完成
事件。由接口.remove
触发。empty, emptied
节点内清空:之前/完成
事件。由接口.empty
触发。normalize, normalized
节点规范化:之前/完成
事件。由接口.normalize
触发。
这对于需要跟踪DOM节点变化的应用,可以获得节点改变之前、完成或出错三个阶段的监听处理能力。事件冒泡且不可取消,附加的消息(
event.detail
)包含了关联的数据。注:出错和完成事件不会同时发生,两者仅有其一。另外,对于在元素上绑定和解绑事件处理器也提供了如下通知事件:
bind, bound
在元素上绑定事件处理器之前/后,适用tQuery.on()/one()
接口。unbind, unbound
在元素上解绑事件处理器之前/后,适用tQuery.off()
接口。
节点变化事件的功能默认关闭,需要执行
$.config( {bindevent:true, varyevent:true} )
开启。 -
泛节点接口。 tQuery 中加入了5个包含非空文本和注释节点的检索接口,以便更仔细地分辨节点位置。它们是:
prevNode/nextNode
获取当前节点之前或之后的下一个节点,节点包含:元素、非空文本节点和可选的注释节点。如果迭代到末端依然没有条件符合,则返回null
。prevNodes/nextNodes
获取当前节点之前或之后的兄弟节点集,节点包含范围同上。siblingNodes
获取当前节点同级的兄弟节点集,节点包含范围同上。
tQuery 也支持 Sizzle 中很有用的直接子元素选择器 >...
。如:$('>b, >a', ctx)
,表示选取 ctx
内 <b>
和 <a>
直接子元素。
tQuery 可以脱离 Sizzle 使用,它采用了浏览器内置的 querySelector()/querySelectorAll()
通用方法,但该方法并不支持上面的选择器形式。实际上,tQuery 只是简单地用一个临时属性名补充到 >
之前,从而构造出一个合法的选择器(形如:P[___tquery_bcc6c0df_]>...
)。
临时属性名由一个固定的前缀 ___tquery_
和当前时间戳(16进制)以及一个结尾 _
构成,以避免与应用冲突(您知道这点更好)。