前端学习笔记之DOM(一)

DOM介绍

  • 1.DOM简介
    • 1.1 什么是DOM
    • 1.2 DOM树
  • 2. 获取元素
    • 2.1 如何获取页面元素
    • 2.2 根据ID获取
    • 2.3 根据标签名获取
    • 2.4 通过 HTML5 新增的方法获取
    • 2.5 获取特殊元素(body、html)
      • 2.5.1 获取body元素
      • 2.5.2 获取html元素对象
  • 3. 事件基础
    • 3.1 事件概述
    • 3.2 事件三要素
      • 3.2.1 案例
    • 3.3 执行事件的步骤
    • 3.4 常见的鼠标事件
    • 3.5 分析事件三要素
  • 4. 操作元素
    • 4.1 改变元素内容
    • 4.2 常用元素的属性操作
    • 4.3 表单元素的属性操作
    • 4.4 样式属性的操作
    • 4.5 案例
      • 4.5.1 案例一:点击关闭二维码
      • 4.5.2 案例二:精灵图背景
      • 4.5.3 案例三:显示/隐藏 搜索框文字
      • 4.5.4 案例四:密码框格式提示错误信息
    • 4.6 自定义属性的操作
      • 4.6.1 获取属性值
      • 4.6.2 设置属性值
      • 4.6.3 移除属性
    • 4.7 H5自定义属性
      • 4.7.1 设置H5自定义属性
      • 4.7.2 获取H5自定义属性
  • 5.节点操作
    • 5.1 为什么学节点操作
    • 5.2 节点概述
    • 5.3 节点层级
      • 5.3.1. 父级节点
      • 5.3.2 子节点
      • 5.3.3 兄弟节点
    • 5.4 创建节点
    • 5.5 删除节点
      • 5.5.1 案例:动态生成表格
    • 5.6 复制(克隆)节点
    • 5.7 动态创建元素的区别
  • 6 DOM操作总结
  • END

1.DOM简介

1.1 什么是DOM

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

1.2 DOM树

  • 文档:一个页面即一个文档,用 document 表示;
  • 元素:页面中的所有标签都是元素,用 element 表示;
  • 节点:网页中的所有内容都是节点(标签、属性、文本、注释等),用 node 表示。
    ——而文档、元素、节点在DOM中看做对象
    前端学习笔记之DOM(一)_第1张图片

2. 获取元素

2.1 如何获取页面元素

在实际开发中,DOM主要用来操作元素,获取页面元素主要有以下几种方式:

  • 根据 ID 获取;
  • 根据标签名获取;
  • 通过 HTML5 新增的方法获取;
  • 特殊元素获取。

2.2 根据ID获取

  • getElementById() 方法:获取带有 ID 的元素对象;
document.getElementById('id');

console.dir()打印出获取的元素对象,以查看对象的属性和方法。

2.3 根据标签名获取

getElementsByTagName() 方法可返回带有指定标签名的对象的集合。

document.getElementsByTagName('标签名');

注:
1). 得到的是对象的集合,所以在操作里面的元素前需要遍历;
2). 得到元素对象是动态的;
3). 如果获取不到元素,则返回空的伪数组(获取不到对象)。

同样,也可以获取某个元素(父元素)内部所有指定标签名的子元素:

element.getElementsByTagName('标签名')

注:父元素必须是单个对象(必须指明是哪一个元素对象). 获取的时候不包括父元素自己。

2.4 通过 HTML5 新增的方法获取

// 1、根据类名返回元素对象集合:
   document.getElementsByClassName('类名');
   
// 2、根据指定选择器返回第一个元素对象:
   document.querySelector('选择器');

// 3、根据指定选择器返回所有元素对象:
   document.querySelectorAll('选择器');   

注意:
querySelectorquerySelectorAll 里面的选择器需要加符号,示例如下:

document.querySelector('#nav');

2.5 获取特殊元素(body、html)

2.5.1 获取body元素

document.body   // 返回body元素对象。

2.5.2 获取html元素对象

document.documentElement  // 返回html元素对象。

3. 事件基础

3.1 事件概述

