【JavaScript从入门到精通】第十一课 DOM 基础

此内容来自开课吧石川微信公众号

在讲JS的时候,我们已经学过,JS是由ECMA,DOM,BOM三部分组成,这节课开始我们将深入学习DOM。

什么是DOM

DOM是JS一个重要组成部分,可以让JS可以操作页面上的元素。实际上,DOM在JS里是以document的形式体现的,所有对页面元素的操作都是通过document进行的。

首先来谈谈浏览器对DOM的支持性。目前主流的浏览器有3种:IE,Chrome和FF(火狐)。实际上,DOM除了是JS的一个组成部分外,也是一套规范,规定了浏览器如何去进行操作。在三种主流浏览器中,FF是最标准的浏览器,它对DOM有99%的支持性,而IE浏览器只有10%左右(IE9以后有了一定提升),Chrome浏览器则介于两者之间,有大概百分之60左右的支持性。

DOM节点

首先我们来看一个最基本的概念:子节点父节点。 在下面一个例子:

<!DOCTYPE html>
<html>
 <head> 
  <meta charset="utf-8" /> 
  <title>无标题文档</title> 
 </head> 
 <body> 
  <ul id="ul1"> 
   <li></li> 
   <li></li> 
  </ul>  
 </body>
</html>

在这个例子中,ul就是li的父节点,body是ul的父节点;反过来说,每个li都是ul的子节点。那么,在JS里,我们要如何对节点进行操作呢?在JS里,选中子节点的方法是:childNodes。 childNodes本质上是个数组,数组里存放的内容就是父节点下的各子节点。现在我们来输出ul1中子节点的个数。

window.onload=function ()
{
  var oUl=document.getElementById('ul1');
  alert(oUl.childNodes.length);
}

效果如下:

【JavaScript从入门到精通】第十一课  DOM 基础

很奇怪,为什么答案是5个而不是2个呢?因为在IE9下,childNodes会把空的文本节点也算为数组中的元素,也就是说<ul><li></li><li></li></ul>一共包含<ul><li>,<li></li>,</li><li>,<li></li>,</li></ul>这5个节点。不过如果使用IE6-8的浏览器就不会出现这个问题,会弹出正确答案2。

当我们想通过childNodes设置样式的时候,这个问题的严重性就会凸显出来,因为文本节点是没有style的,如果我们想给每个子节点设置样式,就会出现错误。为了解决这个问题,我们需要使用另一个属性:nodeType。通过nodeType可以判断节点的类型(其中,文本节点的值为3,元素节点的值为1),只对元素节点的样式进行设置,这样就可以达成我们的目的了。

window.onload=function ()
{
  var oUl=document.getElementById('ul1');
  for(var i=0;i<oUl.childNodes.length;i++)
  {
    if(oUl.childNodes[i].nodeType==1)
    {
      oUl.childNodes[i].style.background='red';
    }
  }
};

实际上,比起childNodes,还有一种名为children的属性,它可以直接选中子节点的元素节点,比起使用childNodes+nodeType更为方便。

值得注意的是,子节点只算父节点下第一层的元素,如果子节点下还有子节点,是不会算入父节点的子节点中的。

同样的,我们也有操纵父节点的方法:parentNode。现在我们来看一个隐藏父元素的例子。

<html>
<head>
    <meta charset="utf-8"/>
    <title>无标题文档</title>
</head>
<body>
    <ul id="ul1">
        <li>dfasdf <a href="javascript:;">隐藏</a></li>
        <li>45346 <a href="javascript:;">隐藏</a></li>
        <li>fghfgcvn <a href="javascript:;">隐藏</a></li>
        <li>vcbxcvbc <a href="javascript:;">隐藏</a></li>
        <li>757465867 <a href="javascript:;">隐藏</a></li>
    </ul>
</body>
</html>
window.onload = function () {
    var aA = document.getElementsByTagName('a');

    for (var i = 0; i < aA.length; i++) {
        aA[i].onclick = function () {
            this.parentNode.style.display = 'none';
        };
    }
};

效果如下:

【JavaScript从入门到精通】第十一课  DOM 基础

点击隐藏a标签后,对应父元素被隐藏。

和parentNode类似的一个属性是offserParent,让我们对比以下两个例子:

<html>
<head>
    <meta charset="utf-8"/>
    <title>无标题文档</title>
</head>
<body>
    <div id="div1">
        <div id="div2"></div>
    </div>
</body>
</html>
#div1 {
    width: 200px;
    height: 200px;
    background: #CCC;
    margin: 100px;
}

