JavaScript DOM

第四章 JavaScript DOM

4.1、DOM概述

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

HTML DOM 模型被结构化为 对象树
在这里插入图片描述
HTML DOM 是关于如何获取更改添加删除 HTML 元素的标准。

4.2、DOM文档节点

4.2.1、节点概述

节点Node,是构成我们网页的最基本的组成部分,网页中的每一个部分都可以称为是一个节点。

常用节点分为四类:

  1. 文档节点:整个HTML文档
  2. 元素节点:HTML文档中的HTML标签
  3. 属性节点:元素的属性
  4. 文本节点:HTML标签中的文本内容
    在这里插入图片描述

4.2.2、节点属性

在这里插入图片描述

4.2.3、文档节点

文档节点(Document)代表的是整个HTML文 档,网页中的所有节点都是它的子节点。

document对象是作为window对象的属性存在的,我们不用获取可以直接使用

4.2.4、元素节点

HTML中的各种标签都是元素节点(Element),这也是我们最常用的一个节点。

浏览器会将页面中所有的标签都转换为一个元素节点, 我们可以通过document的方法来获取元素节点。

4.2.5、属性节点

属性节点(Attribute)表示的是标签中的一个一个的属性,这里要注意的是属性节点并非是元素节点的子节点,而是元素节点的一部分。可以通过元素节点来获取指定的属性节点。

注意:我们一般不使用属性节点。

4.2.6、文本节点

文本节点(Text)表示的是HTML标签以外的文本内容,任意非HTML的文本都是文本节点,它包括可以字面解释的纯文本内容。文本节点一般是作为元素节点的子节点存在的。

获取文本节点时,一般先要获取元素节点,再通过元素节点获取文本节点。

例如:元素节点.firstChild;,获取元素节点的第一个子节点,一般为文本节点。

4.3、DOM文档操作

文档对象代表您的网页,,如果您希望访问 HTML 页面中的任何元素,那么您总是从访问 document 对象开始。

4.3.1、查找 HTML 元素

方法描述
document.getElementById(id)通过元素 id 来查找元素。
document.getElementsByTagName(name)通过标签名来查找元素。
document.getElementsByClassName(name)通过类名来查找元素。
document.querySelector(CSS选择器)通过CSS选择器选择一个元素。
document.querySelectorAll(CSS选择器)通过CSS选择器选择多个元素。

4.3.2、获取 HTML 的值

方法描述
元素节点.innerText获取 HTML 元素的 inner Text。
元素节点.innerHTML获取 HTML 元素的 inner HTML。
元素节点.属性获取 HTML 元素的属性值。
元素节点.getAttribute(attribute)获取 HTML 元素的属性值。
元素节点.style.样式获取 HTML 元素的行内样式值。
<div style="width: 100px;height: 100px;background: red;" id="box">这是一个<strong>盒子</strong></div>


<script>
    var box = document.getElementById("box");

    console.log(box.innerText);
    console.log(box.innerHTML);
    console.log(box.id);
    console.log(box.getAttribute('id'));
    console.log(box.style.width);
</script>

在这里插入图片描述

注意:如果CSS的样式名中含有-,这种名称在JS中是不合法的比如background-color,需要将这种样式名修改为驼峰命名法,去掉-,然后将-后的字母大写,我们通过style属性设置的样式都是行内样式,同样的获取也是行内样式,而行内样式有较高的优先级,所以通过JS修改的样式往往会立即显示,但是如果在样式中写了!important,则此时样式会有最高的优先级,即使通过JS也不能覆盖该样式,此时将会导致JS修改样式失效,所以尽量不要为样式添加!important

拓展知识1:

通过style属性设置和读取的都是内联样式,无法读取样式表中的样式或者说正在应用的样式,如果想要读取当前正在应用的样式属性我们可以使用元素.currentStyle.样式名来获取元素的当前显示的样式,它可以用来读取当前元素正在显示的样式,如果当前元素没有设置该样式,则获取它的默认值;

但是currentStyle只有IE浏览器支持,其它的浏览器都不支持,在其它浏览器中可以使用getComputedStyle()这个方法来获取元素当前的样式,这个方法是window的方法,可以直接使用,但是需要两个参数:

  • 第一个参数:要获取样式的元素
  • 第二个参数:可以传递一个伪元素,一般都传null

该方法会返回一个对象,对象中封装了当前元素对应的样式,可以通过 对象.样式名 来读取样式,如果获取的样式没有设置,则会获取到真实的值,而不是默认值,比如:没有设置width,它不会获取到auto,而是一个长度,但是该方法不支持IE8及以下的浏览器。