JavaScript 能创建动态页面,而事件是能被(JavaScript )侦测的行为。
即: 触发响应机制。
网页中的每个元素都可以产生某些可以触发 JavaScript 的事件,例如,当用户点击按钮时产生一个事件,然后执行某些操作。

3.2 事件三要素

  1. 事件源 (谁);
  2. 事件类型 (什么事件);
  3. 事件处理程序 (做啥);

3.2.1 案例

要求:点击按钮弹出警示框,弹出“你好”警示框。
前端学习笔记之DOM(一)_第2张图片
4. 实现步骤:
1).获取事件源;
2)绑定事件,onclick
3.)编写事件处理程序,写一个函数弹出 alert 警示框。
5. 实现代码

var btn = document.getElementById('btn');
btn.onclick = function() {
alert('你好吗');
};

3.3 执行事件的步骤

1、获取事件源
 - 注册事件(绑定事件)
 - 添加事件处理程序(采取函数赋值形式)

3.4 常见的鼠标事件

鼠标事件 触发条件
onclick 鼠标单击(左键)
onmouseover 鼠标经过
onmouseout 鼠标离开
onfocus 获得鼠标焦点
onblur 失去鼠标焦点
onmousemove 鼠标移动
onmouseup 鼠标弹起
onmousedown 鼠标按下

3.5 分析事件三要素

  • 下拉菜单三要素
  • 关闭广告三要素

4. 操作元素

JavaScriptDOM操作可以改变网页内容、结构和样式。开发中,可利用 DOM 操作元素来改变元素里面的内容 、属性等。注意以下都是属性:

4.1 改变元素内容

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

4.2 常用元素的属性操作

 innerText、innerHTML 改变元素内容
 src、href
 id、alt、title

4.3 表单元素的属性操作

利用 DOM 可以操作如下表单元素的属性:

type、value、checked、selected、disabled
  • 案例:密码框显示/隐藏密码;
  • 要求:点击按钮将密码框切换为文本框,并可以查看密码明文。
  • 实现思路:
    1)图标切换:点击眼睛按钮图标,把密码框类型修改为文本框(此时可以看见里面的密码);
    2)状态切换:一个按钮两个状态,点击一次,切换为文本框,继续点击一次切换为密码框;
    3)算法:利用一个flag变量,来判断flag的值,如果是1 就切换为文本框,flag 设置为0,如果是0 就切换为密码框,flag设置为1
  • 实现代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        .box {
            position: relative;
            width: 400px;
            border-bottom: 1px solid #ccc;
            margin: 100px auto;
        }        
        .box input {
            width: 370px;
            height: 30px;
            border: 0;
            outline: none;
        }        
        .box img {
            position: absolute;
            top: 2px;
            right: 2px;
            width: 24px;
        }
    </style>
</head>

<body>
    <div class="box">
        <label for="">
            <img src="images/close.png" alt="" id="eye">
        </label>
        <input type="password" name="" id="pwd">
    </div>
    <script>
        // 1. 获取元素
        var eye = document.getElementById('eye');
        var pwd = document.getElementById('pwd');
        // 2. 注册事件
        var flag = 0;
        eye.onclick = function() {
            // 点击之后, flag 的值发生变化
            if (flag == 0) {
                pwd.type = 'text';
                eye.src = 'images/open.png';
                flag = 1; // 赋值
            } else {
                pwd.type = 'password';
                eye.src = 'images/close.png';
                flag = 0;
            }
        }
    </script>
</body>
</html>

4.4 样式属性的操作

通过 JavaScript 修改元素的大小、颜色、位置等样式。

element.style        // 行内样式操作
element.className    // 类名样式操作

注:

  • JavaScript样式名称采用驼峰命名法 ,如 fontSizebackgroundColor
  • JavaScript 修改style 样式的操作,产生的是行内样式,CSS 权重高。
  • 如果样式修改较多,可以采取操作类名方式更改元素样式;
  • class是保留字,因此使用className来操作元素类名属性;
  • className 会直接更改、覆盖元素的类名。

4.5 案例

4.5.1 案例一:点击关闭二维码

