JS基礎(chǔ)知識(shí)儲(chǔ)備(DOM與BOM)

一、背景

1、瀏覽器組成

JAVAScript 有三部分構(gòu)成,ECMAScript,DOM和BOM,根據(jù)瀏覽器的不同,具體的表現(xiàn)形式也不盡相同。

  1. DOM是 W3C 的標(biāo)準(zhǔn); [所有瀏覽器公共遵守的標(biāo)準(zhǔn)]
  2. BOM 是 各個(gè)瀏覽器廠商根據(jù) DOM在各自瀏覽器上的實(shí)現(xiàn);[表現(xiàn)為不同瀏覽器定義有差別,實(shí)現(xiàn)方式不同]
  3. window 是 BOM 對(duì)象,而非 js 對(duì)象;

2、DOM和BOM

  • DOM:DOM(文檔對(duì)象模型)是 HTML 和 XML 的應(yīng)用程序接口(API)。
  • BOM:BOM 主要處理瀏覽器窗口和框架,不過通常瀏覽器特定的 JavaScript 擴(kuò)展都被看做 BOM 的一部分。而這些擴(kuò)展則包括:
    (1)彈出新的瀏覽器窗口
    (2)移動(dòng)、關(guān)閉瀏覽器窗口以及調(diào)整窗口大小
    (3)提供 Web 瀏覽器詳細(xì)信息的定位對(duì)象
    (4)提供用戶屏幕分辨率詳細(xì)信息的屏幕對(duì)象
    (5)對(duì) cookie 的支持
    (6)IE 擴(kuò)展了 BOM,加入了 ActiveXObject 類,可以通過 JavaScript 實(shí)例化 ActiveX 對(duì)象

3、兩者聯(lián)系

javacsript是通過訪問BOM(Browser Object Model)對(duì)象來訪問、控制、修改客戶端(瀏覽器),由于BOM的window包含了document,window對(duì)象的屬性和方法是直接可以使用而且被感知的,因此可以直接使用window對(duì)象的document屬性,通過document屬性就可以訪問、檢索、修改XHTML文檔內(nèi)容與結(jié)構(gòu)。因?yàn)閐ocument對(duì)象又是DOM(Document Object Model)模型的根節(jié)點(diǎn)??梢哉f,BOM包含了DOM(對(duì)象),瀏覽器提供出來給予訪問的是BOM對(duì)象,從BOM對(duì)象再訪問到DOM對(duì)象,從而js可以操作瀏覽器以及瀏覽器讀取到的文檔

網(wǎng)上摳了兩張圖(哈哈哈):


image
image

二、DOM基本操作

image

接下來我們來具體學(xué)習(xí)一下DOM的基本操作

(一)定義

DOM:Document Object Model,即文檔對(duì)象模型。DOM 里邊定義了一系列方法,是用 來操作 html 和 xml 功能的一類對(duì)象的集合,也有人稱 DOM 是 html 和 xml 的標(biāo)準(zhǔn)編程 接口。

注意:我們所說的改變不了 css 指的是改變不了 css 樣式表,但是我們可以改變 HTML 的行間樣式,也就是說我們可以通過間接地改變行間樣式來改變他

(二)DOM選擇器、節(jié)點(diǎn)類型和屬性

1、DOM選擇器(方法類操作)

(1) document 代表整個(gè)文檔

document 是一個(gè)對(duì)象,這個(gè)對(duì)象上邊有一些屬性和方法,單獨(dú)的 document 就代表的是整個(gè)文檔在 js 里的顯示形式,我們現(xiàn)在所說的整個(gè)文檔最頂級(jí)的標(biāo)簽看上 去好像是 html 標(biāo)簽,但是如果在 html 標(biāo)簽外邊再套一個(gè)標(biāo)簽的話,這個(gè)標(biāo)簽就是 document,就是說 document 才是真正的代表整個(gè)文檔,html 只是他下面的一個(gè)根標(biāo)簽。

(2)id 選擇器

這個(gè)選擇器和 css 里邊講的極其類似,比如說你在 html 里邊寫上一個(gè)<div id="only">123</div>,然后在 js 里 var div = document.getElementById("only")

(3)標(biāo)簽選擇器

比如說你在 HTML 里邊寫一個(gè)<div>123</div>,然后在 js 里 var div = document.getElementsByTagName("div")

注意:document.getElementsByTagName("*"),里邊可以寫 *,和通配符一樣,選中了所有標(biāo)簽

(4)class選擇器

他和這個(gè)標(biāo)簽選擇器差不多,選出來也是一組,你先<div class="demo">123</div>, 然后 var div = document.getElementsByClassName("demo")[0],此時(shí)訪問 div 就得 到<div class="demo">123</div>。

