首页 > 代码库 > 第十一章:DOM扩展

第十一章:DOM扩展

  • DOM扩展
    • 选择符API
      • querySelector方法
      • querySelectorAll方法
      • matchesSelector方法
    • 元素遍历
    • HTML5
      • 与类相关的补充
        • getElementsByClassName 方法
        • classList属性
      • 焦点管理
      • HTMLDocument的变化
        • readyState 属性
        • 兼容模式
        • head属性
      • 字符集属性
      • 自定义数据属性
      • 插入标记
        • innerHTML 属性
        • outerHTML
        • inserAdjacentHTML 方法
        • 内存和性能问题
        • scrollIntoView 方法
    • 专用扩展
      • 文档模式
      • children属性
      • contains 方法
      • 插入文本
        • innerText 属性
        • outerText 属性
      • 滚动

DOM扩展

  • 尽管DOM作为API已经非常完善了,但为了实现更多的功能,仍然会有一些标准或专有的扩展。对DOM的主要两个扩展是Selectors API(选择符API)和HTML5

选择符API

  • 众多JavaScript库中最常用的一项功能,就是根据CSS选择符选择与某个模式匹配的DOM元素。实际上,jQuery的核心就是通过CSS选择符查询DOM文档取得元素的引用,从而抛开了getElementById和getElementsByTagName()。
  • Selectors API Level 1核心的两个方法是:querySelector()和querySelectorAll()。在兼容的浏览器中,可以通过Document和Element类型的实例调用他们。目前已经支持Selectors API Level 1的浏览器有IE 8+、Firefox 3.5+、Safari 3.1+、Chrome和Opera 10+。

querySelector()方法

  • querySelector()方法接收一个CSS选择符,返回与该模式匹配的第一个元素,如果没有找到匹配的元素,返回null
    if (document.querySelector){
        //get the body element
        var body = document.querySelector("body");
        alert(body.tagName);
        //get the element with the ID "myDiv"
        var myDiv = document.querySelector("#myDiv");
        alert(myDiv);
        //get first element with a class of "selected"
        var selected = document.querySelector(".selected");
        alert(selected.innerHTML);
        //get first image with class of "button"
        var img = document.body.querySelector("img.button");
        alert(img);
    } else {
        alert("Selectors API not supported in this browser");
    }
  • 通过Document类型调用querySelector()会查询文档下匹配的元素。通过Element类型调用querySelector()只会在该元素的后代元素范围内查询匹配的元素。如果传入了不被支持的选择符,该方法会报错。

querySelectorAll()方法

  • 通过名字就可以得知该方法和querySelector()方法的区别是该方法会返回一个NodeList对象。
    if (document.querySelectorAll){
        //get all <em> elements in a <div> (similar to getElementsByTagName("em"))
        var ems = document.getElementById("myDiv").querySelectorAll("em");
        alert(ems.length);
        //get all elements with class of "selected"
        var selecteds = document.querySelectorAll(".selected");
        alert(selecteds.length);
        //get all <strong> elements inside of <p> elements
        var strongs = document.querySelectorAll("p strong");
        alert(strongs.length);
    } else {
        alert("Selectors API not supported in this browser");
    }

matchesSelector()方法

  • Selector API Level 2规范为Element类型增加了一个新方法matchesSelector()。这个方法接收一个CSS选择符,如果调用元素与该选择符匹配,返回true;否则返回false。这个方法可以用来检测某元素是否会被上述两个方法返回。
  • 截至2011年年中,还没有浏览器支持matchesSelector()方法。不过,也有一些实验性的体现。IE9+中是msMatchesSelector(),Firefox 3.6+通过mozMatchesSelector(),Chrome和Safari 5+通过webkitMatchesSelector()支持该方法。
    function matchesSelector(element, selector){
        if (element.matchesSelector){
            return element.matchesSelector(selector);
        } else if (element.msMatchesSelector){
            return element.msMatchesSelector(selector);
        } else if (element.mozMatchesSelector){
            return element.mozMatchesSelector(selector);
        } else if (element.webkitMatchesSelector){
            return element.webkitMatchesSelector(selector);
        } else {
            throw new Error("Not supported.");
        }
    }
    if (matchesSelector(document.body, "body.page1")){
        alert("It‘s page 1!");
    }