通过currentStyle和getComputedStyle()读取到的样式都是只读的,不能修改,如果要修改必须通过style属性,因此,我们可以写一个适配各个浏览器的读取元素样式的方法:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title></title>
    <style>
        /*样式表的样式*/
        #box {
            width: 200px;
            height: 200px;
            background-color: green;
        }
    </style>
</head>

<body>
<div style="width: 100px;height: 100px;" id="box"></div>

<script>
    /*通用的获取元素样式的方法*/
    function getStyle(obj, name) {
        if (window.getComputedStyle) {
            //正常浏览器的方式,具有getComputedStyle()方法
            return getComputedStyle(obj, null)[name];
        } else {
            //IE8的方式,没有getComputedStyle()方法
            return obj.currentStyle[name];
        }
    }

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

    console.log(getStyle(box, "width"));    //100px
    console.log(getStyle(box, "height"));    //100px
    console.log(getStyle(box, "background-color"));    //rgb(0, 128, 0)
</script>
</body>
</html>

4.3.3、改变 HTML 的值

方法描述
元素节点.innerText = new text content改变元素的 inner Text。
元素节点.innerHTML = new html content改变元素的 inner HTML。
元素节点.属性 = new value改变 HTML 元素的属性值。
元素节点.setAttribute(attribute, value)改变 HTML 元素的属性值。
元素节点.style.样式 = new style改变 HTML 元素的行内样式值。

拓展知识1:

修改节点的内容除了常用的innerHTML和innerText之外,还有insertAdjacentHTMLinsertAdjacentText方法,可以在指定的地方插入内容。insertAdjacentText方法与insertAdjacentHTML方法类似,只不过是插入纯文本,参数相同。

语法说明:

object.insertAdjacentHTML(where,html);
object.insertAdjacentText(where,text)

参数说明:

where:

  • beforeBegin:插入到开始标签的前面
  • beforeEnd:插入到结束标签的前面
  • afterBegin:插入到开始标签的后面
  • afterEnd:插入到结束标签的后面

在这里插入图片描述

注意事项:

  • 这两个方法必须等文档加载好后才能执行,否则会出错。
  • insertAdjacentText只能插入普通文本,insertAdjacentHTML插入html代码。
  • 使用insertAdjacentHTML方法插入script脚本文件时,必须在script元素上定义defer属性。
  • 使用insertAdjacentHTML方法插入html代码后,页面上的元素集合将发生变化。
  • insertAdjacentHTML方法不适用于单个的空的元素标签(如img,input等)。

4.3.4、修改 HTML 元素

方法描述
document.createElement(element)创建 HTML 元素节点。
document.createAttribute(attribute)创建 HTML 属性节点。
document.createTextNode(text)创建 HTML 文本节点。
元素节点.removeChild(element)删除 HTML 元素。
元素节点.appendChild(element)添加 HTML 元素。
元素节点.replaceChild(element)替换 HTML 元素。
元素节点.insertBefore(element)在指定的子节点前面插入新的子节点。

4.3.5、查找 HTML 父子

方法描述
元素节点.parentNode返回元素的父节点。
元素节点.parentElement返回元素的父元素。
元素节点.childNodes返回元素的一个子节点的数组(包含空白文本Text节点)。
元素节点.children返回元素的一个子元素的集合(不包含空白文本Text节点)。
元素节点.firstChild返回元素的第一个子节点(包含空白文本Text节点)。
元素节点.firstElementChild返回元素的第一个子元素(不包含空白文本Text节点)。
元素节点.lastChild返回元素的最后一个子节点(包含空白文本Text节点)。
元素节点.lastElementChild返回元素的最后一个子元素(不包含空白文本Text节点)。
元素节点.previousSibling返回某个元素紧接之前节点(包含空白文本Text节点)。
元素节点.previousElementSibling返回指定元素的前一个兄弟元素(相同节点树层中的前一个元素节点)。
元素节点.nextSibling返回某个元素紧接之后节点(包含空白文本Text节点)。
元素节点.nextElementSibling返回指定元素的后一个兄弟元素(相同节点树层中的下一个元素节点)。

4.4、DOM文档事件

4.4.1、事件概述

HTML事件可以触发浏览器中的行为,比方说当用户点击某个 HTML 元素时启动一段 JavaScript。

4.4.2、窗口事件

由窗口触发该事件 (同样适用于 标签):

属性描述
onblur当窗口失去焦点时运行脚本。
onfocus当窗口获得焦点时运行脚本。
onload当文档加载之后运行脚本。
onresize当调整窗口大小时运行脚本。
onstorage当 Web Storage 区域更新时(存储空间中的数据发生变化时)运行脚本。

4.4.3、表单事件

表单事件在HTML表单中触发 (适用于所有 HTML 元素,但该HTML元素需在form表单内):