注意:class 選擇器在 ie8 和 ie8 以下的瀏覽器中沒有,但是新版本是可以的, 所以在 js 里,class 選擇器并沒有標(biāo)簽選擇器那么常用,標(biāo)簽選擇器 getElementsByTagName 在任意一個(gè)瀏覽器里都好使。

(5)name選擇器

比如<input name="abc">,然后 var input = document.getElementsByName("abc")[0], 訪問 input 就得到<input name="abc">。需注意這個(gè) name 屬性只對(duì)部分元素生效,如 表單、表單元素、img 等,name 選擇器很少用。

(6)css選擇器

css 選擇器能讓我們?cè)?js 里選擇元素的時(shí)候和 css 里一樣靈活,比如說:

<div> 
        <strong></strong>
</div>
<div>
        <span>
             <strong></strong>
        </span>
</div>

然后在 js 里寫上 var strong = document.querySelector("div span strong");括號(hào) 里寫的東西就和 css 里選擇標(biāo)簽的方法是一樣的,此時(shí)訪問 strong 就得到 <strong></strong>,這選的是一個(gè),還有一個(gè) var strong = document.querySelectorAll("div span strong");他選出來是一組,你再訪問 strong 就得到 NodeList[strong]

注意:在 ie7 及以下的版本沒有,這個(gè)對(duì)我們并沒有什么影響,還有一個(gè)致命的問題,就是 這個(gè) querySelector 和 querySelectorAll 選出來的東西不是實(shí)時(shí)的,在用法上就及其受局限,除非極特殊情況,你就想選他的副本保存起來才會(huì)用這個(gè),否則的話我 們不用。

2、遍歷節(jié)點(diǎn)樹(非方法類操作)

(1)parentNode:父節(jié)點(diǎn)

比如說:

<div>
    <span></span>
    <strong></strong> 
    <em></em>
</div>
<script type="text/javascript">
    var strong = document.getElementsByTagName("strong")[0]; 
</script>

現(xiàn)在訪問 strong.parentNode 就是他的父節(jié)點(diǎn),得到<div>...</div>,繼續(xù) strong.parentNode.parentNode 就是 div 的父親,即<body>...</body>,繼續(xù)就是 body 的父級(jí),即<html>...</html>, 再就是 HTML 的父級(jí),即 #document,再繼續(xù)就得到 null,這就說明 document 就到頂層了,他是頂層的父級(jí)節(jié)點(diǎn),代表整個(gè)文檔。

(2)childNodes 子節(jié)點(diǎn)們

遍歷的是節(jié)點(diǎn)樹,并不是只有元素節(jié)點(diǎn)算節(jié)點(diǎn),節(jié)點(diǎn)的類型有很多,它包括文本節(jié)點(diǎn)、元素節(jié)點(diǎn)、屬性節(jié)點(diǎn)、注釋節(jié)點(diǎn) 等
比如:

<div>
  <!-- this is comment! --> 
  <strong></strong> 
  <span></span>
</div>
<script type="text/javascript">
  var div = document.getElementsByTagName("div")[0]; 
</script>

訪問 div.childNodes 就得到 odeList(7)[text, comment, text, strong, text, span, text],可見他有七個(gè)節(jié)點(diǎn):依次是文本節(jié)點(diǎn)、注釋節(jié)點(diǎn)、文本節(jié)點(diǎn)、元素節(jié)點(diǎn)、 文本節(jié)點(diǎn)、元素節(jié)點(diǎn)、文本節(jié)點(diǎn)。(空格文本和文本和回車文本都寫在一起,就是一個(gè)文本 節(jié)點(diǎn)

(3)firstChild/lastChild 第一個(gè)子節(jié)點(diǎn)/最后一個(gè)子節(jié)點(diǎn)

例如上邊的,現(xiàn)在 div.firstChild 就是文本 123 和回車,div.lastChild 就是#text, 還是文本節(jié)點(diǎn),只不過是空的,他就那樣顯示了。

(4)nextSibling/previousSibling 后一個(gè)兄弟節(jié)點(diǎn)/前一個(gè)兄弟節(jié)點(diǎn)

還是上邊的,var strong = document.getElementsByTagName("strong")[0];,然后 strong.nextSibling 就得到#text

3、遍歷元素節(jié)點(diǎn)樹

這幾種方法只遍歷的是元素節(jié)點(diǎn),其他的都不摻雜了。比如說:

<div> 123
  <!-- this is comment! --> 
  <strong></strong> 
  <span></span>
</div>

(1)parentElement 元素父節(jié)點(diǎn)

在 js 里 var div = document.getElementsByTagName("div")[0]; 然 后 div .parentElement 他 的 元 素 父 節(jié) 點(diǎn) 就 是 <body>...</body> , 然 后 div.parentElement.parentElement,就是 body 的元素父節(jié)點(diǎn),即<html>...</html>, 再父節(jié)點(diǎn)就是 null,因?yàn)?document 不叫 元素節(jié)點(diǎn),他自稱為一個(gè)節(jié)點(diǎn),所以 parentNode 和 parentElement 的區(qū)別就在于有沒有document。