元素遍历

  • 对于元素间的空格,IE9及之前的版本不会返回文本节点,而其他浏览器都会返回文本节点。这样就导致了在使用childNodes和firstChild等属性时的行为不一致。为了弥补这一差异,而同时又保持DOM规范不变,Element Traversal规范新定义了一组属性。
    1. childElementCount:返回子元素(不包括文本节点和注释)的个数。
    2. firstElementChild:指向第一个子元素(不包括文本节点和注释)。
    3. lastElementChild
    4. previousElementSibling:指向前一个同辈元素(不包括文本节点和注释)。
    5. nextElementSibling
  • 根据上面的新属性,可以使用下面的代码遍历所有的子元素节点,而不用再判断nodeType是否为1:
    var child = element.firstElementChild;
    while (child != element.lastElementChild) {
        //todo
        child = nextElementSibling;
    }
  • 支持Element Traversal规范的浏览器有IE 9+、FireFox 3.5+、Safari 4+、Chrome和Opera 10+。

HTML5

  • HTML5规范围绕如何使用新增标记定义了大量JavaScript API。其中一些API和DOM重叠,定义了浏览器应该支持的DOM扩展。

与类相关的补充

getElementsByClassName() 方法

  • 可以通过document对象及所有HTML元素调用该方法。该方法接收一个参数,即一个包含一个或多个类型的字符串。类名的先后顺序不重要:
    <body>
    <h1 class="h1"></h1>
    <h1 class="h1 h2"></h1>
    <h1 class="h1 h2 h3"></h1>
    <h1 class="h1 h2 h3 h4"></h1>
    <h1 class="h1 h2 h3 h4 h5"></h1>

    <script type="text/javascript">
        alert(document.getElementsByClassName("h1").length);//5
        alert(document.getElementsByClassName("h2").length);//4
        alert(document.getElementsByClassName("h1 h2").length);//4
        alert(document.getElementsByClassName("h2 h1").length);//4
        alert(document.getElementsByClassName("h5 h1").length);//1
        alert(document.getElementsByClassName("h5  h1").length);//1 空格数好像是没关系的
    </script>
</body>
  • 返回的对象是NodeList,所以使用这个方法与使用getElementsByTagName()以及其他返回NodeList的DOM方法都具有同样的性能问题(每请求一次都会重新查询该元素以保证他是最新的)。
    <h1 class="h1"></h1>
    <h1 class="h1 h2"></h1>
    <h1 class="h1 h2 h3"></h1>
    <h1 class="h1 h2 h3 h4"></h1>
    <h1 class="h1 h2 h3 h4 h5" id="xx"></h1>

    <script type="text/javascript">
        var xx1 = document.getElementsByClassName("h1 h4");
        alert (xx1.length);//2
        var xx2 = document.getElementById("xx");
        xx2.className = "h1 h2 h3 h5";
        alert (xx1.length);//1 这说明的确是NodeList对象(或者类似),所以避免频繁访问该类对象
    </script>

classList属性

  • 原来要想操作className必须把整个字符串赋值过去(见上面的例子xx2.className = “h1 h2 h3 h5”;),这显然很不方便,比如我们想要动态的删除h4类,通过原来的方法只能这样写:
    var classNames = xx2.className.split(/\s+/);
    for (var i=0, len = classNames.length; i < len; i++) {
        if (className[i] == "h4") {//这里可以以参数名的形式传递
            classNames.splice(i, 1);
            break;
        }
    }
    xx2.className = classNames.join(" ");
  • HTML5 新增了一种操作类型的方式,可以让操作更简单也更安全,那就是为所有元素添加classList属性。这个属性是新集合类型DOMTokenList的实例,与其他DOM集合类似,DOMTokenList有一个表示自己包含多少元素的length属性,可以通过item()方法(没有nameItem()),也可以用花括号方法。此外还有以下方法:
    1. add(value) 将给定的字符串添加到列表中。如果值已存在,则不添加。
    2. contains(value) 表示列表中是否存在给定的值。有则返回true。
    3. remove(value) 从列表中删除给定的字符串。
    4. toggle(value) 如果值已存在,移除。否则添加(理解成切换)。
  • 这样上面的代码就可以用一句话:xx2.classList.remove("h4")去解决。
  • 支持classList属性的浏览器有Firefox 3.6+和Chrome。

