You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
wrapAll: function(structure){// 如果选中的元素存在if(this[0]){// 则将制定structure结构通过before方法,插入到选中的第一个元素的前面$(this[0]).before(structure=$(structure))varchildren// drill down to the inmost element// 获取structure的最深层次的第一个子元素while((children=structure.children()).length)structure=children.first()// 将当前的元素集合通过append方法添加到structure末尾$(structure).append(this)}// 反则直接返回this进行后续的链式操作returnthis}
前言
原文链接
github项目地址
删除元素
remove
遍历当前集合中的元素,当该元素的父节点存在的时候,使用
removeChild
删除该元素。detach
可以看到就是在$的原型上添加了一个指向
remove
函数的方法detach
。empty
遍历当前集合中的元素,然后将元素的innerHTML属性设置为空。也就达到了清除DOM内容的目的。
插入元素
append, prepend, after, before
以上是
append
,appendTo
,prepend
,prependTo
,after
,insertAfter
,before
,insertBefore
八个方法的基本用法,以及用过之后的dom结构。我们总结一下他们的区别。首先每个方法的入参都可以为html字符串,dom节点,或者节点组成的数组。参考自zeptojs_api
append
,appendTo
,prepend
,prependTo
都是在元素内部插入内容,而after
,insertAfter
,before
,insertBefore
则是在元素外部插入内容。append
,appendTo
是在元素的末尾插入内容,prepend
,prependTo
是在元素的初始位置插入,after
,insertAfter
是在元素的后面插入内容,before
,insertBefore
则是在元素的前面插入内容接下来我们开始学习和阅读实现这8大方法的核心源码部分
遍历adjacencyOperators数组给$原型添加对应的方法
可以看到通过循环遍历
adjacencyOperators
从而给$的原型添加对应的方法。转换node节点
例子
因为传入的内容可以为html字符串,dom节点,或者节点组成的数组。这里对可能的情况分类型做了处理。通过内部的
type
函数判断每个参数的数据类型并保存在argType
中。当参数类型为数组(类似上面例子中的4)的时候,再对该参数进行遍历,如果该参数中的元素存在
nodeType
属性则将该元素推进数组arr,如果该参数中的元素是一个
Zepto对象
,则调用get方法,将arr与返回的原生元素数组进行合并。当参数类型为
object
或者null
的时候直接返回,否则就是处理字符串形式了,通过调用zepto.fragment(这个函数在后面的文章中会详细讲解,现在就其理解为将html字符串处理成dom节点数组就可以了)处理并将结果返回。到现在为止,我们已经明白了怎么将传入的
content
转化为对应的dom节点
。接下来我们来看如何将
nodes
中创建好的dom节点插入到目标位置。先留意一下
parent
,以及copyByClone
这两个变量,挺重要的,具体作用下面会详细说明。并且如果需要插入的元素数组的长度小于1,那么也就没有必要继续往下走了,直接return this
进行链式操作。整个后续代码就是两层嵌套循环,第一层遍历当前选中的元素集合,第二层就是需要插入的nodes节点集合。通过两个循环来最终完成元素的插入操作,并且很重要的一点是,不管是
append
还是after
等方法都是通过insertBefore
来模拟完成的。确定parent节点以及target目标节点
通过上面的分析我们知道通过insertBefore(在当前节点的某个子节点之前再插入一个子节点)来完成节点的插入,很重要的几个因素就是
parentNode.insertBefore(newNode, referenceNode)
所以确定以上1和3就显得极其重要了。怎么确定呢?
inside是个啥啊!!!,让我们回到顶部看这段
所以说当要往$原型上添加的方法是
prepend
和append
的时候inside
为1也就是真,当为after
和before
的时候为0也就是假。因为
prepend
和append
都是往当前选中的元素内部添加新节点,所以parent
当然就是target
本身了,但是after
和before
确是要往选中的元素外部添加新节点,自然parent
就变成了当前选中元素的父节点。到这里上面的三要素1,已经明确了,还有3(target)如何确定呢?好啦三要素3页已经明确了,接下来我们把重要放在第二个循环。
将新节点插入到指定位置
在将节点插入到指定位置的前有一个判断,如果
copyByClone
为真,就将要插入的新节点复制一份。为什么要这么做呢?我们来看个例子。先将cloneNode那部分给注销了,我们期望往三个li的前面都插入两个span,但是结果会怎么样呢?只有最后一个节点前面可以成功地插入两个span节点。这样就不是我们先要的结果了,根据insertBefore mdn解释,如果newElement已经在DOM树中,newElement首先会从DOM树中移除。,所以当我们需要往多个li中插入同样类似的两个节点的时候,才需要将新节点克隆一份再插入。
我们接着回到源码。
如果需要(当前选中元素的个数大于1)克隆节点的时候,先将新节点克隆一份,如果没有找到对应的parent节点,就讲要插入的新节点删除,最后通过
insertBefore
方法插入新节点。到了这里我们似乎已经完成了从
创建
新节点
=>将新节点插入到指定位置
的操作了。任务好像已经完成了,但是革命尚未成功,同志仍需努力啊。接下来看最后一点代码,主要是处理,当插入的节点是script
标签的时候,需要手动去执行其包含的js代码。
先提前看一下traverseNode这个函数的代码
这个函数的主要作用就是将传入的node节点作为参数去调用传入的fun函数。并且递归的将node节点的子节点,交给fun去处理。
接下来继续看。
首先通过
$.contains
方法判断parent
是否在document
文档中,接着需要满足一下几个条件才去执行后续操作。确定window对象
新节点存在ownerDocument mdn则window对象为defaultView mdn,否则使用window对象本身。
这里主要会考虑node节点是iframe种的元素情况,才需要做三目处理。
最后便是调用
target['eval'].call(target, el.innerHTML)
去执行script中的代码了。到这里我们终于知道了'after', 'prepend', 'before', 'append'实现全过程(偷乐一下😀,不容易啊)。
appendTo, prependTo, insertBefore, insertAfter
紧接着我们继续往前走,前面说了插入操作有很多个方法,其中
insertAfter
,insertBefore
,prependTo
,appendTo
的实现基于上述几个方法。如果是
append
或者prepend
则往$原型上添加appendTo
和prependTo
方法,如果是before
或者after
的时候,便往$的原型上添加insertBefore
和insertAfter
方法。因为其两两对应的方法本质上是同样的功能,只是在使用上有点相反的意思,所以简单的反向调用一下就可以了。html
例子
源码实现
当没有传html参数的时候,先判断当前选中的元素是否存在,存在则读取第一个元素的innerHTML并返回,否则直接返回null
当传了html参数的时候。对当前选中的元素集合进行遍历设置,先保存当前元素的innerHTML到originHtml变量中,再将当前元素的innerHTML置空,并将funcArg函数执行之后返回的html插入到当前元素中。
可以看到funcArg会对传入arg进行类型判断,如果是函数,就把对应的参数传入函数再将函数的执行结果返回,不是函数就直接返回arg。
text
text实现方法与html比较类似有些不同的是没有传参数的时候,html是获取第一个元素的innerHTMLtext则是将当前所有元素的textContent拼接起来并返回.
复制元素
clone
对当前选中的元素集合进行遍历操作,底层还是用的浏览器cloneNode,并传参为true表示需要进行深度克隆(其实感觉这里是不是将true设置为可选参数比较好呢,让使用者决定是深度克隆与否不是更合理?)
需要注意的地方是cloneNode方法不会复制添加到DOM节点中的Javascript属性,例如事件处理程序等,这个方法只复制特性,子节点,其他一切都不会复制,IE在此存在一个bug,即他会赋值事件处理程序,所以我们建议在赋值之间最好先移除事件处理程序(摘自《JavaScript高级程序设计第三版》10.1.1 Node类型小字部分)
替换元素
replaceWidth
源码实现其实很简单分两步,第一步调用前面我们讲的before方法将制定newContent插入到元素的前面,第二部步将当前选中的元素删除。自然也就达到了替换的目的。
包裹元素
wrapAll
源码实现直接看注释就可以了,这里需要注意一下
children
函数是获取对象集合中所有的直接子节点。而first
函数则是获取当前集合的第一个元素。另外我们看一下下面两个例子。
执行上述代码之后dom结构会变成
可以看到原来ul结构还是存在,仿佛是复制了一份ul及其子节点到wrap中被包裹起来。
接下来再看一个例子,唯一的区别就在wrap结构中嵌套了基层。
但是最后执行
$('.box').wrapAll('.wrap')
得到的dom结果是。嘿嘿可以看到,ul原来的结构不见了,被移动到了第一个wrap的第一个子节点here中。具体原因是什么呢?大家可以重新回去看一下append的核心实现。
wrap
wrapInner
需要注意的是这个函数和前面的wrapAll和wrap有点不一样,这里强调的是将当前**元素中的内容(包括元素节点和文本节点)**进行包裹。
unwrap
结尾
参考
读Zepto源码之操作DOM
Zepto源码分析-zepto模块
ownerDocument
insertBefore
innerHTML
《JavaScript高级程序设计第三版》
文章记录
form模块
zepto模块
event模块
ajax模块
The text was updated successfully, but these errors were encountered: