JS學習11(DOM2&DOM3)

DOM1級主要是在定義HTML和XML文檔的低層結構。D2和D3則在這個結構的基礎上引入了更多的交互能力。它們被分為了許多模塊:

  • DOM Level 2 Core:為1級核心添加了更多方法和屬性
  • DOM Level 2 Views:為文檔定義了基于樣式信息的不同視圖
  • DOM Level 2 Events:說明了如何使用事件與DOM文檔交互
  • DOM Level 2 Style:有關CSS
  • DOM Level 2 Traversal and Range:遍歷和選擇的新API
  • DOM Level 2 HTML:添加了新方法和屬性的HTML

DOM變化

DOM2級核心沒有引進新類型,增強了既有類型。DOM3級核心既引進了新類型又增強了既有類型。
DOM Level 2 Views、DOM Level 2 HTML也提供了新的屬性和方法。
重點之一是對命名空間的支持。
看瀏覽器兼不兼容:

var supportsDOM2Core = document.implementation.hasFeature("Core", "2.0");  
var supportsDOM3Core = document.implementation.hasFeature("Core", "3.0"); 
var supportsDOM2HTML = document.implementation.hasFeature("HTML", "2.0"); 
var supportsDOM2Views = document.implementation.hasFeature("Views", "2.0"); 
var supportsDOM2XML = document.implementation.hasFeature("XML", "2.0"); 

針對 XML命名空間的變化

有了XML命名空間,不同XML文檔的元素就可以混合在一起。技術上說HTML不支持XML命名空間,但JSP,XHTML支持。
命名空間使用xmlns特性來指定。XHTML的命名空間是http://www.w3.org/1999/xhtml。

<html xmlns="http://www.w3.org/1999/xhtml">     
    <head>         
        <title>Example XHTML page</title>     
    </head>     
    <body>         
        Hello world!     
    </body> 
</html> 

在上面的例子中,所有元素都默認為XHTML命名空間的元素。想要明確的指定那些元素屬于這個命名空間就要使用前綴:

<xhtml:html xmlns:xhtml="http://www.w3.org/1999/xhtml">     
    <xhtml:head>         
        <xhtml:title>Example XHTML page</xhtml:title>     
    </xhtml:head>     
    <xhtml:body xhtml:class="home">         
        Hello world!     
    </xhtml:body> 
</xhtml:html> 

這時所有的XHTML元素的前綴都要是這個才行,有時為了避免沖突,也需要用命名空間來限定特性。這個在使用單一語言來編寫XML文檔時沒啥用,但是在多語言時就有用了:

<html xmlns="http://www.w3.org/1999/xhtml">     
    <head>         
        <title>Example XHTML page</title>     
    </head>     
    <body>        
        <svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 100 100" style="width:100%; height:100%">             
            <rect x="0" y="0" width="100" height="100" style="fill:red"/>         
        </svg>     
    </body> 
</html>  

<html xmlns="http://www.w3.org/1999/xhtml">     
    <head>         
        <title>Example XHTML page</title>     
    </head>     
    <body>         
        <s:svg xmlns:s="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 100 100" style="width:100%; height:100%">             
            <s:rect x="0" y="0" width="100" height="100" style="fill:red"/>         
        </s:svg>     
    </body> 
</html>  

這個例子中通過設置命名空間,將svg標識為了與包含文檔無關的元素。此時svg元素的所有子元素以及這些元素的所有特性都屬于了http://www.w3.org/2000/svg。所以即便這是一個XHTML文檔,其中的svg代碼還是有效的。
DOM2同時提供了相應的查詢和創建有命名空間歸屬的節點版本的方法。
Node類型的變化
在DOM2級中,node類型包含下列特定于命名空間的屬性。

  • localName:不帶命名空間前綴的節點名稱
  • namespaceURI:命名空間URI
  • prefix:命名空間前綴
    DOM3級中有如下方法:
  • isDefaultNamespace(namespaceURI):看看當前節點的默認命名空間是不是傳入的參數
  • lookupNamespaceURI(prefix):返回給定前綴的命名空間
  • lookupPrefix(namespaceURI):返回給定URI的前綴

