继续5,6章小结(一)的内容,作者认为我们会用css中的选择符来定位HTML DOM中的元素,给其添加样式,那么为什么不利用css选择符来定位得到我们想要的DOM节点呢,由于这样的想法产生了jquery中灵活强大的选择器(selector)帮助定位查找元素,作者也简要说明了下xpath。
如何获得一个元素的文本内容,如:
1 <p><strong>hello</strong>how are you doing?</p>
假定<strong>对应strongElem那么:
1 strongElem.innerText; //非Mozilla内核的浏览器 2 3 strongElem.firstChild.nodeValue; //适合所有平台
文中给出了一个通用的取出元素文本内容的函数
1 function text(e) { 2 var t = ""; 3 4 //如果单个元素传入,获取它的子节点 5 //否则假设e是个节点数组 6 e = e.childNodes || e; 7 8 //遍历所有的子节点 9 for(var j = 0; j < e.length; j++) { 10 //如果不是一个元素,追加到t 11 //否则递归遍历它的所有子节点 12 t += e[j].nodeType != 1 ? e[j].nodeValue : text(e[j].childNodes); 13 } 14 //返回匹配的文本 15 16 return t; 17 }
获取一个元素内的HTML,我们很快会想到innerHTML,但它只对HTML DOM有效对XML DOM就不行了。
关于元素的属性,有个判定一个元素是否具有某个指定属性的方法
1 function hasAttribute(elem, name) { 2 return elem.getAttribute(name) !== null; 3 }
一对HTML,XML DOM的通用方法:getAttribute和setAttribute 例:
1 id("everywhere").getAttribute("id") ; 2 3 tag("input")[0].setAttribute("value", "your name");
除了这对标准的方法,还有一些快速访问元素属性的方式,如:
1 tag("div")[0].id = "main"; 2 3 tag("input")[0].value;
但是有一些属性如class --> className, float-->cssFloat, text-->cssText,因为像class,float,text这些词本来就是javascript中的保留字。
文中有个attr方法,通过参数个数决定它的作用是设置属性值,还是获取属性值:
1 function attr(elem, name, value) { 2 //确保提供了一个有效的name 3 if(!name || name.constructor != String) return ""; 4 5 //理解不合常规的命名 6 name = {'for':'htmlFor', 'class':'className'}[name] || name; 7 8 //如果用户传入value 9 if(typeof value != 'undefined') { 10 //先用快速访问法 11 elem[name] = value; 12 13 //如果可以,用标准的setAttribute 14 if(elem.setAttribute) elem.setAttribute(name, value); 15 } 16 17 //返回属性值 18 return elem[name] || elem.getAttribute(name) || ''; 19 }
这个方法既能读又能取,参数中如果不带value那么返回已有的属性值,如果带了value,那么给对应的属性设置值,这和jquery中的attr基本是一样的,只不过我们用jquery的时候把DOM元素封装成了jquery对象。
修改DOM包括创建,插入,删除等,有了这些我们就能打造动态的页面效果,xhtml是xml一个子集,在创建元素时带个namespace
function create(elem) { return document.createElementNS ? document.createElementNS('http://www.w3.org/1999/xhtml', elem) : document.createElement(elem); }
对于插入DOM,有两个标准方法:
1 parentBeforeNode.insertBefore(nodeToInsert, beforeNode) 2 3 parentElem.append(nodeToInsert)
相信大家对这两个方法并不陌生,书中基于这两个方法做了函数封装
1 function before(parent, before, elem) { 2 3 //检查是否提供父节点,如果像这样调用:before(elem1, elem2)将elem2插到elem1之前 4 if(elem == null) { 5 elem = before; 6 before = parent; 7 parent = before.parentNode; 8 } 9 10 parent.insertBefore(checkElem(elem), before); 11 12 } 13 14 function append(parent, elem) { 15 parent.appendChild(checkElem(elem)); 16 } 17 18 function checkElem(elem) { 19 //如果传入的是个字符串,那么转换成TextNode 20 return elem && elem.constructor == String ? 21 document.createTextNode(elem) : elem; 22 }
向元素中注入HTML,tag("ul")[0].innerHTML = "<li>Cats</li><li>Dogs</li><li>Mice</li>";
比起上面的方法来说,确实方便,但用innerHTML有以下缺点:
1.就像之前提到的,它不支持纯粹的XML
2.innerHTML的赋值是把元素内的内容全部覆盖掉,很不灵活
文章中作者给出了一个很不错的解决方案:
1 function checkElem(a) { 2 var r = []; 3 4 //如果a不是数组,把a初始化为数组 5 if(a.constructor != Array) a = [a]; 6 7 for(var i = 0; i < a.length; i++) { 8 9 //如果是构造HTML字符串 10 if(a[i].constructor == String) { 11 //创建一个临时元素来持有HTML 12 var div = document.createElement("div"); 13 14 //注入这个HTML,把它转变成DOM结构 15 div.innerHTML = a[i]; 16 17 //从这个临时的div中取出DOM元素 18 for(var j = 0; j < div.childNodes.length; j++) { 19 r[r.length] = div.childNodes[j]; 20 } 21 22 } else if (a[i].length) { 23 //如果是它是个数组,假设是个DOM节点的数组 24 for(var j = 0; j < a[i].length; j++) { 25 r[r.length] = a[i][j]; 26 } 27 else { 28 //否则就假设它是个DOM节点 29 r[r.length] = a[i]; 30 } 31 32 return r; //参数a解析后的dom节点数组 33 } 34 }
再把原来的before,append函数扩展下:
1 function before(parent, before, elem) { 2 if(elem == null) { 3 elem = before; 4 before = parent; 5 parent = before.parentNode; 6 } 7 8 //得到新的元素数组 9 var elems = checkElem(elem); 10 11 //倒序遍历数组elems 12 for(var i = elems.length - 1; i >= 0; i--) 13 parent.insertBefore(elems[i], before); 14 } 15 16 function append(parent, elem) { 17 var elems = checkElem(elem); 18 19 for(var i = 0; i < elems.length; i++) 20 parent.appendChild(elems[i]); 21 }
然后我们就可以这样调用了append(first(tag('ul')[0]), '<li>Mouse trap.</li>');而之前第二个参数只能是个单独的节点(如<p>,<li>或者textNode);如此一来大大增强了可用性。
小结的第二部分就到这吧。。测试代码下载