当鼠标点击二维码关闭按钮的时候,则关闭整个二维码。
前端学习笔记之DOM(一)_第3张图片

  • 实现思路:

1)利用样式的显示和隐藏:display:none 隐藏元素 display:block 显示元素;
2)点击按钮,二维码盒子隐藏。

  • 实现代码:
// 1、获取元素
var btn = document.querySelector('.close-btn');
var box = document.querySelector('.box');
// 2.注册事件 程序处理
btn.onclick = function(){
    box.style.display = 'none';
}

4.5.2 案例二:精灵图背景

核心思路:
1)利用for循环修改精灵图片的背景位置 background-position
2)让循环里面的索引号 i × 44 即为每个li(图片)的indexy坐标)。

实现代码:

var lis = document.querySelectorAll('li');
for (var i = 0; i < lis.length; i++) {
        var index = i * 44;
        lis[i].style.backgroundPosition = '0 -' + index + 'px';
}

4.5.3 案例三:显示/隐藏 搜索框文字

**实现效果:**鼠标单击时,默认文字隐藏;当鼠标离开时,文字显示。
在这里插入图片描述
实现思路:
1)两个事件:获得焦点 onfocus 失去焦点 onblur
2)获得焦点,判断表单里面内容是否为默认文字,如果是,就清空表单内容;
3)如果失去焦点, 判断表单内容是否为空,如果为空,则表单内容改为默认文字。

实现代码:

<body>
    <input type="text" value="手机">
    <script>
        // 1.获取元素
        var text = document.querySelector('input');
        // 2.注册事件 获得焦点事件
        text.onfocus = function() {
                if (this.value === '手机') {
                    this.value = '';
                }
                // 获得焦点时,文字颜色变深
                this.style.color = '#333';
            }
            // 3. 注册事件 失去焦点事件
        text.onblur = function() {
            if (this.value === '') {
                this.value = '手机';
            }
            // 失去焦点,文字颜色变浅
            this.style.color = '#999';
        }
    </script>
</body>

4.5.4 案例四:密码框格式提示错误信息

  • 实现效果:用户如果离开密码框,判断输入个数,不符合则提示错误信息。
    在这里插入图片描述
    ** 实现思路:**
    1)首先对表单失去焦点事件进行判断 onblur
    2)如果输入正确则提示正确的信息,颜色为绿色小图标
    3)如果输入位数不符,则提示错误信息,颜色为红色小图标;
    考虑里面变化样式较多,采取className修改样式。

实现代码:

<body>
    <div class="register">
        <input type="password" class="ipt">
        <p class="message">请输入6~16位密码</p>
    </div>
    <script>
        // 1.获取元素
        var ipt = document.querySelector('.ipt');
        var message = document.querySelector('.message');
        //2. 注册事件 失去焦点
        ipt.onblur = function() {
            // 根据表单内值的长度 ipt.value.length
            if (this.value.length < 6 || this.value.length > 16) {
                // console.log('错误');
                message.className = 'message wrong';
                message.innerHTML = '您输入的位数不对要求6~16位';
            } else {
                message.className = 'message right';
                message.innerHTML = '您输入的正确';
            }
        }
    </script>
</body>

4.6 自定义属性的操作

4.6.1 获取属性值

 element.属性   // 获取属性值。
 element.getAttribute('属性');

区别:

  • element.属性:获取内置属性值(元素本身自带的属性);
  • element.getAttribute(‘属性’):主要获得自定义的属性(标准) ,程序员自定义的属性

4.6.2 设置属性值

element.属性 = '值'   // 设置内置属性值。
element.setAttribute('属性', '值');

区别:

  • element.属性:设置内置属性值
  • element.setAttribute(‘属性’):主要设置自定义的属性 (标准)

4.6.3 移除属性

element.removeAttribute('属性');

4.7 H5自定义属性

  • 自定义属性目的*:保存并使用数据。有些数据可以保存到页面中而无需保存到数据库;
  • 自定义属性获取是通过 getAttribute(‘属性’)
    由于个别自定义属性,不易判断是元素的内置还是自定义属性。因此 H5新增了自定义属性:

4.7.1 设置H5自定义属性

H5规定,自定义属性以 data- 开头做为属性名并赋值。
例如:

<div data-index="1"></div>            // 或者
                                      //  使用 JavaScript 设置:
element.setAttribute('data-index',2)

4.7.2 获取H5自定义属性

element.getAttribute('data-index');   //  兼容性获取;
element.dataset.index                 //  或者
element.dataset['index']              //  H5新增,IE 11才开始支持.

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

5.节点操作

5.1 为什么学节点操作

获取元素通常使用的两种方式:

一、利用DOM提供的方法获取元素 二、利用节点层级关系获取元素
document.getElementById() 利用父子兄节点关系获取元素
document.getElementsByTagName() 逻辑性强, 但是兼容性稍差
document.querySelector
逻辑性不强、繁琐

这两种方式都可以获取元素节点,但是节点操作更简单!

5.2 节点概述

网页中的所有内容都是节点标签、属性、文本、注释等),在DOM 中,节点用 node 表示。
HTML DOM 树中的所有节点均可通过 JavaScript 进行访问,所有 HTML 元素(节点)均可被修改,也可以创建或删除。

前端学习笔记之DOM(一)_第4张图片
一般地,节点至少拥有nodeType(节点类型)、nodeName(节点名称)和nodeValue(节点值)这三个基本属性。

  • 元素节点 nodeType 为 1
  • 属性节点 nodeType 为 2
  • 文本节点 nodeType 为 3 (文本节点包含文字、空格、换行等)

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

5.3 节点层级

利用 DOM 树可以把节点划分为不同的层级关系,常见的是父子兄层级关系
前端学习笔记之DOM(一)_第5张图片

5.3.1. 父级节点

node.parentNode
  • parentNode 属性可返回某节点的父节点,注意是最近的一个父节点
  • 如果指定的节点没有父节点则返回 null

5.3.2 子节点

parentNode.childNodes    // 标准 
parentNode.children      // 非标准(各浏览器均支持,可放心使用)
parentNode.firstChild    // 返回第一个子节点,找不到则返回null(所有的节点)。
parentNode.lastChild     // 返回最后一个子节点,找不到则返回null(所有的节点)
parentNode.firstElementChild  // 返回第一个子元素节点,找不到则返回null。
parentNode.lastElementChild   // 返回最后一个子元素节点,找不到则返回null

注:

  • parentNode.childNodes返回包含指定节点的子节点的集合,该集合是实时更新的。返回值里包含所有的子节点(包括元素节点,文本节点等)。一般不提倡使用childNodes,如果只想要获得里面的元素节点,需要做如下处理:
var ul = document. querySelector('ul');
for(var i = 0; i < ul.childNodes.length;i++) {
    if (ul.childNodes[i].nodeType == 1) { // ul.childNodes[i] 是元素节点
         console.log(ul.childNodes[i]); 
    }
} 
  • parentNode.children是只读属性,返回所有的子元素节点。它只返回子元素节点,其余节点不返回 (重点掌握)。children 虽然是非标准,各浏览器均支持,可放心使用。
  • parentNode.firstElementChildparentNode.lastElementChild 这两个方法有兼容性问题,IE9 以上才支持。

实际开发中,firstChildlastChild 包含其他节点,操作不方便,而 firstElementChildlastElementChild 又有兼容性问题,那么该如何去获取第一个子元素节点或最后一个子元素节点?

解决方案:

  • 如果想要第一个子元素节点,可以使用 parentNode.chilren[0]
  • 如果想要最后一个子元素节点,可以使用 parentNode.chilren[parentNode.chilren.length - 1]来获取。

5.3.3 兄弟节点

1. node.nextSibling

nextSibling 返回当前元素的下一个兄弟元素节点,找不到则返回null。同样,也是包含所有的节点。

2. node.previousSibling

previousSibling 返回当前元素上一个兄弟元素节点,找不到则返回null。同样,也是包含所有的节点。

3. node.nextElementSibling

nextElementSibling 返回当前元素下一个兄弟元素节点,找不到则返回null

