1、介绍
1.1 什么是 DOM?
DOM 是 W3C(万维网联盟)的标准。
DOM 定义了访问 HTML 和 XML 文档的标准:
“W3C 文档对象模型 (DOM) 是中立于平台和语言的接口,它允许程序和脚本动态地访问和更新文档的内容、结构和样式。”
W3C DOM 标准被分为 3 个不同的部分:
- 核心 DOM - 针对任何结构化文档的标准模型
- XML DOM - 针对 XML 文档的标准模型
- HTML DOM - 针对 HTML 文档的标准模型
编者注:DOM 是 Document Object Model(文档对象模型)的缩写。
1.2 什么是 HTML DOM?
HTML DOM 是:
HTML 的标准对象模型
HTML 的标准编程接口
W3C 标准
HTML DOM 定义了所有 HTML 元素的对象和属性,以及访问它们的方法。换言之,HTML DOM 是关于如何获取、修改、添加或删除
2、DOM的顶级对象是 document
2.1 Document 对象常用的属性和方法
属性 / 方法 | 描述 |
document.getElementById | 返回对拥有指定 id |
document.getElementsByTagName | 返回带有指定标签名的对象集合。 |
document.querySelector | 返回文档中匹配指定的CSS选择器的第一元素 |
document.querySelectorAll | HTML5中引入的新方法,返回文档中匹配的CSS选择器的所有元素节点列表 |
document.body | 获取 body 元素 |
document.documentElement | 获取 html 元素 |
2.2 使用例子
document.getElementById
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="time">2019-9-9</div>
<script>
// 1.因为我们文档页面从上往下加载,所以先得有标签 所以我们的script写在下面
// 2.get 获取 element 元素 by 通过 驼峰命名法
// 3.参数 id是大小写字母敏感的字符串
// 4.返回的是一个元素对象
var timer = document.getElementById('time');
console.log(timer);//输出的是一个对象
console.log(typeof timer);//object
// 5.console.dir(timer); 打印我们返回的元素对象 更好的查看里面的属性和方法
console.dir(timer);
</script>
</body>
</html>
document.getElementsByTagName
<body>
<ul>
<li>知否知否,应是等你好久1</li>
<li>知否知否,应是等你好久2</li>
<li>知否知否,应是等你好久3</li>
<li>知否知否,应是等你好久4</li>
<li>知否知否,应是等你好久5</li>
</ul>
<ol id="ol">
<li>生僻字</li>
<li>生僻字</li>
<li>生僻字</li>
<li>生僻字</li>
<li>生僻字</li>
</ol>
<script>
// 返回的是 获取过来的元素对象的结合 以伪数组的方式存储的
var lis = document.getElementsByTagName('li');
console.log(lis);
console.log(lis[0]);
// 2.我们向要依次打印里面的元素对象我们可以采取遍历的方式
for (var i = 0; i < lis.length; i++) {
console.log(lis[i]);
}
// 3.如果页面只有一个li 返回的还是伪数组的形式
// 4.如果页面中没有这个标签返回的是空的伪数组
// console.log(lis);
// 5.获取父元素指定的标签名
var ol = document.getElementById('ol');
console.log(ol.getElementsByTagName('li'));
</script>
</body>
H5新增获取标签元素的方法 ------ document.querySelector 、document.querySelectorAll
<body>
<div class="box">盒子</div>
<div class="box">盒子</div>
<div id="nav">
<ul>
<li>首页</li>
<li>产品</li>
</ul>
</div>
<script>
// 1.getElementsByClassName 根据类名获取某些元素
var boxs = document.getElementsByClassName('box');
console.log(boxs);
// 2.querySelector 返回指定选择器的第一个元素对象
var firstBox = document.querySelector('.box');
console.log(firstBox);
var nav = document.querySelector('#nav');
console.log(nav);
var li = document.querySelector('li');
console.log(li);
// 3.querySelectorAll() 返回指定选择器的 所有元素对象集合
var allBox = document.querySelectorAll('.box');
console.log(allBox);
var lis = document.querySelectorAll('li');
console.log(lis);
</script>
</body>
获取 body 和 html 元素 ------document.body 、document.documentElement
<body>
<script>
// 1.获取body 元素
var bodyEle = document.body;
console.log(bodyEle);
console.dir(bodyEle);
// 2.获取html 元素
var htmlEle = document.documentElement;
console.log(htmlEle);
</script>
</body>
3、事件
3.1 事件三要素
事件是由三部分组成 事件源 事件类型 事件处理程序 我们也称为事件三要素
- 事件源事件被触发的对象 谁 比如:按钮
- 事件类型 如何触发 什么事件 比如鼠标点击事件(onclick)
- 事件处理程序 通过一个函数赋值的方式 完成
代码示例:
<body>
<button id="btn">唐伯虎</button>
<script>
// 点击按钮,弹出对话框
// 1.事件是由三部分组成 事件源 事件类型 事件处理程序 我们也称为事件三要素
// (1).事件源事件被触发的对象 谁 比如:按钮
var btn = document.getElementById('btn');
// (2).事件类型 如何触发 什么事件 比如鼠标点击事件(onclick)
// (3).事件处理程序 通过一个函数赋值的方式 完成
btn.onclick = function () {
alert('点秋香');
}
</script>
</body>
3.2 执行事件的步骤
步骤:
- 获取事件源
- 绑定事件 ,注册事件事件类型
- 添加事件处理程序
代码示例:
<body>
<div>123</div>
<script>
// 执行事件的步骤
// 点击div 控制台输出 我被选中了
// 1.获取事件源
var div = document.querySelector('div');
// 2.绑定事件 注册事件 事件类型
// div.onclick
// 3.添加事件处理程序
div.onclick = function () {
console.log('我被选中了');
}
</script>
</body>
注意: 给元素绑定事件,处理函数内的 this 指向的是事件函数的调用者,也就是当前标签的对象的引用(比如:给button标签绑定事件,this就指向button标签)
3.3 常见的鼠标事件
事件名称 | 说明 |
onclick | 鼠标点击事件 |
onmouseover | 鼠标经过触发 |
onmouseout | 鼠标离开触发 |
onfocus | 获取鼠标焦点触发 |
onblur | 失去鼠标焦点触发 |
onmousemove | 鼠标移动触发 |
onmouseup | 鼠标弹起触发 |
onmousedown | 鼠标按下触发 |
使用示例:
<body>
<div>123</div>
<script>
var div = document.querySelector('div');
div.onmousedown = function () {
alert('我是你大爷!!!')
}
</script>
</body>
4、修改HTML标签的内容
实现方法:
- .innerTwxt 从起始位置到终点位置的内容,但它除去html标签,同时空格和换行会去掉
- .innerHTML 从起始位置到终点位置的内容,包括html标签,保留空格和换行
代码示例:
<body>
<button>显示当前系统时间</button>
<div>显示系统时间的标签</div>
<p></p>
<script>
// 改变页面元素1. div.innerTwxt 从起始位置到终点位置的内容,但它除去html标签,同时空格和换行会去掉
// 改变页面元素2. div.innerHTML 从起始位置到终点位置的内容,包括html标签,保留空格和换行
// 当我们点击了按钮,div里面的元素发生变化
// 1.获取元素
var btn = document.querySelector('button');//获取按钮标签
var div = document.querySelector('div');//获取div标签
var p = document.querySelector('p')
// 给button按钮绑定点击事件, 利用 .innerHTML 修改标签内容
btn.onclick = function () {
div.innerHTML = '<strong>日期:</strong>' + getDate();
}
// 封装一个时间日期函数
function getDate() {
// 格式化日期 年月日
var date = new Date();
var year = date.getFullYear();//年
var month = date.getMonth() + 1;//月
var dates = date.getDate();//日
var arr = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'];
var day = date.getDay();//周几
return ('今天是:' + year + '年' + ' ' + month + '月' + ' ' + dates + '日' + ' ' + arr[day]);
}
// 利用 .innerText 修改标签内容
p.innerText = getDate();
</script>
</body>
innerText 和 innerHTML 的区别
修改数据的区别
- innerText 不识别 HTML 标签 非标准 会去除空格和换行
- innerHTML 可以识别 HTML 标签 W3C标准
获取数据的区别
- innerText 会去掉html标签
- innerHTML 保留html标签 空格和换行
代码示例:
<body>
<div></div>
<p>我是文字
<span>123</span>
</p>
<script>
var div = document.querySelector('div');
// 1. innerText 不识别 HTML 标签 非标准 会去除空格和换行
// div.innerText = '<strong>今天是</strong>:2021'
//2. innerHTML 可以识别 HTML 标签 W3C标准
div.innerHTML = '<strong>今天是</strong>:2021'
// 这个属性是可读写的 可以获取元素里面的内容
var p = document.querySelector('p')
// innerText 会去掉html标签
console.log(p.innerText) //我是文字123
// innerHTML 保留html标签 空格和换行
console.log(p.innerHTML) //我是文字<span>123</span
</script>
</body>
5、修改HTML标签的属性
5.1 显示内容属性
比如:src 、title、value、disabled
src 、title
<style>
img {
height: 400px;
}
</style>
<body>
<button id="ldh">刘德华</button>
<button id="zxy">张学友</button>
<br>
<img src="img/liudehu.jpg" alt="图片加载失败">
<script>
// 1.获取元素
var ldh = document.getElementById('ldh');
var zxy = document.getElementById('zxy');
var img = document.querySelector('img');
// 2.注册事件 处理程序
ldh.onclick = function () {
img.src = "img/liudehu.jpg";
img.title = '刘德华';
}
zxy.onclick = function () {
img.src = "img/zhangxueyuo.jpg";
img.title = '张学友';
}
</script>
</body>
value、disabled
<body>
<button>按钮</button>
<input type="text" value="输入内容">
<script>
// 1.获取元素
var btn = document.querySelector('button');
var input = document.querySelector('input');
//2.注册事件 处理程序
btn.onclick = function () {
// 表单里的值 文字内容是通过value 来修改的
input.value = '被点击了';
// 如果想要某个表单被禁用 不能再点击 我们想要button这个按钮被禁用
// btn.disabled = true;
this.disabled = true;
// this 指向的是事件函数的调用者,也就是 button 对象的引用
}
</script>
</body>
案列.仿京东显示密码
实现思路:
- 点击眼睛按钮,把密码框类型改成文本框就可以看到里面的密码
- 一个按钮两个状态,点击一次,切换为文本框,继续点击一次切换为密码框
- 算法: 利用一个flag变量,来判断flag的值,如果是1就切换为文本框,flag 设置为0,如果是0就设置成密码框,flag设置为1
代码:
<style>
.box {
position: relative;
width: 400px;
border-bottom: 1px solid #ccc;
margin: 100px auto;
}
.box input {
width: 370px;
border: 0;
/* 取消表单点击轮廓 */
outline: none;
}
.box img {
position: absolute;
top: 2px;
right: 2px;
width: 20px;
}
</style>
<body>
<div class="box">
<label for="">
<img src="img/by.png" alt="眼睛" id="ete">
</label>
<input type="password" name="" id="pwd">
</div>
<script>
// 1.获取元素
var ete = document.getElementById('ete');
var pwd = document.getElementById('pwd');
// 2.注册事件 处理程序
var flag = 0;
ete.onclick = function () {
// this.src = '';
if (flag == 0) {
this.src = 'img/ky.png'
pwd.type = 'text';
flag = 1;
} else {
this.src = 'img/by.png'
pwd.type = 'password';
flag = 0;
}
}
</script>
</body>
style
通过 JS 修改的style 样式操作,产生的是行内样式,css 的权重比较高
代码示例 :
<style>
div {
width: 200px;
height: 200px;
background-color: pink;
}
</style>
<body>
<div></div>
<script>
// 1.获取元素
var div = document.querySelector('div');
// 2.注册事件 处理程序
var flag = 0;
div.onclick = function () {
if (flag == 0) {
this.style.backgroundColor = 'purple';
this.style.width = '200px';
flag = 1;
} else {
// div.style里面的属性 采取驼峰命名法
this.style.backgroundColor = 'pink';
this.style.width = '250px';
flag = 0;
}
// JS 修改的style 样式操作,产生的是行内样式,css 的权重比较高
}
</script>
</body>
5.3 修改标签样式名称 class
如果要修改的样式比较多,就可以用这种方式
代码示例:
<style>
div {
width: 200px;
height: 200px;
background-color: pink;
}
.con {
background-color: purple;
width: 100px;
height: 100px;
margin: 100px auto;
}
.fn {
line-height: 100px;
font-size: 20px;
color: red;
}
</style>
<body>
<div class="fn">文本</div>
<script>
// 1.使用 element.style 获得修改元素样式 如果样式比较多代码太多
var test = document.querySelector('div');
test.onclick = function () {
// this.style.backgroundColor = 'purple';
// 2.使用element.className 获得修改元素样式 点击之后为div添加类名 con 使用于样式比较多
// 使用element.className 会直接更改以前的类名 会覆盖掉以前的 id的不影响
this.className = 'con';
// 如果想保留之前的类名 可以使用多类名选择器
this.className = 'fn con';
}
</script>
</body>
6、排他思想
干掉所有人,留下我自己
代码示例:
<body>
<button>按钮1</button>
<button>按钮2</button>
<button>按钮3</button>
<button>按钮4</button>
<button>按钮5</button>
<script>
// 1.获取所有按钮元素
var btns = document.getElementsByTagName('button');
// btns得到的是伪数组 里面的每一个元素 btns[i]
for (var i = 0; i < btns.length; i++) {
btns[i].onclick = function () {
// console.log('11');
// (1)我们去除所有的背景颜色(干掉其它人)
for (var i = 0; i < btns.length; i++) {
btns[i].style.backgroundColor = '';
}
// (2)然后才让当前的背景颜色为pink(留下我自己)
this.style.backgroundColor = 'pink';
}
}
// 首先:干掉其它人 再到:留下我自己
</script>
</body>
7、自定义属性
介绍:
自己添加的属性就是自定义属性,如:<div id="demo" index="1"></div> 这里的 index 就是自定义属性
7.1 获取自定义属性
<body>
<div id="demo" index="1"></div>
<script>
var div = document.querySelector('div');
// 1.获取元素的属性值
// (1)element.属性
console.log(div.id);
// (2)element.getAttribut('属性') get得到获取 attribut属性
// 自己添加的属性就是自定义属性
console.log(div.getAttribute('id'));
console.log(div.getAttribute('index'));
</script>
</body>
7.2 设置和移除自定义属性
<body>
<div id="demo" index="1"></div>
<script>
var div = document.querySelector('div');
// 1.获取元素的属性值
// (1)element.属性
console.log(div.id);
// (2)element.getAttribut('属性') get得到获取 attribut属性 我们程序员
// 自己添加的属性就是自定义属性
console.log(div.getAttribute('id'));
console.log(div.getAttribute('index')) // 1
// 2.设置元素属性值
// (1)element.属性='值';
div.id = 'test';
// 添加了一个class='navs' 类名 如果原来有的话就会被修改掉
div.className = 'navs';
// (2)element.setAttribute('属性','值');主要针对自定义属性
div.setAttribute('index', 2);
console.log(div.getAttribute('index')) // 2
div.setAttribute('class', 'footer');//class 特殊 这里写的就是class 不是 className
// 3.移除属性 removeAttribute('属性')
div.removeAttribute('index');
</script>
</body>
7.3 H5自定义属性
介绍:
- H5自定义属性:是为了保存并使用数据。有些数据可以保存到页面中,而不是保存到数据库中 。
- 自定义属性获取是通过getAttribute('属性')获取。
- 但是有些自定自定义属性很容易引起歧义,不容易判断是元素的内置属性还是自定义属性
- H5规定自定义属性 data-开头 的作为属性名并且赋值 ,比如:<div data-index="1"></div>或者使用JS设置 element.setAttribute('data-index',2)
- 获取属性H5新增:element.dataset.index 或者 element.dataset['index'] ie 11才支持
代码示例:
<body>
<div data-time="5" data-getTim="20" data-list-name="andy"></div>
<script>
var div = document.querySelector('div');
console.log(div.getAttribute('data-getTime'));
div.setAttribute('data-index', 2);
console.log(div.getAttribute('data-index'));
// H5新增获取自定义属性的方法
console.log(div.dataset.time);
console.log(div.dataset.index);
console.log(div.dataset['time']);
// dataset 是一个集合里面存放了所有以data开头的自定义属性
console.log(div.dataset);
console.log(div.getAttribute('data-list-name'));
// 如果自定义属性里有多个-链接的属性名 要用驼峰写法
console.log(div.dataset.listName);
console.log(div.dataset['listName']);
</script>
</body>
8、节点
8.1 介绍:
- 页面中的所有内容都是节点(标签、属性、文本、注释等),在DOM中,节点使用 node 来表示。
- HTML DOM 树中的所有的节点均可通过 HavanaScript 进行访问,所有的HTML元素(节点)均可被修改,也可以创建或删除
- nodeType (节点类型)、nodeName(节点名称)和nodeValue(节点值)这三个基本属性
8.2 nodeType
- 元素节点 nodeType 为1
- 属性节点 nodeType 为2
- 文本节点 nodeType 为3(文本节点包含文字、空格、换行等)
- 我们在实际开发中,节点操作主要操作的是元素节点
代码示例:
<body>
<!-- 节点的优点 -->
<div>我是div</div>
<span>我是span</span>
<ul>
<li>我是li</li>
<li>我是li</li>
<li>我是li</li>
<li>我是li</li>
</ul>
<div class="box">
<span class="reweima">x</span>
</div>
<script>
var box = document.querySelector('.box');
// console.dirxml()用来显示网页的某个节点(node)所包含的html/xml代码。
console.dir(box);
</script>
</body>
8.3 节点操作
节点操作之父节点 node.parentNode
<body>
<div>我是div</div>
<span>我是span</span>
<ul>
<li>我是li</li>
<li>我是li</li>
<li>我是li</li>
<li>我是li</li>
</ul>
<div class="demo">
<div class="box">
<span class="erweima">x</span>
</div>
</div>
<script>
// 1.父节点 parentNode
var erweima = document.querySelector('.erweima');
// var box = document.querySelector('box');
// erweima 的父节点
erweima.parentNode;//得到的是离元素最近的父级 这里可以直接拿到 box
console.log(erweima.parentNode);
</script>
</body>
节点操作之子节点 parentNode.childNodes (标准)
parentNode.childNodes 返回包括指定节点的子节点的集合,该集合为及时更新的集合
<body>
<div>我是div</div>
<span>我是span</span>
<ul>
<li>我是li</li>
<li>我是li</li>
<li>我是li</li>
<li>我是li</li>
</ul>
<ol>
<li>我是ol的li</li>
<li>我是ol的li</li>
<li>我是ol的li</li>
<li>我是ol的li</li>
<li>我是ol的li</li>
</ol>
<div class="demo">
<div class="box">
<span class="erweima">x</span>
</div>
</div>
<script>
/* nodeType(节点类型)
元素节点 nodeType 为1
属性节点 nodeType 为2
文本节点 nodeType 为3 */
// DOM 提供的方法(API)获取
var ul = document.querySelector('ul');
var lis = ul.querySelectorAll('li');
// 1.子节点 childNodes(标准) 获得所有的子节点 包含 元素节点 和子节点、文本节点(文本节点包含文字、空格、换行等)等等
console.log(ul.childNodes);
// 2.子节点 children(非标准) 获取所有的子元素节点 也是我们实际开发常用的
console.log(ul.children);
</script>
</body>
子节点-第一个子元素和最后一个子元素
关键字:
- firstChild 获取元素第一个节点,早不到返回NULL 同样也是包含所有的节点
- lastChild
<body>
<ol>
<li>我是li1</li>
<li>我是li2</li>
<li>我是li3</li>
<li>我是li4</li>
</ol>
<script>
var ol = document.querySelector('ol');
// 1.firstChild 获取的是 第一个子节点 不管是文本节点还是元素节点
console.log(ol.firstChild);
// 2.lastChild 获取元素最后一个节点
console.log(ol.lastChild);
// 以下俩个节点有兼容性问题,IE9以上才支持
// 3.返回的是 第一个子元素节点
console.log(ol.firstElementChild);
// 4.lastElementChild 返回的是 最后一个子元素节点
console.log(ol.lastElementChild);
// 5.实际开发的写法 既没有兼容性问题又能放回第一个子元素
console.log(ol.children[0]);
// 返回的是 最后一个子元素节点
console.log(ol.children[ol.children.length - 1]);
</script>
</body>
兄弟节点 node.nextSibling
<body>
<div>我是div</div>
<span>我是span</span>
<span>我是span1</span>
<script>
var div = document.querySelector('div');
var span = document.querySelector('span')
// 1.nextSibling 得到的是下一个兄弟节点 包含元素节点、文本节点等等
console.log(div.nextSibling);
// 2.previousSibling 得到的是上一个兄弟节点 包含元素节点、文本节点等等
console.log(div.previousSibling);
// 以下的 IE9 以上才支持
// 3.nextElementSibling 得到的是下一个兄弟元素节点 找不到返回null
console.log(div.nextElementSibling);
// 4.previousElementSibling 得到的是上一个兄弟元素节点
console.log(span.previousElementSibling);
// 解决兼容性的方案
function getNextElementSibling(element) {
var el = element;
// nextElementSibling 得到的是下一个兄弟元素节点
while (el = el.nextElementSibling) {
if (el.nodeType == 1) {//元素节点的类型是1 nodeType节点类型
return el;
}
}
return null;
}
var fn = getNextElementSibling(div);
console.log(fn);
</script>
</body>
创建、添加节点
语法:
- 创建元素节点 document.createElement()
- 添加节点 node.appendChild(child) 方法将一个节点添加到指定父节点的字节点列表末尾,类似于css里面的after 伪元素
<body>
<ul>
<li>123</li>
</ul>
<script>
// 1.创建元素节点 document.createElement()
var li = document.createElement('li');
// 2.添加节点 node.appendChild(child) node父级 child子级
var ul = document.querySelector('ul') // 获取到父级的 DOM
ul.appendChild(li);//后面添加元素
// 3.添加节点 node.insertBefore(child,指定添加的位置)
var lili = document.createElement('li');
ul.insertBefore(lili, ul.children[0]); // children获取所有的子元素节点
</script>
</body>
删除节点 node.removeChild(child)
node.removeChild(child) 方法从DOM 中删除一个子节点,返回删除的节点 删除节点中的子节点
<body>
<button>删除</button>
<ul>
<li>熊大</li>
<li>熊二</li>
<li>光头强</li>
</ul>
<script>
// 1.获取元素
var ul = document.querySelector('ul');
// 2.删除节点
// ul.removeChild(ul.children[0]);
// 3.点击按钮依次删除
var btn = document.querySelector('button');
btn.onclick = function () {
// 如果想要某个表单被禁用 不能再点击 disabled 我们想要button这个按钮被禁用
// btn.disabled = true;
if (ul.children.length == 1) {
alert('大爷手下留节~~')
btn.disabled = true //禁用按钮
} else {
ul.removeChild(ul.children[0]);
}
}
</script>
</body>
克隆节点 onde.cloneNode()
onde.cloneNode() 节点克隆(复制)
- 如果括号里面的内容为空或者为false,则为浅拷贝,既只克隆节点本身,不克隆里面的字节点
- 如果括号里面的内容为空或者为true,则为深拷贝,复制标签里面的内容
<body>
<ul>
<li>1234</li>
<li>2</li>
<li>3</li>
</ul>
<script>
var ul = document.querySelector('ul');
// var lili = ul.children[0].cloneNode(); // 默认是false
var lili = ul.children[0].cloneNode(true);
ul.appendChild(lili);后面添加元素
</script>
</body>
9、三种创建元素方式的区别
1. document.write() 创建元素
document.write是直接将内容写入页面的内容流,但是文档流执行完毕,则它会导致页面全部重绘
2. innerHTML 创建元素
innerHTML创建多个元素效率更高(前提是不要采取字符串拼接,采取数组形式拼接)。结构稍微复杂
3. document.createElement() 创建元素
document.createElement()创建多个元素效率稍微低一点点。结构稍微清晰一点
<body>
<button>点击</button>
<p>abc</p>
<div class="inner"></div>
<div class="create"></div>
<script>
// 三种创建元素方式的区别
// 1.document.write() 创建元素
var btn = document.querySelector('button');
btn.onclick = function () {
document.write('<div>123</div>');
}
// 2.innerHTML 创建元素
var inner = document.querySelector('.inner');
// for (var i = 0; i < 5; i++) {
// inner.innerHTML += '<a href="#">百度</a>' + '<br>'; 创建多个元素时效率低不采用
// }
var arr = [];
for (var i = 0; i <= 100; i++) {
arr.push('<a href="#">百度</a>');
};//数组转换为字符串
// join() 方法用于把数组中的所有元素转换一个字符串。 元素是通过指定的分隔符进行分隔的。
inner.innerHTML = arr.join('');//不写就是没有分隔符 数组自带逗号分隔符 我们去掉
// 3.document.createElement() 创建元素
var create = document.querySelector('.create');
for (var i = 0; i < 5; i++) {
var a = document.createElement('a');
create.appendChild(a);
}
// 经典面试题
</script>
</body>
10、DOM重点核心
介绍:
- DOM文档对象模型(简称:DOM)获取过来的节点都是对象
- 文档:整个页面就是文档
- 元素:html标签就是元素
- 节点:页面所有的东西都是节点
- 关于DOM操作,我们主要针对元素操作。具体主要有:增、删、改、查 、属性操作、事件操作。
注意:以下只是总结操作DOM的方法,如需看使用例子请往上翻找 ,也可以使用 ctrl + f 键进行快速查找。
10.1 创建
- document.write()
- node.innerHTML
- document.createElement()
区别:
- document.write
- innerHTML
- document.createElement() 创建多个元素效率稍微低一点点。结构稍微清晰一点
10.2 添加 DOM 元素
node.appendChild(child) 添加到指定父节点的字节点列表末尾
参数: node 父节点 child 子节点
node.insertBefore(child,index) 添加到指定的位置
参数:node 父节点 child 子节点 index 指定添加的位置
10.3 移除
node.removeChild(child)
参数:node 父节点 child 子节点
10.4 修改 DOM 元素
主要修改dom的元素属性,dom元素的内容、属性、表单的值等等
- 修改元素属性:src、href、title等
- 修改普通元素内容:innerHTML(保留空格和换行)、innerText
- 修改表单元素:value、type、disabled等 // btn.disabled = true;表单被禁用
- 修改元素样式: style、className
查询
- DOM提供的API方法:getElementById、getElementsByTagName 古老用法 不推荐
- H5提供的新方法:querySelector、querySelectorAll 提倡
- 利用节点操作的获取元素:父( parentNode )、子( children )、兄( previousElementSibling (得到的是上一个兄弟元素节点)、nextElementSibling(得到的是下一个兄弟元素节点))
属性操作
主要针对自定义属性,自己添加的属性就是自定义属性
- setAttribute
- getAttribute 得到dom的属性值 element.getAttribut('属性')
- removeAttribute 移除属性 removeAttribute('属性')
10.7 事件操作
给元素注册事件,采取事件源.事件类型=事件处理程序
事件类型 | 事件名称 |
onclick | 鼠标点击事件 |
onmouseover | 鼠标经过触发 |
onmouseout | 鼠标离开触发 |
onfocus | 获取鼠标焦点触发 |
onblur | 失去鼠标焦点触发 |
onmousemove | 鼠标移动触发 |
onmouseup | 鼠标弹起触发 |
onmousedown | 鼠标按下触发 |
11、注册事件(绑定事件)
注册事件有两种方式:
传统的方式和方法监听注册方式
传统注册方式:
onkclick
<button onclick="alert('hi'~)"></button>
var btn = document.querySelectorAll('button');
btn.onclick=function(){}
特点:
注册事件的唯一性,同一个元素同一个事件只能设置一个处理函数,最后注册的处理程序将会覆盖前面注册的处理程序
方法监听注册方式:
W3C 标准 推荐的方式
addEventListener()
IE9之前IE不支持此方法,可以使用attachEvent()代替
特点:
同一个元素同一个事件可以注册多个监听器会按照注册的顺序依次执行
语法:
eventTarget.addEventListener('type',listener[,usecapture])
eventTarget.addEventListener() 方法将指定的监听器注册到eventTarget(目标对象)上
当该对象触发指定的事件时,就会执行事件处理函数。
该方法接收三个参数:
- type:事件类型字符串,比如click、mouseover,注意这里不要带on
- listener:事件处理函数,事件发生时,会调用该监听函数
- useCapture:可选参数,是一个布尔值,默认是false.
代码示例:
<body>
<button>传统注册事件</button>
<button>方法监听注册事件</button>
<button>IE9以前的</button>
<script>
var btns = document.querySelectorAll('button');
// 传统注册方式
btns[0].onclick = function () {
alert('hi~');
}
btns[0].onclick = function () {
alert('Hi~');//会覆盖前面的
}
// 2.利用事件监听注册事件 iE9 以上才支持
// (1)里面的事件类型是字符串,必定加'' 不带on
// (2) 同一个元素 同一个事件可以添加多个侦听器(事件处理程序)
btns[1].addEventListener('click', function () {
alert('Hi~');
})
btns[1].addEventListener('click', function () {
alert('你好~');//不会覆盖前面的
})
// 3.IE9以下的可以使用eventTarget.attachEvent(eventNamewithOn,callback) (不支持使用)
// eventTarget.attachEvent()方法将指定的监听器注册到eventTarget(目标对象)上,当该对象触发
// 指定的事件时,指定的回调函数就会被执行
// 该方法接收两个参数:
// (1).eventNamewithOn: 事件类型字符串,比如onclick、onmouseover,这里要带on
// (2).callback: 事件处理函数,当目标触发事件时回调函数
// attachEvent ie9 以前的版本支持
btns[2].attachEvent('onclick', function () {
alert(11);
});
</script>
</body>
12、删除事件( 解绑事件 )
1. 传统方式解绑事件
divs[0].onclick = null
2. removeEventListener 删除事件
divs[1].removeEventListener('click', fn);
<style>
div {
width: 50px;
height: 100px;
background-color: pink;
}
</style>
<body>
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
<script>
var divs = document.querySelectorAll('div');
divs[0].onclick = function () {
alert(11);
//1.传统方式解绑事件
divs[0].onclick = null;
}
//2. addEventListener 利用事件监听注册事件
divs[1].addEventListener('click', fn)//里面的fn不需要调用加小括号()
function fn() {
alert(22);
// removeEventListener 删除事件
divs[1].removeEventListener('click', fn);
}
</script>
</body>
事件流
介绍:
事件流:描述的是从页面中接收事件的顺序。
事件发生时会在元素节点之间按照特定的顺序传播,这个传播的过程即DOM事件流。
DOM 事件流分为3个阶段:
- 捕获阶段 网景最早提出的:从最顶层的节点开始,然后逐级向下传播到最具体的元素(目标点)接收的过程
- 当前目标阶段 找到点击事件时就是目标阶段
- 冒泡阶段 IE最早提出的: 事件开始时由最具体的元素接收,然后逐级向上传播到DOM最顶层节点的过程
事件捕获和冒泡理解:
通俗的点的解释:我们向水里扔一块石头,首先它会有一个下降过程,这个过程就可以理解为从最顶层向事件发生最具体元素(目标点)的捕获过程;之后会产生泡泡,会在最低点向上冒(最具体的元素漂浮在水面),这个过程相当于事件冒泡。
代码示例:
<style>
.father {
position: relative;
width: 200px;
height: 200px;
background-color: pink;
margin: 100px auto;
}
.father .son {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 100px;
height: 100px;
background-color: purple;
text-align: center;
line-height: 100px;
}
</style>
<body>
<div id="app" v-cloak>
<div class="father" @click.capture="fatherClick">
<div class="son" @click="sonClick">son盒子</div>
</div>
</div>
<script>
const app = new Vue({
el: '#app',
data: {},
methods: {
sonClick() {
/*
默认情况下:点击son盒子时冒泡阶段 先执行 sonClick方法 再到 fatherClick方法
执行过程: son(目标)->father ->body ->html-> document
打印:
先:son盒子事件触发了
后:father盒子事件触发了
*/
console.log('son盒子事件触发了')
/*
给 father 盒子的点击事件加了 .capture 修饰符 开启事件捕获
点击son盒子时捕获阶段 先执行 fatherClick方法 再到 sonClick方法
过程:document-> html -> body -> father(目标) ->son(目标)
打印:
先:father盒子事件触发了
后:son盒子事件触发了
*/
},
fatherClick() {
console.log('father盒子事件触发了')
}
}
})
</script>
注意:
- JS代码中只能执行捕获或者冒泡其中的一个阶段。
- 实际开发中我们很少使用使用事件捕获,我们更关注事件冒泡
- 有些事件没有冒泡,比如onblur、onfocus、onmouseenter、onmouseleave、 onblur 、onfocus
14、事件对象
14.1 介绍:
- event 就是一个事件对象 写到侦听函数的小括号里面当形参来看
- 事件对象只有调用了事件才会存在,它是系统给我们自动创建的,不需要我们传递参数
- 事件对象是我们事件的一系列相关数据的集合,比如:鼠标点击里面就包含了鼠标的相关信息,鼠标坐标,如果是键盘事件就包含了键盘事件的信息 比如 判断用户按下了那个键
- 这个事件对象我们可以自己重命名
- 事件对象也有兼容性的问题 ie678 通过window.event 来获取对象 兼容性写法 e = e || window.event;
代码示例:
<style>
div {
width: 100px;
height: 100px;
background-color: pink;
}
</style>
<body>
<div>123</div>
<script>
// 事件对象
var div = document.querySelector('div');
div.onclick = function (e) {
// console.log(event);
// console.log(window.event);//ie678 规定写法
// 兼容性写法
e = e || window.event;
console.log(e);
}
div.addEventListener('click', function (e) {
console.log(e);
})
</script>
</body>
14.2 常见事件对象属性和方法
事件属性或方法 | 说明 |
e.target | 返回触发事件的对象 标准 |
e.srcElement | 返回触发事件的对象 非标准 ie6-8使用 |
e.type | 返回事件的类型 比如 click mouseover 不带on |
e.cancelBubble | 该属性阻止冒泡 非标准 ie6-8使用 |
e.returnValue | 该属性 阻止默认事件(默认行为) 非标准 ie6-8使用 比如不让链接跳转 |
e.preventDefault() | 阻止默认事件(默认行为) 标准 比如不让链接跳转 |
e.stopPropagation() | 阻止冒泡 标准 |
代码示例:
<body>
<div>123</div>
<ul>
<li>asd1</li>
<li>asd2</li>
<li>asd3</li>
</ul>
<script>
// 常见的事件对象的属性和方法
// e.target 返回触发事件的对象(元素) 标准 this 返回的是绑定事件的对象(元素)
var div = document.querySelector('div');
div.addEventListener('click', function (e) {
console.log(e.target);
console.log(this);
})
var ul = document.querySelector('ul');
ul.addEventListener('click', function (e) {
// 我们个给ul绑定事件 那么 this 就指向 ul
console.log(this, e.currentTarget) // ul
// e.currentTarget 和 this 是相同的,但是 e.currentTarget ie678不认识
console.log(e.currentTarget === this);// true
// e.target 指向我们点击的那个对象
console.log(e.target) //li
})
</script>
</body>
14.3 事件对象阻止默认行为
<body>
<div>123</div>
<a href="http://www.baidu.com">百度</a>
<form action="http://www.baidu.com">
<input type="submit" value="提交" name="sub">
</form>
<script>
// 常见事件对象的属性和方法
// 1.返回事件类型
var div = document.querySelector('div')
var a = document.querySelector('a')
div.addEventListener('click', fn)
div.addEventListener('mouseover', fn)//鼠标经过
div.addEventListener('mouseout', fn)//鼠标离开
function fn(e) {
console.log(e.type)
}
// 2.阻止默认行为(事件) 让链接不跳转 或者让 提交按钮不提交
a.onclick = function (e) {
// e.preventDefault() //标准
// ie 678 才识别 e.returnValue
// e.returnValue //
/* 我们也可以利用return false 也能阻止默认行为 特点:return false 后面的代码不会被执行
而且只限于传统的注册方式 */
return false
alert(11)
}
</script>
</body>
14.4 阻止事件冒泡
方式:
- e.stopPropagation() DOM 推荐的标准方式
- e.cancelBubble 该属性阻止冒泡 非标准 ie6-8使用
- e.cancelBubble = true
代码示例:
<style>
.father {
position: relative;
width: 200px;
height: 200px;
background-color: pink;
margin: 100px auto;
}
.father .son {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 100px;
height: 100px;
background-color: purple;
text-align: center;
line-height: 100px;
}
</style>
<body>
<div class="father">
<div class="son">son盒子</div>
</div>
<script>
// 阻止冒泡 dom 推荐的标准 e.stopPropagation();
var son = document.querySelector('.son');
son.addEventListener('click', function (e) {
alert('son');// 点击son时冒泡阶段 先执行 son 再到 father
// 过程: son(目标)->father ->body ->html-> document
// 兼容性方案
if (e && e.stopPropagation) {
e.stopPropagation();
} else {
window.event.cancelBubble = true;
}
}, false);
var father = document.querySelector('.father');
father.addEventListener('click', function () {
alert('father');
}, false);
// 5.实际开发中我们很少使用使用事件捕获,我们更关注事件冒泡
// 6.有些事件没有冒泡,比如onblur、onfocus、onmouseenter、onmouseleave
// onblur 失去鼠标焦点触发 onfocus 获取鼠标焦点触发
</script>
</body>
14.5 事件委托
事件委托的原理: 不是每一个子节点单独设置事件监听器,而是事件监听器设置在其父节点上,然后利用冒泡原理影响每个子节点
代码示例:
<bnody>
<!--
以下案例:给ul注册点击事件,然后利用事件对象的target来找到当前点击的li,因为点击li,
事件会冒泡到ul上,ul有注册事件,就会触发事件监听器
事件委托的作用:我们只操作了一次DOM,提高了程序的性能
-->
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
<li>7</li>
<li>8</li>
<li>9</li>
<li>10</li>
</ul>
<script>
var ul = document.querySelector('ul')
var li = document.querySelectorAll('li')
ul.addEventListener('click', fn) // 给 ul 节点绑定事件,但是你点击 li 节点,事件一样会触发
function fn(e) {
// 利用排他思想先清空其他节点的背景色
for (var i = 0; i < li.length; i++) {
li[i].style.backgroundColor = '';
}
console.log(e.target) // e.target 返回触发事件的对象 标准
// 使用 e.target 事件属性才能准确捕捉到当前点击的节点
e.target.style.backgroundColor = 'pink'
alert('知否知否,点我应有弹框在手!')
}
</script>
</bnody>
14.6 鼠标事件对象
介绍:
event对象代表事件的状态,跟事件相关的一系列星系的集合,包括了鼠标事件对象、键盘事件对象等
鼠标事件对象 | 说明 |
e.clientX | 返回鼠标相对于浏览器窗口可视区X坐标 |
e.clientY | 返回鼠标相对于浏览器窗口可视区Y坐标 |
e.pageX | 返回鼠标相对于文档页面的X坐标 |
e.pageY | 返回鼠标相对于文档页面的Y坐标 |
e.screenX | 返回鼠标相对于电脑屏幕的X坐标 |
e.screenY | 返回鼠标相对于电脑屏幕的Y坐标 |
代码示例:
<style>
body {
height: 2000px;
}
</style>
<body>
<script>
// 鼠标事件对象 MouseEvent
document.addEventListener('click', function (e) {
// 返回鼠标相对于浏览器窗口可视区坐标
console.log(e.clientX);
console.log(e.clientY);
console.log('---------------------------------------------------------------------------------------------------------');
// 返回鼠标相对于文档页面的坐标
console.log(e.pageX);
console.log(e.pageY);
console.log('---------------------------------------------------------------------------------------------------------');
// 返回鼠标相对于电脑屏幕的坐标
console.log(e.screenX);
console.log(e.screenY);
})
</script>
</body>
15、键盘事件
键盘事件 | 触发条件 |
onkeyup | 某个按键松开时 触发 |
onkeydown | 某个按键按下时 触发 |
onkeypress | 某个按键按下时 触发 但是它不识别功能键 |
代码示例
<body>
<script>
// 常用的键盘事件
// 1.keyup 按键弹起的时候触发
// document.onkeyup = function () {
// console.log('我键盘弹起时触发');
// }
document.addEventListener('keydown', function () {
console.log('我键盘按下时触发');
})
document.onkeypress = function () {
console.log('我键盘按下时触发,不识别功能键');
}
// 三个事件的执行顺序 keydown->keypress->keyup
</script>
</body>
keyCode 属性可以得到相应的ASCII码值
案例:判断用户按下那个键
<body>
<script>
// 1.键盘事件对象中的keyCode属性可以得到相应的ASCII码值
// 2.onkeyup 某个按键松开触发 onkeydown某个按键按下时触发 事件 它们不区分字母大小写
// 3.onkeypress某个按键按下时触发但是它不识别功能键 它区分字母大小写
document.addEventListener('keyup', function (e) {
console.log('不区分大小写keyup:' + e.keyCode);//A
if (e.keyCode === 65) {
alert('您按下了a键')
} else {
alert('您没有按下了a键')
}
})
// 三个事件的执行顺序 keydown->keypress->keyup
document.addEventListener('keypress', function (e) {
console.log('我区分大小写press:' + e.keyCode);
})
</script>
</body>