焦点管理

  • HTML5也添加了辅助管理DOM焦点的功能。首先就是document.activeElement属性,这个属性始终会引用DOM中当前获得了焦点的元素。元素获得焦点的方式有页面加载、用户输入(通常是通过按Tab键)和在代码中调用focus()方法。
    var button = document.getElementById("myButton");
    button.focus();
    alert(button == document.activeElement);//true
  • 默认情况下,文档刚刚加载完成时,document.activeElement中保存的是document.body的引用。文档加载期间,document.activeElement的值为null。也许是我理解的文档加载期间有错,或者浏览器的差异,当script元素在body下面Chrome的activeElement是body元素(IE是null)。而当script元素在head中时为null。
<!DOCTYPE html>
<html>
<head>
    <title>Selectors API Example</title>
    <script type="text/javascript">
        alert("loading:"+document.activeElement);
        var xx1 = document.activeElement;//null
    </script>
</head>
<body onload="alert(‘loaded:‘+document.activeElement);alert(xx2 == document.activeElement)">
    <button id="myButton"></button>

    <script type="text/javascript">
        alert("loading:"+document.activeElement);
        var xx2 = document.activeElement;//body
        alert(document.readyState);//loading 下面会说到
    </script>
</body>
</html>
  • 另外还有document.hasFocus()判断是否有元素获得了焦点。
  • 实现了该属性和方法的浏览器有:IE 4+、Firefox 3+、Safari 4+、Chrome和Opera 8+。

HTMLDocument的变化

readyState 属性

  • IE 4最早为document对象引入了readyState属性,其他浏览器也陆陆续续添加该属性,最终HTML5把这个属性纳入了标准之中。Document的readyState属性有两个可能的值:
    1. loading:,正在加载文档;
    2. complete,已经加载完文档;
    //最常用的用法
    if (document.readyState == "complete") {
        //todo
    }
  • 支持该属性的浏览器有:IE 4+、Firefox 3.6+、Safari、Chrome和Opera 9+。

兼容模式

  • 自从IE 6开始区分渲染页面的模式是标准还是混杂的,检测页面的兼容模式就成为浏览器的必要功能。IE为此给document添加了一个名为compatMode的属性,这个属性就是为了告诉开发人员浏览器采用了哪种渲染模式。在标准模式下,document.compatMode的值等于”CSS1Compat”。在混杂模式下,该值为”BackCompat”.
    //IE下可以通过
    if (document.compatMode == "CSS1Compat") {
        alert("Standards mode");
    } else {
        alert("Quirks mode");
    }

head属性

  • 作为对document.body引用文档body元素的补充,HTML5新增了document.head属性,引用文档的head元素。
    var head = document.head || document.getElementsByTagName("head")[0];
  • 实现document.head属性的浏览器包括Chrome和Safari 5。

字符集属性

  • HTML5新增了几个与文档字符集有关的属性。其中,charset属性表示文档实际使用的字符集,也可以用来指定新字符集。默认情况下,这个属性是”UTF-16”,可以通过<meta>元素、响应头部或直接设置charset属性修改这个值。
    alert(document.charset);//Chrome:window-1251 IE:gb2312
    document.charset = "UTF-8";
  • 另外一个属性是defaultCharset,表示默认字符集。书上说IE、Firefox、Safari、Opera和Chrome都支持charset。支持defaultCharset属性的浏览器有Chrome(但是我的Chrome结果是undefined)、IE(结果也是gb2312)和Safari。

