11. JS DOM

DOM 简介

DOM 获取元素

DOM 操作

DOM 节点(Node)

DOM 应用

练习

一、DOM 简介

  • HTML的标准对象模型

  • HTML 的标准编程接口

  • W3C 标准

  • 当页面加载时,浏览器会创建页面的文档对象模型(Document Object Model)

  • HTML DOM 定义了所有 HTML 元素的对象和属性,以及访问它们的方法。
    换言之,HTML DOM 是关于如何获取、修改、添加或删除 HTML 元素的标准

  • DOM 将 HTML 文档呈现为带有元素、属性和文本的树结构,即节点树

我们之所以能够对Web页面进行添加、删除、更新、操控元素等等活动,就是因为DOM才得以实现。它定义了一套对象(方法)规则,使得JavaScript可以根据这些规则来进行编程,更像是一个文档API。

DOM结构树:

  • 形成原型链:document--->HTMLDocument.prototype-->Document.prototype-->Node.prototype-->EventTarget.prototype-->Object.prototype-->null

二、DOM 获取元素

每个载入浏览器的 HTML 文档都会成为 Document 对象。

Document 对象使我们可以从脚本中对 HTML 页面中的所有元素进行访问。

提示:Document 对象是 Window 对象的一部分,可通过 window.document 属性对其进行访问。

所谓的 DOM,实际上就是 document,获取元素就是操作 document。

JS 要想操作 HTML 元素,那么首先就必须先找到该元素,通常使用以下几种方法完成。

1. document.getElementById('元素id');

  • 通过元素 id 获取节点

定义了一个工具函数,这样您就可以通过一个较短的名字来使用 getElementById() 方法了

  function id(x) {
      if (typeof x == "string") return document.getElementById(x);
      return x;
  }
  // 上面这个函数接受元素 ID 作为它们的参数。使用前编写 x = id(x) 就可以了。

2. document.getElementsByTagName('元素标签'); ==> 最常用

  • 通过元素标签获取节点

  • 返回的是带有指定标签名的对象的集合,也就是以数组的形式返回,返回的顺序是他们在文档中的顺序

  • 如果把特殊字符串 "*" 传递给 getElementsByTagName()方法,它将返回文档中所有元素的列表,元素排列的顺序就是它们在文档中的顺序

传递给 getElementsByTagName() 方法的字符串可以不区分大小写

3. document.getElementsByName('元素name属性'); ==> 基本不用

  • 通过元素的 name 属性获取节点

  • 只有部分标签 name 可生效(表单,img,iframe)

  • 返回带有指定名称的对象的集合

该方法与 getElementById() 方法相似,但是它查询元素的 name 属性,而不是 id 属性。
另外,因为一个文档中的 name 属性可能不唯一(如 HTML 表单中的单选按钮通常具有相同的 name 属性),所有 getElementsByName() 方法返回的是元素的数组,而不是一个元素。

<body>
<input name="txt" type="text" value="1">
<input name="txt" type="text" value="2"><br>
<input name="txt" type="text" value="3">
<input name="txt" type="text" value="4"><br>
<input name="txt" type="text" value="5">
<input name="aaa" type="text" value="6">

<script>
//获取所有name值为txt的元素
var oTxt = document.getElementsByName("txt");  

//获取元素的个数
alert(oTxt.length);       //返回:5

//获取第二个元素的值
alert(oTxt[1].value);    //返回:2
</script>

</body>

4. document.getElementsByClassName('class名')

  • 查找带有相同类名的所有 HTML 元素的列表

在 Internet Explorer 5,6,7,8 中无效,所以常用 getElementsByTagName

<div class="demo"></div>
<p class = "demo"></p>
<div class="demo">
   <span class= "demo"></span>
</div>

var div = document.getElementsByClassName('demo');

object.className = 'className'

  • 用于设置或者返回元素的 class 类名

  • 该方法可以控制 class 类名,返回元素的 class 属性,作用是可以为网页中某个元素指定一个 className 来更改该元素的外观

    • 示例:简单的网页换肤
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>网页换肤</title>

