DOM模型

DOM模型

DOM:文檔對象模型( Document Object Model ),它的作用是將網(wǎng)頁轉(zhuǎn)為一個(gè) js 對象

節(jié)點(diǎn) Node

DOM最小組成單位叫做節(jié)點(diǎn)

節(jié)點(diǎn)的類型有七種:

  • Document:整個(gè)文檔節(jié)點(diǎn)(包含整個(gè)節(jié)點(diǎn)樹)
  • DocumentType:文檔聲明類型 <!DOCTYPE html>
  • Element:元素節(jié)點(diǎn),網(wǎng)頁的各種HTML標(biāo)簽(<body>、divimg等等)
  • Attribute:網(wǎng)頁元素的屬性(比如class="right"
  • Text:標(biāo)簽之間或標(biāo)簽包含的文本
  • Comment:注釋
  • DocumentFragment:文檔的片段

根節(jié)點(diǎn)

document 根節(jié)點(diǎn),文檔的第一層只有一個(gè)節(jié)點(diǎn)

節(jié)點(diǎn)的關(guān)系

除了根節(jié)點(diǎn),其他節(jié)點(diǎn)都有三種層級關(guān)系。

  • 父節(jié)點(diǎn)關(guān)系
<!-- button的直接父節(jié)點(diǎn)是div -->
<div>
  <button>按鈕</button>
</div>
  • 子節(jié)點(diǎn)關(guān)系
<!-- div的直接子節(jié)點(diǎn)是button -->
<div>
  <button>按鈕</button>
</div>
  • 同級節(jié)點(diǎn)關(guān)系
<!-- button的同級節(jié)點(diǎn)是h2 -->
<div>
  <button>按鈕</button>
  <h2>標(biāo)題2</h2>
</div>

Node 接口的屬性

所有 DOM 節(jié)點(diǎn)都繼承了 Node 接口

  • Node.nodeType:

返回一個(gè)整數(shù)值,表示節(jié)點(diǎn)的類型,有以下類型:

  1. document:9 表示 文檔
  2. element: 1 表示 元素
  3. attr: 2 表示 屬性
  4. text: 3 表示 文本
  5. DocumentFragment: 11 表示 文檔片段
  6. DocumentType: 10 表示 文檔類型
  7. Comment: 8 表示 注釋
<div id="box">你好</div>
<script>
  var box = document.getElementById('box');
  console.log( box.nodeType ); //1 元素
  console.log( box.childNodes[0].nodeType );//3 文本
</script>
  • Node.nodeName:
<div id="box">你好</div>
<script>
  var box = document.getElementById('box');
  console.log( box.nodeName ); //DIV 默認(rèn)是大寫
  console.log( box.childNodes[0].nodeName );//#text
</script>
  • Node.nodeValue

nodeValue屬性返回一個(gè)字符串,表示當(dāng)前節(jié)點(diǎn)本身的文本值

注意:該屬性主要用于文本節(jié)點(diǎn)

var box = document.getElementById('box');
console.log( box.nodeValue );//null
console.log( box.childNodes[0].nodeValue );//您好
  • Node.textContent:

textContent屬性返回當(dāng)前節(jié)點(diǎn)和它的所有后代節(jié)點(diǎn)的文本內(nèi)容。

自動(dòng)忽略當(dāng)前節(jié)點(diǎn)內(nèi)部的HTML標(biāo)簽,提取文本內(nèi)容,它和innerText功能一樣

該屬性可讀可寫

<div id="box">
  您好
  <p>
    張三
  </p>
</div>

<script>
  var box = document.getElementById('box');
  console.log( box.textContent );// 您好 張三
</script>
  • Node.baseURI

返回一個(gè)字符串,表示當(dāng)前網(wǎng)頁的絕對路徑

會受<base href="#"> 基礎(chǔ)地址影響,而location.href不會。

console.log( document.baseURI );
//file:///F:/studyspace/web1905/javascript/dom.html

console.log( window.location.href );
//file:///F:/studyspace/web1905/javascript/dom.html
  • Node.ownerDocument

返回當(dāng)前節(jié)點(diǎn)所在的頂層文檔對象,即document對象。

<div id="box">

</div>

<script>
  var box = document.getElementById('box');
  console.log( box.ownerDocument == document );//true
</script>

節(jié)點(diǎn)關(guān)系查找

父節(jié)點(diǎn)關(guān)系
  • Node.childNodes:

    父節(jié)點(diǎn)下所有的子節(jié)點(diǎn),注意包含文本、注釋、元素節(jié)點(diǎn)

  • Node.children:

    父節(jié)點(diǎn)下所有的子元素節(jié)點(diǎn),只是元素節(jié)點(diǎn)

  <ul id="box">
  <li>一分</li>
  <li>二分</li>
  <li>三分</li>
  <li>四分</li>
  <li>五分</li>
</ul>

<script>
var box = document.getElementById('box');
var lis1 = box.childNodes;
var lis2 = box.children;

console.log( lis1, lis2);
</script>
子節(jié)點(diǎn)關(guān)系
  • parentNode

    當(dāng)前節(jié)點(diǎn)的直接的父節(jié)點(diǎn)

  • parentElement

    當(dāng)前節(jié)點(diǎn)的直接的父元素節(jié)點(diǎn)

<div>
  <span>
    <button id="btn">按鈕</button>
  </span>
</div>

<script>
document.getElementById('btn').onclick = function(){
  var THIS = this;
  while( THIS.parentElement ){
    THIS = THIS.parentElement;
    if(THIS.nodeName == 'BODY'){
      THIS.style.backgroundColor='red';
    }
  }
}
</script>

同級節(jié)點(diǎn)關(guān)系

  • Node.nextSibling

    下一個(gè)節(jié)點(diǎn),注意包含文本、注釋、元素節(jié)點(diǎn)

  • Node.nextElementSibling:

    下一個(gè)元素節(jié)點(diǎn),只是元素節(jié)點(diǎn)。

<button onclick="setBox(this)">按鈕</button>
<div></div>

<script>
//單擊按鈕,給div設(shè)置寬200 高200 背景顏色紅色
function setBox( btn ){
  btn.nextElementSibling.style.cssText = `width:200px;height:200px;background-color:red`;
}
</script>
  • Node.previousSibling

    上一個(gè)節(jié)點(diǎn),注意包含文本、注釋、元素節(jié)點(diǎn)

  • Node.previousElementSibling

    上一個(gè)元素節(jié)點(diǎn),只是元素節(jié)點(diǎn)。

    綜合的例子

  <ul>
  <li>一分</li>
  <li>二分</li>
  <li>三分</li>
  <li>四分</li>
  <li>五分</li>
</ul>

<script>
var lis = document.querySelectorAll('li');

lis.forEach( function( item ){

  item.onclick = function(){
    var THIS1 = this;
    var THIS2 = this;
    
    //查找當(dāng)前元素往上的所有元素
    while( THIS1.previousElementSibling ){
      THIS1 = THIS1.previousElementSibling;
      THIS1.className = 'active' 
    }

    //查找當(dāng)前元素往下的所有元素
    while( THIS2.nextElementSibling ){
      THIS2 = THIS2.nextElementSibling;
      THIS2.className = 'active' 
    }

  }

})
</script>

經(jīng)典面試題:請用至少3種辦法生成一個(gè)隨機(jī)不重復(fù)的字符串

// 方法1
var id = new Date().getTime();
console.log( id );

// 方法2
var str = Math.random().toString(36).slice(2);
console.log(str);

// 方法3
var str = 'abcdefghijkmnopqrstuvwxyzABCDEFGHIJKMNOPQRSTUVWXYZ0123456789';
var arr = str.split('');
var newArr = arr.sort(function(){
  return .5 - Math.random();
}).slice(0,20);
console.log( newArr.join('') );

// 方法4
var str = 'abcdefghijkmnopqrstuvwxyzABCDEFGHIJKMNOPQRSTUVWXYZ0123456789';
var arr = str.split('');
var temp = '';
for(var i=0;i<arr.length;i++){
  var index = Math.floor(Math.random()*arr.length);
  temp += arr[index];
}
console.log( temp );
  • Node.isConnected

返回一個(gè)布爾值,表示當(dāng)前節(jié)點(diǎn)是否在文檔之中

<div id="box1"></div>

<script>
//文檔本身就存在
var box1 = document.getElementById('box');
console.log( box1.isConnected );//true

//創(chuàng)建了元素,但是并沒有插入到文檔中
var box2 = document.createElement('div');
console.log( box2.isConnected );//false 
</script>

Node 接口的方法

  • document.createElement

在文檔中創(chuàng)建一個(gè)元素

語法:

document.createElement('標(biāo)簽名');

示例

var div = document.createElement('div');
console.log( div );//<div></div>

綜合示例

//1. 創(chuàng)建一個(gè)div元素
var div = document.createElement('div');

//2. 創(chuàng)建一個(gè)屬性節(jié)點(diǎn)
var cls = document.createAttribute('class');

//3. 設(shè)置屬性節(jié)點(diǎn)的值
cls.value = 'red';

//4. 把屬性節(jié)點(diǎn)應(yīng)用到目標(biāo)元素上
div.setAttributeNode( cls );

//5. 創(chuàng)建注釋
var zs = document.createComment('新的div');

//6. 將上面的注釋添加到div的內(nèi)部后面
div.appendChild( zs );

//7. 創(chuàng)建一個(gè)p標(biāo)簽
var p = document.createElement('p');

//8. 創(chuàng)建一個(gè)文本標(biāo)簽
var text = document.createTextNode('今天的天氣有點(diǎn)陰沉!');

//9. 將文本節(jié)點(diǎn)追加到p標(biāo)簽內(nèi)部的后面
p.appendChild( text );

//10. 將上面的p標(biāo)簽追加到div內(nèi)部后面
div.appendChild( p );

//11. 輸出新創(chuàng)建的節(jié)點(diǎn)
console.log( div );

使用JS標(biāo)準(zhǔn)API創(chuàng)建節(jié)點(diǎn)示例

<script>
var data = [
  {id:1,name:'首頁',url:'#'},
  {id:2,name:'關(guān)于我們',url:'#', active: true},
  {id:3,name:'聯(lián)系我們',url:'#'},
];

var div = document.createElement('div');
var divClass = document.createAttribute('class');
divClass.value = 'nav';

var divStyle = document.createAttribute('style');
divStyle.value = 'width:100px;';

div.setAttributeNode( divClass );

div.setAttributeNode( divStyle );

var ul = document.createElement('ul');

for(var i=0;i<data.length;i++){

  var li = document.createElement('li');
  var a = document.createElement('a');
  
  var aHref = document.createAttribute('href');
  aHref.value = data[i].url;
  a.setAttributeNode( aHref );

  if( data[i].active ){
    var aClass = document.createAttribute('class');
    aClass.value = 'active';
    a.setAttributeNode( aClass );
  }

  var text = document.createTextNode( data[i].name );

  a.appendChild( text );
  li.appendChild( a );
  ul.appendChild( li );
}

div.appendChild( ul );

document.getElementsByTagName('body')[0].appendChild( div );

</script>

示例

<button onclick="createBox()">創(chuàng)建盒子并附加樣式</button>

<script>

function createBox(){
  
  var div = document.createElement('div');

  // var divClass = document.createAttribute('class');
  // divClass.value ='box';
  // div.setAttributeNode( divClass );

  //等同于上面的寫法
  div.className = 'box';

  // var text = document.createTextNode('段落');
  // div.appendChild( text );

  //等同于上面的寫法
  div.innerText = '段落';

  var style = document.createElement('style');
  style.innerHTML = `
  .box{
    width: 100px;
    height: 100px;
    background-color: red;
  }`;

  document.getElementsByTagName('head')[0].appendChild( style );

  document.getElementsByTagName('body')[0].appendChild( div );

}
</script>

頁碼示例

<div id="box1"></div>

<div id="box2"></div>

<script>

makePage( 'box1', 10, 1 );
makePage( 'box2', 5, 2 );

function makePage( id, totalPage, page=1 ){
  
  var target = document.getElementById( id );
  target.innerHTML = '';

  for(let p=1;p<=totalPage;p++){

    var btn = document.createElement('button');
    btn.innerText = p;
    if(p==page){
      btn.className = 'active';
    }

    //因?yàn)閯?chuàng)建的是dom對象,該對象尚未插入到文檔中,所以這里可以直接加上事件
    btn.onclick = function(){
      // console.log( p );
      makePage( id, totalPage, p );
    }

    target.appendChild( btn );

  }
}

</script>
  • Node.appendChild

往目標(biāo)節(jié)點(diǎn)內(nèi)部的后面插入新節(jié)點(diǎn),返回被插入的新節(jié)點(diǎn)

var div = document.createElement('div');
div.innerText = '內(nèi)容';
var text = document.createTextNode('段落');
div.appendChild( text );

console.log( div );// <div>內(nèi)容段落</div>

穿梭框效果

 <style>
  ul{
    float: left;
    list-style: none;
    margin: 0;
    padding: 0;
    overflow: auto;
    height: 200px;
    width: 160px;
    border: 1px solid #ccc;
    margin-right: 20px;
  }
  .btns{
    float: left;
    padding-top: 22px;
    width: 100px;
   
  }
  .btns button{
    margin-bottom: 20px;
  }
  ul li{
    line-height: 30px;
    font-size: 14px;
    padding: 0 10px;
    cursor: pointer;
  }
  ul li:nth-child(even){
    background-color: #eee;
  }
  ul li.active{
    background-color: rgb(2, 141, 255);
    color: white;
  }
  </style>
<h1>穿梭框效果</h1>

<ul id="left">
  <li>陳旻</li>
  <li>李杰</li>
  <li>曾崇博</li>
  <li>鄧聰</li>
  <li>鐘旺</li>
  <li>鄧紹志</li>
  <li>劉江湖</li>
  <li>代晨</li>
</ul>

<div class="btns">
    <button onclick="addRightAll()"> 全部追加 </button>
    <button onclick="addRight()"> 向右添加 </button>
    <button onclick="addLeft()"> 向左添加 </button>
    <button onclick="addLeftAll()"> 全部移除 </button>
</div>

<ul id="right">

</ul>

<button onclick="getVal()">取值</button>

<script>
var left = document.getElementById('left');
var leftLis = left.children;

var right = document.getElementById('right');
var rightLis = right.children;

//添加單擊選中事件
for(var i=0;i<leftLis.length;i++){
  leftLis[i].onclick = function(){
    this.classList.toggle('active');
  }
}

//向右追加全部
function addRightAll(){
  addItem( right,  leftLis, 'all' );
}

//向左移除全部
function addLeftAll(){
  addItem( left,  rightLis, 'all' );
}

//向右追加
function addRight(){
  addItem( right,  leftLis );
}

//向左追加
function addLeft(){
  addItem( left,  rightLis );
}

//追加li元素
function addItem( target,  lis, flag ){

  //倒著刪除
  for( var i = lis.length-1; i >= 0 ; i-- ){
    if( lis[i].classList.contains('active') || flag == 'all' ){
      lis[i].classList.remove('active');
      target.appendChild( lis[i] );
    }
  }

}

//取值
function getVal(){
  var val = '';
  for( var i=0; i < rightLis.length; i++ ){
    val += rightLis[i].innerText+',';
  }
  val = val.slice(0, -1);
  alert( val );
}


</script>

代碼片段

<div id="box">
</div>

<button onclick="add()">添加</button>

<script>
var box = document.getElementById('box');
function add(){

  var p = document.createElement('p');
  var span = document.createElement('span');
  var a = document.createElement('a');

  //創(chuàng)建一個(gè)代碼片段節(jié)點(diǎn),代碼片段節(jié)點(diǎn)沒有名稱
  var fragment = document.createDocumentFragment();
  fragment.appendChild( p );
  fragment.appendChild( span );
  fragment.appendChild( a );

  box.appendChild( fragment );

}
</script>
  • Node.hasChildNodes

注意:節(jié)點(diǎn)包含7種類型

<div id="box">

</div>

<script>
var box = document.getElementById('box');
console.log( box.hasChildNodes() );//true 因?yàn)榘谋竟?jié)點(diǎn)
</script>
  • Node.cloneNode

用于克隆一個(gè)節(jié)點(diǎn)。它接受一個(gè)布爾值作為參數(shù),表示是否同時(shí)克隆子節(jié)點(diǎn)。它的返回值是一個(gè)克隆出來的新節(jié)點(diǎn)。

注意事項(xiàng):

  • 克隆一個(gè)節(jié)點(diǎn),會拷貝該節(jié)點(diǎn)的所有屬性,但是會喪失事件方法
  • 該方法返回的節(jié)點(diǎn)不在文檔之中,即沒有任何父節(jié)點(diǎn),必須使用諸如Node.appendChild這樣的方法添加到文檔之中。
  • 克隆一個(gè)節(jié)點(diǎn)之后,DOM 有可能出現(xiàn)兩個(gè)有相同id屬性
<span id="span">
  <b>文本</b>
</span>

<div id="div"></div>

<button onclick="copy()">復(fù)制文本</button>

<script>
function copy(){
  var span = document.getElementById('span');
  var div = document.getElementById('div');

  //復(fù)制節(jié)點(diǎn),加true表示連同子節(jié)點(diǎn)一起復(fù)制
  var _span = span.cloneNode( true );

  div.appendChild( _span );

}

</script>
  • Node.insertBefore

用于將某個(gè)節(jié)點(diǎn)插入父節(jié)點(diǎn)內(nèi)部的指定位置,給參考節(jié)點(diǎn)外部前面插入新節(jié)點(diǎn)。

語法:

父節(jié)點(diǎn).insertBefore( 新節(jié)點(diǎn), 參考節(jié)點(diǎn));

示例

<button onclick="before( this )">按鈕 </button>

<script>
function before( btn ){
  var parent = btn.parentNode;
  var p = document.createElement('p');
  p.innerText= '文本';
  parent.insertBefore( p, btn );
}
</script>
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 一、基本概念 1.1、DOM DOM是JS操作網(wǎng)頁的接口,全稱為“文檔對象模型”(Document Object ...
    周花花啊閱讀 3,440評論 0 6
  • 基本概念 DOM DOM 是 JavaScript 操作網(wǎng)頁的接口,全稱為“文檔對象模型”(Document Ob...
    許先生__閱讀 931評論 0 1
  • 一、概述 document節(jié)點(diǎn)是整個(gè)文檔樹的頂層節(jié)點(diǎn),每張網(wǎng)頁都有自己的document節(jié)點(diǎn)。window.doc...
    周花花啊閱讀 1,420評論 0 1
  • ??DOM(文檔對象模型)是針對 HTML 和 XML 文檔的一個(gè) API(應(yīng)用程序編程接口)。 ??DOM 描繪...
    霜天曉閱讀 3,866評論 0 7
  • DOM模型 DOM(文檔對象模型)是針對HTML和XML的一個(gè)API,DOM描繪了一個(gè)層次化的節(jié)點(diǎn)樹,允許開發(fā)人員...
    FWHeart閱讀 788評論 0 2

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