属性描述
onblur当元素失去焦点时运行脚本。
onfocus当元素获得焦点时运行脚本。
onchange当元素改变时运行脚本。
oninput当元素获得用户输入时运行脚本。
oninvalid当元素无效时运行脚本。
onselect当选取元素时运行脚本。
onsubmit当提交表单时运行脚本。

4.4.4、键盘事件

通过键盘触发事件,类似用户的行为:

属性描述
onkeydown当按下按键时运行脚本。
onkeyup当松开按键时运行脚本。
onkeypress当按下并松开按键时运行脚本。

案例演示:使div可以根据不同的方向键向不同的方向移动

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
<div id="box" style="width: 100px;height: 100px;background: red;position: absolute;"></div>

<script>
    var box = document.getElementById("box");

    //为document绑定一个按键按下的事件
    document.onkeydown = function (event) {
        event = event || window.event;

        // 定义移动速度
        var speed = 10;

        // 选择移动方向
        switch (event.keyCode) {
            case 37:
                box.style.left = box.offsetLeft - speed + "px";
                break;
            case 39:
                box.style.left = box.offsetLeft + speed + "px";
                break;
            case 38:
                box.style.top = box.offsetTop - speed + "px";
                break;
            case 40:
                box.style.top = box.offsetTop + speed + "px";
                break;
        }
    };
</script>
</body>
</html>

拓展知识:

当事件的响应函数被触发时,浏览器每次都会将一个事件对象作为实参传递进响应函数。

Event 对象代表事件的状态,比如事件在其中发生的元素、键盘按键的状态、鼠标的位置、鼠标的状态。

在IE8中,响应函数被触发时,浏览器不会传递事件对象,在IE8及以下的浏览器中,是将事件对象作为window对象的属性保存的。

解决事件对象的兼容性问题:event = event || window.event;

键鼠属性

属性描述
ctrlKey返回当事件被触发时,“CTRL” 键是否被按下。
altKey返回当事件被触发时,“ALT” 是否被按下。
shiftKey返回当事件被触发时,“SHIFT” 键是否被按下。
clientX返回当事件被触发时,鼠标指针的水平坐标。
clientY返回当事件被触发时,鼠标指针的垂直坐标。
screenX返回当某个事件被触发时,鼠标指针的水平坐标。
screenY返回当某个事件被触发时,鼠标指针的垂直坐标。

4.4.5、鼠标事件

通过鼠标触发事件,类似用户的行为:

属性描述
onclick当单击鼠标时运行脚本。
ondblclick当双击鼠标时运行脚本。
onmousedown当按下鼠标按钮时运行脚本。
onmouseup当松开鼠标按钮时运行脚本。
onmousemove当鼠标指针移动时运行脚本。
onmouseover当鼠标指针移至元素之上时运行脚本,不可以阻止冒泡。
onmouseout当鼠标指针移出元素时运行脚本,不可以阻止冒泡。
onmouseenter当鼠标指针移至元素之上时运行脚本,可以阻止冒泡。
onmouseleave当鼠标指针移出元素时运行脚本,可以阻止冒泡。
onmousewheel当转动鼠标滚轮时运行脚本。
onscroll当滚动元素的滚动条时运行脚本。

案例演示:编写一个通用的拖拽元素函数,创建两个div,进行拖拽演示,要求兼容IE8、火狐、谷歌等主流浏览器

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
<div id="box1" style="width: 100px;height: 100px;background: red;position: absolute;"></div>
<div id="box2" style="width: 100px;height: 100px;background: green;position: absolute;"></div>

<!-- 在这里写JavaScript代码,因为JavaScript是由上到下执行的 -->
<script>
    var box1 = document.getElementById("box1");
    var box2 = document.getElementById("box2");

    drag(box1);
    drag(box2);

    /*
     * 提取一个专门用来设置拖拽的函数
     * 参数:开启拖拽的元素
     */
    function drag(obj) {
        //当鼠标在被拖拽元素上按下时,开始拖拽
        obj.onmousedown = function (event) {
            // 解决事件的兼容性问题
            event = event || window.event;

            // 设置obj捕获所有鼠标按下的事件
            /**
             * setCapture():
             * 只有IE支持,但是在火狐中调用时不会报错,
             * 而如果使用chrome调用,它也会报错
             */
            obj.setCapture && obj.setCapture();

            // obj的偏移量 鼠标.clentX - 元素.offsetLeft
            // obj的偏移量 鼠标.clentY - 元素.offsetTop
            var ol = event.clientX - obj.offsetLeft;
            var ot = event.clientY - obj.offsetTop;

            // 为document绑定一个鼠标移动事件
            document.onmousemove = function (event) {
                // 解决事件的兼容性问题
                event = event || window.event;
                // 当鼠标移动时被拖拽元素跟随鼠标移动
                // 获取鼠标的坐标
                var left = event.clientX - ol;
                var top = event.clientY - ot;
                // 修改obj的位置
                obj.style.left = left + "px";
                obj.style.top = top + "px";
            };

            // 为document绑定一个鼠标松开事件
            document.onmouseup = function () {
                // 取消document的onmousemove事件
                document.onmousemove = null;
                // 取消document的onmouseup事件
                document.onmouseup = null;
                // 当鼠标松开时,取消对事件的捕获
                obj.releaseCapture && obj.releaseCapture();
            };

            /*
             * 当我们拖拽一个网页中的内容时,浏览器会默认去搜索引擎中搜索内容,
             * 此时会导致拖拽功能的异常,这个是浏览器提供的默认行为,
             * 如果不希望发生这个行为,则可以通过return false来取消默认行为,
             * 但是这招对IE8不起作用
             */
            return false;
        };
    }