<style>
body{
    background:lightgreen;
}
.col1{
    background:lightgray;
}
.col2{
    background:lightblue;
}
.col3{
    background:violet;
}
.col4{
    background:pink;
}
.col5{
     background:#f93;
}
</style>

</head>

<body id="boy">
点击切换:<input type="button" value="灰色" onclick="gr()">
<input type="button" value="蓝色" onclick="bl()">
<input type="button" value="紫色" onclick="vi()">
<input type="button" value="粉色" onclick="pi()">
<input type="button" value="橘色" onclick="or()">

<script>
var x = document.getElementById('boy');
function gr(){
    x.className = 'col1';
}

function bl(){
    x.className = 'col2';
}

function vi(){
    x.className = 'col3';
}

function pi(){
    x.className = 'col4';
}

function or(){
    x.className = 'col5';
}
</script>

</body>
</html>

  • 设置多个 class 类名相同的元素的样式(效果和 getElementsByClassName 一样)

    • 示例:将有序列表中所有 class 属性值为"col"的元素背景颜色设置为绿色
<body>
<ol id="o1">
    <li>热点</li>
    <li class="col">美食</li>
    <li>数码</li>
    <li class="col">科技</li>
    <li>社会</li>
    <li class="col">养生</li>
</ol>
<script>
//通过id获取父元素
var aOl = document.getElementById('o1');
//通过标签名获取父元素下所有子元素
var oLi = aOl.getElementsByTagName('li');
//循环遍历返回的子元素数组
for(var i=0; i<oLi.length; i++){
    //如果当前子元素的className等于设置的class属性值,则将其背景设置为绿色
    if(oLi[i].className == 'col') oLi[i].style.background = 'green';
}
</script>
</body>

通过 class 属性值获取元素的封装函数

  • 解决getElementsByClassName浏览器兼容问题
<ol id="o1">
    <li>热点</li>
    <li class="col">美食</li>
    <li>数码</li>
    <li class="col">科技</li>
    <li>社会</li>
    <li class="col">养生</li>
</ol>
// 封装函数
function getByClass(oParent,aClass){ //第一个参数为获取的父元素,第二个参数为class属性值。
	
  //如果浏览器支持 会得到一个函数体
  if(oParent.getElementsByClassName){
    return oParent.getElementsByClassName(aClass);
  }

  //通过标签名获取父元素下所有子元素。标签名不固定,所以设置为*,便于传入。
  var allItems = oParent.getElementsByTagName("*");
  
  //设置空数组备用,最后可以把找到的所有className都存放在里边并返回。
  var newArr = [];

  //查找每一个元素的 className 看其中是否包含 aClass 参数
  for(var i = 0; i < allItems.length; i++){
    var arrClass = allItems[i].className.split(" ");
    for(var j = 0; j < arrClass.length; j++){
      if(arrClass[j]==name){
        newArr.push(allItems[i]);
      }
    }
  }
  // 最后返回数组
  return newArr;
}

//封装函数的使用:
//先通过id获取父元素
var aOl = document.getElementById('o1');

//再调用封装好的函数传入参数,获取的父元素,子元素的class属性值
//如果父元素是文档就传入 document
var oCol = getByClass(aOl,'col');

//最后循环遍历,设置样式
for(var i=0; i<oCol.length; i++){
    oCol[i].style.background = 'green';
}

5. querySelector()querySelectorAll()

querySelector() 返回文档中匹配指定 CSS 选择器的一个元素

参数:CSS 选择器, 必须。指定一个或多个匹配元素的 CSS 选择器。 可以 使用它们的 id, 类, 类型, 属性, 属性值等来选取元素。对于多个选择器,使用逗号隔开,返回一个匹配的元素。

querySelector() 方法仅仅返回匹配指定选择器的第一个元素。如果你需要返回所有的元素,请使用 querySelectorAll() 方法替代。querySelector 返回的是单个 DOM 元素;querySelectorAll 返回的是 NodeList.