這里有個神奇的事情:

//這里比較有趣,svg節點的defaultNameSpace不是我們給他設置的那個而是上一級的。
alert(svg.isDefaultNamespace("http://www.w3.org/1999/xhtml")); //true
alert(svg.isDefaultNamespace("http://www.w3.org/2000/svg")); //false

Document類型的變化
createElementNS(namespaceURI, tagName)
createAttributeNS(namespaceURI, attributeName)
getElementsByTagNameNS(namespaceURI, tagName)
Element類型的變化
getAttributeNS(namespaceURI,localName)
getAttributeNodeNS(namespaceURI,localName)
getElementsByTagNameNS(namespaceURI, tagName)
hasAttributeNS(namespaceURI,localName)
removeAttriubteNS(namespaceURI,localName)
setAttributeNS(namespaceURI,qualifiedName,value)
setAttributeNodeNS(attNode)
NamedNodeMap 類型的變化
getNamedItemNS(namespaceURI,localName)
removeNamedItemNS(namespaceURI,localName)
setNamedItemNS(node)

其他方面變化

DocumentType
新增3個屬性publicId、systemId、internalSubset
Document類型的變化
importNode()
這個方法用于導入一個來自其他文檔的節點appendChild()如果加入一個來自其他文檔的節點會報錯。這個方法會把別的文檔的節點轉化成本文檔的。這個方法有點像cloneCode(),都是接收一個節點和一個布爾值,返回淺復制或深復制的節點,只不過這個節點的ownerDocument會被重置。

var newNode = document.importNode(oldNode, true); 
document.body.appendChild(newNode);

defaultView
這個指針指向擁有給定文檔的窗口或框架,View。IE不支持,I使用parentWindow,所以要是想判斷文檔歸屬的窗口:

var parentWindow = document.defaultView || document.parentWindow;

createDocumentType()、createDocument()
document.implementation的方法,Core。創建一個DocumentType、創建一個新文檔

