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

文档:一个页面就是一个文档,DOM 中使用 document 表示
元素:页面中的所有标签都是元素,DOM 中使用 element 表示
节点:网页中的所有内容都是节点(标签、属性、文本、注释等),DOM 中使用 node 表示
DOM 把以上内容都看做是对象
获取元素方法
如何获取页面元素
DOM 在我们实际开发中主要用来操作元素。
我们如何来获取页面中的元素呢?
获取页面中的元素可以使用以下几种方式:
根据 ID 获取
根据标签名获取
通过 HTML5 新增的方法获取
特殊元素获取
根据ID获取
- 使用 getElementById() 方法可以获取带有 ID 的元素对象。
1 | document.getElementById('id'); |
- 使用 console.dir() 可以打印我们获取的元素对象,更好的查看对象里面的属性和方法。
1 | // 1. 因为我们文档页面从上往下加载,所以先得有标签 所以我们script写到标签的下面 |
根据标签名获取
- 使用 getElementsByTagName() 方法可以返回带有指定标签名的对象的集合。
1 | document.getElementsByTagName('标签名'); |
1 | <body> |
- 注意:
- 因为得到的是一个对象的集合,所以我们想要操作里面的元素就需要遍历。
- 得到元素对象是动态的
H5新增方法
1 | document.getElementsByClassName('类名');// 根据类名返回元素对象集合 |
1 | document.querySelector('选择器'); // 根据指定选择器返回第一个元素对象 |
1 | document.querySelectorAll('选择器'); // 根据指定选择器返回 |
- querySelector 和 querySelectorAll 里面的选择器需要加符号,比如:document.querySelector(‘#nav’);
1 | <body> |
获取body/HTML
1 | //获取body元素 |
1 | //获取html元素 |
1 | // 1.获取body 元素 |
事件操作
事件概述
JavaScript 使我们有能力创建动态页面,而事件是可以被 JavaScript 侦测到的行为。
简单理解: 触发— 响应机制。
网页中的每个元素都可以产生某些可以触发 JavaScript 的事件,例如,我们可以在用户点击某按钮时产生一个事件,然后去执行某些操作。
事件三要素
- 事件源 (谁)
- 事件类型 (什么事件)
- 事件处理程序 (做啥)
案例-弹出警示框

- 案例分析:
- 01 获取事件源(按钮)
- 02 注册事件(绑定事件),使用 onclick
- 03 编写事件处理程序,写一个函数弹出 alert 警示框
1 | <body> |
执行事件的步骤
- 01 获取事件源
- 02 注册事件(绑定事件)
- 03 添加事件处理程序(采取函数赋值形式)
1 | <body> |
常见的鼠标事件

- mouseenter 和 mouseover 的区别:
- 当鼠标移动到元素上时就会触发 mouseenter 事件
- 类似 mouseover,它们两者之间的差别是
- mouseover 鼠标经过自身盒子会触发,经过子盒子还会触发。
- mouseenter 只会经过自身盒子触发
- 之所以这样,就是因为 mouseenter 不会冒泡
- 跟 mouseenter 搭配 鼠标离开 mouseleave 同样不会冒泡
- mouseover 和 mouseout 会触发事件冒泡
添加事件监听
01 传统注册方式: 同一个元素,同一个事件,只能设置一个处理函数,最后注册的处理函数将会覆盖前面注册的处理函数
02 addEventListener 方法监听注册方式:
- 同一个元素,同一个事件,可以注册多个监听,按注册顺序依次执行,w3c 标准推荐方式
- 该方法接收三个参数:
- type:事件类型字符串,比如 click 、mouseover ,注意这里不要带 on
- listener:事件处理函数,事件发生时,会调用该监听函数
- useCapture:可选参数,是一个布尔值,默认是 false
03 attachEvent() 方法:
- 将指定的监听器注册到 eventTarget(目标对象) 上,当该对象触发指定的事件时,指定的回调函数就会被执行。
- 该方法接收两个参数:
- eventNameWithOn:事件类型字符串,比如 onclick 、onmouseover ,这里要带 on
- callback: 事件处理函数,当目标触发事件时回调函数被调用
- 注意:IE8 及早期版本支持
1 | <body> |
1 | // 2. 事件侦听注册事件 addEventListener |
1 | // 3. attachEvent ie9以前的版本支持 |
- 注册事件兼容性解决方案
- 兼容性处理的原则: 首先照顾大多数浏览器,再处理特殊浏览器
1 | function addEventListener(element, eventName, fn) { |
移除事件监听
1 | <body> |
1 | // 2. removeEventListener 删除事件 |
1 | // 3. detachEvent |
- 删除事件兼容性解决方案:
1 | function removeEventListener(element, eventName, fn) { |
冒泡与捕获
- 事件流描述的是从页面中接收事件的顺序。
- 事件发生时会在元素节点之间按照特定的顺序传播,这个传播过程即 DOM 事件流。
- 比如我们给一个 div 注册了点击事件:
- DOM 事件流分为3个阶段:
- 捕获阶段
- 当前目标阶段
- 冒泡阶段

- 事件冒泡:IE 最早提出,事件开始时由最具体的元素接收,然后逐级向上传播到到 DOM 最顶层节点的过程。
- 我们向水里面扔一块石头,首先它会有一个下降的过程,这个过程就可以理解为从最顶层向事件发生的最具体元素(目标点)的捕获过程;之后会产生泡泡,会在最低点( 最具体元素)之后漂浮到水面上,这个过程相当于事件冒泡。

- 事件捕获: 网景最早提出,由 DOM 最顶层节点开始,然后逐级向下传播到到最具体的元素接收的过程。
- 注意
- JS 代码中只能执行捕获或者冒泡其中的一个阶段。
- onclick 和 attachEvent 只能得到冒泡阶段。
- addEventListener(type, listener[, useCapture])第三个参数如果是 true,表示在事件捕获阶段调用事件处理程序;如果是 false(不写默认就是false),表示在事件冒泡阶段调用事件处理程序。
- 实际开发中我们很少使用事件捕获,我们更关注事件冒泡。
- 有些事件是没有冒泡的,比如 onblur、onfocus、onmouseenter、onmouseleave
- 事件冒泡有时候会带来麻烦,有时候又会帮助很巧妙的做某些事件,我们后面讲解。
1 | <body> |
事件对象
- 官方解释:event 对象代表事件的状态,比如键盘按键的状态、鼠标的位置、鼠标按钮的状态。
- 简单理解:事件发生后,跟事件相关的一系列信息数据的集合都放到这个对象里面,这个对象就是事件对象 event,它有很多属性和方法。
- 比如:
- 谁绑定了这个事件。
- 鼠标触发事件的话,会得到鼠标的相关信息,如鼠标位置。
- 键盘触发事件的话,会得到键盘的相关信息,如按了哪个键。
- 事件对象的使用语法:
- 这个 event 是个形参,系统帮我们设定为事件对象,不需要传递实参过去。
- 当我们注册事件时, event 对象就会被系统自动创建,并依次传递给事件监听器(事件处理函数)。
1 | eventTarget.onclick = function(event) { |
1 | <body> |
1 | <body> |

阻止默认行为
1 | <body> |
阻止事件冒泡
- 事件冒泡:开始时由最具体的元素接收,然后逐级向上传播到到 DOM 最顶层节点。
- 事件冒泡本身的特性,会带来的坏处,也会带来的好处,需要我们灵活掌握。
- 标准写法:利用事件对象里面的 stopPropagation()方法
- e.stopPropagation()
- 非标准写法:IE 6-8 利用事件对象 cancelBubble 属性
- e.cancelBubble = true;
1 | <body> |
- 阻止事件冒泡的兼容性解决方案
1 | if(e && e.stopPropagation){ |
事件委托
- 事件委托
- 事件委托也称为事件代理, 在 jQuery 里面称为事件委派。
1 | <ul> |
- 事件委托的原理
- 不是每个子节点单独设置事件监听器,而是事件监听器设置在其父节点上,然后利用冒泡原理影响设置每个子节点。
- 以上案例:给 ul 注册点击事件,然后利用事件对象的 target 来找到当前点击的 li,因为点击 li,事件会冒泡到 ul 上,ul 有注册事件,就会触发事件监听器。
- 事件委托的作用
- 我们只操作了一次 DOM ,提高了程序的性能。
1 | <body> |
鼠标事件
- 常用的鼠标事件

1 | <body> |
1 | <body> |
- 鼠标事件对象
- event 对象代表事件的状态,跟事件相关的一系列信息的集合

1 | <body> |
案例_图片跟随鼠标移动
1 | <body> |
键盘事件
- 常用键盘事件

- 注意:
- 如果使用 addEventListener 不需要加 on
- onkeypress 和前面 2 个的区别是,它不识别功能键,比如左右箭头,shift 等。
- 三个事件的执行顺序是: keydown – keypress — keyup
1 | <body> |
键盘事件对象

- 注意: onkeydown 和 onkeyup 不区分字母大小写,onkeypress 区分字母大小写。
- 在我们实际开发中,我们更多的使用 keydown 和 keyup, 它能识别所有的键(包括功能键)
- keypress 不识别功能键,但是 keyCode 属性能区分大小写,返回不同的 ASCII 值
1 | <body> |
案例_按下S键输入框获得焦点
当我们按下 s 键, 光标就定位到搜索框
案例分析:
- ① 核心思路: 检测用户是否按下了 s 键,如果按下 s 键,就把光标定位到搜索框里面
- ② 使用键盘事件对象里面的 keyCode 判断用户按下的是否是 s 键
- ③ 搜索框获得焦点: 使用 js 里面的 focus() 方法
1 | <body> |
案例_模拟京东快递单号查询
要求:当我们在文本框中输入内容时,文本框上面自动显示大字号的内容。
案例分析:
- ① 快递单号输入内容时, 上面的大号字体盒子(con)显示(这里面的文字
- ② 同时把快递单号里面的值(value)获取过来赋值给 con 盒子(innerText)做为内容
- ③ 如果快递单号里面内容为空,则隐藏大号字体盒子(con)盒子
- ④ 注意: keydown 和 keypress 在文本框里面的特点: 他们两个事件触发的时候,文字还没有落入文本框中。
- ⑤ keyup 事件触发的时候, 文字已经落入文本框里面了
- ⑥ 当我们失去焦点,就隐藏这个 con 盒子
- ⑦ 当我们获得焦点,并且文本框内容不为空,就显示这个 con 盒子
1 | <body> |
元素操作
- JavaScript 的 DOM 操作可以改变网页内容、结构和样式,我们可以利用 DOM 操作元素来改变元素里面的内容 、属性等。
改变元素内容
- 从起始位置到终止位置的内容, 但它去除 html 标签(不解析HTML标签), 同时空格和换行也会去掉
1 | element.innerText |
- 起始位置到终止位置的全部内容,包括 html 标签(解析HTML标签),同时保留空格和换行
1 | element.innerHTML |
- innerText 和 innerHTML 的区别:
1 | <body> |
- 案例:
1 | <body> |
常见元素的属性操作
- innerText、innerHTML 改变元素内容
- src、href
- id、alt、title
1 | <body> |
案例-根据时间显示问候语
根据不同时间,页面显示不同图片,同时显示不同的问候语。
如果上午时间打开页面,显示上午好,显示上午的图片。
如果下午时间打开页面,显示下午好,显示下午的图片。
如果晚上时间打开页面,显示晚上好,显示晚上的图片。
案例分析:
- ① 根据系统不同时间来判断,所以需要用到日期内置对象
② 利用多分支语句来设置不同的图片
③ 需要一个图片,并且根据时间修改图片,就需要用到操作元素 src 属性
④ 需要一个 div 元素,显示不同问候语,修改元素内容即可
1 | <body> |
表单元素属性的操作
利用 DOM 可以操作如下表单元素的属性:
- type、value、checked、selected、disabled
1 | <body> |
案例-显示隐藏密码
- 点击按钮将密码框切换为文本框,并可以查看密码明文。

案例分析:
- ① 核心思路: 点击眼睛按钮,把密码框类型改为文本框就可以看见里面的密码
② 一个按钮两个状态,点击一次,切换为文本框,继续点击一次切换为密码框
- ③ 算法:利用一个 flag 变量,来判断 flag 的值,如果是 1 就切换为文本框,flag 设置为 0,如果是 0 就切换为密码框,flag 设置为 1
1 | <head> |
样式属性操作
- 我们可以通过 JS 修改元素的大小、颜色、位置等样式。
1 | //1. element.style 行内样式操作 |
1 | <head> |
1 | <body> |
01 JS 里面的样式采取驼峰命名法 比如 fontSize、 backgroundColor
02 JS 修改 style 样式操作,产生的是行内样式,CSS 权重比较高
03 如果样式修改较多,可以采取操作类名方式更改元素样式。
04 class 因为是个保留字,因此使用 className 来操作元素类名属性
05 className 会直接更改元素的类名,会覆盖原先的类名。
案例-点击关闭二维码
- 当鼠标点击二维码关闭按钮的时候,则关闭整个二维码。

- 案例分析:
- 01 核心思路: 利用样式的显示和隐藏完成, display:none 隐藏元素 display:block 显示元素
- 02 点击按钮,就让这个二维码盒子隐藏起来即可
1 | <body> |
案例-循环精灵图
- 可以利用 for 循环设置一组元素的精灵图背景

- 案例分析:
- 01 首先精灵图图片排列有规律的
- 02 核心思路: 利用 for 循环 修改精灵图片的背景位置 background-position
- 03 剩下的就是考验你的数学功底了
- 04 让循环里面的 i 索引号 * 44 就是每个图片的y坐标
1 | var lis = document.querySelectorAll('li'); |
案例-显示隐藏文本框内容
- 当鼠标点击文本框时,里面的默认文字隐藏,当鼠标离开文本框时,里面的文字显示。

- 案例分析:
- ① 首先表单需要 2 个新事件,获得焦点 onfocus 失去焦点 onblur
- ② 如果获得焦点, 判断表单里面内容是否为默认文字,如果是默认文字,就清空表单内容
- ③ 如果失去焦点, 判断表单内容是否为空,如果为空,则表单内容改为默认文字
1 | <body> |
案例-密码框格式错误提示
- 用户如果离开密码框,里面输入个数不是6~16,则提示错误信息,否则提示输入正确信息

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

其他案例
- 世纪佳缘 用户名 显示隐藏内容
- 京东关闭广告(直接隐藏即可)
- 新浪下拉菜单(微博即可)
- 开关灯案例(见素材)
1 | <body> |
排它思想

- 如果有同一组元素,我们想要某一个元素实现某种样式,需要用到循环的排他思想算法:
- 所有元素全部清除样式(干掉其他人)
- 给当前元素设置样式 (留下我自己)
- 注意顺序不能颠倒,首先干掉其他人,再设置自己
1 | <body> |
案例-百度换背景
- 案例分析:
- ① 这个案例练习的是给一组元素注册事件
- ② 给 4 个小图片利用循环注册点击事件
- ③ 当我们点击了这个图片,让我们页面背景改为当前的图片
- ④ 核心算法: 把当前图片的 src 路径取过来,给 body 做为背景即可
1 | <body> |
案例-表格隔行变色

- 案例分析:
- 用到新的鼠标事件,鼠标经过 onmouseover 鼠标离开 onmouseout
- 核心思路:鼠标经过 tr 行,当前的行变背景颜色, 鼠标离开去掉当前的背景颜色
- 注意: 第一行(thead里面的行)不需要变换颜色,因此我们获取的是 tbody 里面的行
1 | <script> |
案例:全选/取消全选

业务需求:
- 点击上面全选复选框,下面所有的复选框都选中(全选)
- 再次点击全选复选框,下面所有的复选框都不中选(取消全选)
- 如果下面复选框全部选中,上面全选按钮就自动选中
- 如果下面复选框有一个没有选中,上面全选按钮就不选中
- 所有复选框一开始默认都没选中状态
案例分析:
- ① 全选和取消全选做法: 让下面所有复选框的 checked 属性(选中状态) 跟随全选按钮即可
- ② 下面复选框需要全部选中, 上面全选才能选中做法: 给下面所有复选框绑定点击事件,每次点击,都要循环查看下面所有的复选框是否有没选中的,如果有一个没选中的, 上面全选就不选中。
- ③ 可以设置一个变量,来控制全选是否选中
1 | <script> |
属性操作
获取属性值
- element.属性 获取属性值。
- element.getAttribute(‘属性’);
1 | var div = document.querySelector('div'); |
- 区别:
- element.属性 获取内置属性值(元素本身自带的属性)
- element.getAttribute(‘属性’); 主要获得自定义的属性 (标准) 我们程序员自定义的属性
设置属性值
element.属性 = ‘值’ , 设置内置属性值。
element.setAttribute(‘属性’, ‘值’);
1 | // 2. 设置元素属性值 |
- 区别:
element.属性 设置内置属性值
element.setAttribute(‘属性’); 主要设置自定义的属性 (标准)
移除属性
- element.removeAttribute(‘属性’);
1 | // 3 移除属性 removeAttribute(属性) |
案例-tab栏切换
- 当鼠标点击上面相应的选项卡(tab),下面内容跟随变化

- 案例分析:
- ① Tab 栏切换有 2 个大的模块
- ② 上的模块选项卡,点击某一个,当前这一个底色会是红色,其余不变(排他思想) 修改类名的方式
- ③ 下面的模块内容,会跟随上面的选项卡变化。所以下面模块变化写到点击事件里面。
- ④ 规律:下面的模块显示内容和上面的选项卡一一对应,相匹配。
- ⑤ 核心思路: 给上面的 tab_list 里面的所有小 li 添加自定义属性,属性值从 0 开始编号。
- ⑥ 当我们点击 tab_list 里面的某个小 li,让 tab_con 里面对应序号的 内容显示,其余隐藏(排他思想)
1 |
|
设置H5自定义属性
自定义属性目的:是为了保存并使用数据。有些数据可以保存到页面中而不用保存到数据库中。
自定义属性获取是通过 getAttribute(‘属性’) 获取。
但是有些自定义属性很容易引起歧义,不容易判断是元素的内置属性还是自定义属性。
H5 给我们新增了自定义属性:
H5 规定自定义属性 data- 开头做为属性名并且赋值。
比如
<div data-index="1"></div>或者使用 JS 设置element.setAttribute(‘data-index’, 2)
获取H5自定义属性
- 兼容性获取 element.getAttribute(‘data-index’);
- H5 新增 element.dataset.index 或者 element.dataset[‘index’] , ie 11才开始支持
1 | <body> |
classList
1 | <body> |
节点操作
为什么学节点操作
- 获取元素通常使用两种方式:

- 这两种方式都可以获取元素节点,我们后面都会使用,但是节点操作更简单
节点概述
网页中的所有内容都是节点(标签、属性、文本、注释等),在 DOM 中,节点使用 node 来表示。
HTML DOM 树中的所有节点均可通过 JavaScript 进行访问,所有 HTML 元素(节点)均可被修改,也可以创建或删除。

一般地,节点至少拥有 nodeType(节点类型)、nodeName(节点名称)和 nodeValue(节点值)这三个基本属性。
元素节点 nodeType 为 1
属性节点 nodeType 为 2
文本节点 nodeType 为 3 (文本节点包含文字、空格、换行等)
我们在实际开发中,节点操作主要操作的是元素节点
节点层级
- 利用 DOM 树可以把节点划分为不同的层级关系,常见的是父子兄层级关系。
父级节点
1 | node.parentNode |
1 | <div class="demo"> |
- parentNode 属性可返回某节点的父节点,注意是最近的一个父节点
- 如果指定的节点没有父节点则返回 null
子节点
- 01 parentNode.childNodes(标准)
1 | <body> |
parentNode.childNodes 返回包含指定节点的子节点的集合,该集合为即时更新的集合。是一个数组,里面包含了各种类型的子节点
注意:返回值里面包含了所有的子节点,包括元素节点,文本节点等。
如果只想要获得里面的元素节点,则需要专门处理。 所以我们一般不提倡使用 childNodes
1 | var ul = document. querySelector(‘ul’); |
02 parentNode.children(非标准)
parentNode.children 是一个只读属性,返回所有的子元素节点。它只返回子元素节点,其余节点不返回 (这个是我们重点掌握的)。
虽然 children 是一个非标准,但是得到了各个浏览器的支持,因此我们可以放心使用
1 | // 2. children 获取所有的子元素节点 也是我们实际开发常用的 |
03 parentNode.firstChild
- firstChild 返回第一个子节点,找不到则返回 null。同样,也是包含所有的节点。
04 parentNode.lastChild
- lastChild 返回最后一个子节点,找不到则返回 null。同样,也是包含所有的节点。
05 parentNode.firstElementChild
- firstElementChild 返回第一个子元素节点,找不到则返回 null。
06 parentNode.lastElementChild
- lastElementChild 返回最后一个子元素节点,找不到则返回 null。
注意:这两个方法有兼容性问题,IE9 以上才支持。
实际开发中,firstChild 和 lastChild 包含其他节点,操作不方便,而 firstElementChild 和 lastElementChild 又有兼容性问题,那么我们如何获取第一个子元素节点或最后一个子元素节点呢?
-
解决方案:- 如果想要第一个子元素节点,可以使用 parentNode.chilren[0]
- 如果想要最后一个子元素节点,可以使用 parentNode.chilren[parentNode.chilren.length - 1]
1 | <body> |
案例-下拉菜单

- 案例分析:
- ① 导航栏里面的 li 都要有鼠标经过效果,所以需要循环注册鼠标事件
- ② 核心原理: 当鼠标经过 li 里面的 第二个孩子 ul 显示, 当鼠标离开,则 ul 隐藏
1 | <script> |
兄弟节点
01 node.nextSibling
- nextSibling 返回当前元素的下一个兄弟节点,找不到则返回 null。同样,也是包含所有的节点。
02 node.previousSibling
- previousSibling 返回当前元素上一个兄弟节点,找不到则返回 null。同样,也是包含所有的节点。
03 node.nextElementSibling
- nextElementSibling 返回当前元素下一个兄弟元素节点,找不到则返回 null。
04 node.previousElementSibling
- previousElementSibling 返回当前元素上一个兄弟元素节点,找不到则返回 null。
1 | <body> |
- 注意:这两个方法有兼容性问题, IE9 以上才支持。
1 | //解决兼容性 |
创建节点
1 | document.createElement('tagName') |
- document.createElement() 方法创建由 tagName 指定的 HTML 元素。因为这些元素原先不存在,是根据我们的需求动态生成的,所以我们也称为动态创建元素节点。
添加节点
01 node.appendChild(child)
- node.appendChild() 方法将一个节点添加到指定父节点的子节点列表末尾。类似于 CSS 里面的 after 伪元素。
02 node.insertBefore(child, 指定元素)
- node.insertBefore() 方法将一个节点添加到父节点的指定子节点前面。类似于 CSS 里面的 before伪元素。
1 | <body> |
案例-简单版留言版
- 案例分析:
- ① 核心思路: 点击按钮之后,就动态创建一个 li,添加到ul 里面。
- ② 创建 li 的同时,把文本域里面的值通过 li.innerHTML 赋值给 li
- ③ 如果想要新的留言后面显示就用 appendChild 如果想要前面显示就用 insertBefore
1 |
|
删除节点
- node.removeChild() 方法从 DOM 中删除一个子节点,返回删除的节点。
1 | <body> |
案例-删除留言
① 当我们把文本域里面的值赋值给 li 的时候,多添加一个删除的链接
② 需要把所有的链接获取过来,当我们点击当前的链接的时候,删除当前链接所在的 li
③ 阻止链接跳转需要添加 javascript:void(0); 或者 javascript:;
1 |
|
克隆节点
node.cloneNode() 方法返回调用该方法的节点的一个副本。 也称为克隆节点/拷贝节点
注意:
- 如果括号参数为空或者为 false ,则是浅拷贝,即只克隆复制节点本身,不克隆里面的子节点。
- 如果括号参数为 true ,则是深度拷贝,会复制节点本身以及里面所有的子节点。
1 | <body> |
案例-动态生成表格

- 案例分析:
- ① 因为里面的学生数据都是动态的,我们需要 js 动态生成。 这里我们模拟数据,自己定义好数据。 数据我们采取对象形式存储。
- ② 所有的数据都是放到 tbody 里面的行里面。
- ③ 因为行很多,我们需要循环创建多个行(对应多少人)
- ④ 每个行里面又有很多单元格(对应里面的数据),我们还继续使用循环创建多个单元格,并且把数据存入里面(双重for循环)
- ⑤ 最后一列单元格是删除,需要单独创建单元格。
- ⑥ 最后添加删除操作,单击删除,可以删除当前行。
1 |
|
三种动态创建元素的区别
1 | // document.write() |
区别:
- document.write 是直接将内容写入页面的内容流,但是文档流执行完毕,则它会导致页面全部重绘
- innerHTML 是将内容写入某个 DOM 节点,不会导致页面全部重绘
- innerHTML 创建多个元素效率更高(不要拼接字符串,采取数组形式拼接),结构稍微复杂
- createElement() 创建多个元素效率稍低一点点,但是结构更清晰
总结:不同浏览器下,innerHTML 效率要比 creatElement 高
1 | // 三种创建元素方式区别 |
DOM 重点核心总结
文档对象模型(Document Object Model,简称 DOM),是 W3C 组织推荐的处理可扩展标记语言( HTML 或者 XML )的标准编程接口。
我们获取过来的 DOM 元素是一个对象(object),所以称为文档对象模型
W3C 已经定义了一系列的 DOM 接口,通过这些 DOM 接口可以改变网页的内容、结构和样式。
- 对于 JavaScript,为了能够使 JavaScript 操作 HTML,JavaScript 就有了一套自己的 dom 编程接口。
- 对于 HTML,dom 使得 html 形成一棵 dom 树. 包含 文档、元素、节点

- 关于 dom 操作,我们主要针对于元素的操作。主要有创建、增、删、改、查、属性操作、事件操作。
创建
- document.write
- innerHTML
- createElement
增加
- appendChild
- insertBefore
删除
- removeChild
修改
- 主要修改 dom 的元素属性,dom 元素的内容、属性, 表单的值等
- 修改元素属性: src、href、title等
- 修改普通元素内容: innerHTML 、innerText
- 修改表单元素: value、type、disabled等
- 修改元素样式: style、className
查询
- DOM 提供的 API 方法: getElementById、getElementsByTagName 古老用法 不太推荐
- H5提供的新方法: querySelector、querySelectorAll 提倡
- 利用节点操作获取元素: 父(parentNode)、子(children)、兄(previousElementSibling、nextElementSibling) 提倡
属性操作
- setAttribute:设置dom的属性值
- getAttribute:得到dom的属性值
- removeAttribute移除属性
事件操作
- 给元素注册事件, 采取 事件源.事件类型 = 事件处理程序

PC端网页特效
元素偏移量 offset
- offset 翻译过来就是偏移量, 我们使用 offset 系列相关属性可以动态的得到该元素的位置(偏移)、大小等。
- 获得元素距离带有定位父元素的位置
- 获得元素自身的大小(宽度高度)
- 注意: 返回的数值都不带单位

- offset 系列常用属性:

1 | <body> |
offset 与 style 区别
offset
- offset 可以得到任意样式表中的样式值
- offset 系列获得的数值是没有单位的
- offsetWidth 包含 padding+border+width
- offsetWidth 等属性是只读属性,只能获取,不能赋值
- 所以,我们想要获取元素大小位置,用 offset 更合适
style
- style 只能得到行内样式表中的样式值
- style.width 获得的是带有单位的字符串
- style.width 获得不包含 padding 和 border 的值
- style.width 是可读写属性,可以获取也可以赋值
- 所以,我们想要给元素更改值,则需要用 style 改变
案例-鼠标在盒子内的坐标
- ① 我们在盒子内点击,想要得到鼠标距离盒子左右的距离。
- ② 首先得到鼠标在页面中的坐标(e.pageX, e.pageY)
- ③ 其次得到盒子在页面中的距离 ( box.offsetLeft, box.offsetTop)
- ④ 用鼠标距离页面的坐标减去盒子在页面中的距离,得到 鼠标在盒子内的坐标
- ⑤ 如果想要移动一下鼠标,就要获取最新的坐标,使用鼠标移动事件 mousemove
1 | <head> |
案例-模态框拖拽
弹出框,我们也称为模态框。
- 01 点击弹出层, 会弹出模态框, 并且显示灰色半透明的遮挡层。
- 02 点击关闭按钮,可以关闭模态框,并且同时关闭灰色半透明遮挡层。
- 03 鼠标放到模态框最上面一行,可以按住鼠标拖拽模态框在页面中移动。
- 04 鼠标松开,可以停止拖动模态框移动。
案例分析:
- ① 点击弹出层, 模态框和遮挡层就会显示出来 display:block;
- ② 点击关闭按钮,模态框和遮挡层就会隐藏起来 display:none;
- ③ 在页面中拖拽的原理: 鼠标按下并且移动, 之后松开鼠标
- ④ 触发事件是鼠标按下 mousedown, 鼠标移动mousemove 鼠标松开 mouseup
- ⑤ 拖拽过程: 鼠标移动过程中,获得最新的值赋值给模态框的left和top值, 这样模态框可以跟着鼠标走了
- ⑥ 鼠标按下触发的事件源是 最上面一行,就是 id 为 title
- ⑦ 鼠标的坐标 减去 鼠标在盒子内的坐标, 才是模态框真正的位置。
- ⑧ 鼠标按下,我们要得到鼠标在盒子的坐标。
- ⑨ 鼠标移动,就让模态框的坐标 设置为 : 鼠标坐标 减去盒子坐标即可,注意移动事件写到按下事件里面。
- ⑩ 鼠标松开,就停止拖拽,就是可以让鼠标移动事件解除
1 |
|
案例-仿京东放大镜
1 |
元素可视区 client
- client 翻译过来就是客户端,我们使用 client 系列的相关属性来获取元素可视区的相关信息。通过 client 系列的相关属性可以动态的得到该元素的边框大小、元素大小等。


1 | // client 宽度 和我们 offsetWidth 最大的区别就是 不包含边框 |
案例- flexible.js 源码分析
1 | //... |
元素滚动 scroll
- scroll 翻译过来就是滚动的,我们使用 scroll 系列的相关属性可以动态的得到该元素的大小、滚动距离等。


- 如果浏览器的高(或宽)度不足以显示整个页面时,会自动出现滚动条。当滚动条向下滚动时,页面上面被隐藏掉的高度,我们就称为页面被卷去的头部。滚动条在滚动时会触发 onscroll 事件。
- 页面被卷去的头部兼容性解决方案:
1 | /* |
1 | <script> |
案例-仿淘宝固定右侧侧边栏
- ① 需要用到页面滚动事件 scroll 因为是页面滚动,所以事件源是 document
- ② 滚动到某个位置,就是判断页面被卷去的上部值。
- ③ 页面被卷去的头部:可以通过window.pageYOffset 获得 如果是被卷去的左侧 window.pageXOffset
- ④ 注意,元素被卷去的头部是 element.scrollTop , 如果是页面被卷去的头部 则是 window.pageYOffset
- ⑤ 其实这个值 可以通过盒子的 offsetTop 可以得到,如果大于等于这个值,就可以让盒子固定定位了
1 |
|
三大系列总结


- 他们主要用法:
- offset系列 经常用于获得元素位置 offsetLeft offsetTop
- client 经常用于获取元素大小 clientWidth clientHeight
- scroll 经常用于获取滚动距离 scrollTop scrollLeft
- 注意页面滚动的距离通过 window.pageXOffset 获得
常见网页特效案例
网页轮播图
- 轮播图也称为焦点图,是网页中比较常见的网页特效。
- 功能需求:
- 鼠标经过轮播图模块,左右按钮显示,离开隐藏左右按钮。
- 点击右侧按钮一次,图片往左播放一张,以此类推, 左侧按钮同理。
- 图片播放的同时,下面小圆圈模块跟随一起变化。
- 点击小圆圈,可以播放相应图片。
- 鼠标不经过轮播图, 轮播图也会自动播放图片。
- 鼠标经过,轮播图模块, 自动播放停止。
1 |
返回顶部
- 案例分析
- ① 带有动画的返回顶部
- ② 此时可以继续使用我们封装的动画函数
- ③ 只需要把所有的left 相关的值 改为 跟 页面垂直滚动距离相关就可以了
- ④ 页面滚动了多少,可以通过 window.pageYOffset 得到
- ⑤ 最后是页面滚动,使用 window.scroll(x,y)
1 |
筋头云案例
- 案例分析:
- ① 利用动画函数做动画效果
- ② 原先筋斗云的起始位置是0
- ③ 鼠标经过某个小li, 把当前小li 的 offsetLeft 位置 做为目标值即可
- ④ 鼠标离开某个小li, 就把目标值设为 0
- ⑤ 如果点击了某个小li, 就把li当前的位置存储起来,做为筋斗云的起始位置
1 |
移动端网页特效
触屏事件概述
- 移动端浏览器兼容性较好,我们不需要考虑以前 JS 的兼容性问题,可以放心的使用原生 JS 书写效果,但是移动端也有自己独特的地方。比如触屏事件 touch(也称触摸事件),Android 和 IOS 都有。
- touch 对象代表一个触摸点。触摸点可能是一根手指,也可能是一根触摸笔。触屏事件可响应用户手指(或触控笔)对屏幕或者触控板操作。
- 常见的触屏事件如下:

1 | <body> |
触摸事件对象
TouchEvent 是一类描述手指在触摸平面(触摸屏、触摸板等)的状态变化的事件。这类事件用于描述一个或多个触点,使开发者可以检测触点的移动,触点的增加和减少,等等
touchstart、touchmove、touchend 三个事件都会各自有事件对象。
触摸事件对象重点我们看三个常见对象列表:

1 | <body> |
移动端拖动元素
- 01 touchstart、touchmove、touchend 可以实现拖动元素
- 02 但是拖动元素需要当前手指的坐标值 我们可以使用 targetTouches[0] 里面的pageX 和 pageY
- 03 移动端拖动的原理: 手指移动中,计算出手指移动的距离。然后用盒子原来的位置 + 手指移动的距离
- 04 手指移动的距离: 手指滑动中的位置 减去 手指刚开始触摸的位置
- 拖动元素三步曲:
- 01 触摸元素 touchstart: 获取手指初始坐标,同时获得盒子原来的位置
- 02 移动手指 touchmove: 计算手指的滑动距离,并且移动盒子
- 03 离开手指 touchend:
- 注意:手指移动也会触发滚动屏幕所以这里要阻止默认的屏幕滚动 e.preventDefault();
1 | <body> |
移动端常见特效
移动端轮播图
click 延时解决方案
移动端 click 事件会有 300ms 的延时,原因是移动端屏幕双击会缩放(double tap to zoom) 页面。
01 禁用缩放。 浏览器禁用默认的双击缩放行为并且去掉 300ms 的点击延迟。
1 | <meta name="viewport" content="user-scalable=no"> |
- 02 利用 touch 事件自己封装这个事件解决 300ms 延迟。
- 原理就是:
- 当我们手指触摸屏幕,记录当前触摸时间
- 当我们手指离开屏幕, 用离开的时间减去触摸的时间
- 如果时间小于150ms,并且没有滑动过屏幕, 那么我们就定义为点击
- 原理就是:
1 | //封装tap,解决click 300ms 延时 |
- 03 使用插件。 fastclick 插件解决 300ms 延迟。
移动端常用开发插件
- 什么是插件:
- 移动端要求的是快速开发,所以我们经常会借助于一些插件来帮我完成操作,那么什么是插件呢?
- JS 插件是 js 文件,它遵循一定规范编写,方便程序展示效果,拥有特定功能且方便调用。如轮播图和瀑布流插件。
- 特点:它一般是为了解决某个问题而专门存在,其功能单一,并且比较小。
- 我们以前写的animate.js 也算一个最简单的插件
- fastclick 插件解决 300ms 延迟。 使用延时
- GitHub官网地址: https://github.com/ftlabs/fastclick
- 插件的使用
- 略
- 移动端常用插件
- superslide: http://www.superslide2.com/
- iscroll: https://github.com/cubiq/iscroll
- 移动端视频插件 zy.media.js:
- H5 给我们提供了 video 标签,但是浏览器的支持情况不同。
- 不同的视频格式文件,我们可以通过source 解决。
- 但是外观样式,还有暂停,播放,全屏等功能我们只能自己写代码解决。
- 这个时候我们可以使用插件方式来制作。
- fastclick.js的使用
1 | <body> |
移动端常用开发框架
- 框架,顾名思义就是一套架构,它会基于自身的特点向用户提供一套较为完整的解决方案。框架的控制权在框架本身,使用者要按照框架所规定的某种规范进行开发。
- 前端常用的框架有 Bootstrap、Vue、Angular、React 等。既能开发PC端,也能开发移动端
- 前端常用的移动端插件有 swiper、superslide、iscroll等。
- 插件一般是为了解决某个问题而专门存在,其功能单一,并且比较小。
- 框架: 大而全,一整套解决方案
- 插件: 小而专一,某个功能的解决方案
- 感谢你赐予我前进的力量
