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阅读 159,569评论 4 363
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,499评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,271评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,087评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,474评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,670评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,911评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,636评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,397评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,607评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,093评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,418评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,074评论 3 237
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,092评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,865评论 0 196
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,726评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,627评论 2 270

推荐阅读更多精彩内容