#div2 {
    width: 100px;
    height: 100px;
    background: red;
    position: absolute;
    left: 50px;
    top: 50px;
}
window.onload = function () {
    var oDiv2 = document.getElementById('div2');

    alert(oDiv2.offsetParent);
};

效果如下:

【JavaScript从入门到精通】第十一课  DOM 基础

<html>
<head>
    <meta charset="utf-8"/>
    <title>无标题文档</title>
</head>
<body>
    <div id="div1">
        <div id="div2"></div>
    </div>
</body>
</html>
#div1 {
    width: 200px;
    height: 200px;
    background: #CCC;
    margin: 100px;
    position: relative;
}

#div2 {
    width: 100px;
    height: 100px;
    background: red;
    position: absolute;
    left: 50px;
    top: 50px;
}
window.onload = function () {
    var oDiv2 = document.getElementById('div2');

    alert(oDiv2.offsetParent);
};

效果如下:

【JavaScript从入门到精通】第十一课  DOM 基础

可以看到,二者的唯一区别在于div1的position属性,在第一个例子里,div1的positon属性为空,所以div2实际上是根据body来进行定位的,而第二个例子里div1的positon为relative,因此div2是根据div1来定位。而offsetParent的作用就是获取该元素用于定位的父级。

首位子节点和兄弟节点

这里介绍简单介绍一些DOM的基础操作和属性。

  • firstChild,firstElementChild,获取元素的第一个子节点
  • lastChild,lastElementChild,获取元素的最后一个子节点
  • nextSibling,nextElementSibling,获取元素的上一个兄弟节点
  • previousSibling,previousElementSibling,获取元素的下一个兄弟节点

这些方法都存在一定的兼容性问题,在高版本浏览器下firstChild与childNodes相同指的是第一个文本节点,因此我们需要用firstElementChild的方法才能选中其真正的第一个子节点。(其它操作也是如此)

设置属性的第三种方法

我们前面已经学习过oDiv.style.display=“block”和oDiv.style[“display”]=“block”这两种设置属性的方法,现在我们来学习第三种:Dom方式操作元素属性,这里我们采用的是这几个方法:

  • getAttribute(名称),用于获取
  • setAttribute(名称,值得),用于设置
  • removeAttribute(名称),用于删除

className选择元素

过去我们选择元素都是使用id,虽然很精准,但元素过多的时候会很繁杂。后面我们又学习了使用标签名寻找元素,但精确度又差了一些。这里我们学习一种新的获取元素的方法:用class获取元素。使用class获取元素,有以下好处:1.可以批量化;2.可以具有选择性;3.页面发生变化时程序不会出现问题。

<html>
<head>
    <meta charset="utf-8"/>
    <title>无标题文档</title>
</head>
<body>
    <ul id="ul1">
        <li class="box"></li>
        <li class="box"></li>
        <li></li>
        <li></li>
        <li></li>
        <li class="box"></li>
        <li></li>
    </ul>
</body>
</html>
window.onload = function () {
    var oUl = document.getElementById('ul1');
    var aLi = oUl.getElementsByTagName('li');

    for (var i = 0; i < aLi.length; i++) {
        if (aLi[i].className == 'box') {
            aLi[i].style.background = 'red';
        }
    }
};

效果如下:

【JavaScript从入门到精通】第十一课  DOM 基础

凡是class为box的li背景颜色都变为了红色。通过class获取元素的原理非常简单,但是如果我们经常使用它,这种写法会显得非常复杂,因此我们打算把它封装成一个函数使用。

<html>
<head>
    <meta charset="utf-8"/>
    <title>无标题文档</title>
</head>
<body>
    <ul id="ul1">
        <li class="box"></li>
        <li class="box"></li>
        <li></li>
        <li></li>
        <li></li>
        <li class="box"></li>
        <li></li>
    </ul>
</body>
</html>
function getByClass(oParent, sClass) {
    var aResult = [];
    var aEle = oParent.getElementsByTagName('*');

    for (var i = 0; i < aEle.length; i++) {
        if (aEle[i].className == sClass) {
            aResult.push(aEle[i]);
        }
    }
    return aResult;
}

window.onload = function () {
    var oUl = document.getElementById('ul1');
    var aBox = getByClass(oUl, 'box');

    for (var i = 0; i < aBox.length; i++) {
        aBox[i].style.background = 'red';
    }
};

这其中需要注意的是,为了让函数具有更好的通用性,我们将getElementsByTagName的参数设为了*通配符,代表了所有标签,这样可以选取所有的元素。此外,我们在函数内定义了一个aResult数组,用于存放className符合要求的元素,最后将整个数组作为返回值返回。

如需转载,烦请注明出处:https://www.qdskill.com/javascript/512.html

发表评论

登录后才能评论