DOM 基础详解

一、Web APIs 简介

我们前面已经学习完了 JS 的基本语法,但是发现很多常用的网页交互效果依然无法实现,这时候就需要学习 Web APIs 来帮助我们实现网页的交互功能。
API 是为我们程序员提供的一个接口,帮助我们实现某种功能。Web APIs 是浏览器提供的一套操作浏览器功能和页面元素的 API(BOM 和 DOM)。

二、什么是 DOM

DOM 是文档对象模型,是 W3C 组织推荐的处理可扩展标记语言(HTML 或 XML)的标准编程接口。W3C 已经定义了一系列的DOM 接口,通过这些 DOM 接口可以改变网页的内容、结构和样式。
在这里插入图片描述

① 文档:一个页面就是一个文档,DOM 中使用 document 表示;
② 元素:页面中的所有标签,DOM 中使用 element 表示;
③ 节点:网页中的所有内容都是节点(标签、属性、文本、注释等),DOM 中使用 node 表示。

DOM 把以上内容都看做是对象!

三、获取元素

DOM 在我们实际开发中主要用来操作元素。获取页面中的元素我们可以使用以下几种方式:

① 根据 ID 获取
使用 getElementById() 方法可以获取带有 ID 的元素对象。

<div id = "age"> 19 </div>
<script>
var ager = document.getElementById('age');
console.log(ager); //<div id = "age"> 19 </div> 完整标签选取出来
console.log(typeof ager); //object
</script>

注意点:
① 因为我们文档页面是从上往下加载的,所以先得有标签,script 写到标签下面;
② get 获得,element 元素,by 通过(驼峰命名法);
③ 参数 id 是严格区分大小写的字符串,必须加引号;
④ 返回的结果是一个元素对象;
⑤ console.dir 打印我们返回的元素对象,更好地查看里面的属性和方法。

② 根据标签名获取
使用 getElementsByTagName() 方法可以返回带有指定标签名的对象集合。

<ul>
<li>111</li>
<li>222</li>
<li>333</li>
<li>444</li>
</ul>
<script>
var lis = document.getElementsByTagName('li');
console.log(lis); //[li,li,li,li]
console.log(lis[0]); //<li>111</li>
for (var i = 0; i < lis.length; i++) {
    console.log(lis[i]);
}  //循环打印
</script>

注意点:
① 返回的是获取过来的元素对象的集合,是以伪数组的形式存储的;
② 如果想要依次打印里面的元素对象,我们可以采取遍历的方法实现;
③ 得到的元素对象是动态的,标签内容改变获取的结果也跟着改变;
④ 如果页面中只有一个 li,返回的还是伪数组,如果页面中没有该元素,返回的是一个空的伪数组。

当页面中有多个相同的标签时,我们想要有选择地获取某个标签(父元素)内部所有指定标签名的子元素,这个时候可以这样写:element.getElementsByTagName(‘标签名’);

<ol id = "ols"> 
<li>11</li>
<li>22</li>
<li>33</li>
</ol>
<script>
var ool = document.getElementById('ols'); //通过id值把ols这一个元素获取过来
var lis = ool.getElementsByTagName('li'); //获取指定父元素内的指定子元素
console.log(lis);
</script>

注意父元素必须是单个确切的对象,获取时不包括父元素自己!

③ HTML5 新增方法获取

document.getElementsByClassName('类名'); //根据类名返回元素对象集合
document.querySelector('选择器'); //根据指定选择器返回第一个元素对象
document.querySelectorAll('选择器'); //返回指定选择器内所有元素对象的集合