(2)children 元素子節(jié)點(diǎn)

現(xiàn)在 div.children 就得到 HTMLCollection(2)[strong,span],只有兩個(gè)。

(3)childElementCount === children.length 元素子節(jié)點(diǎn)的個(gè)數(shù)

比如說 div.childElementCount 就得到 2,你 div.children.length 也是 2,兩者用法一樣

(4)firstElementChild/lastElementChild 第一個(gè)元素子節(jié)點(diǎn)/最后一個(gè)元素子節(jié) 點(diǎn)

現(xiàn)在 div.firstElementChild 就是<strong></strong>,div.lastElementChild 就是 <span></span>。

(5)nextElementSibling/previousElementSibling 后一個(gè)兄弟元素節(jié)點(diǎn)/前一個(gè)兄 弟元素節(jié)點(diǎn)

strong.nextElementSibling 就得到 <span></span>

備注:以上遍歷節(jié)點(diǎn)樹的方法所有瀏覽器都兼容,但是遍歷元素節(jié)點(diǎn)樹的方法除 children 以外,ie9 及以下的瀏覽器都不兼容。

4、節(jié)點(diǎn)的四個(gè)屬性

<div> 
  123
  <!-- this is comment! -->
  <strong></strong> 
  <span></span> 
  <em></em>
  <i></i>
  <b></b>
</div>
<script type="text/javascript">
  var strong = document.getElementsByTagName("strong")[0];
</script>

(1)nodeName 元素的標(biāo)簽名,只讀

var div = document.getElementsByTagName("div")[0];
你訪問 document.nodeName 就得到 "#document",
訪問 div.firstChild.nodeName,他是一個(gè)文本節(jié)點(diǎn),就得到"#text",
繼續(xù) div.childNodes[1].nodeName,第二個(gè)子節(jié)點(diǎn)是注釋,就得到"#comment", div.childNodes[3].nodeName 是元素節(jié)點(diǎn),就得到"STRONG"。返回的是一個(gè)字符串, 只讀就是只能讀取不能寫入,比如說我把 div.childNodes[3].nodeName = "abc",再 訪問的話還是"STRONG"。

(2)nodeValue text節(jié)點(diǎn)或comment節(jié)點(diǎn)的文本內(nèi)容,可讀寫

這個(gè)屬性只有文本節(jié)點(diǎn)和注釋節(jié)點(diǎn)才有,
訪問 div.childNodes[0].nodeValue 就得到 文本的回車和 123,這個(gè)可以改,你 div.childNodes[0].nodeValue = "234",
再訪問 的話就是"234",再比如訪問 div.childNodes[1].nodeValue 就得到" this is comment! ",如果 div.childNodes[1].nodeValue = " that is comment! ",再訪問 div.childNodes[1]就是<! -- that is comment! -->。

(3)nodeType 該節(jié)點(diǎn)的類型,只讀

比如說現(xiàn)在有一個(gè)節(jié)點(diǎn),我也不知道里邊是什么節(jié)點(diǎn),就有他來分辨,每一個(gè)節(jié)點(diǎn)都 有這個(gè) nodeType 屬性,你調(diào)用他返回的是一個(gè)具體的值:
元素節(jié)點(diǎn)是 1,
屬性節(jié)點(diǎn)是 2,
文本節(jié)點(diǎn)是 3,
注釋節(jié)點(diǎn)是 8,
document 節(jié)點(diǎn)是 9,
DocumentFragment(文檔碎片節(jié)點(diǎn))是 11

現(xiàn)在 document.nodeType 就是 9,div.childNodes[1].nodeType 第二個(gè)是 注釋節(jié)點(diǎn)就返回 8,div.childNodes[0].nodeType 文本節(jié)點(diǎn)返回 3, div.childNodes[3].nodeType 元素節(jié)點(diǎn)就是 1。

練習(xí)題
還是上邊的例子,現(xiàn)在封裝一個(gè)方法,要求返回 div 的直接子元素節(jié)點(diǎn),但是 不允許用 children。

function retElementChild(node) { 
  var temp = {
              length: 0,
              push: Array.prototype.push, 
              splice: Array.prototype.splice
              },
      child = node.childNodes, len = child.length;
      for (var i = 0; i < len; i++) { 
        if (child[i].nodeType === 1) {
            temp.push(child[i]); 
            }
        }
    return temp;
 }

(4)attributes 元素節(jié)點(diǎn)的屬性集合

