JavaScript 之DOM(一)

一. DOM介绍

1. 什么是DOM?

DOM:文档对象模型。DOM 为文档提供了结构化表示,并定义了如何通过脚本来访问文档结构。

目的其实就是为了能让js操作html元素而制定的一个规范。

DOM就是由节点组成的。

2. 解析过程

HTML加载完毕,渲染引擎会在内存中把HTML文档,生成一个DOM树,getElementById是获取内中DOM上的元素节点。然后操作的时候修改的是该元素的属性。

3. DOM树(一切都是节点)

元素节点:HMTL标签。

文本节点:标签中的文字(比如标签之间的空格、换行)

属性节点::标签的属性。

整个html文档就是一个文档节点。所有的节点都是Object。

4. DOM可以做什么?

找对象(元素节点)

设置元素的属性值

设置元素的样式

动态创建和删除元素

事件的触发响应:事件源、事件、事件的驱动程序

DOM的数据结构如下:

 

上图可知,在HTML当中,一切都是节点:(非常重要)

  文档节点(document对象):代表整个文档

  元素节点(element 对象):代表一个元素(标签)

  文本节点(text对象):代表元素(标签)中的文本

  属性节点(attribute对象):代表一个属性,元素(标签)才有属性

注释是注释节点(comment对象)

  JavaScript 可以通过DOM创建动态的 HTML:

  JavaScript 能够改变页面中的所有 HTML 元素

  JavaScript 能够改变页面中的所有 HTML 属性

  JavaScript 能够改变页面中的所有 CSS 样式

  JavaScript 能够对页面中的所有事件做出反应(鼠标点击事件,鼠标移动事件等)整个html文档就是一个文档节点。所有的节点都是Object。

二. DOM节点的获取

DOM节点的获取方式其实就是获取事件源的方式。

操作元素节点,必须首先找到该节点。有三种方式可以获取DOM节点:

var div1 = document.getElementById("box");      //方式一:通过id获取单个标签

var arr1 = document.getElementsByTagName("div");     //方式二:通过 标签名 获得 标签数组,所以有s

var arr2 = document.getElementsByClassName("box");  //方式三:通过 类名 获得 标签数组,所以有s

 

既然方式二、方式三获取的是标签数组,那么习惯性是先遍历之后再使用。

特殊情况:数组中的值只有1个。即便如此,这一个值也是包在数组里的。这个值的获取方式如下:

document.getElementsByTagName("div")[0];    //取数组中的第一个元素

 

document.getElementsByClassName("box")[0];  //取数组中的第一个元素

三.DOM访问关系的获取

 

 

节点的访问关系,是以属性的方式存在的。

JS中的父子兄访问关系:

 

 

这里我们要重点知道parentNodechildren这两个属性的用法比较常用。下面分别介绍。

下面的都以这个html为例子进行操作:

<div class="father">

    <span class="s1"></span>

    <p id="p1"><span></span></p>

    <span class="s2"></span>

</div>

<div class="f">

    <span class="s3"></span>

</div>

1. 获取父节点

调用者就是节点。一个节点只有一个父节点,调用方式就是

节点.parentNode

//获取父亲节点的方法具体例子

//获取p1节点

var p1 = document.getElementById('p1');

// 获取父亲节点

var fa = p1.parentNode;

console.log(fa);

2.获取兄弟节点

(1)下一个

(1)nextSibling:

 指的是下一个节点(包括标签、空文档和换行节点)

火狐、谷歌、IE9+版本:都指的是下一个节点(包括标签、空文档和换行节点)。

IE678版本:指下一个元素节点(标签)。

本文用的是谷歌浏览器,所有这个方式只能获取到空文档代码见(2)后的例子及截图结果。

(2)nextElementSibling:

火狐、谷歌、IE9+版本:都指的是下一个元素节点(标签)。

js代码如下:

// 获取下一个节点

// 法一:

var pnext1 = p1.nextSibling; //var pnext1 = p1.nextSibling.nextSibling;

console.log(pnext1)

// 法二

var pnext2 = p1.nextElementSibling;

console.log(pnext2);

效果图为:

 

总结:为了获取下一个元素节点,我们可以这样做:在IE678中用nextSibling,在火狐谷歌IE9+以后用nextElementSibling。于是,综合这两个属性,可以这样写:

下一个兄弟节点 = 节点.nextElementSibling || 节点.nextSibling

// 综合方法三:

var pnext = p1.nextElementSibling || p1.nextSibling  ;

console.log(pnext)

(2)前一个

previous的中文是: 前一个

(1)previousSibling:

火狐、谷歌、IE9+版本:都指的是前一个节点(包括标签、空文档和换行节点)。

IE678版本:指前一个元素节点(标签)。

本文用的是谷歌浏览器,所有这个方式只能获取到空文档代码见(2)后的例子及截图结果。

(2)previousElementSibling:

火狐、谷歌、IE9+版本:都指的是前一个元素节点(标签)。

// 获取上一个节点

// 法一:

var pre1 = p1.previousSibling; //var pre1 = p1.previousSibling.previousSibling;

console.log(pre1)

// 法二

var pre2 = p1.previousElementSibling;

console.log(pre2);

 

总结:为了获取前一个元素节点,我们可以这样做:在IE678中用previousSibling,在火狐谷歌IE9+以后用previousElementSibling,于是,综合这两个属性,可以这样写:

前一个兄弟节点 = 节点.previousElementSibling || 节点.previousSibling

// 综合方法三:

var pre = p1.previousElementSibling || p1.previousSibling;

console.log(pre)

 

补充:获得任意一个兄弟节点:

节点自己.parentNode.children[index];  //随意得到兄弟节点

节点自己.parentNode.children;  //获取所有的兄弟节点(伪数组,包含自己在内)

3.获取单个的子元素

和2中的一样3中的(1)的方法也是存在不兼容问题,所有都可以2的解放方法一样,就不一一举例。

(1)第一个子节点 | 第一个子元素节点

(1)firstChild:

火狐、谷歌、IE9+版本:都指的是第一个子节点(包括标签、空文档和换行节点)。

IE678版本:指第一个子元素节点(标签)。

(2)firstElementChild:

火狐、谷歌、IE9+版本:都指的是第一个子元素节点(标签)。

总结:为了获取第一个子元素节点,我们可以这样做:在IE678中用firstChild,在火狐谷歌IE9+以后用firstElementChild,于是,综合这两个属性,可以这样写:

第一个子元素节点 = 节点.firstElementChild || 节点.firstChild

(2) 最后一个子节点 | 最后一个子元素节点

(1)lastChild:

火狐、谷歌、IE9+版本:都指的是最后一个子节点(包括标签、空文档和换行节点)。

IE678版本:指最后一个子元素节点(标签)。

(2)lastElementChild:

火狐、谷歌、IE9+版本:都指的是最后一个子元素节点(标签)。

总结:为了获取最后一个子元素节点,我们可以这样做:在IE678中用lastChild,在火狐谷歌IE9+以后用lastElementChild,于是,综合这两个属性,可以这样写:

最后一个子元素节点 = 节点.lastElementChild || 节点.lastChild

 4.获取所有的子节点

(1)childNodes

标准属性。返回的是指定元素的子节点的集合(包括元素节点、所有属性、文本节点)。是W3C的亲儿子。

火狐 谷歌等高本版会把换行也看做是子节点。(了解)

用法:

子节点数组 = 父节点.childNodes;   //获取所有节点。

(2)children

非标准属性。返回的是指定元素的子元素节点的集合。【重要】

它只返回HTML节点,甚至不返回文本节点。

在IE6/7/8中包含注释节点(在IE678中,注释节点不要写在里面)。

虽然不是标准的DOM属性,但它和innerHTML方法一样,得到了几乎所有浏览器的支持。

用法:(用的最多)

子节点数组 = 父节点.children;   //获取所有节点。用的最多。

四.关于DOM的事件操作

JS是以事件驱动为核心的一门语言。

HTML 4.0 的新特性之一是有能力使 HTML 事件触发浏览器中的动作(action),比如当用户点击某个 HTML 元素时启动一段 JavaScript。下面是一个属性列表,这些属性可插入 HTML 标签来定义事件动作。

常见事件如下:

onclick        当用户点击某个对象时调用的事件句柄。

ondblclick     当用户双击某个对象时调用的事件句柄。