querySelector 和 querySelectorAll IE8+浏览器支持。

  <div class="demo">
       <span class= "demo">a</span>
       <i class = "a">123</i>
       <div class = "inner">
           <strong></strong>
       </div>
   </div>
  
  var strong= document.querySelector('div.demo  div.inner strong'); // 选择 strong 标签

queryselect()queryselectAll()缺点:

  • 它不是实时的,它只是保存了选择出来的那些元素的副本,当它们动态改变的时候,用queryselect()和queryselectAll()选出来的还是原来的,不会跟着改变。

三、DOM 操作

  • 获取到 HTML 元素之后,就可以进行相应的操作。

1. 改变HTML

  • 修改 HTML 内容的最简单的方法时使用 innerHTML 属性。innerHTML 顾名思义,inner 就是内部的,既然是 HTML,那么就可以给里边放 HTML。该属性可用于获取和替换 HTML 元素的内容。

  • document.getElementById(id).innerHTML = new HTML

//<p id="intro">Hello World!</p>

var txt = document.getElementById("intro").innerHTML; //获取
document.write(txt);

/*
Hello World!
Hello World!
*/
------------------------------------------
//<p id="p-id">...</p>
var p = document.getElementById('p-id');

// 设置文本为abc:
p.innerHTML = 'ABC'; // ABC

// 设置HTML:
p.innerHTML = 'ABC <span style="color:red">RED</span> XYZ';
// <p>...</p>的内部结构已修改
// ABC RED XYZ

2. 操作元素属性

(1) 获取属性:getAttribute()
  • 语法:元素节点.getAttribute(元素属性名)
  • 获取元素节点中指定属性的属性值

(2) 设置属性:setAttribute()
  • 语法:元素节点.setAttribute(属性名,属性值)
  • 添加一个新属性并指定值,或者把一个现有的属性设定为指定的值

(3) 删除属性:removeAttribute()
  • 语法:元素节点.removeAttribute(属性名)
  • 删除元素中的指定属性

<input id="txt1" type="text">
<input id="btn1" type="button" value="按钮">
var oTxt = document.getElementById('txt1');
var oBtn = document.getElementById('btn1');

//获取按钮value属性的值
var a = oBtn.getAttribute('value');
console.log(a);    //按钮

oBtn.onclick = function (){
    //操作元素属性有三种方法:
    //第一种方法
    //oTxt.value='请输入文字';

    //第二种方法
    //oTxt['value']='请输入文字';

    //第三种方法
    //修改文本框value属性的值
    oTxt.setAttribute('value','请输入文字');

    //删除按钮type属性
    oBtn.removeAttribute('type');
    //按钮删除后默认变成文本框,原来的 value 值变成文本框中的文本
};

3. 改变CSS

  • document.getElementById(id).style.样式名 = new style

  • DOM 节点的 style 属性对应所有的 CSS,可以直接获取或设置。

  • 因为CSS允许 font-size 这样的名称,但它并非 JS 有效的属性名,所以需要在 JS 中改写为驼峰式命名 fontSize

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>JavaScript实例</title>
<style>
#div1{
    height:400px;
    width:600px;
    border:1px solid black;
    padding:5px;
}
p{
    line-height:18px;
    text-indent:2em;
}
</style>
</head>
<body>
<h2>HTML DOM</h2>
<div id="div1">
    <h3>JS可以使网页添加动态效果并实现与用户交互的功能。</h3>
    <p>1. JS能够改变页面中所有的 HTML 元素。</p>
    <p>2. JS能够改变页面中所有的 HTML 属性。</p>
    <p>3. JS能够改变页面中所有的 HTML 元素的CSS样式。</p>
</div>

<input type="button" value="改变颜色" onclick="color()">
<input type="button" value="改变宽高" onclick="hig()">
<input type="button" value="隐藏内容" onclick="none()">
<input type="button" value="显示内容" onclick="block()">
<input type="button" value="取消设置" onclick="cancel()">

<script>
var oDiv = document.getElementById('div1');
function color(){
    oDiv.style.color = 'white';
    oDiv.style.fontFamily = 'Microsoft YaHei';
    oDiv.style.backgroundColor = 'green';
}