這個(gè)屬性就是訪問元素的屬性節(jié)點(diǎn)的,
<div id="only" class="demo"></div>
然后繼續(xù)把 div 選出來:var div = document.getElementsByTagName("div")[0];現(xiàn) 在 div.attributes 就得到 NamedNodeMap{0: id, 1: class, id: id, class: class, length: 2},
訪問 div.attributes[0]就得到 id="only",
訪問 div.attributes[1]就 是 class="demo"。
div.attributes[1].nodeType 就得到 2. 你也可以把他的屬性名和屬性值都取出來,
div.attributes[0].name 就得到"id",
div.attributes[0].value 就得到"only"。
屬性名是只讀的,屬性值可讀可寫。

5、節(jié)點(diǎn)的一個(gè)方法 Node.hasChildNodes()

這個(gè)方法就是判斷這個(gè)元素有沒有子節(jié)點(diǎn),現(xiàn)在 div.hasChildNodes()就返回 true, 因?yàn)榭崭窕剀囄谋疽菜阄谋竟?jié)點(diǎn),除非<div id="only" class="demo"></div>的話, 訪問 div.hasChildNodes()是 false,中間啥都沒有(屬性節(jié)點(diǎn)不算,他是 div 自己的, 不能算子節(jié)點(diǎn))才能返回 false。

(三)DOM 繼承樹及基本操作

1、DOM繼承樹

image
  • 首先我們知道 document 代表的是整個(gè)文檔,訪問就得到#document,但是我訪問 Document 就得到? Document() { [native code] },是一個(gè)構(gòu)造函數(shù)。假如說你給 Document 的原型上加一些屬 性的話,比如 Document.prototype.abc = "abc",那么 document 就能繼承他的屬性, 你訪問 document.abc 就得到"abc",上邊的結(jié)構(gòu)樹就表示這一系列繼承的關(guān)系。
  • 第二個(gè) CharacterData 下邊有 Text 和 Comment,這就說明文本節(jié)點(diǎn)能用的屬性和 方法全部繼承自 Text.prototype,注釋節(jié)點(diǎn)的方法則全部繼承自 Comment.prototype, 然后一層一層向上繼承。
  • 第三個(gè)最長(zhǎng),Element 下邊有一個(gè) HTMLElement(那下邊就肯定還有一個(gè) XMLElement, 只不過沒寫),然后在下邊有一堆東西,最后還沒寫完,但是你會(huì)發(fā)現(xiàn)那一堆東西都是 一些標(biāo)簽?zāi)苡玫囊恍傩院头椒?/li>
  • 現(xiàn)在 document.__ proto__得到 HTMLDocument{...},
    document.__ proto__.__ proto__就得到 Document{...},
    document.__ proto__.__ proto__.__ proto__得到 Node{...},
    document.__ proto__.__ proto__.__ proto__.__ proto__得到 EventTarget{...}
    document.__ proto__.__ proto__.__ proto__.__ proto__.__ proto__就得到 Object{}.
    這就說明 DOM 對(duì)象最終也繼承自 Object.prototype,比如你訪問 document.toString() 就得到"[object HTMLDocument]",這個(gè) Object.prototype 是所有對(duì)象原型鏈上的終端。

2、DOM 結(jié)構(gòu)樹的應(yīng)用

  1. getElementById 方法定義在 Document.prototype 上,即 Element 節(jié)點(diǎn)上不能使用
  2. getElementsByName 方法定義在 HTMLDocument.prototype 上,即非 html 中的 document 不能使用(xml 的 document 和 Element 不能用)。
  3. getElementsByTagName 方法定義在 Document.prototype 和 Element.prototype 上。
    解釋:這個(gè)方法在兩個(gè)地方都定義了,就都能用,比如說
<div>
  <span>1</span>
</div>
<span></span>
<script type="text/javascript">
  var div = document.getElementsByTagName('div')[0];
  var span = div.getElementsByTagName("span")[0]; 
</script>
  1. HTMLDocument.prototype 定義了一些常用的屬性,body,head,分別指代 HTML 文 檔中的<body>和<head>標(biāo)簽。
    解釋:要選 head 標(biāo)簽或者 body 標(biāo)簽的話就直接 document.head 或者 document.body 就可以了。
  2. Document.prototype 上定義了 documentElement 屬性,指代文檔的根元素,在 HTML 文檔中,他總是指代<html>元素。
  3. getElementsByClassName、querySelectorAll、querySelector 這幾個(gè)方法在 Document.prototype 和 Element.prototype 類中均有定義。

練習(xí)題1:遍歷元素節(jié)點(diǎn)樹(在原型鏈上編程)