onfocus        元素获得焦点。               // 练习:输入框

onblur         元素失去焦点。             应用场景:用于表单验证,用户离开某个输入框时,代表已经输入完了,我们可以对它进行验证.

onchange       域的内容被改变。             应用场景:通常用于表单元素,当元素内容被改变时触发.(select联动)

onkeydown      某个键盘按键被按下。          应用场景: 当用户在最后一个输入框按下回车按键时,表单提交.

onkeypress     某个键盘按键被按下并松开。

onkeyup        某个键盘按键被松开。

onload         一张页面或一幅图像完成加载。

onmousedown    鼠标按钮被按下。

onmousemove    鼠标被移动。

onmouseout     鼠标从某元素移开。

onmouseover    鼠标移到某元素之上。

 

onselect      在文本框中的文本被选中时发生。

onsubmit      确认按钮被点击,使用的对象是form。

1. 事件的三要素

事件的三要素:事件源、事件、事件驱动程序

比如,我用手去按开关,灯亮了。这件事情里,事件源是:手。事件是:按开关。事件驱动程序是:灯的开和关。

再比如,网页上弹出一个广告,我点击右上角的X,广告就关闭了。这件事情里,事件源是:X。事件是:onclick。事件驱动程序是:广告关闭了。

于是我们可以总结出:谁引发的后续事件,谁就是事件源。

总结如下:

    事件源:引发后续事件的html标签。

    事件:js已经定义好了(见下图)。

    事件驱动程序:对样式和html的操作。也就是DOM。

  代码书写步骤如下:

获取事件源:document.getElementById(“box”);

绑定事件: 事件源box.事件onclick = function(){ 事件驱动程序 };

书写事件驱动程序:关于DOM的操作

 

代码举例一个事件例子:

<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8">

    <title>Title</title>

<style>

div{

    width: 100px;

    height: 100px;

    background: green;

}

</style>

</head>

<body>

<div class="box" οnclick="foo()"></div><!-- 方式三绑定事件 -->

 

<script>

    // 1.获取事件源

    var div1 = document.getElementsByClassName("box")[0];

 

 

    // 2.绑定事件

    // 方式一:(通过匿名函数绑定,常用的)

    div1.onclick = function () {

        // 3.事件驱动程序

        div1.style.backgroundColor = 'red';

    };

 

    // 方式二:

    div1.onclick = foo;  // 注意没有括号

    // 通过命名函数绑定

    function foo() {

        // 3.事件驱动程序

        div1.style.backgroundColor = 'red';

    }

</script>

</body>

</html>

下面针对这事件的三要素,进行分别介绍。

(1)获取事件源的方式

 // 1.获取事件源

 var div1 = document.getElementsByClassName("box")[0];

(2)绑定事件的方式

方式一:直接绑定匿名函数(最常用)

<script>

    var odiv = document.getElementById("box");

    odiv.onclick = function(){

        odiv.style.background = "red";

    }

</script>

方式二:先单独定义函数,再绑定

<script>

    var odiv = document.getElementById("box");

    odiv.onclick = fn; //注意,这里是fn,不是fn()。fn()指的是返回值。

    //单独定义函数

    function fn(){

        odiv.style.background = "red";

    }

</script>

 

方式三:行内绑定

 

// 行内绑定

<div id="box" οnclick="fn()"></div>

// 注意第一行代码,绑定时,是写的"fn()",不是写的"fn"。因为绑定的这段代码不是写在js代码里的,而是被识别成了字符串。

 

 

<script>

    function fn(){

        odiv.style.background = "red";

    }

</script>

(3)事件驱动程序

我们上面的例子中改变背景颜色,就是事件驱动程序。

  需求:

1. 默认盒子宽度和高度为100px,背景色为绿色;

2. 单击后的效果为盒子宽度和高度为200px,背景色为红色;

3. 让其上面的效果可以来回进行切换。

html代码:

 <div class="box" ></div>

css样式:

<style>

div{

    width: 100px;

    height: 100px;

    background: green;

}

</style>

js代码:

<script>

    var div1 = document.getElementsByClassName("box")[0];

    var flag = false;

    div1.onclick = function () {

        if (!flag) {

            div1.style.width = "200px";

            div1.style.height = "200px";

            div1.style.backgroundColor = "red";

            flag = true;

        } else {

            div1.style.width = "100px";

            div1.style.height = "100px";

            div1.style.backgroundColor = "green";

            flag = false;

        }

    }

</script>

 

上方代码的注意事项:

在js里写属性值时,要用引号

在js里写属性名时,是backgroundColor,不是CSS里面的background-Color。

记得所有的像css属性的text-*,line-*、backgroun-*等在js中都写成驼峰。

(4)onload事件

当页面加载(文本和图片)完毕的时候,触发onload事件。

举例:

<head>

    <script>

        window.onload = function () {

            console.log(111);

        }

    </script>

</head>

<body>

    <script>

        console.log(222);

    </script>

</body>

 

 

有一点我们要知道:js的加载是和html同步加载的。因此,如果使用元素在定义元素之前,容易报错。这个时候,onload事件就能派上用场了,我们可以把使用元素的代码放在onload里,就能保证这段代码是最后执行。

建议是:整个页面上所有元素加载完毕在执行js内容。所以,window.onload可以预防使用标签在定义标签之前。

2. 事件案例

 

案例一:盒子的显示与隐藏

css样式:

    <style>

        div {

            width: 100px;

            height: 100px;

            background: green;

        }

</style>

html内容:

<input type="text" id="input1" value="隐藏">

<button id="btn1">隐藏</button>

 

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

 

js代码:

<script>

    var oBtn = document.getElementById("btn1");

    var oDiv = document.getElementById("box");

    var oInput = document.getElementById("input1");

    var flag = false;

    oBtn.onclick = function () {

        if (!flag){

            oInput.value = "显示";

            oDiv.style.display = "none";

            oBtn.innerText = "<span>显示</span>";

            flag = true;

        }else{

//只进行赋值操作

            oInput.value = "隐藏";

//事件驱动程序

            oDiv.style.display = "block";

            oBtn.innerHTML = "<span>隐藏</span>";

            flag = false;

        }

    }

</script>

 

 

三个知识点:1.oInput.value  2.oBtn.innerText  3. oBtn.innerHTML

innerText 与innerHTML的区别在于,innerText直接将 "<span>显示</span>"里面的内容直接变成文本显示,而innerHTML将 "<span>隐藏</span>"里面的span内容语意话不显示span,

如下效果图:

innerText效果:

 

innerHTML效果:

 

案例二:

要求实现效果:

1. 当鼠标悬停在img上时,更换为另外一张图片;

2. 鼠标离开时,还原为本来的图片。

<img src="https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=2121206715,2955288754&fm=26&gp=0.jpg" alt="" id="image">

 

<script>

    var oImg = document.getElementById("image");

    oImg.onmouseover = function () {

        this.src = "https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=3488187566,3835668069&fm=26&gp=0.jpg";

    };

    oImg.onmouseout = function () {

        this.src = "https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=2121206715,2955288754&fm=26&gp=0.jpg";

    }

</script>

3.事件冒泡

事件冒泡的条件:

必须是父子级关系。

必须是相同的绑定的方式(相同的事件)。

例:

<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8">

    <title>Title</title>

    <style>

        .father{

            width: 500px;

            height: 500px;

            background: green;

        }

        .box1{

            width: 300px;

            height: 300px;

            background: blue;

        }

        .box2{

            width: 100px;

            height: 100px;

            background: red;

        }

    </style>

</head>

<body>

<div class="father">

    <div class="box1">

        <div class="box2"></div>

    </div>

</div>

<script>

    var father = document.getElementsByClassName("father")[0];

    var box1 = document.getElementsByClassName("box1")[0];

    var box2 = document.getElementsByClassName("box2")[0];

 

    father.onclick = function () {

        console.log("我是 father")

};

//加event防止冒泡

    box1.onclick = function (event) {

        event.stopPropagation();

        console.log("我是 box1")

};

//function里面加event阻止冒泡

//然后加event.stopPropagation();阻止冒泡

    box2.onclick = function (event) {

        event.stopPropagation();

        console.log("我是 box2")

    };

</script>

</body>

</html>

解决方法:

function里面加event阻止冒泡

然后加event.stopPropagation();阻止冒泡

继续学习:点我

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值