</script>
</body>
</html>

4.4.6、媒体事件

4.4.7、其它事件

4.4.8、事件冒泡

事件的冒泡(Bubble):所谓的冒泡指的就是事件的向上传导,当后代元素上的事件被触发时,其祖先元素的相同事件也会被触发,在开发中大部分情况冒泡都是有用的,如果不希望发生事件冒泡可以通过事件对象来取消冒泡。

案例演示:
创建两个div,叠放在一起,分别绑定单击事件,这时点击最里边的div,会触发两个div的单击事件。
如果想要点击最里边的div,不会触发两个div的单击事件,只会触发自己的单击事件,这时候我们可以取消事件冒泡:

<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
    <title></title>
    <style>
        #div1 {
            width: 200px;
            height: 200px;
            background: pink;
        }

        #div2 {
            width: 100px;
            height: 100px;
            background: coral;
        }
    </style>
</head>

<body>
    <div id="div1">
        我是DIV1
        <div id="div2">
            我是DIV2
        </div>
    </div>

    <!-- 在这里写JavaScript代码,因为JavaScript是由上到下执行的 -->
    <script>
        var div1 = document.getElementById("div1");
        var div2 = document.getElementById("div2");

        // 为div1绑定单击事件
        div1.onclick = function () {
            console.log("div1 的单击事件触发了!");
            stopBubble();
        };

        // 为div2绑定单击事件
        div2.onclick = function () {
            console.log("div2 的单击事件触发了!");
            stopBubble();
        };

        // 取消事件冒泡
        function stopBubble(event) {
            // 如果提供了事件对象,则这是一个非IE浏览器
            if (event && event.stopPropagation) {
                // 因此它支持W3C的stopPropagation()方法
                event.stopPropagation();
            } else {
                // 否则,我们需要使用IE的方式来取消事件冒泡
                window.event.cancelBubble = true;
            }
        }
    </script>
</body>

</html>

4.4.9、事件委派

我们希望只绑定一次事件,即可应用到多个的元素上,即使元素是后添加的,我们可以尝试将其绑定给元素的共同的祖先元素,也就是事件的委派。

事件的委派,是指将事件统一绑定给元素的共同的祖先元素,这样当后代元素上的事件触发时,会一直冒泡到祖先元素,从而通过祖先元素的响应函数来处理事件。

事件委派是利用了事件冒泡,通过委派可以减少事件绑定的次数,提高程序的性能。

案例演示:为ul列表中的所有a标签都绑定单击事件

<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
    <title></title>
</head>

<body>
    <ul id="u1">
        <li><a href="javascript:;" class="link">超链接一</a></li>
        <li><a href="javascript:;" class="link">超链接二</a></li>
        <li><a href="javascript:;" class="link">超链接三</a></li>
    </ul>

    <!-- 在这里写JavaScript代码,因为JavaScript是由上到下执行的 -->
    <script>
        var u1 = document.getElementById("u1");
       

        // 为ul绑定一个单击响应函数
        u1.onclick = function (event) {
            event = event || window.event;
            // 如果触发事件的对象是我们期望的元素,则执行,否则不执行
            if (event.target.className == "link") {
                console.log("我是ul的单击响应函数");
            }
        };


        var li = document.createElement("li");
        var a = document.createElement("a");
        a.innerText = "新加的超链接";
        // a.class = "link";    //不行
        a.setAttribute("class", "link");
        a.setAttribute("href", "javascript:;");    //意外发现,a标签需要有href属性才会有a的默认样式
        li.appendChild(a);
        u1.appendChild(li);

        console.log(document.getElementById("u1"))
        
    </script>
</body>

</html>

4.4.10、事件绑定

4.4.11、事件传播

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不知-_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值