JavaScript DOM 编程之高级篇

1.样式
    ①判断是否支持css2样式   document.implementation.hasFeature("CSS2", "2.0");
    ②访问元素之间的样式
        a.DOM样式属性和方法
        eg:设置和获取元素的样式
            var div = document.createElement("div");
            div.style.width = "100px";
            div.style.height = "100px";
            div.style.backgroundColor = "red";
            document.body.appendChild(div);
            for( var i = 0, len = div.style.length; i < len; i++) {
                pro = div.style[i];
                alert( pro + " = " + div.style.getPropertyValue(pro)); // 获取各个属性与值的键值对
            }
            // 获取计算的样式
            var computedStyle = document.defaultView.getComputedStyle(div, null) || div.currentStyle;
            alert(computedStyle.width);
            alert(computedStyle.height);
            alert(computedStyle.backgroundColor);
            alert(computedStyle.border);
        b.计算样式(只读)  值从其他样式表折叠影响当前元素样式信息
    ③操作样式表      
        a.可以通过两种方法获取css样式表
        eg: HTML部分:<link rel="stylesheet" type="text/css" href="css/example1.css"/>
            JS部分:
                    // 1.用styleSheets集合
                    var links = document.styleSheets;
                    for(var i = 0, len = links.length; i < len; i++) {
                        alert(links[i].href); 
                    }
                    // 2.先获取link元素,在调用其的sheet||styleSheet属性
                    function getStyleSheet(ele) {
                        return ele.sheet || ele.styleSheet;
                    }
                    var links = document.querySelectorAll("link");
                    for(var i = 0, len = links.length; i < len; i++) {
                        var sheets = getStyleSheet(links[i]);
                        alert(sheets.href);
                    }
        b.CSS规则 获取、创建、删除规则
            eg : 对样式规则进行读取、插入和删除
                HTML/CSS部分:
                    <div></div>
                    div {
                        width : 100px;
                        height : 100px;
                        background : red;
                        border : 1px solid black;
                    }
                JS部分:
                    var styleRule = {
                        // 获取样式规则
                        get : function () { // 这个方法定义的不妥
                            var sheet = document.styleSheets[0]; // 获取第一个样式表
                            var rules = sheet.cssRules || sheet.rules; // 样式规则
                            return rules; // 返回所有样式规则的集合
                        },
                        /**创建样式规则 * param sheet : 样式表 * param selectorText : 选择器 * param cssText : css代码 * param position : 插入规则的位置 */
                        insert : function (sheet, selectorText, cssText, position){
                            if (sheet.insertRule){
                                sheet.insertRule(selectorText + "{" + cssText + "}", position);
                            } else if (sheet.addRule){
                                sheet.addRule(selectorText, cssText, position);
                            }
                        },
                        /**删除样式规则 * param sheet : 样式表 * param index : 要删除规则的位置 */
                        remove : function (sheet, index){
                            if (sheet.deleteRule){
                                sheet.deleteRule(index);
                            } else if (sheet.removeRule){
                                sheet.removeRule(index);
                            }
                        }
                    };
                    // 获取div的css代码
                    // var divCSS = styleRule.get()[0];
                    // alert(divCSS.cssText); // 返回第一条规则的所有css代码
                    // alert(divCSS.style.width); // 返回单个属性值
                    // 重设body与div的样式
                    styleRule.insert(document.styleSheets[0], "body", "background : green", 0); // 第一条规则
                    styleRule.insert(document.styleSheets[0], "div", "background : pink", 2); // 第二条规则
                    // 删除body的样式
                    styleRule.remove(document.styleSheets[0], 0);
    ④元素大小
        a.偏移量
            1) offsetHeight : 元素在垂直方向占用的空间大小。
                    offsetHeight = height + padding + border + 滚动条
            2) offsetWidth : 元素在水平方向占用的空间大小。
                    offsetHeight = width + padding + border + 滚动条
            3) offsetTop : 元素的上外边框至包含元素的上内边框之间的像素距离
            4) offsetLeft : 元素的左外边框至包含元素的左内边框之间的像素距离
            5) offsetParent : 表示包含元素的元素
            eg : 获取某个元素在页面上的偏移量
                function getElementLeft(element){
                    var actualLeft = element.offsetLeft; // 获取offsetLeft
                    var current = element.offsetParent; // 获取包含元素,父元素
                    while (current !== null){               // 如果父元素不存在
                        actualLeft += current.offsetLeft;
                        current = current.offsetParent;
                    }
                    return actualLeft;
                }
                function getElementTop(element){
                    var actualTop = element.offsetTop;
                    var current = element.offsetParent;
                    while (current !== null){
                        actualTop += current. offsetTop;
                        current = current.offsetParent;
                    }
                    return actualTop;
                }
        b.客户端大小
            1) clientHeight = height + padding-top + padding-bottom
            2) clientWidth = width + padding-left + padding-right
                eg: 获取视口大小
                    function getViewport(){
                        if (document.compatMode == "BackCompat"){   // ie7的混杂模式
                            return {
                                width: document.body.clientWidth,
                                height: document.body.clientHeight
                            };
                        } else {
                            return {
                                width: document.documentElement.clientWidth,
                                height: document.documentElement.clientHeight
                            };
                        }
                    }
        c.滚动大小
            1) scrollHeight:在没有滚动条的情况下,元素内容的总高度。
            2) scrollWidth:在没有滚动条的情况下,元素内容的总宽度。
            3) scrollLeft:被隐藏在内容区域左侧的像素数
            4) scrollTop:被隐藏在内容区域上方的像素数
        d.确定元素的大小
            eg : 跨浏览器使用自身的属性offset来判断是否要对坐标进行调整
            function getBoundingClientRect(element){
                var scrollTop = document.documentElement.scrollTop;
                var scrollLeft = document.documentElement.scrollLeft;
                if (element.getBoundingClientRect){
                    if (typeof arguments.callee.offset != "number"){
                        var temp = document.createElement("div");
                        temp.style.cssText = "position:absolute;left:0;top:0;";
                        document.body.appendChild(temp);
                        arguments.callee.offset = -temp.getBoundingClientRect().top - scrollTop;
                        document.body.removeChild(temp);
                        temp = null;
                    }
                    var rect = element.getBoundingClientRect();
                    var offset = arguments.callee.offset;
                    return {
                        left: rect.left + offset,
                        right: rect.right + offset,
                        top: rect.top + offset,
                        bottom: rect.bottom + offset
                    };
                } else {
                    var actualLeft = getElementLeft(element);
                    var actualTop = getElementTop(element);
                    return {
                        left: actualLeft - scrollLeft,
                        right: actualLeft + element.offsetWidth - scrollLeft,
                        top: actualTop - scrollTop,
                        bottom: actualTop + element.offsetHeight - scrollTop
                    }
                }
            }
            var div = document.querySelector("div");
            var rect = getBoundingClientRect(div); 
3.遍历
    1.NodeIterator
        eg: 遍历元素,过滤出自己想要的元素
        HTML部分:
            <div id="div1">
                <p><b>Hello</b> world!</p>
                <ul>
                    <li>List item 1</li>
                    <li>List item 2</li>
                    <li>List item 3</li>
                </ul>
            </div>
        JS部分:
            var div = document.getElementById("div1");
            var filter = function(node){    // 只考虑li元素
                    return node.tagName.toLowerCase() == "li" ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP;
                };
            var iterator = document.createNodeIterator(div, NodeFilter.SHOW_ELEMENT, filter, false);
            var node = iterator.nextNode();
            while (node !== null) {
                alert(node.tagName); //输出标签名 LI,LI,LI
                node = iterator.nextNode(); 
            }
    2.TreeWalker
        它除了包含NodeIterator类型的方法属性外,还具有以下属性方法:
            ①parentNode():遍历到当前节点的父节点;
            ②firstChild():遍历到当前节点的第一个子节点;
            ③lastChild():遍历到当前节点的最后一个子节点;
            ④nextSibling():遍历到当前节点的下一个同辈节点;
            ⑤previousSibling():遍历到当前节点的上一个同辈节点。
            eg: 
            HTML: 上述一致
            JS部分:
            var div = document.getElementById("div1");
            var walker = document.createTreeWalker(div, NodeFilter.SHOW_ELEMENT, null, false);
            walker.firstChild(); //转到<p>
            walker.nextSibling(); //转到<ul>
            var node = walker.firstChild(); //转到第一个<li>
            while (node !== null) {
                alert(node.tagName);
                node = walker.nextSibling();
            }
4.范围    通过范围接口可以选取一个区域
    ①判断浏览器是否支持范围操作
        alert(document.implementation.hasFeature("Rang", "2.0"));
        alert(typeof document.createRange == "function");
    ②DOM中操作范围
        a.可以通过document.createRange来创建一个范围,它包括以下的属性:
            1) startContainer:包含范围起点的节点(即选区中第一个节点的父节点)
            2) startOffset:范围在startContainer 中起点的偏移量。
            3) endContainer:包含范围终点的节点(即选区中最后一个节点的父节点)
            4) endOffset:范围在endContainer 中终点的偏移量
            5) commonAncestorContainer:startContainer 和endContainer 共同的祖先节点在文档树中位置最深的那个。
        b.用DOM范围实现简单选择,可以用selectNode()和selectNodeContents(),前者包含自己,后者只包括子孙节点
            eg:<div><p id="p1"><b>Hello</b> world!</p></div>
                var range1 = document.createRange();// range: <p id="p1"><b>Hello</b> world!</p>
                range2 = document.createRange(); // range: <b>Hello</b> world!
                p1 = document.getElementById("p1");
                range1.selectNode(p1); 
                range2.selectNodeContents(p1);
            分析:上述例子中,在调用selectNode时,startContainerendContainer和commonAncestorContainer
            都是div,而startOffset是body下的一个元素的索引,即0,endOffset是p标签加1,即1
            在调用selectNodeContents时,startContainer endContainer和commonAncestorContainer都是p,
            而startOffset是在p元素下的第一元素为0,而endOffset等于p下的元素的数量为2.
        c.另外还有一些方法,可以更精确的控制元素的范围
            1) setStartBefore(refNode):将范围的起点设置在refNode 之前,因此refNode 也就是范围
                选区中的第一个子节点。同时会将startContainer 属性设置为refNode.parentNode,将
                startOffset 属性设置为refNode 在其父节点的childNodes 集合中的索引。
        2) setStartAfter(refNode):将范围的起点设置在refNode 之后,因此refNode 也就不在范
                围之内了,其下一个同辈节点才是范围选区中的第一个子节点。同时会将startContainer 属
                性设置为refNode.parentNode,将startOffset 属性设置为refNode 在其父节点的
                childNodes 集合中的索引加13) setEndBefore(refNode):将范围的终点设置在refNode 之前,因此refNode 也就不在范围
                之内了,其上一个同辈节点才是范围选区中的最后一个子节点。同时会将endContainer 属性
                设置为refNode.parentNode,将endOffset 属性设置为refNode 在其父节点的childNodes
                集合中的索引。
            4) setEndAfter(refNode):将范围的终点设置在refNode 之后,因此refNode 也就是范围选区
                中的最后一个子节点。同时会将endContainer 属性设置为refNode.parentNode,将
                endOffset 属性设置为refNode 在其父节点的childNodes 集合中的索引加1。
        d.要实现更复杂的范围选取操作,必须用到setStart和setEnd方法,并接受两个参数,第一个表示参照节点,第二个为偏移量;对于setStart而言,参照节点就是startContainer,而偏移量则是startOffset;对于setEnd而言,参照节点就是endContainer,而偏移量则是endOffset
            eg:我们用setStart和setEnd方法,来模拟selectNode和selectNodeContents方法
                var range1 = document.createRange(),
                    range2 = document.createRange(),
                    p1 = document.getElementById("p1"),
                    p1Index = -1;
                    i, len;
                for (i=0, len=p1.parentNode.childNodes.length; i < len; i++) {
                    if (p1.parentNode.childNodes[i] == p1) {
                        p1Index = i;
                        break;
                    }
                }
                range1.setStart(p1.parentNode, p1Index);
                range1.setEnd(p1.parentNode, p1Index + 1);
                range2.setStart(p1, 0);
                range2.setEnd(p1, p1.childNodes.length);
                // 同样我们还可以选取hello中的llo到world中的o为止的字符,即llo wo这6个字符
                var hello = p.firstChild.firstChild;
                var world = p.lastChild;
                rang1.setStart(hello, 2); // llo
                range1.setEnd(world, 3); // wor 
        e.操作DOM范围中的内容
            1)第一个方法:deleteContents表示将选取范围的内容从原有的元素内容中删除,并返回之后剩下的元素
                rang1.setStart(hello, 2); // llo
                range1.setEnd(world, 3); // wor
                range.deleteContents(); // 剩下的元素为:<p><b>He</b>rld!</p>
            2) extractContents()会从文档中移除范围选区,且可以将范围的内容插入到文档中的其他地方。
                var fragment = range.extractContents();
                p1.parentNode.appendChild(fragment);// 将<b>llo</b>wor添加到<div>中去
            3) 还一种做法,即使用cloneContents()创建范围对象的一个副本,然后在文档的其他地方插入该副本
                var fragment = range.cloneContents();
                p1.parentNode.appendChild(fragment); // <p><b>Hello</b> world!</p><b>llo</b> wo
        f.插入DOM范围中的内容,用insertNode方法,将指定的节点添加到选取范围内容的最开始位置
            var span = document.createElement("span");
            span.style.color = "red";
            span.appendChild(document.createTextNode("Inserted text"));
            range.insertNode(span);
            结果:<p id="p1"><b>He<span style="color: red">Inserted text</span>llo</b> world</p>
        g.还可以环绕范围添加内容,用surroundContents,接受一个参数为环绕范围内容的节点,该操作执行以下骤:
            1) 提取出范围中的内容(类似执行extractContent());
            2) 将给定节点插入到文档中原来范围所在的位置上;
            3) 将文档片段的内容添加到给定节点中。
            range.selectNode(hello);
            var span = document.createElement("span");
            span.style.backgroundColor = "yellow";
            range.surroundContents(span);
            结果:<p><b><span style="background-color:yellow">Hello</span></b> world!</p>
        h.折叠DOM范围,是指范围未选取文档的任何部分的内容。使用collapse(布尔值),
          当为true表示折叠到开始,false表示折叠到结束位置,而属性collapsed表示是否折叠
            <p id="p1">Paragraph 1</p><p id="p2">Paragraph 2</p>
            var p1 = document.getElementById("p1"),
            p2 = document.getElementById("p2"),
            range = document.createRange();
            range.setStartAfter(p1);
            range.setStartBefore(p2);
            alert(range.collapsed); //输出true
        i.比较DOM范围,用比较点.compareBoundaryPoints(比较参数,参照点)来比较,当比较点位于参照点以前,
          返回-1;当相等返回0;当比较点在参照点之后,返回1;比较参数如下:
            1)Range.START_TO_START(0):比较第一个范围和第二个范围的起点;
            2)Range.START_TO_END(1):比较第一个范围的起点和第二个范围的终点;
            3)Range.END_TO_END(2):比较第一个范围和第二个范围的终点;
            4)Range.END_TO_START(3):比较第一个范围的终点和第一个范围的起点。
            eg: var range1 = document.createRange();
                var range2 = document.createRange();
                var p1 = document.getElementById("p1");
                range1.selectNodeContents(p1); // <b>Hello</b> world!
                range2.selectNodeContents(p1);
                range2.setEndBefore(p1.lastChild); // <b>Hello</b>
                alert(range1.compareBoundaryPoints(Range.START_TO_START, range2)); //0
                alert(range1.compareBoundaryPoints(Range.END_TO_END, range2)); //1
        j.复制DOM范围,用cloneRange()
        k.清除DOM范围,用detach()
            eg: range.detach(); //从文档中分离
                range = null; //解除引用
    ③Less IE8操作范围
        a.用IE范围实现简单的选择
            eg: <div><p id="p1"><b>Hello</b> world!</p></div>
                var range = document.body.createTextRange();
                var found = range.findText("Hello");
                alert(found); //true
                alert(range.text); //"Hello"
                // IE 中与DOM 中的selectNode()方法最接近的方法是moveToElementText()
                range.moveToElementText(p1);// 选取p1以及p1的子元素
                // parentElement()方法倒是与DOM 的commonAncestorContainer 属性类似
                var ancestor = range.parentElement(); // div
        b.使用IE范围实现复杂的选择
            move()、moveStart()、moveEnd()和expand()方法,接受两个参数,移动单位和移动单位的数量
            移动单位如下:
            1) "character":逐个字符地移动。
            2) "word":逐个单词(一系列非空格字符)地移动。
            3) "sentence":逐个句子(一系列以句号、问号或叹号结尾的字符)地移动。
            4) "textedit":移动到当前范围选区的开始或结束位置。
                range.moveStart("word", 2); //起点移动2 个单词
                range.moveEnd("character", 1); //终点移动1 个字符
                range.move("character", 5); //移动5 个字符
        c.操作IE范围中的内容。读取用findText(文本),修改用rang.text = value;要插入带html的文本用pasteHMTL
            var range = document.body.createTextRange();
            range.findText("Hello"); // 读取
            range.text = "Howdy"; // 修改
            range.pasteHTML("<em>Howdy</em>");// 插入带html的文本
        d.折叠IE范围。折叠ie的范围,也用collapse(布尔)值,但是判断需要用到boundingWidth == 0属性判断
            range.collapse(true); //折叠到起点
            var isCollapsed = (range.boundingWidth == 0);
        e.比较范围,用compareEndPoints()和isEqual()以及isRnage(),
            var range1 = document.body.createTextRange();
            var range2 = document.body.createTextRange();
            range1.findText("Hello world!");
            range2.findText("Hello");
            alert(range1.compareEndPoints("StartToStart", range2)); //0
            alert(range1.compareEndPoints("EndToEnd", range2)); //1
            alert("range1.isEqual(range2): " + range1.isEqual(range2)); //false
            alert("range1.inRange(range2):" + range1.inRange(range2)); //true
        f.复制IE范围。用duplicate复制范围节点
            var newRange = range.duplicate();// 新创建的范围会带有与原范围完全相同的属性。

你可能感兴趣的:(DOM样式操作,DOM高级篇,DOM元素大小,DOM遍历,DOM范围)