自定义数据属性

  • HTML5规定可以为元素添加非标准的属性,但要添加前缀data-,目的是为元素提供与渲染无关的信息,或者提供语义信息。这些属性可以任意添加、随便命名,只要以data-开头即可。添加完自定义属性后,可以通过元素的dataset属性来访问自定义属性的值。dataset属性的值是DOMStringMap的一个实例,在这个映射中,每个data-name形式的属性都会有一个对应的属性,只不过属性名没有data-前缀(而且我在Chrome中还发现如果后面跟着大写字母会同意转成小写,再用大写去访问会出现undefined)
<!DOCTYPE html>
<html>
<head>
    <title>Selectors API Example</title>
</head>
<body>
    <div id="myDiv" data-appId="123456" data-MYNAME="hange"></div>
    <script>
        var div = document.getElementById("myDiv");
        var appId = div.dataset.appid;//appId 居然是undefined 难道都转成了小写?
        var myname = div.dataset.myname;//MYNAME 居然是undefined 难道都转成了小写?
        alert(appId);
        alert(myname);
        div.dataset.appId = "234567";
        div.dataset.myname = "miaoch";
        if (div.dataset.myname) {
            alert(div.dataset.myname);
            alert(div.dataset.appid);//123456
        }
    </script>
</body>
</html>
  • Firefox 6+和Chrome支持自定义属性。

插入标记

  • 前面有接触过,当要动态修改表格结构的时候,使用DOM操作会非常的麻烦,即使DOM给表格添加了独特的方法,依然还是很麻烦。在HTML5规范中,引入了插入标记的技术,直接插入HTML字符串不仅更简单,速度也更快。

innerHTML 属性

  • 在读模式下,innerHTML属性返回与调用元素的所有子节点(包括元素,文本和注释节点)对应的HTML标记。在写模式下,innerHTML会根据指定的值创建新的DOM树,然后用这个DOM树完全替换调用元素原先的所有子节点。
    <div id="content">
        <p>this is a <strong>paragraph</strong> with a list following it.</p>
        <ul>
            <li>item 1</li>
            <li>item 2</li>
            <li>item 3</li>
        </ul>
    </div>
    <script>
        var div = document.getElementById("content");
        console.log(div.innerHTML);
    </script>
  • 不同浏览器返回的文本格式会有所不同。IE和Opera会将所有标签转换为大写形式(但是我的IE 9没有改成大写…相反的,把大写的字母改成了小写),而Safari、Chrome(大写的字母改成了小写)和Firefox则会原原本本地按照原先文档中(或指定这些标签时)的格式返回HTML,包括空格和缩进。由于我的测试结果和书上大有不同,所以这段话随便看看吧。
  • 至于写模式,我相信大多数人都用过吧。不过这里要提一个点:
    div.innerHTML = "Hello & welcome, <b>\"reader\"!</b>";
    console.log(div.innerHTML);//Hello &amp; welcome, <b>"reader"!</b>
  • 其中的’&’号会被解析为’&amp’,为innerHTML设置了HTML字符串后,浏览器会将这个字符串解析为相应的DOM树。因此返回的字符串是根据原始HTML字符串创建的DOM树经过序列化后的结果
  • 接下来有一个问题,那就是能否用innerHTML插入<script>节点。我在Chrome中测试如下代码:
    <button onclick="hello();">222</button>
    <div id="content">
        <p>this is a <strong>paragraph</strong> with a list following it.</p>
        <UL>
            <li>item 1</li>
            <li>item 2</li>
            <li>item 3</li>
        </UL>
    </div>
    <script>
        var div = document.getElementById("content");
        console.log(div.innerHTML);
        div.innerHTML = "_<script>function hello(){alert(‘hello‘);}<\/script>";
    </script>
  • 我发现即使<script>元素已经插进去了,但是毫无作用,点击按钮依然会找不到hello()。而且我把一个花括号删掉,令其语法错误,也不会报错。可见在Chrome中确实不能这么做。而书上说IE8及更早版本是唯一能在这种情况下执行脚本的浏览器,but我试了毫无卵用啊。还说了一大堆东西,首先不能是<script>开头,因为这个是无作用域的元素,所以必须在前面加一个文本节点或者元素节点。推荐就是加一个隐藏的input元素。但是我测试下来还是无法执行,所以这一块我就不继续研究了,毕竟谁会这么写代码啊!
  • 还有插入<style>元素,大部分浏览器都是支持的
    <body>
    <div id="content" class="test">
        <p>this is a <strong>paragraph</strong> with a list following it.</p>
        <UL>
            <li>item 1</li>
            <li>item 2</li>
            <li>item 3</li>
        </UL>
    </div>
    <script>
        var div = document.getElementById("content");
        div.innerHTML = "<style> body { background-color: red;}</style>";
    </script>