function hig(){
    oDiv.style.width = '400px';
    oDiv.style.height = '300px';
    oDiv.style.border = '5px solid #ccc';
}

function none(){
    oDiv.style.display = 'none';
}

function block(){
    oDiv.style.display = 'block';
}

//取消设置
function cancel(){
    var clean = confirm('确定取消所有设置?');
    if(clean == true){
        oDiv.removeAttribute('style');
    }
}
</script>
</body>
</html>

4. 对事件做出响应

<!--全选和反选,输入对应的序号选中-->
<form id="list">
    请选择你的业余爱好:<br>
    1. 音乐<input type="checkbox" name="love" id="like1">
    2. 阅读<input type="checkbox" name="love" id="like2">
    3. 游泳<input type="checkbox" name="love" id="like3">
    4. 篮球<input type="checkbox" name="love" id="like4">
    5. 足球<input type="checkbox" name="love" id="like5">
    6. 散步<input type="checkbox" name="love" id="like6">
    7. 泡吧<input type="checkbox" name="love" id="like7">
    8. 逛街<input type="checkbox" name="love" id="like8"><br>
    <input type="button" value = "全选" onclick="optAll()">
    <input type="button" value = "反选" onclick="noAll()">

    <p>输入1-8序号选择,每次只可以选择一项:</p>
    <input id="txt1" type="text">
    <input id="btn1" type="button" value="确定">
</form>
//通过获取标签名设置全选
var oList = document.getElementById('list');
var aCheck = oList.getElementsByTagName('input');

function optAll(){
    for(var i=0; i<aCheck.length; i++){
        if(aCheck[i].type == 'checkbox'){
            aCheck[i].checked = true;
        }
    }
}

//通过获取设置的name属性值设置反选
var aLove = document.getElementsByName('love'); 

function noAll(){ 
    for(var i=0; i<aLove.length; i++){
        if(aLove[i].type == 'checkbox'){
            aLove[i].checked = false;
        }
    }
}

var oBtn = document.getElementById('btn1');
//给获取的按钮添加点击事件

oBtn.onclick = function (){
    noAll();    // 清空选项

    //获取文本框输入的值
    var oTxt = document.getElementById("txt1").value;

    //定义的复选框id值为like1-8。括号中进行的是字符串连接,id+输入到文本框的值=该元素的id值
    var oLike = document.getElementById('like' + oTxt);
    oLike.checked = true;
}

四、DOM 节点(Node)

  • HTML DOM 将 HTML 文档视作树结构

  • HTML 文档可以说是由节点构成的集合,常见的 DOM 节点有三种,即元素节点、属性节点和文本节点。

  • 元素节点就是 HTML 标签,标签的属性就是属性节点,文本节点就是页面可以浏览的内容。

  • 在文档对象模型中,每一个节点都是一个对象,DOM 节点有三个重要的属性:节点的名称,节点的值和节点的类型。

节点父、子和同胞

节点树中的节点彼此拥有层级关系。

父(parent)、子(child)和同胞(sibling)等术语用于描述这些关系。父节点拥有子节点,同级的子节点被称为同胞(兄弟或姐妹)。

  • 在节点树中,顶端节点被称为根(root)

  • 每个节点都有父节点、除了根(它没有父节点)

  • 一个节点可拥有任意数量的子节点

  • 同胞是拥有相同父节点的节点

下面的图片展示了节点树的一部分,以及节点之间的关系:

操作一个DOM节点实际上就是这么几个操作:

  • 更新:更新该DOM节点的内容,相当于更新了该DOM节点表示的HTML的内容;
  • 遍历:遍历该DOM节点下的子节点,以便进行进一步操作;
  • 添加:在该DOM节点下新增一个子节点,相当于动态增加了一个HTML节点;
  • 删除:将该节点从HTML中删除,相当于删掉了该DOM节点的内容以及它包含的所有子节点。

1. DOM 节点属性

(1) nodeName:节点的名称

  • nodeName 属性返回节点的名称

  • 元素节点的名称与标签名相同(大写),属性节点的名称是属性的名称,文本节点的名称永远都是 #text,文档节点的名称永远都是 #document。

  • 注释:nodeName 始终包含 HTML 元素的大写字母标签名