//新建一個XHTML文檔
var doctype = document.implementation.createDocumentType("html", 
                    " -//W3C//DTD XHTML 1.0 Strict//EN",
                    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd");
var doc = document.implementation.createDocument("http://www.w3.org/1999/xhtml", "html", doctype);

createHTMLDocument()
用來創建一個完整的HTML文檔,包括html,head,body,title。接收的字符串參數會放到title里。HTML
Node類型的變化
isSupported()
當前節點具有的能力

if (document.body.isSupported("HTML", "2.0")){ 
}

isSameNode()、isEqualNode()
DOM3
isSameNode()代表兩個節點引用同一個對象。
isEqualNode()代表兩個節點類型相同,屬性相同,屬性值相等。

//相等,不相同的兩個節點
var div1 = document.createElement("div"); 
div1.setAttribute("class", "box");
var div2 = document.createElement("div");
div2.setAttribute("class", "box");
alert(div1.isSameNode(div1)); //true 
alert(div1.isEqualNode(div2)); //true 
alert(div1.isSameNode(div2)); //false

setUserData()
這個方法比較神奇,可以為節點額外添加數據,3個參數:鍵,值,處理函數。這個處理函數會在節點被復制,導入新文檔,刪除,重命名時被調用。這個函數接受5個參數:操作類型(1、2、3、4),數據鍵、數據值、源節點、目標節點。

/***********************Node類型的新方法:setUserData(),不過Safari和chrome都不支持貌似********/
var div = document.createElement("div");
div.setUserData("name", "Nicholas", function(operation, key, value, src, dest){
    if (operation == 1){
        dest.setUserData(key, value, function(){});
    }
});
var newDiv = div.cloneNode(true);
alert(newDiv.getUserData("name"));      //"Nicholas"

框架的變化
框架和內嵌框架HTMLFrameElement、HTMLIFrameElement。這兩個類型有新屬性contentDocument。指向表示框架內容的文檔對象。
在此之前無法通過元素獲得這個對象,這個對象是Document類型的。IE8之前不支持,可以使用contentWindow。contentWindow所有瀏覽器都支持。

var iframe = document.getElementById("myIframe");
var iframeDoc = iframe.contentDocument || iframe.contentWindow.document;

樣式

要支持DOM2級CSS

var supportsDOM2CSS = document.implementation.hasFeature("CSS", "2.0"); 
var supportsDOM2CSS2 = document.implementation.hasFeature("CSS2", "2.0");

訪問元素的樣式

任何支持style特性的HTML元素在JS中都有一個對應的style屬性。它是CSSStyleDeclaration的實例,這里包含通過HTML的style特性指定的所有樣式信息,但不包含外部與內嵌樣式表的樣式。樣式通過屬性訪問,駝峰命名。

var myDiv = document.getElementById("myDiv");
myDiv.style.backgroundColor = "red";
myDiv.style.width = "100px";
myDiv.style.height = "200px";
myDiv.style.border = "1px solid black";

DOM樣式屬性和方法
屬性和方法用來訪問和修改樣式。

  • ? cssText:訪問CSS中的特性代碼,設置時覆蓋原來的。
  • length:CSS屬性的數量
  • parentRule:CSSRule對象
  • getPropertyCSSValue(propertyName):給定屬性的CSSValue
  • getPropertyPriority(propertyName):如果給定屬性有!important則返回"important",否則空字符串。
  • getPropertyValue(propertyName):給定屬性值 ?
  • item(index):給定位置的CSS屬性名稱
  • removeProperty(propertyName):從樣式表中刪除給定屬性
  • setProperty(propertyName,value,priority):為給定屬性設置值和優先級。
var prop, value, i, len;  
for (i=0, len=myDiv.style.length; i < len; i++){     
    prop = myDiv.style[i];  //myDiv.style.item(i)     
    value = myDiv.style.getPropertyValue(prop);     
    alert(prop + " : " + value); 
}

計算的樣式
style只包含直接寫在HTML里的特性,但是不支持樣式表的。這是個大問題。
document.defaultView.getComputedStyle()
這個方法接收兩個參數,要取得計算樣式的元素和一個偽元素字符串。返回一個CSSStyleDeclaration。包含所有計算后的屬性。
IE不支持,但是IE每個節點都有一個currentStyle屬性,這里包含了計算后的屬性。
計算后樣式只讀。

var myDiv = document.getElementById("myDiv");
var computedStyle = document.defaultView.getComputedStyle(myDiv, null);
//IE不支持,使用currentStyle
//var computedStyle = myDiv.currentStyle;
alert(computedStyle.height);    // "200px" 

操作樣式表

CSSStyleSheet類型表示樣式表,繼承自StyleSheet,后者可以作為一個基礎接口來定義非CSS樣式表。CSSStyleSheet繼承了如下屬性。

  • disabled:樣式表是否被禁用
  • href:樣式表的URL
  • media:樣式表支持的媒體類型集合
  • ownerNode:指向擁有當前樣式表節點的指針,IE不支持
  • parentStyleSheet:當前樣式表通過@import導入的情況下,這個屬性指向導入它的樣式表
  • title:ownerNode中title的值
  • type:表示樣式表類型的字符串
  • cssRules:樣式表中包含的樣式規則的集合,IE使用rules
  • ownerRule:當前樣式表通過@import導入的情況下,指向表示導入的規則,IE不支持
  • deleteRule(index):刪除cssRules集合中指定位置的規則,IE使用removeRule()
  • insertRule(rule,index):向cssRules集合中指定位置插入rule字符串,IE使用addRule()

應用于文檔的所有樣式通過document.styleSheets集合來表示。

var sheet = null;
for (var i=0, len=document.styleSheets.length; i < len; i++){
    sheet = document.styleSheets[i];
    alert(sheet.href);
}

直接通過link,style元素取得CSSStyleSheet。

function getStyleSheet(element){
    return element.sheet || element.styleSheet;
}
var link = document.getElementsByTagName("link")[0]; 
var sheet = getStyleSheet(link);
alert(sheet.href);

CSSRule對象
這個對象表示樣式表中的每一條規則。它是一個基類,不止是CSS規則,包括@import、@font-face、@page、@charset等。不過其中最常用的當然是CSS規則咯,是CSSStyleRule類型,有下面這些屬性:

  • cssText:文本咯,只讀的,包括選擇符,花括號等等一整套
  • parentRule:如果當前規則是導入的規則,這個屬性引用導入規則,否則為null
  • parentStyleSheet:規則所歸屬的樣式表
  • selectorText:規則的選擇符文本
  • style:CSSStyleDeclaration 對象,通過這個可以設置和取得規則中的樣式值
  • type:規則類型的常量值
var sheet = document.styleSheets[0]; //取得樣式表
var rules = sheet.cssRules || sheet.rules;   //為兼容IE
var rule = rules[0];                      
alert(rule.selectorText);
alert(rule.cssText);
alert(rule.style.cssText);
alert(rule.style.height);
//這里的修改并不成功????
rule.style.height = "2000ps";
alert(rule.style.height);

創建規則

//添加規則
function insertRule(sheet, selectorText, cssText, position){     
    if (sheet.insertRule){         
        sheet.insertRule(selectorText + "{" + cssText + "}", position);     
    } else if (sheet.addRule){         
        sheet.addRule(selectorText, cssText, position);     
    } 
} 

刪除規則

//刪除規則
function deleteRule(sheet, index){     
    if (sheet.deleteRule){         
        sheet.deleteRule(index);     
    } else if (sheet.removeRule){         
        sheet.removeRule(index);     
    } 
} 

元素尺寸大小

偏移量
元素的可見大小由其內容,內邊距,滾動條和邊框大小決定,并不包括外邊距。有下面4個屬性:

  • offsetHeight
  • offsetWidth
  • offsetLeft
  • offsetTop

其中offsetLeft和offsetTop是相對包含它的元素而言的。包含元素的引用保存在offsetParent中,這個并不一定是元素的父節點,而是父節點中第一個有大小的元素,比如td的就是table而不是tbody。
由于這里的偏移都是基于父元素的,想要獲得絕對偏移就需要迭代父元素。
偏移量屬性只讀,每次讀取時是現計算的。代價比較大,最好保存起來用。

//獲得元素絕對上偏移
function getElementTop(element){     
    var actualTop = element.offsetTop;     
    var current = element.offsetParent;
    while (current !== null){                 
        actualTop += current. offsetTop;         
        current = current.offsetParent;     
    }
    return actualTop; 
}

客戶區大小
clientWidth、clientHeight包括內邊距和內容
滾動大小

  • scrollHeight:元素內容真正的高度
  • scrollWidth:真正的寬度
  • scrollLeft:被隱藏的內容區域左側的像素數
  • scrollTop:頂部的

scrollLeft和scrollTop都可以設置,用來自動滾動元素。
確定元素大小
每個元素有個方法:getBoundingClientRect()
這個方法返回一個矩形對象,包含 4個屬性left,top,right,bottom。不過有個小問題,IE8及以前的版本會認為文檔左上角的坐標是(2,2),其他的都是正常的(0,0)。
還有就是有的老瀏覽器可能不支持這個方法,使用之前的getElementLeft()函數得到left,再加加offsetWidth得到right。

function getBoundingClientRect(element){
    var scrollTop = document.documentElement.scrollTop;
    var scrollLeft = document.documentElement.scrollLeft;
    //在支持getBoundingClientRect方法的情況下
    if (element.getBoundingClientRect){
        //這里利用了函數自身的屬性,如果這個函數剛才已經執行過了。arguments.callee.offset就已經存在了
        //就說明這個瀏覽器的調整量已經設置過了,直接使用就好了。就不必執行下面這個開銷比較大的代碼塊了
        if (typeof arguments.callee.offset != "number"){
            //利用一個新元素,將他設置在瀏覽器的左上角,再獲取它的top值
            //看看這個瀏覽器的偏差是多少,反向減掉
            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
        };
    //在支持getBoundingClientRect方法的情況下,使用之前的getElementLeft()函數得到left,再加加offsetWidth得到right
    //這個方法可能不太準確,不過誰叫你不支持getBoundingClientRect的
    } 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 rect = getBoundingClientRect(document.getElementById("myDiv"));
alert(rect.bottom);
alert(rect.top);
alert(rect.left);
alert(rect.right);

遍歷

DOM2級遍歷和范圍模塊定義了兩個用于輔助完成順序遍歷DOM結構的類型。NodeIterator和TreeWalker。這兩個類型能夠基于給定的節點進行深度優先遍歷。IE不支持。
檢測兼容:

var supportsTraversals = document.implementation.hasFeature("Traversal", "2.0"); 
var supportsNodeIterator = (typeof document.createNodeIterator == "function"); 
var supportsTreeWalker = (typeof document.createTreeWalker == "function"); 

NodeIterator

document.createNodeIterator()來創建,這個方法有4個參數:

  • root:搜索起點
  • whatToShow:要遍歷那些類型的節點 ?
  • filter:NodeFilter對象,或者表示接受還是拒絕某種節點的函數
  • entityReferenceExpansion:在HTML中沒啥用

whatToShow通過應用一個或多個過濾器來確定要訪問哪些節點。位掩碼。

  • NodeFilter.SHOW_ALL
  • NodeFilter.SHOW_ELEMENT
  • NodeFilter.SHOW_ATTRIBUTE
  • NodeFilter.SHOW_TEXT
  • NodeFilter.SHOW_CDATA_SECTION
  • NodeFilter.SHOW_ENTITY_REFERENCE
  • NodeFilter.SHOW_ENTITYE
  • NodeFilter.SHOW_PROCESSING_INSTRUCTION
  • NodeFilter.SHOW_COMMENT
  • NodeFilter.SHOW_DOCUMENT
  • NodeFilter.SHOW_DOCUMENT_TYPE
  • NodeFilter.SHOW_DOCUMENT_FRAGMENT
  • NodeFilter.SHOW_NOTATION
var whatToShow = NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_TEXT; 
var filter = {
    acceptNode: function(node){
        return node.tagName.toLowerCase() == "p" ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP;
    }
};
//直接定義函數也行
// var filter = function(node){
//     return node.tagName.toLowerCase() == "p" ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP;
// };
var iterator = document.createNodeIterator(document.documentElement, NodeFilter.SHOW_ELEMENT, filter, false);
//或者遍歷所有節點
iterator = document.createNodeIterator(document, NodeFilter.SHOW_ALL, null, false); 
var node = iterator.nextNode();
while (node !== null) {
    alert(node.tagName);
    node = iterator.nextNode();
}

NodeIterator的兩個方法是nextNode()和previousNode(),在遍歷到頭的時候,這兩個方法返回null。

TreeWalker

TreeWalker是高級的NodeIterator:

  • parentNode() ?
  • firstChild() ?
  • lastChild() ?
  • nextSibling() ?
  • previousSibling()
  • nextNode()
  • previousNode()

創建和NodeIterator接受一樣的參數,不過過濾器在這里有些不同,有3種返回值:NodeFilter.FILTER_SKIP、NodeFilter.FILTER_REJECT、NodeFilter.FILTER_ACCEPT。reject會跳過該節點及其子樹,skip就單單跳過這個節點。

var walker = document.createTreeWalker(document.documentElement, NodeFilter.SHOW_ELEMENT, null, false);
walker.firstChild();
walker.nextSibling();
var node = walker.firstChild();
while (node !== null) {
    alert(node.tagName);
    node = walker.nextSibling();
}

它還有一個currentNode屬性,表示上一次遍歷的節點,這個屬性可以設置,就改變了繼續遍歷的起點。
IE啥都不支持

范圍

范圍用來選擇文檔中的一個區域而不必考慮節點的界限。在常規的DOM操作不能更有效的修改文檔時,范圍往往可以實現目的。除IE外都支持,IE8及以前有自己的實現方式。

DOM中的范圍(除IE8及以下瀏覽器外支持的范圍)

使用createRange()方法創建DOM范圍。新創建的范圍與創建它的文檔相關聯,不能用于其它文檔。在創建了范圍并設置了其位置之后,可以針對范圍的內容實現多種操作,從而實現對底層DOM樹的更精細的控制。
每個范圍由一個Range類型的實例表示,這個實例由很多屬性和方法,下列屬性提供了當前范圍在文檔中的位置信息。

  • startContainer:包含范圍起點的節點,也就是選區中第一個節點的父節點
  • startOffset:范圍在startContainer中起點的偏移量。如果startContainer是文本節點、注釋節點或CDATA節點,那么startOffset就是范圍起點之前跳過的字符數量。否則就是范圍中第一個子節點在父節點(startContainer)中的索引
  • endContainer:包含范圍終點的節點
  • endOffset:范圍在endContainer中終點的偏移量
  • commonAncestorContainer:startContainer和endContainer共同的祖先節點在文檔樹中位置最深的那個

用DOM范圍實現簡單選擇
selectNode()、selectNodeContents()
這兩個方法都接受一個DOM節點作為參數,然后使用該節點中的信息來填充范圍,selectNode()選擇整個節點包括子節點;selectNodeContents()只選擇節點的子節點。

<body>
    <div id="myDiv" data-appId="12345" data-myname="Nicholas">
        哈哈哈我在div里
        <span>測試Span</span>
        <a>我是一個a標簽~~~~~</a>
    </div>
</body>
var range1 = document.createRange();
var range2 = document.createRange();
var div = document.getElementById("myDiv");
range1.selectNode(div);
range2.selectNodeContents(div);
alert(range1.startContainer.tagName); //body
alert(range1.endContainer.tagName); //body
alert(range1.commonAncestorContainer.tagName); //body
alert(range1.startOffset); //這個div在body中的索引哦,1
alert(range1.endOffset); //startOffset+1,因為只選擇了一個節點
alert(range2.startContainer.tagName); //div
alert(range2.endContainer.tagName); //div
alert(range2.commonAncestorContainer.tagName); //div
alert(range2.startOffset); //永遠都是0
alert(range2.endOffset); //子節點數目

如果想要更精細的控制,有下面這些方法:

  • setStartBefore(refNode):將范圍起點設置在refNode之前,refNode就成為了范圍中第一個節點。startContainer會被設為refNode.parentNode,startOffset會被設成refNode在其父節點childNodes中的索引。
  • setStartAfter(refNode)
  • setEndBefore(refNode)
  • setEndAfter(refNode)

用DOM范圍實現復雜選擇
setStart()和setEnd()
這兩個方法接受兩個參數:一個參照節點和一個偏移量值。setStart()的參照節點會變成startContainer,偏移量會變成startOffset;setEnd()同理。

var div = document.getElementById("myDiv");
var textNode = div.childNodes[1].firstChild;
var worldNode = div.lastChild;
var range = document.createRange();
range.setStart(textNode, 4);
range.setEnd(worldNode, 0);
alert(range);  //an /n 我是一個a標簽~~~~~

操作DOM范圍中的內容
創建范圍時,內部會為這個范圍創建一個文檔片段,范圍所屬的所有節點都會被添加到這個文檔片段中,為了創建這個文檔片段,范圍的格式必須正確有效,這就意味著要有正確的DOM結構,但是像我們剛才那樣選擇,起始和結束都在一個節點的內部,這樣的DOM結構并不正確。不過范圍知道自己缺少哪些標簽,并重新構建有效的DOM結構。不過在你真正對DOM做出修改之前,范圍是不會修改DOM結構的,也確實沒必要。
在創建了范圍之后,就可以使用各種方法對范圍的內容進行操了,表示范圍的內部文檔片段中所有節點都只是指向文檔中相應節點的指針。

  • deleteContents():刪除范圍中所包含的內容。
  • extractContents():同樣是刪除,只不過會返回范圍的文檔片段。可以將其插入其他地方。
  • cloneContents():復制內容
var fragment = range.extractContents();
document.getElementById("myButton").parentNode.appendChild(fragment);

插入DOM范圍中的內容
對于這里的方法要注意,范圍并不會在使用這里的方法的時候自動創建有效的DOM結構,這對insertNode()的影響不大,但是對 surroundContents()就有影響了,因為這很可能出現錯亂的DOM結構。
insertNode()方法在范圍選區的開始插入一個節點

var span = document.createElement("span");
span.style.color = "red";
span.appendChild(document.createTextNode("Inserted text"));
range.insertNode(span);

surroundContents()環繞范圍插入節點,后臺會做這些事情:

  1. 提取范圍中的內容
  2. 將給定節點插入到文檔中原來范圍所在位置
  3. 將文檔片段內容添加到給定節點中

如果你選中的是像之前那樣不完整的DOM節點。。。那這里就會添加失敗。。。這里范圍不會自己創建有意義的DOM結構

var div = document.getElementById("myDiv");
var textNode = div.childNodes[1].firstChild;
var range = document.createRange();
range.selectNode(textNode);
var span = document.createElement("span");
span.style.backgroundColor = "yellow";
range.surroundContents(span);
alert(range);

折疊DOM范圍
collapse()
折疊后的范圍不選擇文檔的任何部位,傳入true可以折疊到范圍起始位置,false折疊到范圍結束位置。通過范圍的collapsed可以檢測是否折疊,這個屬性就是檢測范圍的起始和結尾是不是同一個位置,如果是,就算不是使用collapse()折疊的也會返回true。這個可以用來檢測范圍是不是空的。
比較DOM范圍
compareBoundaryPoints()
比較兩個范圍是否有公共起點和終點

alert(range1.compareBoundaryPoints(Range.START_TO_START, range2)); 

Range.START_TO_START(0) ?比較起點
Range.START_TO_END(1) ? 第一個的起點和第二個的終點
Range.END_TO_END(2) ?
Range.END_TO_START(3)

第一個點在第二個前面-1,相等0,后面1。
復制DOM范圍

var newRange = range.cloneRange(); 

清理DOM范圍

range.detach();      //從文檔中分離
range = null;        //解除引用 

IE8及更早版本中的范圍

IE8以及之前的版本不支持DOM范圍,但是支持一種文本范圍。
可以在文檔和元素上創建文本范圍,在元素上創建的文本范圍只能在本元素內使用。

var range = document.body.createTextRange();  

簡單選擇
findText()接收一個字符串,可選的傳入方向值,返回一個布爾
這個方法會找到第一次出現的給定文本,并將范圍移過來環繞該文本。

var range = document.body.createTextRange();
var found = range.findText("我是");
var foundAgain = range.findText("我是", 1);
alert(found);           //true 
alert(range.text);
alert(foundAgain);
alert(range.text);

moveToElementText()接收一個節點,并選擇這個節點所有的文本,如果這個元素里有HTML標簽,使用htmlText屬性可以同時獲取到標簽和文本。

range.moveToElementText(div);
alert(range.text);
alert(range.htmlText);

parentElement()可以得到選區的父節點
復雜選擇
move()、moveStart()、moveEnd()、expand()
這些方法都接收兩個參數,移動單位和移動單位的數量,移動單位是字符串:"character"、? "word"、? "sentence"、"textedit"。
expand("word")會將現有的選區里單詞不全的選全。
move會先折疊選區,再將范圍移動指定的單位數量。然后再moveStart()、moveEnd()手動展開選區。
操作內容

range.text = "Howdy";
range.pasteHTML("<em>Howdy</em>");

折疊范圍
collapse()
這個倒是和DOM范圍一樣。不過檢測時要使用boundingWidth、boundingHeight、boundingLeft、boundingTop這些是范圍的尺寸信息,以像素為單位,boundingWidth為0就代表范圍折疊了。
比較范圍
compareEndPoints()
這個是差不多的方法,"StartToStart""StartToEnd""EndToEnd""EndToStart"

range1.compareEndPoints("StartToStart", range2)

還有兩個特別的方法:

range1.isEqual(range2)
range1.inRange(range2)

復制IE范圍

var newRange = range.duplicate(); 
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,237評論 6 537
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,957評論 3 423
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 177,248評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,356評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,081評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,485評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,534評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,720評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,263評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,025評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,204評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,787評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,461評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,874評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,105評論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,945評論 3 395
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,205評論 2 375

推薦閱讀更多精彩內容