4. node.previousElementSibling

previousElementSibling 返回当前元素上一个兄弟节点,找不到则返回null

注意:3、4这两个方法有兼容性问题, IE9 以上才支持。

解决方案:

  • 封装一个函数解决兼容性问题
function getNextElementSibling(element) {
       var el = element;
       while (el = el.nextSibling) {
            if (el.nodeType === 1) {
            return el;
            }
       }
       return null;
}

5.4 创建节点

document.createElement('tagName')

document.createElement() 方法创建由 tagName 指定的 HTML 元素。这些元素根据我们的需求动态生成,所以也称为动态创建元素节点

1. node.appendChild(child)

node.appendChild() 方法将一个节点添加到指定父节点的子节点列表末尾。类似于 CSS 里面的 after 伪元素。

2. node.insertBefore(child,指定元素)

node.insertBefore() 方法将一个节点添加到父节点的指定子节点前面。类似于 CSS 里面的 before 伪元素

案例(应用场景):发布留言功能
前端学习笔记之DOM(一)_第6张图片

  • 实现思路:
    1)每单击按钮,就动态创建一个li添加到ul 里面。
    2)创建li 的同时,把文本域里面的值通过li.innerHTML 赋值给 li
    3)如果设定新留言在最后面显示,就用 appendChild ;反之,如果想要始终在前面显示,就用insertBefore
  • 实现代码
<body>
    <textarea name="" id=""></textarea>
    <button>发布</button>
    <ul>

    </ul>
    <script>
        // 1. 获取元素
        var btn = document.querySelector('button');
        var text = document.querySelector('textarea');
        var ul = document.querySelector('ul');
        // 2. 注册事件
        btn.onclick = function() {
            if (text.value == '') {
                alert('您没有输入内容');
                return false;
            } else {
                // console.log(text.value);
                // (1) 创建元素
                var li = document.createElement('li');
                // 先有li 才能赋值
                li.innerHTML = text.value;
                // (2) 添加元素
                // ul.appendChild(li);
                ul.insertBefore(li, ul.children[0]);
            }
        }
    </script>
</body>

5.5 删除节点

node.removeChild(child)

node.removeChild() 方法从 DOM 中删除一个子节点,返回删除的节点。

结合上面的留言发布案例,做为本节的删除案例予以实现

案例:删除留言案例

  • 实现思路:
    1)当把文本域内的值赋值给li 时,同时添加一个删除的链接(a标签);
    2)获取所有的链接,当点击当前链接时,删除当前链接所在的li
    3)由于a标签被单击时,地址栏尾部会出现#,故需阻止链接跳转,相应的就要添加 javascript:void(0); 或者 javascript:;(推荐后者,在使用上更简单方便)。

5.5.1 案例:动态生成表格

前端学习笔记之DOM(一)_第7张图片

  • 案例分析:
    1)由于学生数据是动态的,因此需要用JavaScript 动态生成。 这里采用模拟数据,采取对象形式存储;
    2)所有的数据都放到tbody里面的行里面;
    3)因为行比较多,需要循环创建多行(对应人数);
    4)每行面又有很多单元格(对应里面的数据),还需继续使用循环创建多个单元格,并且把数据存入里面(双重for循环);
    5)最后一列单元格是删除,需要单独创建单元格;
    6)添加删除程序,单击删除,可以删除当前行。

  • 实现代码

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        table {
            width: 500px;
            margin: 100px auto;
            border-collapse: collapse;
            text-align: center;
        }       
        td,
        th {
            border: 1px solid #333;
        }
        
        thead tr {
            height: 40px;
            background-color: #ccc;
        }
    </style>
</head>