(2) nodeValue:节点的值

  • nodeValue 属性返回节点的值。

  • 元素节点的值是 undegined 或 null,属性节点的值是属性的值,文本节点的值是文本自身。

(3) nodeType:节点的类型

  • nodeType 属性返回节点的类型。
节点类型 说明
元素节点 每一个HTML标签都是一个元素节点,如 <div> 、 <p>、<ul> 等 1
属性节点 元素节点(HTML标签)的属性,如 id 、class 、name 等。 2
文本节点 元素节点或属性节点中的文本内容。 3
注释节点 表示文档注释,形式为。 8
文档节点 表示整个文档(DOM 树的根节点,即 document )。 9
<body>
<ul>
    <li>JS</li>
    <li>DOM</li>
</ul>
<script>
var nodes = document.getElementsByTagName('li');
for(var i=0; i<nodes.length; i++){
    document.write('第' + (i+1) + '个节点的名称是' + nodes[i].nodeName + '<br>');
    document.write('第' + (i+1) + '个节点的值是' + nodes[i].nodeValue + '<br>');
    document.write('第' + (i+1) + '个节点的类型是' + nodes[i].nodeType + '<br>');
    document.write('<br>');
} 

/*
返回:
第1个节点的名称是LI
第1个节点的值是null
第1个节点的类型是1

第2个节点的名称是LI
第2个节点的值是null
第2个节点的类型是1
*/
</script>
</body>

(4) attributes:Element节点的属性集合

<div id='only' class = 'demo'></div>    // div 有两个属性 id='only' 和 class = 'demo'

div.attributes // {0:id,1:class,length:2} 类数组

div.attributes[0] // id='only'

div.attributes[0].nodeType  // 2 属性节点

节点的一个方法:Node.hasChildNodes()

  • 查看元素是否有子节点
<div id='only' class = 'demo'></div> // div.hasChildNodes() --> flase

<div id='only' class = 'demo'> </div>   // div.hasChildNodes() --> true 有个文本节点

JS 中函数可以嵌套使用,有父函数有子函数,HTML 标签也可以嵌套使用,那么就说明存在着各种不同的节点关系,比如父节点、子节点和兄弟节点。为了方便操作,DOM定义了一些节点的公共属性。

2. 遍历元素节点树

children 使用率最高

(1) 子节点:

  • childNodes 属性返回节点的子节点集合,可使用 length 属性返回子节点的数量,然后就可以和数组一样获取需要的信息。
<body>
<ul id="u1">
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    <li>5</li>
</ul>

<!--<ul id="u1">   第1个节点(文本节点)    -->
<!--    <li>第2个节点(元素节点)</li> 第3个节点(文本节点)-->
<!--    <li>第4个节点(元素节点)</li> 第5个节点(文本节点)-->
<!--    <li>第6个节点(元素节点)</li> 第7个节点(文本节点)-->
<!--    <li>第8个节点(元素节点)</li> 第9个节点(文本节点)-->
<!--    <li>第10个节点(元素节点)</li> 第11个节点(文本节点)-->
<!--</ul>-->

<script>
var oUl = document.getElementById('u1');
alert(oUl.childNodes.length);   
</script>
</body>

因为通过 childNodes 属性返回的子节点集合,不仅包括元素节点,而且还包括文本节点,浏览器会将标签之间的空白默认为文本节点,如果在空白处输入文字,就会显示在页面上,这就造成了不必要的麻烦。

所以建议使用 `children` 属性,该属性只返回元素节点,不包括文本节点,并且不包括注释节点。

<body>
<ul id="u1">
    <li>
        我是个文本节点
        <span>我是span元素。</span>
    </li>
    <li></li>    <!-- 注释 -->
    <li></li>
    <li></li>
    <li></li>
</ul>
<script>
var oUl = document.getElementById('u1');
alert(oUl.children.length);    // ul 下有 5 个 li 元素,返回子节点个数为 5
</script>
</body>
  • children 属性要比 childNodes 属性好用太多了,只返回元素的子节点,还不包括孙子辈节点。