</body>
  • 然后书上说IE 8及以前的浏览器不能这么写,说style也是无作用域的元素,必须前置一个元素节点或者文本节点。这个我测了是真的。
  • 并不是所有元素都支持innerHTML属性。不支持innerHTML属性的元素有:<col><colgroup><frameset><head><html><style><table><tbody><thead><tfoot><tr>,此外在IE 8及更早版本中,<title>元素也没有innerHTML属性。
  • IE 8提供了window.toStaticHTML()方法,这个方法接收一个参数,即一个HTML字符串,返回一个无害处理后的版本。从源HTML中删除所有脚本节点和事件处理程序属性。
    var text = "<a href=\"#\" onclick=\"alert(‘hi‘)\">click me</a>";
    alert(window.toStaticHTML(text));//<a href="#">click me</a>

outerHTML

  • 这个属性和innerHTML的区别在于,这个属性包含了调用节点本身
  • 支持该属性的浏览器有 IE 4+、Safari 4+、Chrome和Opera 8+。Firefox 7及之前版本都不支持outerHTML属性。

inserAdjacentHTML() 方法

  • 这是插入标记的最后一个方法。这个方法最早出现在IE中,接受2个参数,插入位置和要插入的HTML文本。第一个参数必须是下列值之一:
    1. ”beforebegin”,在当前元素之前插入一个紧邻的同辈元素
    2. “afterbegin”,在当前元素之下插入一个新的子元素或在第一个子元素之前再插入新的子元素
    3. “beforeend”,在当前元素之下插入一个新的子元素或在最后一个子元素之后再插入新的子元素
    4. “afterend”,在当前元素之后插入一个紧邻的同辈元素
  • 第二个参数是一个HTML字符串。和innerHTML用法相同。
  • 在这里也不多说了,这4个方法应该挺有用的。不过2、3方法完全可以用e.innerHTML = e.innerHTML + newHTML;去解决(调换顺序)。

内存和性能问题

  • 使用上述提到的替换子节点可能会导致内存占用问题,特别是IE,问题更加严重。在删除带有事件处理程序或引用了其他JavaScript对象子树时,就有可能导致内存占用问题。
  • 不过,在插入大量HTML标记时,使用innerHTML等方法比多次DOM操作创建节点再指定关系效率要高得多。这是因为在设置innerHTML(或outerHTML等),就会创建一个HTML解析器。这个解析器是在浏览器级别的代码(通常是C++)基础上运行的,因此比JavaScript快得多。不过创建和销毁HTML解析器也会带来性能损失。所以要尽量避免多次使用innerHTML(或其他)。例如最好不要将该赋值语句写在for循环里面。

scrollIntoView() 方法

  • HTML5选择了scrollIntoView() 方法用来控制页面滚动。
  • 该方法可以在所有HTML元素上调用,通过滚动浏览器窗口或某个容器元素,调用元素就可以出现在视口中。如果给这个方法传入true作为参数,或者不传任何参数,那么窗口滚动之后会让调用元素的顶部与视口顶部尽量平齐。如果传入false,调用元素会尽可能出现在视口中(可能的话,调用元素的底部会与视口顶部平齐)。
  • 支持该方法的浏览器有IE、Firefox、Safari和Opera(而我的Chrome也可以。false元素的底部会与视口底部平齐)。

专用扩展

  • 虽然所有浏览器开发商都知晓坚持标准的重要性,但在发现某项功能缺失时,这些开发商都会一如既往地向DOM中添加专有扩展,以弥补功能上的不足。