① 任何选择器都可以,切记里面的选择器要加符号(.box、#box、box);
② 第一种方法里的类名直接写,不需要加符号。

④ 获取 body 和 html 元素

document.body; //获取body元素
document.documentElement; //获取html元素

因为一个页面只有一个 body 和 html,所以直接写就可以了!

四、事件基础

JavaScript 使我们有能力创建动态页面,而事件是可以被 JavaScript 侦测到的行为。
简单理解:触发响应机制。

1.事件三要素

事件有三部分组成,事件源、事件类型和事件处理程序。

① 事件源,事件被触发的对象(触发谁?比如一个按钮);
② 事件类型,如何触发(什么事件?比如鼠标点击、鼠标经过,还是键盘按下);
③ 事件处理程序,通过一个函数赋值的方式完成。

<!--案例 点击按钮弹出一个对话框-->
<button id = "btn">提交</button>
<script>
var btn = document.getElementById('btn');
btn.onclick = function() {
    alert('提交成功!');
}
</script>

2.执行事件过程

① 获取事件源;
② 注册事件(绑定事件);
③ 添加事件处理程序(采取函数赋值形式)。

<!--案例 点击div,控制台输出我被选中了-->
<div>123</div>
<script>
var dic = document.querySelector('div'); //获取事件源
div.onclick = function() {
    console.log('我被选中了');
}  //注册事件并添加事件处理程序
</script>

3.常见的鼠标事件

在这里插入图片描述

五、操作元素

JavaScript 的 DOM 操作可以改变网页的内容、结构和样式,我们可以利用 DOM 操作元素来改变元素里面的内容、属性等。

1.改变元素内容

element.innerText; //从起始位置到终止位置的内容,但它去除html标签,同时空格和换行也会去掉
element.innerHTML; //起始位置到终止位置的全部内容,包括html标签,同时保留空格和换行  

下面看一个案例!

<!--案例 点击按钮,div里面的文字会发生变化-->

<button>显示当前系统时间</button>
<div>某个时间</div>
<script>
//获取事件
var btn = document.querySelector('button');
var div = document.querySelector('div');

//也可以不添加事件,获取过来直接操作(打开页面就显示时间 div.innerText = getDate();)
btn.onclick = function() {
    div.innerText = getDate();
}

//获取当前时间日期
function getDate() {
var date = new Date();
var year = date.getFullYear();
var month = date.date.getMonth() + 1;
var dates = date.getDate();
var arr = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'];
var day = date.getDay();
return '今天是:' + year + '年' + month + '月' + dates + '日' + arr[day];
}
</script>

innerText 和 innerHTML 的区别:
① innerText 不识别 HTML 标签,当修改后的内容有 HTML 标签时,innerText 会直接把标签也显示出来,同时去除空格和换行;
② innerHTML 是我们 W3C 推荐的标准方法,可识别 HTML标签,同时保留空格和换行(常用);
③ 这两个属性可修改元素里的内容,同样也可以读取元素内容( console.log(div.innerText); );

2.修改元素属性

2.1 按钮切换图片
<!--案例 点击不同的按钮,切换不同的图片-->
<button id = "pg">苹果</button>
<button id = "xj">香蕉</button>
<img src = "pg.jpg" title = "苹果" alt = ""/>
<script>
//1.获取元素
var pg = document.getElementById('pg');
var xj = document.getElementById('xj');
var img = document.querySelector('img');
//2.注册事件 处理程序
pg.onclick = function() {
    img.src = 'pg.jpg';
    img.title = '苹果';
}
xj.onclick = function() {
    img.src = 'xj.jpg';
    img.title = '香蕉';
}
</script>
2.2 分时显示图片

案例分析:
① 根据系统不同时间判断,所以需要用到日期内置对象;
②利用多分支语句来设置不同的图片;
③ 需要一个图片,并且根据时间修改图片,就需要用到操作元素 src 属性;
④ 需要一个 div 元素,显示不同的问候语,然后修改元素内容即可。

<!--案例 根据不同时间显示不同图片,同时显示不同的问候语-->
<img src = "swh.jpg" alt = ""/>
<div>上午好</div>
<script>
//1.获取元素
var img = document.querySelector('img');
var div = document.querySelector('div');
//2.获取当前小时数
var date = new Date();
var h = date.getHours();
//3.判断小时数改变图片和文字信息
if (h < 12) {
    img.src = 'swh.jpg';
    div.innerHTML = '上午好!';     
} else if (h >= 12 && h < 18) {
    img.src = 'xwh.jpg';
    div.innerHTML = '下午好!';
} else {
    img.src = 'wsh.jpg';
    div.innerHTML = '晚上好!';
}
</script>

3.修改表单属性

<button>按钮</button>
<input type = "text" value = "输入内容"/>
<script>
var btn = document.querySelector('button');
var input = document.querySelector('input');
btn.onclick = function() {
    input.value = '被点击了'; //修改表单文本域中的内容
    this.disabled = true; //点击之后按钮被禁用,this指向函数的调用者
}  
</script>

① innerHTML 这个是修改普通盒子(如 div)里面的内容,而对于表单元素属性的修改我们一律使用属性名;
② 如果想要一个按钮点击之后被禁用不允许再点击,可以用 disabled 来实现( btn.disabled = true ),实际上我们通常用 this 代替 btn 更简单。

3.1 显示隐藏密码

案例分析:
① 核心思路,点击眼睛按钮,把密码框类型改为文本框就可以看见里面的密码了。
② 一个按钮两种状态,点击一次,切换为文本框,继续点击一次切换为密码框。
③ 算法,利用一个 flag 变量,通过判断 flag 的值,如果是1就切换为文本框,如果为0就变为密码框。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>显示密码测试</title>
    <style>
        body {
            background-color: cadetblue;
        }
        .box {
            position: relative;
            width: 240px;
            border-bottom: 1px solid #ccc;
            margin: 200px auto;
            background-color: white;
        }
        .box input {
            width: 210px;
            height: 26px;
            border: 0;
            font-size: 19px;
            /* 去掉轮廓边框 */
            outline: none;  
        }
        /*通过伪类选择器修改密码框默认提示字体*/
        ::-webkit-input-placeholder {
            color:#ccc;
            font-size: 16px;
        }
        .box img {
            position: absolute;
            top: 6px;
            right: 4px;
            width: 25px;
        }
    </style>
</head>
<body>
    <div class="box">
        <label for="">
            <img src="close.png" id = "eye"/>
        </label>
        <input type="password" placeholder="请输入密码" id="pwd"/>
    </div>

    <script>
        var eye = document.getElementById('eye');
        var pwd = document.getElementById('pwd');
        //利用flag实现睁眼闭眼效果的切换
        var flag = 0;
        eye.onclick = function() {
            if (flag == 0) {
                pwd.type = 'text';
                eye.src = 'open.png';
                flag = 1;
            }else {
                pwd.type = 'password';
                eye.src = 'close.png';
                flag = 0;
            }
        }
    </script>
</body>
</html>

特别记住,要学会利用 flag 值来合理切换不同情况下的事件!

运行结果:

在这里插入图片描述
在这里插入图片描述

我把这两个眼睛图片也放这里吧,有需要自行保存!

在这里插入图片描述
在这里插入图片描述


4.修改样式属性

element.style; //行内样式操作
element.className; //类名样式操作 
4.1 行内样式操作
 <!--案例 点击盒子,盒子就改变颜色-->
 <!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        div {
            width: 200px;
            height: 200px;
            background-color: blue;
        }
    </style>
</head>
<body>
    <div></div>
    <script>
        var div = document.querySelector('div');
        div.onclick = function() {
            this.style.backgroundColor = 'pink'; //属性采取驼峰命名法
        }
    </script>
</body>
</html>

注意:
① JS 里的样式属性采取驼峰命名法(比如:fontSize、backgroundColor 等);
② JS 修改 style 样式操作,产生的是行内样式,权重较高。

4.1.1 关闭二维码

案例分析:
① 核心思路:利用样式的显示和隐藏完成,display: none 隐藏元素,display: block 显示元素。
② 点击叉号,就让这个二维码盒子隐藏起来。

<div class = "box">
二维码
<img src = "ewm.jpg" alt = ""/>
<i class = "close-btn">x</i>
</div>
<script>
var btn = document.querySelector('.close-btn');
var box = document.querySelector('.box');
btn.onclick = function() {
    box.style.display = 'none';
}
</script>

注意不是删掉,而是隐藏起来了!

4.1.2 循环精灵图

如果使用我们以往的方法添加精灵图,会使得我们的代码量非常大,写起来也很麻烦。那么有没有一种简单的方法,可以一次性添加大量的精灵图呢?当然是有的,我们可以利用 for 循环设置一组元素的精灵图背景。(这里不知道精灵图是什么的,可以看我上一篇文章。)

案例分析:
① 首先精灵图图片的排列是有规律的;
② 核心思路,利用 for 循环修改精灵图片的背景位置(background-position);
③ 让循环里面的 i 索引号 * 44 就是每个图片的 y 坐标(竖着排列两个精灵图的间隔测量出来是44)。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>循环精灵图</title>
    <style>
        * {
            margin: 0;
            padding: 0;
        }
        li {
            list-style-type: none;
        }
        .box {
            width: 250px;
            margin: 100px auto;
        }
        .box li {
            float: left;
            width: 24px;
            height: 24px;
            background-color: brown;
            margin: 15px;
            background: url(图.png) no-repeat;
        }
    </style>
</head>
<body>
    <div class="box">
        <li></li>
        <li></li>
        <li></li>
        <li></li>
        <li></li>
        <li></li>
        <li></li>
        <li></li>
        <li></li>
        <li></li>
        <li></li>
        <li></li>
    </div>
<script>
    var lis = document.querySelectorAll('li');
    for (var i = 0; i < lis.length; i++) {
        var index = i * 44;
        lis[i].style.backgroundPosition = '0 -' + index + 'px';
    }
</script>
</body>
</html>

在这里插入图片描述
前提是精灵图里面的小图标要竖着排列,保证间隔一致!

4.1.3 隐藏文本框内容

当鼠标点击文本框时,里面的默认文字隐藏,当鼠标离开文本框时,里面的文字显示。
案例分析:
① 首先表单需要两个新事件,获得焦点 onfocus 失去焦点 onblur;
② 如果获得焦点,判断表单里面内容是否为默认文字,如果是默认文字就清空表单内容;
③ 如果失去焦点,判断表单内容是否为空,如果为空则将表单内容修改为默认文字。

<input type = "text" value = "手机"/>
<script>
var text = document.querySelector('input');
//获得焦点事件
text.onfocus = function() {
    if (this.value === '手机') {
        this.value = '';
    }
    //获得焦点时需要把文本框里面的文字颜色变黑
    this.style.color = '#333';
}
//失去焦点
text.onblur = function() {
    if (this.value === '') {
        this.value = '手机';
    }
    //失去焦点时需要把文本框里面的文字颜色变浅
    this.style.color = '#999';
}
</script>
4.1.4 排他思想(算法)

案例分析:
① 这里有一组按钮,当我们点击一个按钮的时候,只有该按钮变色,且其它按钮都恢复原色;
② 需要用到循环的排他算法。
③ 所有元素全部清除样式,只给当前元素设置样式。
④ 注意顺序不能颠倒,首先清除他人,然后设置自己。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <button>按钮1</button>
    <button>按钮2</button>
    <button>按钮3</button>
    <button>按钮4</button>
    <button>按钮5</button>
    <script>
        var btns = document.getElementsByTagName('button');
        for (var i = 0; i < btns.length; i++) {
            btns[i].onclick = function() {
                //1.清空所有按钮的样式
                for (var i = 0; i < btns.length; i++) {
                    btns[i].style.backgroundColor = '';
                }
                //2.再给自己设置样式
                this.style.backgroundColor = 'blue';
            }
        }
    </script>
</body>
</html>
4.2 类名样式操作

样式比较少或者功能简单的情况下,我们使用上面的行内样式操作。但是
如果样式比较多的时候,我们还使用这种方法是不是显得很啰嗦呢?没关系,这里我们学习第二种修改样式属性的方法 —— 类名样式操作。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
       .box {
           width: 400px;
           height: 600px;
           background-color: blue;
           font-size: 30px;
           color: black;
           margin: 200px 200px;
       }
       .change {
           width: 400px;
           height: 400px;
           background-color: coral;
           margin: auto;
       }
    </style>
</head>
<body>
    <div class = "box">大盒子<div>
    <script>
        var box = document.querySelector('div');
        box.onclick = function() {
            if (this.className === 'change') {
                this.className = 'box';
            }else {
                this.className = 'change';
            }
        } 
    </script>    
</body>
</html>

注意:
① 如果样式修改较多,可以采用操作类名方式更改元素样式;
② class 是个保留字,因此使用 className 来操作元素类名属性;
③ className 会直接更改元素的类名,也就是会直接覆盖掉原先的类名。

但是大多数时候,我们并不需要把原先类里面所有的属性都修改掉,大量重复的样式再写进新的类里面显然是很繁琐的,当然是有办法可以解决的,还记得多类名选择器吗?

this.className = 'first change';

使用多类名选择器,这样我们的新类里面就不需要写那么多本不需变动的样式,只需要将需要改变的样式属性写到新类里面,两个类同时使用即可。

4.2.1 密码框验证信息

案例分析:
① 首先判断的事件是表单失去焦点 onblur。
② 如果输入正确,则提示正确的信息,颜色为绿色,小图标变化。
③ 如果输入位数不是6到16位,则提示错误信息颜色为红色,小图标变化。
④ 因为里面变化样式较多,我们采取 className 修改样式。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>密码框验证</title>
    <style>
        div {
            width: 600px;
            margin: 300px auto;
        }
        .message {
          display: inline-block;
          font-size: 13px;
          color: #999;
          background: url(提示.png) no-repeat left center;
          background-size:16px 16px;
          padding-left: 20px;
        }
        .wrong {
            color: red;
            background-image: url(叉号.png);
        }
        .right {
            color: green;
            background-image: url(对号.png);
        }
    </style>
</head>
<body>
    <div>
        <input type="text" class="ipt"/>
        <p class="message">请输入6到16位密码!</p>
    </div>
    <script>
        var ipt = document.querySelector('.ipt');
        var message = document.querySelector('.message');
        ipt.onblur = function() {
            if (this.value.length < 6 || this.value.length > 16) {
                message.className = 'message wrong';
                message.innerHTML = '您输入的密码位数不满足条件!';
            }else {
                message.className = 'message right';
                message.innerHTML = '密码格式正确!';
            }
        }
    </script>
</body>
</html>

运行结果:在这里插入图片描述
在这里插入图片描述

4.2.2 表格隔行变色

案例分析:
① 用到新的鼠标事件,鼠标经过 onmouseover,鼠标离开 onmouseout。
② 核心思路,鼠标经过 tr 行,当前行改变背景颜色,鼠标离开后去掉该背景颜色。
③ 注意第一行 thead 不需要变换颜色,我们要获取的是 tbody 里面的行。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        table {
            width: 800px;
            margin: 100px auto;
            text-align: center;
            /* 合并相邻边 */
            border-collapse: collapse;
            font-size: 14px;
            border: 1px solid aqua;
        }
        thead tr {
            height: 30px;
            background-color: aqua;
        }
        tbody tr {
            height: 30px;
        }
        .bg {
            background-color: burlywood;
        }
    </style>
</head>
<body>
    <table>
        <thead>
           <tr>
               <th>代码</th>
               <th>名称</th>
               <th>累计净值</th>
               <th>前单位净值</th>
               <th>净值增长率</th>
           </tr>
        </thead>
        <tbody>
            <tr>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
            </tr>
            <tr>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
            </tr>
            <tr>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
            </tr>
            <tr>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
            </tr>
            <tr>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
            </tr>
        </tbody>
    </table>
    <script>
        var trs = document.querySelector('tbody').querySelectorAll('tr');
        for (var i = 0; i < trs.length;i++) {
            trs[i].onmouseover = function() {
                this.className = 'bg';
            }
            trs[i].onmouseout = function() {
                this.className = '';
            }
        }
    </script>
</body>
</html>
4.2.3 表单全选取消

案例分析:
① 全选和取消全选做法:让下面所有复选框的 选中状态(checked 属性)跟随全选按钮的选中状态即可。
② 下面复选框只要有一个未选中,全选就取消做法:给下面所有复选框绑定点击事件,每次点击都要循环查看其他的复选框有没有全部都选中,如果发现有一个未选中,上面全选取消。
③ 可以设置一个变量,来控制全选是否选中。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        table {
            width: 800px;
            margin: 100px auto;
            text-align: center;
            border-collapse: collapse;
        }
        thead tr {
            height: 30px;
            background-color:rgb(62, 62, 227);
        }
        tbody tr {
            height: 30px;
            background-color: antiquewhite;
        }
    </style>
</head>
<body>
    <div class="wrap">
        <table>
            <thead>
            <tr>
                <th>
                    <input type="checkbox" id="j_cbAll"/>
                </th>
                <th>商品</th>
                <th>价格</th>
            </tr>
            </thead>
            <tbody id="j_tb">
            <tr>
                <td>
                    <input type="checkbox"/>
                </td>
                <td>iPhone8</td>
                <td>8000</td>
            </tr>
            <tr>
                <td>
                    <input type="checkbox"/>
                </td>
                <td>iPad Pro</td>
                <td>5000</td>
            </tr>
            <tr>
                <td>
                    <input type="checkbox"/>
                </td>
                <td>iPad Air</td>
                <td>2000</td>
            </tr>
            <tr>
                <td>
                    <input type="checkbox"/>
                </td>
                <td>Apple Watch</td>
                <td>2000</td>
            </tr>
            </tbody>
        </table>
    </div>
    <script>
        var j_cbAll = document.getElementById('j_cbAll');
        var j_tbs = document.getElementById('j_tb').getElementsByTagName('input');
        //1.点击全选,下面所有复选框都被选中
        j_cbAll.onclick = function() {
            for (var i = 0; i < j_tbs.length; i++) {
                j_tbs[i].checked = this.checked;
            }
        }
        //2.复选框只要有一个没有被选中,全选就取消
        for (var i = 0; i < j_tbs.length; i++) {
            j_tbs[i].onclick = function() {
                //flag控制全选按钮是否被选中
                var flag = true;
                for (var i = 0; i < j_tbs.length; i++) {
                    if (!j_tbs[i].checked) {
                    flag = false;
                    //只要发现有一个没被选中结果就已经确定了,后面无需再判断
                    break; 
                    }
                }
                j_cbAll.checked = flag;
            }
        }
    </script>
</body>
</html>

运行结果:
在这里插入图片描述

5.修改自定义属性

对属性的操作我们有两种方法,第一种是我们前面所学的元素.id,但是这种方法只能对内置属性进行操作,而我们这里所讲的是另一种方法元素.setAttribute(),它不仅能对内置属性进行操作,更主要的功能是用来操作自定义的属性。

<div id-"demo" index = "1"></div>

<script>
    var div = document.querySelector('div');
    //获取元素的属性值
    var a = div.id; //demo 第一种方法,只能获取内置属性的值
    var b = div.getAttribute('id'); //demo 第二种方法,主要用来获取自定义属性的值  
      
    //修改元素的属性值
    div.setAttribute('id', 'play');
    
    //移除自定义属性
    div.removeAttribute('index'); 
</script>
5.1 tab 栏切换

重点案例!!
案例分析:
① 当鼠标点击上面相应的选项卡,下面的内容会跟着变化。
② Tab 栏有两大模块,点击上面的某一个选项卡,当前这一底色变为红色,其余不变,你是否想到了用排他思想修改类名?
③ 下面的模块内容,会随着上面的选项卡的变化而变化,所以该变化要写到点击事件里面。
④ 下面的模块显示内容和上面的选项卡是一一对应的,相匹配。
⑤ 核心思路,给上面的 tab_list 里面的所有的 li 添加自定义属性,属性值从0开始编号。
⑥ 点击 tab_list 里面的某个 li,让 tab_con 里面对应序号的内容显示,其余隐藏即可。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        .tab {
            width: 660px;
            height: 350px;
            margin: 200px auto;
        }
        .tab_list li {
            float: left;
            height: 39px;
            line-height: 39px;
            padding: 0 20px;
            text-align: center;
            list-style: none;
            cursor: pointer;
        }
        .tab_list .current {
            background-color: brown;
            color: aliceblue;
        }
        .tab_con {
            font-size: 15px;
            padding: 60px 41px;
        }
        .item {
            display: none;
        }
    </style>
</head>
<body>
    <div class="tab">
        <div class="tab_list">
            <ul>
                <li class="current">商品介绍</li>
                <li>规格与包装</li>
                <li>售后保障</li>
                <li>商品评价(5000)</li>
                <li>手机社区</li>
            </ul>
        </div>
        <div class="tab_con">
            <div class="item" style="display: block;">
                商品介绍模块内容
            </div>

            <div class="item">
                规格与包装模块内容
            </div>

            <div class="item">
                售后保障模块内容
            </div>
             
            <div class="item">
                商品评价模块内容
            </div>

            <div class="item">
                手机社区模块内容
            </div>
        </div>
    </div>

    <script>
        var tab_list = document.querySelector('.tab_list');
        var lis = tab_list.querySelectorAll('li'); 
        var items = document.querySelectorAll('.item');
        //for循环绑定点击事件
        for (var i = 0; i < lis.length; i++) {
            //给li设置索引号
            lis[i].setAttribute('index', i);
            lis[i].onclick = function() {
                //1.清除所有li的样式
                for (var i = 0; i < lis.length; i++) {
                    lis[i].className = '';
                }
                //2.给当前li添加样式
                this.className = 'current';
                var index = this.getAttribute('index');
                for (var i = 0; i < lis.length; i++) {
                    items[i].style.display = 'none';
                }
                items[index].style.display = 'block';
            }
        }   
    </script>
</body>
</html>

运行结果:
在这里插入图片描述

5.2 H5 自定义属性

自定义属性目的:是为了保存并使用数据。有些数据可以保存到页面中而不用保存到数据库中。
自定义属性通过 getAttribute(‘属性’) 获取。但是有些自定义属性很容易引起歧义,不容易判断是元素的内置属性还是自定义属性。H5 给我们新增了自定义属性,H5 规定自定义属性的属性名都以 data- 开头。
比如<div data-index = "1"></div>,或者使用 JS 设置element.setAttribute('data-index', 2)

div.getAttribute('data-index'); //这是我们之前获取自定义属性的方法
div.dataset.index; //这是H5新增的获取自定义属性的方法
div.dataset['index']; //同上

H5 新增方法只有 ie11 以上版本才支持,所以我们一般还是用老方法 getAttribute!

六、节点操作

1.为什么学习节点

获取元素通常使用两种方式:
① 利用 DOM 提供的方法获取(我们前面所学的),缺点就是逻辑性不强,非常繁琐;
② 利用节点层级关系获取,通过父子兄弟节点关系获取元素,相较于上一种方法,它的逻辑性更强,操作简单,但是兼容性较差。

① 网页中所有的内容都是节点,在 DOM 中节点用 node 来表示;
② 一般地,节点至少拥有 nodeType、nodeName 和 nodeValue 这三个基本属性;
③ 元素节点类型为1,属性节点类型为2,文本节点类型为3;

我们实际开发中,节点操作主要操作的是元素节点!

2.节点层级

<ul>
    <li><li>
    <li><li>
    <li><li>
    <li><li>
</ul>
<div class="box">
<span class="top"></span>
</div>
<script>
    //1.父节点 parentNode返回的是它的父亲(离它最近的父结点)
    var top = document.querySelector('.top');
    console.log(top.parentNode);

    //2.子节点 children返回所有的元素子节点,也是我们实际开发中常用的
    var ul = document.querySelector('ul');
    console.log(ul.children);
    
    //3.第一个和最后一个子节点 firstChild 和 lastChild
      var ul = document.querySelector('ul');
    console.log(ul.firstChild); //#text 注意这里返回的是第一个子节点(包括文本节点和元素节点等)
    console.log(ul.firstElementChild); //与上面的不同,这个方法返回的直接是第一个元素子节点,但缺点是兼容性差,低版本不支持
    console.log(ul.children[0]); //实际开发中的写法,既没有兼容性问题又可以返回第一个子元素
    //4.兄弟节点 不常用
    var ul = document.querySelector('ul');
    console.log(ul.nextSibling); //返回当前元素的下一个兄弟节点,同样也包含文本节点等所有的节点
    console.log(ul.previousSibling); //返回当前元素的上一个兄弟节点,同样也包含文本节点等所有的节点
    console.log(ul.nextElementSibling); //返回当前元素的下一个兄弟元素节点,有兼容性问题
    console.log(ul.previousElementSibling);//返回当前元素的上一个兄弟元素节点
</script>

子节点除了 parentNode.children 外,其实还有另一种方法 parentNode.childNodes,但我们不推荐!
因为它返回的是所有的孩子节点,包括元素节点、文本节点等,想要单独把元素节点显示出来得使用 for 循环来实现,显然太过繁琐。所以我们不使用该方法,但上面的 parentNode.children 是要重点掌握的。

2.1 下拉菜单

① 导航栏里面的 li 都要有鼠标经过效果,所以需要循环注册鼠标事件。
② 核心原理,当鼠标经过, li 里面的 ul 显示,鼠标离开 ul 隐藏。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        * {
            margin: 0;
            padding: 0;
        }
        li {
            list-style: none;
        }
        a {
            text-decoration: none;
            color: black;
        }
        .nav {
          margin: 60px 500px;
        }
        .nav>li{
          position: relative;  
          float: left;  
          height: 41px;
          width: 114px;
          text-align: center;
          background-color: aliceblue;
          color: black;
        }
        .nav>li>a {
            display:inline-block;
            width: 100%;
            height: 100%;
            line-height: 41px;
            
        }
        .nav>li>a:hover {
            background-color:rgb(196, 172, 245);
        }
        .nav ul {
            display: none;
            position: absolute;
            top: 41px;
            left: 0;
            width: 100%;
            border-left: 1px solid rgb(196, 92, 231);
            border-right: 1px solid rgb(196, 92, 231);
        }
        .nav ul li {
            border-bottom: 1px solid rgb(196, 92, 231);
        }
        .nav ul li a {
            display: block;
            line-height: 37px;
            font-size: 13px;
            width: 100%;
            height: 100%;
        }
        .nav ul li a:hover {
            background-color: antiquewhite;
        }
    </style>
</head>
<body>
  <ul class="nav">
      <li>
          <a href="#">微博</a>
          <ul>
              <li>
                  <a href="#">私信</a>
              </li>
              <li>
                  <a href="#">评论</a>  
              </li>
              <li>
                  <a href="#">@我</a> 
              </li>
          </ul>
      </li>
      <li>
          <a href="#">博客</a>
          <ul>
            <li>
                <a href="#">博客评论</a> 
            </li>
            <li>
                <a href="#">未读提醒</a>  
            </li>
        </ul>
      </li>
      <li>
          <a href="#">邮箱</a>
          <ul>
            <li> 
                <a href="#">免费邮箱</a>
            </li>
            <li> 
                <a href="#">VIP邮箱</a>
            </li>
            <li> 
                <a href="#">企业邮箱</a>
            </li>
        </ul>
    </li>
  </ul>  
  <script>
      var nav = document.querySelector('.nav');
      var lis = nav.children; //得到4个li
      for (var i = 0; i < lis.length; i++) {
          lis[i].onmouseover = function() {
              this.children[1].style.display = 'block';
          }
          lis[i].onmouseout = function() {
              this.children[1].style.display = 'none';
          }
      }
  </script>
</body>
</html>

运行结果:

在这里插入图片描述

3.添加节点

//1.创建节点
document.createElement('tagName');
//2.添加节点 两种方法
node.appendChild(child);
node.insertBefore(child, 指定元素);

① document.createElement() 方法创建由 tagName 指定的 HTML 元素。因为这些元素原先不存在,是根据我们的需求动态生成的,所以也称为动态创建元素节点。
② node.appendChild() 方法将一个节点添加到指定父节点的子节点列表末尾。
③ node.insertBefore() 方法可以将一个节点添加到父节点的指定子节点前面。

// 给ul添加li
<ul></ul>
<script>
    var li = document.createElement('li'); //创建节点元素li
    var ul = document.querySelector('ul');
    ul.appendChild(li); //给父级ul添加子级li,末尾追加(常用)
    ul.insertBefore(li, ul.children[1]); //将li添加到ul的第二个子节点的前面,索引从0开始
</script>

4.删除节点

node.removeChild(child);

该方法从 DOM 中删除一个子节点,并返回删除的节点。

4.1 发布及删除留言

案例分析:
① 点击按钮之后,就动态创建一个 li,添加到 ul 里面。
② 创建 li 的同时,把文本域里面的值通过 li.innerHTML 赋值给 li。
③ 留言在前面显示用 insertBefore 。
④ 当我们把文本域里面的值赋值给 li 的时候,多添加一个删除的链接。
⑤ 需要把所有的链接获取过来,当我们点击当前的链接的时候,就删除当前链接所在的 li。
⑥ 点击删除链接的时候,地址会发生改变,为了阻止链接跳转,href 里面写javascript:;即可

<textarea name="" id="">123</textarea>
<button>发布</button>
<ul>
</ul>
<script>
    var btn = document.querySelector('button');
    var text = document.querySelector('textarea');
    var ul = document.querySelector('ul');
    btn.onclick = function() {
    if (text.value == '') {
        alert('您没有输入内容!');
        return false;
    }else{
         //1.创建元素 
         var li = document.createElement('li');
         li.innerHTML = text.value + "<a href='javascript:;'>删除</a>"; //把文本框中的内容给li,显示出来并添加删除键
         //2.添加元素
         ul.insertBefore(li, ul.children[0]);
         //3.删除元素
         var as = document.querySelector('a');
         for (var i = 0; i < as.length; i++) {
             as[i].onclick = function() {
                 ul.removeChild(this.parentNode); //当前链接的父亲就是我们要删除的元素li 
             }
         }
    }
    }
</script>

5.复制节点

<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
<script>
    var ul = document.querySelector('ul');
   var lili = ul.children[0].cloneNode(true); //将第一个li复制上
   ul.appendChild(lili); //将复制好的内容追加到原列表后面
</script>
node.cloneNode();

node.cloneNode() 方法返回调用该方法节点的一个副本,也称为克隆节点或拷贝节点。如果括号里面的参数为空或者为 false,则是浅拷贝,即只克隆复制节点本身,并不会克隆里面的内容,只有括号里面为 true 时,才会将标签及标签里面的内容全部复制上。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

栈老师不回家

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

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

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

打赏作者

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

抵扣说明:

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

余额充值