注:IE6 到 IE8 完全支持 children 属性,但是,返回元素节点和注释节点,IE9 以上版本只返回元素节点。

(2) 首尾子节点:

  • firstElementChild 属性返回 children 数组的第一个节点

    • node.firstElementChild ==> element.children[0]
  • lastElementChild 属性返回 children 数组的最后一个节点

    • node.lastElementChild ==> element.children[element.children.length-1]

IE6/7/8中不支持firstElementChild属性,可以使用 children[i] 属性

<body>
<div style="border:2px solid green" id="div1">
   空白节点
  <p>JS</p>
  <div>DOM</div>
  <h3>jQuery</h3>
</div>
<script>
var x = document.getElementById('div1');
document.write('第一个节点的名称:' + x.firstElementChild.nodeName + '<br>');
//返回:第一个子节点的名称:P
document.write('最后一个节点的名称:' + x.lastElementChild.nodeName)
//返回:最后一个子节点的名称:H3
</script>
</body>

(3) 父节点:

  • parentNode 属性用于获取指定节点的父节点。

  • 最顶端的parentNode#document

  • 注意:父节点只能有一个。通过使用两个获取父节点,可获取祖节点

实例:点击子节点,隐藏父节点

<ul id="u1">
    <li>aaa <a href="javascript:;">点击隐藏</a></li>
    <li>bbb <a href="javascript:;">点击隐藏</a></li>
    <li>ccc <a href="javascript:;">点击隐藏</a></li>
    <li>ddd <a href="javascript:;">点击隐藏</a></li>
    <li>eee <a href="javascript:;">点击隐藏</a></li>
</ul>
var oUl = document.getElementById('u1');
//查看ul元素的父节点
alert(oUl.parentNode);    //返回:[object HTMLBodyElement]

//通过标签名获取所有的a元素
var aA = oUl.getElementsByTagName('a');
for(var i=0; i<aA.length; i++){
    aA[i].onclick = function (){    // 为每个按钮设置点击事件
        //设置当前节点的父节点为隐藏
        this.parentNode.style.display = 'none';
    };
}

(4) 兄弟节点:

  • nextElementSibling 属性返回同一树层级中某个节点之后紧跟的节点

    • element.nextElementSibling
  • previousElementSibling 属性返回同一树层级中某个节点之前紧跟的节点

    • element.previousElementSibling

IE6/7/8中不支持可以使用 children[i] 属性

实例:获取 li 元素节点的兄弟节点

<ul>   
    <li>HTML</li>   
    <li>CSS</li>
    <li>JS</li>   
</ul> 
var aLi = document.getElementsByTagName('li');
//获取第二个子节点之后紧跟的节点
var x = aLi[1].nextElementSibling;
alert(x.innerHTML);    //返回:JS

//获取第二个子节点之前紧跟的节点
var y = aLi[1].previousElementSibling;
alert(y.innerHTML);    //返回:HTML

五、DOM 应用

DOM 最实际的应用就是可以通过 JS 创建、插入和删除节点

1. 创建节点

  • createElement() 方法可创建元素节点

    • document.createElement(tagName)

实例:创建并添加 li 元素

<input id="txt1" type="text"value="">
<input id="btn1" type="button"value="创建li">
<ul id="u1"></ul>
var oBtn = document.getElementById('btn1');
var oUl = document.getElementById('u1');
var oTxt = document.getElementById('txt1');

//文本框输入提示
oTxt.placeholder = '请输入文字创建li元素';

oBtn.onclick = function (){
    //创建li元素
    var oLi = document.createElement('li');

    //创建的li元素的HTML=文本框输入的值
    oLi.innerHTML = oTxt.value;

    //插入到oUl父级下,作为子节点,在每个创建的li末尾插入新创建的li元素
    oUl.appendChild(oLi);
    //父级.appendCild(子节点);
};

2. 插入节点

  • appendChild() 方法可在指定节点的末尾插入一个新的子节点,每次都向末尾添加

    • 父级.appendChild(new node)
  • insertBefore() 方法可在已有的子节点前插入一个新的子节点

    • 父级.insertBefore(插入的新子节点, 原有节点)