<body>
    <div>
        <span>
            <em></em>
            <strong>
                <em>
                    <a href=""></a>
                </em>
            </strong>
        </span>
        <p></p>
    </div>
    <span></span>
    <script type="text/javascript">
        var div = document.getElementsByTagName('div')[0];
        Element.prototype.retChildElements = function () {
            var child = this.childNodes,
                len = child.length;
            for (var i = 0; i < len; i++) {
                if (child[i].nodeType === 1) {
                    console.log(child[i]);
                }
            }
        }
    </script>
</body>

練習(xí)題2:封裝函數(shù),返回元素 a 的第 n 層祖先元素節(jié)點(diǎn)

<body>
    <div>
        <span>
            <strong>
                <em>
                    <a href=""></a>
                </em>
            </strong>
        </span>
    </div>
    <script type="text/javascript">
        var a = document.getElementsByTagName('a')[0];

        function retParent(elem, n) {
            while (elem && n) {
                elem = elem.parentElement;
                n--;
            }
            return elem;
        }
    </script>

</body>

練習(xí)題3:編輯函數(shù),封裝 myChildren 功能,解決以前部分瀏覽器的兼容性問題。

<body>
    <div>
        <b></b>
        蠟筆小新
        <!-- this is comment -->
        <strong>
            <span>
                <i></i>
            </span>
        </strong>
    </div>
    <script type="text/javascript">
        Element.prototype.myChildren = function () {
            var child = this.childNodes;
            var len = child.length;
            var arr = [];
            for (var i = 0; i < len; i++) {
                if (child[i].nodeType == 1) {
                    arr.push(child[i]);
                }
            }
            return arr;
        }
        var div = document.getElementsByTagName("div")[0];
    </script>
</body>

練習(xí)題4:自己封裝 hasChildren()方法,不可用 children 屬性。

<body>
    <div>
        <b></b>
        蠟筆小新
        <!-- this is comment --> 
        <strong>
            <span>
                <i></i>
            </span>
        </strong>
    </div>
    <script type="text/javascript">
        Element.prototype.hasChildren = function () {
            var child = this.childNodes;
            var len = child.length;
            for (var i = 0; i < len; i++) {
                if (child[i].nodeType == 1) {
                    return true;
                }
            }
            return false;
        }
        var div = document.getElementsByTagName("div")[0];
    </script>
</body>

練習(xí)題5:封裝函數(shù),返回元素 e 的第 n 個(gè)兄弟元素節(jié)點(diǎn),n 為正,返回后面的兄弟元素 節(jié)點(diǎn),n 為負(fù),返回前面的,n 為 0,返回自己。

<body>
    <div>
        <span></span>
        <p></p> <strong></strong>
        <!-- this is comment --> <i></i>
        <address></address>
    </div>
    <script type="text/javascript">
        function retSibling(e, n) {
            while (e && n) {
                if (n > 0) {
                    if (e.nextElementSibling) {
                        e = e.nextElementSibling;
                    } else {
                        for (e = e.nextSibling; e && e.nodeType != 1; e =
                            e.nextSibling);
                    }
                    n--;
                } else {
                    if (e.previousElementSibling) {
                        e = e.previousElementSibling;
                    } else {
                        for (e = e.previousSibling; e && e.nodeType != 1; e = e.previousSibling);
                    }
                    n++;
                }
            }
            return e;
        }
        var strong = document.getElementsByTagName("strong")[0];
    </script>
</body>

3、DOM基本操作

上邊講的所有方法都是查看操作,下邊講其他的幾個(gè)操作。

(1)增

  • 創(chuàng)建元素節(jié)點(diǎn)(即創(chuàng)建標(biāo)簽):document.createElement()
  • 創(chuàng)建文本節(jié)點(diǎn):document.createTextNode()
  • 創(chuàng)建注釋節(jié)點(diǎn):document.createComment()
  • 創(chuàng)建文檔碎片節(jié)點(diǎn):document.createDocumentFragment()

(2)插

  • appendChild():每個(gè)元素都有 appendChild 方法,這個(gè)方法就跟 push 方法一樣。
    注意:appendChild 進(jìn)行的是剪切操作
  • 父級(jí).insertBefore(a, b):父級(jí)調(diào)用,里邊傳兩個(gè)參數(shù),意思是在 b 之前插入 a

(3)刪

<body>
    <div>
        <span></span>
        <strong></strong>
        <i></i>
    </div>
    <script type="text/javascript">
        var div = document.getElementsByTagName("div")[0];
        var span = document.getElementsByTagName("span")[0];
        var strong = document.getElementsByTagName("strong")[0];
        var i = document.getElementsByTagName("i")[0];
    </script>
</body>
  • parentNode.removeChild(a) 父級(jí)刪除自己的子節(jié)點(diǎn)
    div.removeChild(i)后其實(shí)是把 i 標(biāo)簽剪切出來了,比如說上邊的代碼刷新后 var ii = div.removeChild(i), 你在訪問 ii 就是<i></i>。
  • a.remove()
    比如上邊代碼刷新后 i.remove();strong.remove();div 里邊就只剩下 span 了,remove 是真正的刪除,刪掉后就啥都沒有了。