<body>
    <table cellspacing="0">
        <thead>
            <tr>
                <th>姓名</th>
                <th>科目</th>
                <th>成绩</th>
                <th>操作</th>
            </tr>
        </thead>
        <tbody>

        </tbody>
    </table>
    <script>
        // 1.准备数据(在数组中创建模拟数据替代数据库)
        var datas = [{
            name: '周润发',
            subject: '影视表演',
            score: 99
        }, {
            name: '李小龙',
            subject: '影视表演',
            score: 99
        }, {
            name: '刘德华',
            subject: '流行歌曲',
            score: 95
        }, {
            name: '马云',
            subject: '商业运营',
            score: 95
        }, {
            name: '刘强东',
            subject: '商业运营',
            score: 90
        }];
        // 2. 在tbody 内创建行: 通过数组长度取得人数,从而得到动态的要创建的行数。
        var tbody = document.querySelector('tbody');
        for (var i = 0; i < datas.length; i++) { // 外层for循环决定行数,即tr
            // 1. 创建 tr行
            var tr = document.createElement('tr');
            tbody.appendChild(tr);
            // 2. 行内创建单元格(跟数据有关的单元格) td;
            // 单元格的数量取决于每个对象里属性的个数,for循环遍历对象 datas[i]
            for (var k in datas[i]) { // 内层for循环决定列td
                // k 得到属性名
                // object[k] 得到属性值
                // 创建单元格 
                var td = document.createElement('td');
                // 把对象的属性值 datas[i][k] 赋给td
                td.innerHTML = datas[i][k];
                tr.appendChild(td);
            }
            // 3. 创建存放“删除”a标签的单元格 
            var td = document.createElement('td');
            td.innerHTML = ' 删除 ';
            tr.appendChild(td);

        }
        // 4. 删除 
        var as = document.querySelectorAll('a');
        for (var i = 0; i < as.length; i++) {
            as[i].onclick = function() {
                // 语法:node.removeChild(child) 
                // 单击a标签 删除当前 a 所在的行(a链接的父级的父级)  
                tbody.removeChild(this.parentNode.parentNode)
            }
        }
    </script>
</body>
</html>

5.6 复制(克隆)节点

node.cloneNode()

node.cloneNode() 方法返回调用该方法的节点的一个副本。 也称为克隆节点/拷贝节点

  • 如果括号参数为空或者为 false ,则是浅拷贝(只克隆复制节点本身,不克隆里面的子节点)。
  • 如果括号参数为 true ,则是深度拷贝(会复制节点本身以及里面所有的子节点)。

5.7 动态创建元素的区别

  • document.write()
  • element.innerHTML
  • document.createElement()
方法 特点
document.write() 是直接将内容写入页面的内容流,但是文档流执行完毕,则它会导致页面全部重绘
innerHTML 是将内容写入某个 DOM 节点,不会导致页面全部重绘。
创建多个元素效率更高(数组形式拼接,不要拼接字符串),结构稍微复杂
createElement() 创建多个元素时,比innerHTML数组法的效率稍低一点点,但结构更清晰。

备注:不同浏览器下,innerHTML 效率比 creatElement 要高。

6 DOM操作总结

  • 关于dom操作,我们主要针对于元素的操作。主要有创建、增、删、改、查、属性操作、事件操作;
  • :主要修改dom的元素属性,dom元素的内容、属性, 表单的值等;
  • :主要获取查询dom的元素;
  • 属性操作:主要针对于自定义属性;
序号 创建 属性操作
1 document.write appendChild removeChild 修改元素属性: src、href、title等 DOM提供的API 方法: getElementById、getElementsByTagName (不推荐) setAttribute:设置dom的属性值
2 innerHTML nsertBefore 修改普通元素内容: innerHTML 、innerText H5提供的新方法: querySelector、querySelectorAll 提倡 getAttribute:得到dom的属性值
3 createElement 修改表单元素: value、type、disabled等 利用节点操作获取元素: 父(parentNode)、子(children)、兄(previousElementSibling、nextElementSibling) 提倡 removeAttribute移除属性
4 修改元素样式: style、className
  • 事件操作:给元素注册事件, 采取 事件源.事件类型 = 事件处理程序
鼠标事件 触发条件
onclick 鼠标单击(左键)
onmouseover 鼠标经过
onmouseout 鼠标离开
onfocus 获得鼠标焦点
onblur 失去鼠标焦点
onmousemove 鼠标移动
onmouseup 鼠标弹起
onmousedown 鼠标按下

END

你可能感兴趣的:(前端)