实例:创建并添加 li 元素,每个新创建的 li 元素都插入到之前插入的 li 元素之前

<input id="txt1" type="text" value="">
<input id="btn1" type="button" value="创建li">
<ul id="u1"></ul>
var oBtn = document.getElementById('btn1');
var oUl = document.getElementById('u1');
var oTxt = document.getElementById('txt1');

oBtn.onclick = function (){
    //创建li元素
    var oLi = document.createElement('li');
    //获取所有li元素
    var aLi = oUl.getElementsByTagName('li');
    oLi.innerHTML = oTxt.value;

    //这里需要注意:页面中本没有li元素,li元素是通过JS创建的
    //所以第一个li元素应该添加到父级下最后一个子节点
    //然后基于这个节点,将之后再插入的子节点插入到上一个节点之前

    //如果li元素本来不存在,则执行else,在父级插入一个子节点。
    //如果li元素的个数>0,说明已经创建了,则插入到这个子节点之前。
    if(aLi.length>0){
        oUl.insertBefore(oLi,aLi[0]);
    }
    else{
        oUl.appendChild(oLi);
    }
};

3. 删除节点

  • removeChild() 方法用于删除一个节点

    • 父级.removeChild(要删除的子节点)

实例:简单的表格添加和删除

var oTab = document.getElementById('tab1');
var oName = document.getElementById('user');
var oAge = document.getElementById('age');
var oBtn = document.getElementById('btn1');

//设置添加的ID项的值
var id = oTab.tBodies[0].rows.length+1;

oBtn.onclick = function (){
    //创建一个tr
    var oTr = document.createElement('tr');
    //创建第一个td(ID项)
    var oTd = document.createElement('td');
    //获取ID,已经删除的ID号,不能再重用。
    oTd.innerHTML = id++;
    //将创建的td放入创建的tr中
    oTr.appendChild(oTd);

    //创建第二个td(姓名项)
    var oTd = document.createElement('td');
    oTd.innerHTML = oName.value;
    oTr.appendChild(oTd);

    //创建第三个td(年龄项)
    var oTd = document.createElement('td');
    oTd.innerHTML = oAge.value;
    oTr.appendChild(oTd);

    //创建第四个td(操作项)
    var oTd = document.createElement('td');
    oTd.innerHTML = '<a href="javascript:;">删除</a>';
    oTr.appendChild(oTd);

    oTd.getElementsByTagName('a')[0].onclick = function (){
        //删除整行
        oTab.tBodies[0].removeChild(this.parentNode.parentNode);
    };

    //将创建好的tr放入tbody中
    oTab.tBodies[0].appendChild(oTr);
};
姓名:<input id="user"type="text">
年龄:<input id="age"type="text">
<input id="btn1" type="button" value="添加">
<table id="tab1" border="1" width="500px">
    <caption>员工表</caption>
    <thead>
        <tr>
            <th>ID</th>
            <th>姓名</th>
            <th>年龄</th>
            <th>操作</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>1</td>
            <td>小白</td>
            <td>27</td>
            <td></td>
        </tr>
        <tr>
            <td>2</td>
            <td>小明</td>
            <td>25</td>
            <td></td>
        </tr>
        <tr>
            <td>3</td>
            <td>小红</td>
            <td>21</td>
            <td></td>
        </tr>
        <tr>
            <td>4</td>
            <td>张三</td>
            <td>29</td>
            <td></td>
        </tr>
        <tr>
            <td>5</td>
            <td>李四</td>
            <td>35</td>
            <td></td>
        </tr>
    </tbody>
</table>

4. 替换节点和创建文本节点

  • replaceChild() 方法可用于替换元素节点。

    • node.replaceChild (用于替换的节点, 原有节点)
  • createTextNode() 方法可创建新的文本节点,返回新创建的 Text 节点

    • document.createTextNode(txt)
  • 这两种方法平时几乎用不到,但还是需要了解

六、练习

(1) 封装函数,返回元素e的第n层祖先元素节点