(4)替換

  • parentNode.replaceChild(new, origin):這個(gè)也是父級(jí)調(diào)用,里邊傳入兩個(gè)參數(shù),第一個(gè)是 new 就是新的,第二個(gè)是目標(biāo)

4、Element 節(jié)點(diǎn)的一些屬性

(1)innerHTML

這個(gè)屬性可以改變 html 里的內(nèi)容,這個(gè) innerHTML 取得是 HTML 結(jié)構(gòu),是可讀寫的,所以你寫進(jìn)去什么東西他都會(huì)識(shí)別成 HTML 結(jié)構(gòu)。

(2)innerText

這個(gè)賦值的話里邊的東西就全部被覆蓋了,所以在用這個(gè)方法的時(shí)候需要謹(jǐn)慎, 如果標(biāo)簽底下有其他子標(biāo)簽,最好在賦值的時(shí)候不要用這個(gè)。
還有這個(gè) innerText 老 版本的火狐瀏覽器不兼容,當(dāng)時(shí)火狐有一個(gè)屬性 textContent 和這個(gè)作用是一樣的,但是火狐這個(gè)方法老版本的 ie 不好使(都是老版本的兼容性問題,現(xiàn)在的新版本不存 在不兼容的)。

5、Element 節(jié)點(diǎn)的一些方法

<body>
    <div></div>
    <script type="text/javascript">
        var div = document.getElementsByTagName("div")[0];
    </script>
</body>

(1)元素.setAttribute() 添加屬性

現(xiàn)在 div.setAttribute("class","demo"),括號(hào)里第一個(gè)是屬性名,第二個(gè)是屬性值, 在訪問 div 就得到<div class="demo"></div>,繼續(xù) div.setAttribute("id","only"), 在訪問 div 就是<div class="demo" id="only"></div>。

(2)元素.getAttribute() 查看屬性

接著上邊的,現(xiàn)在 div.getAttribute("id")就得到"only",div.getAttribute("class") 就得到"demo"。
有了這些操作,就更靈活了,比如說我在 css 里定義了一個(gè) class 樣式,然后可以再 js 里動(dòng)態(tài)的添加 class 屬性,讓這個(gè)樣式作用在對(duì)應(yīng)的元素上。

練習(xí)題1:封裝函數(shù) insertAfter(),功能類似 insertBefore(). 提示:可忽略老版本瀏覽器,直接在 Element.prototype 上編程。

<body>
    <div>
        <span></span>
        <i></i>
        <b></b> <strong></strong>
    </div>
    <script type="text/javascript">
        var div = document.getElementsByTagName("div")[0];
        var b = document.getElementsByTagName("b")[0];
        var strong = document.getElementsByTagName("strong")[0];
        Element.prototype.insertAfter = function (targetNode, afterNode) {
            var beforeNode = afterNode.nextElementSibling;
            if (beforeNode == null) {
                this.appendChild(targetNode);
            } else {
                this.insertBefore(targetNode, beforeNode);
            }
        }
        var p = document.createElement("p");
    </script>
</body>

練習(xí)題2:將目標(biāo)節(jié)點(diǎn)的內(nèi)部節(jié)點(diǎn)逆序

<body>
    <div>
        <span></span> <i></i>
        <b></b> <strong></strong>
    </div>
    <script type="text/javascript">
        var div = document.getElementsByTagName("div")[0];
        Element.prototype.inversElement = function () {
            var len = this.children.length;
            for (var i = len - 1; i >= 0; i--) {
                this.appendChild(this.children[i]);
            }
        }
    </script>
</body>

三、獲取窗口屬性、獲取 DOM 尺寸、腳本化 CSS

1、查看滾動(dòng)條的滾動(dòng)距離

  • 標(biāo)準(zhǔn)方法 : window.pageXOffset window.pageYOffset

但是以上兩種方法 ie8 及 ie8 以下瀏覽器不兼容,這些瀏覽器提供了兩種方法:

  • document.body.scrollLeft(和 window.pageXOffset 效果一樣)
    document.body.scrollTop(和 window.pageYOffset 效果一樣)
  • document.documentElement.scrollLeft
    document.documentElement.scrollTop

注意:以上兩種方法兼容性比較混亂,就是 ie8 及 ie8 以下的瀏覽器有的瀏覽器版本第一個(gè) 方法好使,有的版本第二個(gè)方法好使,但是任何一個(gè)瀏覽器版本只要一種方法好使, 返回的有值,另一種不好使的方法返回的一定是 0,所以咱們?cè)?ie8 及 ie8 以下的瀏覽 器不管哪個(gè)版本直接把兩個(gè)值相加就行了。

