jQuery.clean使用方法及思路分析
2023-06-13 09:14:43 时间
一、jQuery.clean使用方法
jQuery.clean(elems,context,fragment,scripts);
二、思路分析
1、处理参数context,确保其为文档根节点document
2、处理参数elems数组(循环遍历数组)
2.1、elem为数字,转换为字符串
2.2、elem为非法值,跳出本次循环
2.3、elem为字符串
2.4、字符串不存在实体编号或html标签,则创建文本节点
2.5、字符串为实体编号或html标签
创建一个div元素并插入到文档碎片中
处理xhtml风格标签
将elem包裹起来,并将包裹后的字符串作为div的innerHTML
如果包裹深度大于1,只留下第一层包裹元素
清除在ie6,7中空table标签自动加入的tbody
将在ie9以下浏览器中剔除的开头空白字符串作为div元素的第一个文本子节点
将elem重新赋值为div的子节点集合(nodeList对象),
移除本次循环中文档碎片中的div,保持下一次循环中干净的div元素
2.3、如果elem为文本节点,则直接添加到要返回的ret数组中,否则将elem(nodeList对象)中的节点合并到数组
2.4、修复在ie6、7中type为radio,checkbox类型的节点的选中状态(checked)失效的bug
3、处理参数fragment
3.1、将ret中各节点添加到文档碎片fragment中
3.2、提取节点中的script子节点,并将其添加到ret数组中,添加的script位置为其原父元素位置后面
4、返回ret数组
三、源码注释分析
1、函数中用到的变量及函数
varnodeNames="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|"+
"header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",
wrapMap={
option:[1,"<selectmultiple="multiple">","</select>"],
legend:[1,"<fieldset>","</fieldset>"],
thead:[1,"<table>","</table>"],
tr:[2,"<table><tbody>","</tbody></table>"],
td:[3,"<table><tbody><tr>","</tr></tbody></table>"],
col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],
area:[1,"<map>","</map>"],
_default:[0,"",""]
},
rxhtmlTag=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,
rtagName=/<([\w:]+)/,
rtbody=/<tbody/i,
rhtml=/<|?\w+;/,
rleadingWhitespace=/^\s+/,
rcheckableType=/^(?:checkbox|radio)$/,
rscriptType=/\/(java|ecma)script/i;
//设置复选框checkbox或单选框radio表单元素的默认选中状态
functionfixDefaultChecked(elem){
if(rcheckableType.test(elem.type)){
elem.defaultChecked=elem.checked;
}
}
//创建一个安全的文档碎片
functioncreateSafeFragment(document){
varlist=nodeNames.split("|"),
safeFrag=document.createDocumentFragment();//ie6,7,8浏览器把safeFrage作为HTMLDocument类型
//针对ie9以下浏览器
if(safeFrag.createElement){
while(list.length){
safeFrag.createElement(
list.pop()
);
}
}
returnsafeFrag;
}
//模拟ES5中Array的新功能
//该函数API:http://www.css88.com/jqapi-1.8/#p=jQuery.grep
jQuery.extend({
grep:function(elems,callback,inv){
varretVal,
ret=[],
i=0,
length=elems.length;
inv=!!inv;
//Gothroughthearray,onlysavingtheitems
//thatpassthevalidatorfunction
for(;i<length;i++){
retVal=!!callback(elems[i],i);
if(inv!==retVal){
ret.push(elems[i]);
}
}
returnret;
}
});
2、源码分析
jQuery.extend({
clean:function(elems,context,fragment,scripts){
//声明变量
vari,j,elem,tag,wrap,depth,div,hasBody,tbody,len,handleScript,jsTags,
safe=context===document&&safeFragment,
ret=[];
//确保变量context为文档根节点document
if(!context||typeofcontext.createDocumentFragment==="undefined"){
context=document;
}
//Usethealready-createdsafefragmentifcontextpermits
for(i=0;(elem=elems[i])!=null;i++){
//如果elem为数字,则将其转换为字符串
if(typeofelem==="number"){
elem+="";
}
//如果elem为undefined,跳出本次循环
if(!elem){
continue;
}
//ConverthtmlstringintoDOMnodes
//转换数组项(字符串)为DOM节点
if(typeofelem==="string"){
//如果不存在html实体编号或标签,则创建文本节点
if(!rhtml.test(elem)){
elem=context.createTextNode(elem);
}
//处理是html标签字符串的数组项
else{
//Ensureasafecontainerinwhichtorenderthehtml
//safe为#document-fragment类型,在ie9以下浏览器中,safe为HTMLDocument类型节点,且nodeNames数组为空
safe=safe||createSafeFragment(context);
//创建一个div元素并将其插入到文档碎片中
div=context.createElement("div");
safe.appendChild(div);
//Fix"XHTML"-styletagsinallbrowsers
//除了area,br,col,embed,hr,img,input,link,meta,param这些标签外,
//将开始标签末尾加入斜杠的标签转换为开始和结束标签
elem=elem.replace(rxhtmlTag,"<$1></$2>");
//Gotohtmlandback,thenpeeloffextrawrappers
//获取左边第一个标签元素
tag=(rtagName.exec(elem)||["",""])[1].toLowerCase();
//获取最外层元素的包裹元素,并将元素包裹在其中
wrap=wrapMap[tag]||wrapMap._default;
depth=wrap[0];
div.innerHTML=wrap[1]+elem+wrap[2];
//Movetotherightdepth
//如果元素的包裹深度大于1,div重新赋值为元素最近的包裹元素(即:包含第一层包裹元素)
while(depth--){
div=div.lastChild;
}
//RemoveIE"sautoinserted<tbody>fromtablefragments
//在IE6,7中,清除字符串中空table标签中自动加入的tbody标签(手动加入的除外)
if(!jQuery.support.tbody){
//Stringwasa<table>,*may*havespurious(伪造的)<tbody>
//判断字符串中是否拥有空tbody标签
hasBody=rtbody.test(elem);
//如果最外层标签为table且table中没有手动加入tbody
//变量tbody为div.firstChild.childNodes(自动加入的tbody标签集合)
tbody=tag==="table"&&!hasBody?
div.firstChild&&div.firstChild.childNodes:
//Stringwasabare<thead>or<tfoot>
//如果字符串中仅有一个空thead或tfoot标签
//变量tbody为div.childNodes(字符串中的thead和tfoot标签集合)
wrap[1]==="<table>"&&!hasBody?
div.childNodes:
[];
for(j=tbody.length-1;j>=0;--j){
//排除thead或tfoot标签
if(jQuery.nodeName(tbody[j],"tbody")&&!tbody[j].childNodes.length){
//清除空table标签中自动加入的tbody
tbody[j].parentNode.removeChild(tbody[j]);
}
}
}
//IEcompletelykillsleadingwhitespacewheninnerHTMLisused
//在ie9以下浏览器中,字符串以空白字符串开头,将空白字符串作为div元素的第一个文本子节点
if(!jQuery.support.leadingWhitespace&&rleadingWhitespace.test(elem)){
div.insertBefore(context.createTextNode(rleadingWhitespace.exec(elem)[0]),div.firstChild);
}
//获取已经处理完毕的div子节点集合(nodeList对象)
elem=div.childNodes;
//Takeoutoffragmentcontainer(weneedafreshdiveachtime)
//在下一次循环处理字符串数组项前,清除处理创建过的div元素
div.parentNode.removeChild(div);
}
}
//如果elem为DOM节点(文本节点)
if(elem.nodeType){
ret.push(elem);
}
//将nodeList对象中节点合并到返回的数组中
else{
jQuery.merge(ret,elem);
}
}
//Fix#11356:ClearelementsfromsafeFragment
if(div){
elem=div=safe=null;
}
//ResetdefaultCheckedforanyradiosandcheckboxes
//abouttobeappendedtotheDOMinIE6/7(#8060)
//在ie6,7中,拥有checked属性的单选按钮,复选框在插入到其他标签后,选中状态会失效(下面代码修复该bug)
if(!jQuery.support.appendChecked){
for(i=0;(elem=ret[i])!=null;i++){
if(jQuery.nodeName(elem,"input")){
fixDefaultChecked(elem);
}elseif(typeofelem.getElementsByTagName!=="undefined"){
jQuery.grep(elem.getElementsByTagName("input"),fixDefaultChecked);
}
}
}
//Appendelementstoaprovideddocumentfragment
//将ret数组中的各DOM节点插入到提供的文档碎片中
//提取dom节点中的script节点,并添加到ret数组中,位置为其原父元素索引位置后
if(fragment){
//Specialhandlingofeachscriptelement
handleScript=function(elem){
//Checkifweconsideritexecutable
//如果elem元素不存在type属性或者type值为javascript或者为ecmascript
if(!elem.type||rscriptType.test(elem.type)){
//Detachthescriptandstoreitinthescriptsarray(ifprovided)orthefragment
//Returntruthytoindicatethatithasbeenhandled
returnscripts?
scripts.push(elem.parentNode?elem.parentNode.removeChild(elem):elem):
fragment.appendChild(elem);
}
};
for(i=0;(elem=ret[i])!=null;i++){
//Checkifwe"redoneafterhandlinganexecutablescript
if(!(jQuery.nodeName(elem,"script")&&handleScript(elem))){
//Appendtofragmentandhandleembeddedscripts
//将elem元素添加到文档碎片中并处理嵌入的脚本(script标签元素)
fragment.appendChild(elem);
if(typeofelem.getElementsByTagName!=="undefined"){
//handleScriptalterstheDOM,sousejQuery.mergetoensuresnapshotiteration
jsTags=jQuery.grep(jQuery.merge([],elem.getElementsByTagName("script")),handleScript);
//Splicethescriptsintoretaftertheirformerancestorandadvanceourindexbeyondthem
//将script标签添加到数组,位置为其原父元素索引位置后
ret.splice.apply(ret,[i+1,0].concat(jsTags));
i+=jsTags.length;
}
}
}
}
returnret;
}
});
相关文章
- jQuery——插件
- jQuery $.each用法详解编程语言
- ios jquery css(‘left’)无法读取属性解决的方法详解编程语言
- jQuery filter()和has()方法
- JQuery绑定事件时传递参数的实现方法
- jquery提示"objectexpected"的解决方法
- 让你的CSS像Jquery一样做筛选的实现方法
- 一些实用的jQuery代码片段收集
- jQuery.buildFragment使用方法及思路分析
- 基于jquery的文章中所有图片width大小批量设置方法
- jQuery实现密保互斥问题解决方案
- 让网页跳转到指定位置的jquery代码非书签
- jquery改变disabled的boolean状态的三种方法
- jQuery(js)获取文字宽度(显示长度)示例代码
- jquery操作下拉列表、文本框、复选框、单选框集合(收藏)
- jquery实现不同大小浏览器使用不同的css样式表的方法
- 使用jQuery重置(reset)表单的方法
- jQuery获取兄弟元素的几种不错方法
- 页面刷新时记住滚动条的位置jquery代码
- 对jQuery中data方法的误解分析
- 基于jquery的手风琴图片展示效果实现方法
- jQuery异步获取json数据方法汇总
- JavaScript用JQuery呼叫Server端方法示例代码
- jQuery动态创建html元素的常用方法汇总