function retParent(elem, n){
    while(elem && n){   //  第 n 层就是循环几次,n = 0 时为 flase ,不再循环。
        // 因为求祖先元素节点最终时返回 null ,当 n = 6 的时候返回的是 elem 返回的是 null ,
        // 条件中的并且关系就不成立了,那后面 n = 7,8....  返回的都是最后的 null
        elem = elem.parentElement;
        n--;
    }
    return elem;
}

var i = document.getElementsByTagName('i')[0]; // 选取元素 e

(2) 在原型链上编辑函数,封装myChildren功能,解决以前部分浏览器不兼容的问题

<div>
    <strong>
        <span>
            <i></i>
        </span>
        <strong>123</strong>
        <img src="" alt="">
    </strong>
    <div></div>
</div>
var div = document.getElementsByTagName('div')[0];
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;
}
console.log(div.myChildren()); //Array [ strong, div ]

(3) 封装一个自己的myHasChildren方法,不可用children属性

Element.prototype.myHasChildren = 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];
console.log(div.myHasChildren());//true

(4) 封装函数,返回元素e的第n个兄弟元素节点;n为正,返回后面的兄弟元素节点;n为负,返回前面的兄弟元素节点;n为0,返回自己。

function retSibling(e, n){
    while(e && n){  // n = 0 ,e = null 临界点
        if(n > 0){
            e = e.nextElementSibling;
            n--;
        }else{
            e = e.previousElementSibling;
            n++;
        }
    }
    return e;   
-------------------------------------------------------
//解决nextElementSibling在IE里面不兼容的问题:

function retSibling(e, n){
    while(e && n){
        if(n > 0){
            if(e.nextElementSibling){   // ie9 以上会执行
                e = e.nextElementSibling;
            }else{  //ie9 以下执行
                for(e = e.nextSibling; e && e.nodeType != 1; e = e.nextSibling);    
                // e 最后一个节点是文本节点,它的后面没有兄弟节点了这时 e.nextSibling 就是 null
                // 再往后 null.nextSibling 就会报错,所以 e && e.nodeType != 1 都需要满足
            }          
            n--;
        }else{
            if(e.previousElementSibling){
                e = e.previousElementSibling;
            }else{
                for(e = e.previousSibling; e && e.nodeType != 1; e = e.previousSibling);
            }  
            n++;
        }
    }
    return e;
}

(5) 不用children方法遍历元素直接子节点

<div>
    <i></i>
    <strong></strong>
    <span></span>
    <div>
        <img src="" alt="">
    </div>
</div>
var div = document.getElementsByTagName('div')[0];
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;
}
console.log(retElementchild(div));
//Object { 0: i, 1: strong, 2: span, 3: div, length: 4, push: push(), splice: splice() }

(6) 封装函数 insertAfter() 类似于 insertBefore()

<div>
    <i></i>
    <strong></strong>
    <span></span>
    <div>
        <img src="" alt="">
    </div>
</div>
-------------------------------结果如下
<div>
    <i></i>
    <strong></strong>
    <span></span>
    <p></p>
    <div>
        <img src="" alt="">
    </div>
</div>
var div = document.getElementsByTagName('div')[0];
var span = document.getElementsByTagName('span')[0];
var p = document.createElement('p');
Element.prototype.insertAfter = function(targetNode,OriginNode) {
        var afterS=OriginNode.nextElementSibling;
        if (afterS==null) {
             this.appendChild(targetNode);
        }else{
       		 this.insertBefore(targetNode,afterS);
       }
   }
div.insertAfter(p,span);

(7) 将目标节点内的节点顺序逆序

<div>
    <i></i>
    <strong></strong>
    <span></span>
</div>
var div = document.getElementsByTagName('div')[0];
     function reverse(a) {
         for (var i =a.children.length-2; i >=0; i--) {
            a.appendChild(a.children[i]);
 		 }
          return a.children;
    }
console.log(reverse(div));//HTMLCollection(3) [ span, strong, i ]
posted @ 2019-07-16 14:30  胤小飞  阅读(151)  评论(0)    收藏  举报