練習(xí)題:封裝兼容性方法,求滾動(dòng)條滾動(dòng)距離 getScrollOffset()

function getScrollOffset() {
            if (window.pageXOffset) {
                return {
                    x: window.pageXOffset,
                    y: window.pageYOffset
                }
            } else {
                return {
                    x: document.body.scrollLeft + document.documentElement.scrollLeft,
                    y: document.body.scrollTop + document.documentElement.scrollTop
                }
            }
        }

2、查看可視區(qū)窗口尺寸

可視區(qū)窗口就是咱們編寫的 html 文檔能看到的部分,不包括菜單欄、地址欄和控制臺(tái)。

  • 標(biāo)準(zhǔn)方法:window.innerWidth window.innerHeight

注意:以上兩個(gè)方法還是 ie8 及 ie8 以下版本不兼容。這些瀏覽器版本提供了 兩種方法,一種是在標(biāo)準(zhǔn)模式下用的,一種是在怪異模式下用的。

備注:什么是怪異模式?比如說在很久以前 ie7 還沒有誕生,我寫了一個(gè)頁(yè)面,語法 全部用的是 ie6 的語法,但是一年之后 ie7 誕生了,人們都開始用新的瀏覽器,那么 我之前寫的那個(gè)頁(yè)面的部分語法就不能用了,因?yàn)橛袥_突,重寫的話又太浪費(fèi)時(shí)間, 后來人們研究了一種新的渲染模式叫怪異模式,比如說現(xiàn)在我啟動(dòng)了怪異模式,在這 個(gè)模式下即使人們用的是 ie7 瀏覽器,他也能根據(jù) ie6 的語法把這個(gè)頁(yè)面渲染出來, 這個(gè)怪異模式也叫混雜模式,這個(gè)模式一經(jīng)啟動(dòng)他識(shí)別的就不是現(xiàn)在的語法而是之前 的語法,起到了一個(gè)向后兼容的作用,兼容之前的語法。那么怎么啟用怪異模式?其 實(shí)我們?cè)谥v html 的時(shí)候他第一行應(yīng)該是<!DOCTYPE html>,這個(gè)我們一直沒說,其實(shí) 有這一行就是標(biāo)準(zhǔn)模式,要想啟動(dòng)怪異模式,直接把這一行刪掉即可。

  • 第一種:標(biāo)準(zhǔn)模式下,任意瀏覽器都能兼容
    document.documentElement.clientWidth
    document.documentElement.clientHeight
  • 第二種:適用于怪異模式下的瀏覽器
    document.body.clientWidth
    document.body.clientHeight

怎么區(qū)分標(biāo)準(zhǔn)模式和怪異模式?
document 上有個(gè)屬性 compatMode,在標(biāo)準(zhǔn)模式下訪問 document.compatMode 得"CSS1Compat",在怪異模式下訪問 document.compatMode 得 "BackCompat"。

練習(xí)題:封裝兼容性方法,返回瀏覽器視口尺寸 getViewportOffset()

function getViewportOffset() {
            if (window.innerWidth) {
                return {
                    w: window.innerWidth,
                    h: window.innerHeight
                }
            } else {
                if (document.compatMode === "BackCompat") {
                    return {
                        w: document.body.clientWidth,
                        h: document.body.clientHeight
                    }
                } else {
                    return {
                        w: document.documentElement.clientWidth,
                        h: document.documentElement.clientHeight
                    }
                }
            }
        }

3、查看元素幾何尺寸

  • dom.getBoundingClientRect()

返回的是一個(gè)對(duì)象,對(duì)象里邊有 left、top、right、bottom 等屬性,left 和 top 代表該元素左上角的 X 和 Y 坐標(biāo),right 和 buttom 代表元素右下角的 X 和 Y 坐標(biāo), 這個(gè)方法兼容性很好,但是老版本的 ie 里并沒有 height 和 width,所以我們?cè)诶习姹?的 ie 只能計(jì)算來求寬高,而且這個(gè)方法返回的結(jié)果并不是實(shí)時(shí)的,比如說我 var box = div. getBoundingClientRect();div.style.width = "200px",再訪問 box 的話里邊 的 width 還是 100px,所以他不是實(shí)時(shí)的。

4、查看元素的尺寸

  • dom.offsetWidth dom.offsetHeight

5、查看元素的位置

  • dom.offsetLeft dom.offsetTop

6、滾動(dòng)條滾動(dòng)

window上有三個(gè)方法:

  • window.scroll()
  • window.scrollTo()
  • window.scrollBy()