文档模式

  • IE 8引入了一个新的概念叫”文档模式”(document mode)。页面的文档模式决定了可以使用什么功能。换句话说,文档模式决定了你可以使用哪个级别的的CSS,可以在JavaScript中使用哪些API,以及如何对待文档类型(doctype)。到了IE 9,总共有4种文档模式。
    1. IE5,以混杂模式渲染页面。IE8 及更高版本的的新功能无法使用
    2. IE7,以IE7标准模式渲染页面。IE8 及更高版本的的新功能无法使用
    3. IE8,以IE8标准模式渲染页面。IE8中的功能都可以使用。因此可以使用Selectors API、更多CSS2级选择符和某些CSS3功能,还有一些HTML5功能,不过IE 9中的新功能无法使用。
    4. IE9,以IE9标准模式渲染页面。IE9中的新功能都可以使用,比如ECMAScript5、完整的CSS3以及更多的HTML5功能。这个文档模式是最高级的模式。
  • 要强制浏览器以某种模式渲染页面,可以使用HTTP头部信息X-UA-Compatible,或通过等价的<meta>标签来设置:
    <meta http-equiv="X-UA-Compatible" content="IE=IEVersion">
  • 这里是IEVersion有以下值:
    1. Edge: 始终以最新文档模式来渲染页面。忽略文档类型声明。
    2. EmulateIE9:如果有文档声明,则以IE9标准模式来渲染页面,否则将文档模式设置为IE5
    3. EmulateIE8:如果有文档声明,则以IE8标准模式来渲染页面,否则将文档模式设置为IE5
    4. EmulateIE7:如果有文档声明,则以IE7标准模式来渲染页面,否则将文档模式设置为IE5
    5. 9:强制以IE9标准模式来渲染页面,忽略文档类型声明。
    6. 8:强制以IE8标准模式来渲染页面,忽略文档类型声明。
    7. 7:强制以IE7标准模式来渲染页面,忽略文档类型声明。
    8. 5:强制将文档模式设置成IE5,忽略文档类型声明。
  • 通过document.documentMode属性可以知道给定页面使用的是声明文档模式。这个属性是IE8新增的,它返回的版本号为5、7、8、9。

children属性

  • 由于IE9之前的版本与其他浏览器在处理文本节点中的空白符时有差异,因此就出现了children属性。该属性只会返回元素子节点,是HTMLCollection的一个实例。(前面的firstElementChild也是一样只返回元素节点)
  • 支持children属性的浏览器有IE5、Firefox3.5、Safari2(有bug)、Safari3(完全支持)、Opera8和Chrome。IE8及更早版本的Children属性也会包含注释节点,IE9后只返回元素节点。
    <div id="test">
        <!--这是一个注释节点-->
        <p>this is a <strong>paragraph</strong> with a list following it.</p>
    </div>
    <script>
        var count = document.getElementById("test").children.length;
        alert(count);
    </script>
  • 我通过切换IE的文档模式的确显示了不一样的结果,这次书上没有骗人。

contains() 方法

  • 在实际开发中,经常需要知道某个节点是不是另外一个节点的后代。IE率先引入了contains()方法。调用该方法的应该是祖先节点,这个方法接收一个参数,即要检测的后代节点。如果要检测的节点是后代节点则返回true。
    alert(document.documentElement.contains(document.body));//true
  • 支持该方法的的浏览器有IE Firefox9+ Safari Opera Chrome
  • 使用DOM Level 3 的compareDocumentPosition()也能够确定节点间的关系。支持这个方法的浏览器有:IE9+ Firefox Safari Opera9.5+和Chrome。该方法返回一个表示关系的位掩码(bitmask)

    掩码 节点关系
    1 无关
    2 居前(给定节点在该节点的前面)
    4 居后
    8 包含(给定节点是该节点的祖先)
    16 被包含
  • 为模仿contains方法,应该关注的掩码是16。

    var result = document.documentElement.compareDocumentPosition(document.body);
    alert(result);//20
    alert(!!(result & 16));//true
  • result等于20是因为,他是后代节点且在原节点的后面。对其进行按位与操作,即可判断掩码中16的那一位是否为1。
  • 由此我们可以写出一种通用的contains()方法
    function contains(refNode, otherNode){
        if (typeof refNode.contains == "function" && 
                (!client.engine.webkit || client.engine.webkit >= 522)){
            //版本号大于522的是至少是Safari 3,低版本有bug
            return refNode.contains(otherNode);
        } else if (typeof refNode.compareDocumentPosition == "function"){
            return !!(refNode.compareDocumentPosition(otherNode) & 16);
        } else {
            var node = otherNode.parentNode;
            do {
                if (node === refNode){
                    return true;
                } else {
                    node = node.parentNode;
                }
            } while (node !== null);
            return false;
        }
    }

