《精通javascript》5,6章小结(二)

  继续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);如此一来大大增强了可用性。

小结的第二部分就到这吧。。测试代码下载

原文地址:https://www.cnblogs.com/AndyWithPassion/p/professional_js.html