用法都是將 x、y 坐標(biāo)傳入,即實(shí)現(xiàn)讓滾動(dòng)條滾動(dòng)到當(dāng)前位置。
window.scroll()和 window.scrollTo()兩個(gè)方法完全一樣,兼容性也一樣,比如說 window.scroll(0,100)他就能讓 y 方向的滾動(dòng)條滾動(dòng)到 100 像素這個(gè)位置,你繼續(xù) window.scroll(0,100)他是不變的,說明他是讓滾動(dòng)條滾動(dòng)到當(dāng)前位置。
而 window.scrollBy()是累加滾動(dòng)當(dāng)前距離,比如說 window.scrollBy(0,10)他是讓滾 動(dòng)條向下滾動(dòng) 10 像素,繼續(xù) window.scrollBy(0,10)就繼續(xù)向下滾動(dòng) 10 像素,繼續(xù) window.scrollBy(0,-10)就又向上滾動(dòng) 10 像素。

練習(xí)題:模仿手機(jī)閱讀器,做一個(gè)自動(dòng)閱讀的功能

<body>
    <div
        style="width:100px;height:100px;background-color:orange;color:#fff;font-si ze:40px;font-weight:bold;text-align:center;line-height:100px;position:fixe d;bottom:200px;right:50px;border-radius: 50%;opacity:0.5;">
        start</div>
    <div
        style="width:100px;height:100px;background-color:#0f0;color:#fff;font-size :40px;font-weight:bold;text-align:center;line-height:100px;position:fixed; bottom:50px;right:50px;border-radius: 50%;opacity:0.5;">
        stop</div>
    <script type="text/javascript">
        var start = document.getElementsByTagName("div")[0];
        var stop = document.getElementsByTagName("div")[1];
        var timer = 0;
        var key = true;
        start.onclick = function () {
            if (key) {
                timer = setInterval(function () {
                    window.scrollBy(0, 10);
                }, 100)
            }
            key = false;
        }
        stop.onclick = function () {
            clearInterval(timer);
            key = true;
        }
    </script>
</body>

7、腳本化css

(1)讀寫元素css屬性 dom.style

任何一個(gè) dom 元素都會(huì)有 style 屬性,我們?cè)诳刂婆_(tái)訪問 div.style 得到,這個(gè) dom.style 沒有任何兼容性問題,但是注意碰到 float 這樣的保留字屬性,前邊 應(yīng)該加上 css,如 div.style.cssFloat = "right"。還有就是復(fù)合屬性(如 border) 最好把他拆解開設(shè)置,但是現(xiàn)在寫在一起也是可以的,最好把他拆解開。

(2)查詢計(jì)算樣式

  • window.getComputedStyle(dom,null)

這個(gè)方法需要傳入兩個(gè)參數(shù),第一個(gè)是 dom 元素,第二個(gè)是 null,返回的也是一個(gè)樣式表,但是和上邊的不一樣,style 里讀的只是行間里的樣式,假如說你在行間沒有設(shè)置的話他就沒有值,但是這個(gè)方法返回的屬性里即使你沒有設(shè)置他也是有值的,是默認(rèn)值,這個(gè)方法獲取的是當(dāng)前元素所展示的一切 css 的顯示值, 就是假如說你通過多個(gè)選擇器給一個(gè)元素設(shè)置了一個(gè)屬性,那么只有權(quán)重最高的那個(gè) 起作用,而這個(gè)方法獲取的只是那個(gè)起作用的也就是顯示的那個(gè)值和一些默認(rèn)值。這個(gè)方法 ie8 及 ie8 以下不兼容。

這個(gè)方法第二個(gè)參數(shù)是干嘛的嗎?為啥要傳 null 呢?第二個(gè)參數(shù)傳對(duì)了,可以獲取偽元素的樣式

(3)查詢樣式

  • dom.currentStyle (ie 獨(dú)有的屬性)

這個(gè)是 ie 獨(dú)有的屬性,他也能返回一個(gè)樣式表,和 window.getComputedStyle()方法 類似,也是只能讀取不能寫入,他獲取的也是最終展示的那個(gè)值,但是他返回的計(jì)算 樣式的值不是經(jīng)過轉(zhuǎn)換的絕對(duì)值,寫啥就展示啥。

練習(xí)題:做一個(gè)小木塊運(yùn)動(dòng)。

<body>
    <div style="width:100px;height:100px;background-color:red;position:absolute;"></div>
    <script type="text/javascript">
        function getStyle(elem, prop) {
            if (window.getComputedStyle) {
                return window.getComputedStyle(elem, null)[prop];
            } else {
                return elem.currentStyle[prop];
            }
        }
        var div = document.getElementsByTagName("div")[0];
        var speed = 2;
        var timer = setInterval(function () {
            speed += speed / 7;
            div.style.left = parseInt(getStyle(div, "left")) + speed + "px";
            if (parseInt(getStyle(div, "left")) > 500) {
                clearInterval(timer);
            }
        }, 10)
    </script>
</body>
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容