插入文本

  • 前面介绍过,IE原来专有的插入标记的属性innerHTML和outerHTML已经被HTML5规范化。但另外两个插入文本的专有属性则没有这么好的运气。

innerText 属性

  • 通过innerText属性可以操作元素中包含的所有文本内容,包括子文档树中的文本。在通过innerText读取值时,属于深度优先遍历。在通过innerText写入值时,则会删除元素中的所有子节点,插入一个文本节点。
    <body>
    <div id="content">
        <p>This is a <strong>paragraph</strong> with a list following it.</p>
        <ul>
            <li>Item 1</li>
            <li>Item 2</li>
            <li>Item 3</li>
        </ul>
    </div>
    <input type="button" value="Get InnerText" onclick="getInnerText()">
    <script type="text/javascript">
        function getInnerText(){
            var div = document.getElementById("content");
            alert(div.innerText);  //works in IE, Safari, and Opera 不过我的Chrome也可以,所有还真没有个准。
        }
    </script>
</body>
  • 通过innerText设置文本节点就不多说了,另外设置特殊字符(如&)也会被编码。通过div.innerText = div.innerText可以去除掉所有的HTML标签。
  • 支持innerText属性的浏览器包括 IE4+、Safari3+、Opera8+和Chrome。Firefox虽然不支持innerText,但是支持类似的textContent属性。textContent属性是DOM Level 3规定的一个属性,其他支持textContent属性的浏览器还有IE 9+、Safari 3+、Opera 10+和Chrome。为了确保浏览器兼容,有必要编写一个类似于下面的函数来检测可以使用哪个属性。
    function getInnerText(element){
        return (typeof element.textContent == "string") ? 
            element.textContent : element.innerText;
    }

    function setInnerText(element, text){
        if (typeof element.textContent == "string"){
            element.textContent = text;
        } else {
            element.innerText = text;
        }
    }

outerText 属性

  • 话不多说,outerText 属性在读模式下和innerText的返回值是一模一样的。在写的模式下,会连自身也一并删除。

滚动

  1. scrollIntoViewIfNeeded(alignCenter): 只在当前元素在视口不可见的情况下,才滚动浏览器窗口或容器元素,最终让他可见。传true时会垂直居中。Safari和Chrome实现了该方法。
  2. scrollByLines(lineCount): 将元素的内容滚动指定的行高,lineCount可正可负。Safari和Chrome实现了该方法。
  3. scrollByPages(pageCount): 将元素的内容滚动指定的页面高度,具体高度由元素的高度决定。Safari和Chrome实现了该方法。
    //将页面主体滚动5行
    document.body.scrollByLines(5);
    //在当前元素不可见的时候,让它进入浏览器的视口
    document.iamges[0].scrollIntoViewIfNeeded();
    //将页面主体往回滚动一页
    document.body.scrollByPages(-1);
  • 需要注意的是,scrollIntoView()(所有浏览器都支持)和scrollIntoViewIfNeeded()的作用对象是元素的容器,而scrollByLines()和scrollByPages()影响的是元素自身。
<script type="text/javascript"> $(function () { $(‘pre.prettyprint code‘).each(function () { var lines = $(this).text().split(‘\n‘).length; var $numbering = $(‘
    ‘).addClass(‘pre-numbering‘).hide(); $(this).addClass(‘has-numbering‘).parent().append($numbering); for (i = 1; i <= lines; i++) { $numbering.append($(‘
  • ‘).text(i)); }; $numbering.fadeIn(1700); }); }); </script>

    第十一章:DOM扩展