DOM
📜学习目标:
1、能够说出什么是DOM?
2、掌握如何获取页面元素?
3、掌握如何给元素注册事件?
4、怎样操作DOM元素的属性?
5、如何操作DOM节点?
梳理方法:元素的创建、增、删、改、查、属性操作、事件操作。
一、Dom简介
-
定义:文档对象模型(Document Object Model),是处理可扩展标记语言的标准编程接口。 -
Dom的作用:a. 可以找到页面中的元素;b. 删除和新建元素;c. 可以对元素的属性和样式进行增删改查。 -
Dom树: a. 文档:一个页面即一个文档(document); b. 元素:页面中所有的标签都是元素(element); c. 节点:网页中所有的内容都是节点,包括标签、属性、文本、注释等(node)。 注意:DOM将以上所有内容都看作是对象。 -
通过DOM获取的元素是一个对象。
二、元素的获取
2.1 通过ID来获取元素
-
🚩语法表达式:let 存放获得元素的变量名 = document.getElementById(‘需要获取元素的id名’); 注意:a. 文档加载是从上向下加载的,所以script标签必须写在下面; ? b. id 是大小写敏感的字符串; ? c. 如果页面上没有这个id,那通过id获取到的就是null; ? d. 返回的是一个元素对象; ? e. id是唯一的,所以有些浏览器支持:不获取元素,直接用id来代替这个元素。(不推荐这样去做) eg:通过ID来获取元素
<body>
<div class="one" id="box"></div>
<script>
let box1 = document.getElementById('box');
console.log(box1);
console.log(box1.id);
</script>
</body>
-
console.dir:可以打印返回的元素对象,更好的查看属性和方法。
2.2 通过标签名来获取元素们
-
🚩语法表达式:let 存放获得元素的变量名 = document.getElementsByTagName(‘需要获取元素的标签’); 注意:a. 返回的是带有指定标签名的对象的集合(伪数组),其中元素对象是动态的; ? b. 可以采用遍历的方式来依次打印里面的元素; ? c. 如果标签只有一个,那也是获取到一个伪数组,只不过这个伪数组里面只有一个标签而已; ? d. 如果页面中没有这个元素返回的是空的伪数组形式。 eg:通过标签名来获取元素们
<body>
<ul>
<li>我是第1个li标签</li>
<li>我是第2个li标签</li>
<li>我是第3个li标签</li>
</ul>
<script>
let lis = document.getElementsByTagName('li');
console.log(lis);
console.log(lis[2]);
</script>
</body>
-
利用这种方法可以获取某个(父元素)内部所指定标签名的子元素。 注:父元素必须是单个对象(必须指明是哪个元素对象) <script>
let ol = document.getElementByTagName('ol');
let lis = ol[0].getElementByTagName('li');
</script>
2.3 通过类名来获取元素们
-
🚩语法表达式1:let 存放获得元素的变量名 = document.getElementsByClassName(‘需要获取元素的className’); 注意:a. 返回的是带有指定类名的对象的集合(伪数组); ? b. 如果标签只有一个,那也是获取到一个伪数组,只不过这个伪数组里面只有一个标签而已。 eg:
<body>
<div class="one two" id="box1">我是div1</div>
<br>
<div class="one" id="box2">我是div2</div>
<script>
let eles = document.getElementsByClassName('one');
console.log(eles);
</script>
</body>
-
🚩语法表达式2:let 存放获得元素的变量名 = document.querySelector(‘选择器’); -
🚩语法表达式3:let 存放获得元素的变量名 = document.querySelectorAll(‘选择器’); 注意:①、document.querySelector获取选择器获取到的元素们的第一个元素; ? ②、document.querySelectorAll获取选择器获取到的符合选择器的所有元素对象的集合; ? ③、切记写在括号里面的选择器要加上符号。eg:.box、#nav。 <body>
<div id="screen">
<ul id='ul1'>
<li><a href="#"><img src="./images/09.jpg" alt=""></a></li>
<li><a href="#"><img src="./images/11.jpg" alt=""></a></li>
<li><a href="#"><img src="./images/28.jpg" alt=""></a></li>
<li><a href="#"><img src="./images/39.jpg" alt=""></a></li>
<li><a href="#"><img src="./images/13.jpg" alt=""></a></li>
</ul>
</div>
<script>
let ul1 = document.querySelector('#ul1');
let ulLis = document.querySelectorAll('#ul1>li');
</script>
</body>
2.4 获取body和html元素
2.4.1 获取body元素
2.4.2 获取html元素
2.5 通过name属性来获取元素
-
🚩语法表达式:let 存放获得元素的变量名 = document.getElementsByName(‘需要获取元素的name属性值’); 注意:a. 普通标签可以自己定义一个name属性,但是表单元素有默认的name属性。 ? b. 通过name属性获取元素,获取到的是一个伪数组。 let eles = document.getElementsByName('one');
console.log(eles);
三、事件注册和事件触发
3.1 事件基础
-
事件三要素: 1、事件源: 事件被触发的对象【谁? 按钮…】 2、事件类型: 如何触发,什么样的事件【鼠标单击,鼠标双击,鼠标移入…】 3、事件处理程序: 通过一个函数赋值完成【做什么? 产生什么样的结果?】 注意:事件的2个时机:1个是注册事件时机,1个触发事件时机。
3.2 执行事件的步骤
- 获取事件源
- 注册事件(绑定事件)
- 添加事件处理程序(采用函数赋值形式)
3.3 常见的鼠标事件
鼠标事件 | 触发事件 |
---|
onclick | 鼠标点击触发 | onmouseover | 鼠标移入触发 | onmouseout | 鼠标移出触发 | onfocus | 获得鼠标焦点触发 | onblur | 失去鼠标焦点触发 | onmousemove | 鼠标移动触发 | onmouseup | 鼠标弹起触发 | onmousedown | 鼠标按下触发 |
例子见下方4.3案例
四、操作元素
4.1 修改元素内容
-
以下三种中修改元素内容的方法作用都是:获取/设置双标签文本。 -
🚩语法表达式1:element.textContent = ‘要修改的内容文本’; 注意:①、获取从起始位置到终止位置的所有节点(包括子代文本和后代元素的文本),但不能识别html标签,,只会把标签当做文本的一部分,同时会将空格和换行也去掉; ? ②、设置文本时会覆盖原来的内容,而且如果内容中有标签,不会把标签解析出来 。 拓展:textContent才是标准的w3c中用来处理文本的,但是一些老的浏览器比如ie6、7、8不支持) -
🚩语法表达式2:element.innerText = ‘要修改的内容文本’; 注意:①、作用效果与textContent相同,获取从起始位置到终止位置的所有节点(包括子代文本和后代元素的文本),但不能识别html标签,只会把标签当做文本的一部分,同时会将空格和换行也去掉; ? ②、设置文本时会覆盖原来的内容,而且如果内容中有标签,不会把标签解析出来 。 拓展:它是由ie浏览器搞出来的,老的浏览器支持innerText,现在很多新的浏览器也支持,故w3c也将其收录了。 -
🚩语法表达式3:element.innerHTML = ‘要修改的内容文本’;(使用最多) 注意:①、获取从起始位置到终止位置的所有节点,可以识别html标签,同时会保留空格和换行; ? ②、设置文本时会覆盖原来的内容,而且如果内容中有标签,会把标签解析出来。 ? ③、innerHTML只能修改普通盒子里面的内容,不能修改表单里面的value值。
4.2 常用元素的属性操作
- innerText、innerHTML改变元素内容;
- src、href
- id、 alt、title
4.3 表单元素的属性操作
-
利用DOM可以操作表单的属性:type、value、checked、selected、disabled; eg: 表单元素的属性操作
<body>
<button>按钮</button>
<input type = 'text' value = '请输入内容'>
<script>
let btn = document.querySelector('button');
let input = document.querySelector('input');
btn.onclick = function(){
input.value = '被点击了';
this.disabled = true;
}
</script>
</body>
4.4 样式属性操作
通过 JavaScript修改元素的大小、颜色、位置等样式;
4.4.1 使用 element.style 修改元素样式
-
🚩语法表达式:element.style.具体样式的属性名 = ‘具体样式的属性值’;(行内样式操作) -
使用场景:修改的样式较少,或者功能简单的情况下使用。 注意:a. JS里面的样式采用的是驼峰命名法。eg:fontSize、backgroundColor ? b. JS修改 style 样式操作,产生的是行内样式,权重比较高。
4.4.2 通过修改元素的className更改元素的样式
-
🚩语法表达式:element.style.具体样式的属性名 = ‘具体样式的属性值’;(类名样式操作) -
使用场景:修改的样式较多,或者功能复杂的情况下使用。 -
使用方法:在css新建一个类选择器,将要修改的样式写入,然后在事件里通过类名调用(this.className = ‘类名’)即可。 注意:1、👀因为class是一个保留字,因此使用className来操作元素类名属性; ? 2、className 会直接更改元素的类名,会覆盖原先的类名; ? 3、如果想要保留原先的类名,我们可以设置为多类名选择器。 -
相关案例:① 、用户名输入框 显示隐藏内容;②、广告关闭/二维码关闭(直接隐藏即可);③、下拉菜单(鼠标移入即可现实下拉菜单,移出则收回);④、开关灯(一个按钮控制,利用flag=0;假设法来做)。
4.6 排他思想
-
设计需求:如果有同一组元素,我们想只要其中的某一个实现某种样式,这个时候就需要用到循环的排他思想算法。(????) -
设计步骤:a. 所有元素样式全部清除(干掉所有人); ? b. 只给当前元素设置样式(留下我自己); **注意:**顺序不能颠倒,首先干掉所有人,在给自己设置样式。 案例引导:
//当点击按钮中的某一个,则它改变颜色,其他不变。
<body>
<button>按钮1</button>
<button>按钮2</button>
<button>按钮3</button>
<button>按钮4</button>
<button>按钮5</button>
<script>
//1、获取所有按钮元素
let btns = document.getElementByTagName('button');
//得到的btns是一个伪数组,而我们需要对其中的每一个元素btn[i]设置点击事件,先使用for循环遍历所有元素,再在循环内部统一设置点击事件.
for(let i = 0; i < btns.length; i++) {
//2、给每个元素注册事件
btns[i].onclick = function(){
//(1)将所有的按钮背景颜色清除(利用排他思想的第一步:干掉所有人)
//此时又要遍历每一个按钮,清除所有按钮背景颜色
for(let j = 0; j < btns.length; j++){
//将背景颜色设置为空字符串即可
btns[j].style.backgroundColor = '';
}
//(2)给选中的当前元素设置背景颜色(利用排他思想的第二步:留下我自己)
this.style.backgroundColor = 'yellowgreen';
}
}
</body>
-
相关案例:①、百度首页换肤案例(美女相册);②、表格隔行换色案例;③、表单全选取消按钮案例(重点掌握)
4.7 自定义属性操作
-
设置自定义属性的目的:为了保存并使用数据,因为有些数据可以只需保存在页面中而不用保存在数据库中。 -
获取属性值: ①、element.属性;只能获取内置属性值(即元素本身自带的属性),无法获取自定义属性; ②、🚩element.getAttribute(‘属性’);通过这种方法可以获取自定义的属性(eg:‘index’)。 -
设置属性值: ①、element.属性 = ‘属性值’;对元素的内置属性值进行修改; ②、🚩element.setAttribute(‘属性’,‘属性值’) ;通过这种方式对自定义的属性值进行修改(eg:‘class’,‘box1’)。 -
移除属性值:🚩 removeAttribute(‘属性’); -
(了解)H5自定义属性:以data-开头作为属性名并且赋值(这样做有利于判断是元素的内置属性还是自定义属性) -
(了解)H5新增获取自定义属性:element.dataset.属性名或者 element.dataset[‘属性名’] 。 注:H5新增获取自定义属性的缺点:它只能获取以data-开头的自定义属性;兼容性差,ie 11才开始支持。 eg:自定义属性操作
<body>
<div id = 'demo' index = '1' class = 'nav' ></div>
<script>
let div = document.querySelector('div');
① console.log(div.id);
② console.log(div.getAttribute('index'));
① div.id = 'test';
② div.setAttribute('index','2')
div.removeAttribute('index');
</script>
</body>
经典案例:tab栏切换(?????)
<style>
* {
margin: 0;
padding: 0;
}
ul {
list-style: none;
}
.box {
width: 400px;
height: 300px;
border: 1px solid #ccc;
margin: 100px auto;
}
.hd {
height: 45px;
}
.hd span {
display: inline-block;
width: 90px;
background-color: pink;
line-height: 45px;
text-align: center;
cursor: pointer;
}
.hd span.current {
background-color: purple;
}
.bd li {
height: 255px;
background-color: purple;
display: none;
}
.bd li.current {
display: block;
}
</style>
</head>
<body>
<div class="box" id="box">
<div class="hd">
<span class="current">体育</span>
<span>娱乐</span>
<span>新闻</span>
<span>综合</span>
</div>
<div class="bd">
<ul id="list">
<li class="current">我是体育模块</li>
<li>我的娱乐模块</li>
<li id="li3">我是新闻模块</li>
<li>我是综合模块</li>
</ul>
</div>
</div>
<script>
let spanAll = document.querySelectorAll('span');
let lis = document.querySelectorAll('#list>li');
for (let i = 0; i < spanAll.length; i++) {
spanAll[i].setAttribute('index', i);
spanAll[i].onclick = function () {
for (let j = 0; j < spanAll.length; j++) {
spanAll[j].setAttribute('class', '');
}
this.setAttribute('class', 'current');
let idx = this.getAttribute('index');
for (let k = 0; k < lis.length; k++) {
lis[k].style.display = 'none';
}
lis[idx].style.display = 'block';
}
}
</script>
五、节点操作
5.1 节点
5.2 节点获取
-
🚩父节点:element.parentNode; 注意:得到是离元素最近的父元素,如果找不到父节点那返回的为null。 -
子节点:element.childNodes; 注意:返回值里面包含了所有的节点,包括元素节点,文本节点和空格等;如果只想要或去里面的元素节点就需要借助 if 判断元素类型是否为 1,所以一般不提倡使用childNodes. -
🚩子元素节点:element.children; 注意:获取到的是所有的子元素节点,实际开发中常用。 -
兄弟节点:(以下两者都有兼容性问题,可以自己封装一个兼容性函数) ①、element.nextSibling / element.previousSibling; 返回当前元素的下一个 / 上一个兄弟节点,找不到返回null,其中包含所有节点; ②、🚩element.nextElementSibling / element.previousElementSibling;返回当前元素的下一个 / 上一个兄弟元素节点,找不到返回null。 -
第一个子元素节点和最后一个子元素节点: ①、element.firstChild / element.lastChild;获取的是第一个/最后一个子节点,可能是文本节点、元素节点及空格等。 ②、element.firstElementChild / element.lastElementChild;获取的是第一个/最后一个子元素节点(但是这种方法只有ie9才支持)。 ③、🚩element.children[0] / element.children[element.children.length-1];获取的是第一个/最后一个子元素节点(实际开发中的写法,没有兼容性问题)。
5.3 创建节点
? 需求:当我们想要在页面添加一个新的元素:1、可以创建元素;2、可以添加元素。
5.3.1 创建元素节点
? ②、创建节点是在已有元素的后面追加元素,类似于数组中的push方法。
5.3.2 插入(添加)元素节点
-
🚩语法表达式:element.insertBefore(child,指定元素); 【换一种看待方法:**父元素.insertBefore(元素A,元素B);**把A元素插到B元素前面】 注意:其中A元素可以是新创建的元素;也可以是已有的元素,可以看作是被剪切后插入B元素前面; 拓展:可以利用element.insertBefore(元素A,元素B.nextElementSibling);来实现将A元素插到B元素的后面。
<body>
<ul>
<li>我是第1个li标签</li>
<li>我是第2个li标签</li>
<li>我是第3个li标签</li>
</ul>
<script>
let li1 = document.createElement('li');
let ul = querySelector('ul');
ul.appendChild(li1);
let li2 = document.createElement('li');
ul.insertBefore(li2,ul.children[0]);
</script>
</body>
5.3.3 三种动态创建元素的区别
-
document.write();是直接将内容写入页面的内容流,如果它在文档流执行完毕后创建元素的话,则会导致页面全面重绘。 -
element.innerHTML();是将内容写入某个DOM节点,不会导致页面重绘。创建多个元素时效率更高(采用数组形式拼接),但是结构会稍微复杂。 -
document.createElement();创建多个元素效率稍低一些,但是结构更清晰。 注意:不同浏览器下创建多个元素,inner.HTML效率要比createElement高。
5.4 删除节点
- 🚩语法表达式:element.removeChild();从DOM中删除一个子节点,返回删除的节点。
5.5 克隆节点
-
🚩语法表达式:element.cloneNode();方法返回调用该方法的节点的一个副本。 注意:①、如果括号参数为空或者为false,则为浅拷贝,只克隆节点本身,不克隆里面的子节点; ? ②、如果括号参数为true,则为深拷贝,会克隆节点本身以及里面所有的子节点。
<body>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>1</li>
</ul>
<script>
let ul = document.querySelector('ul');
let liNew = ul.children[0].cloneNode(true);
ul.appendChild(liNew);
</script>
</body>
六、综合案例:轮播图
<!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;
}
body {
background-color: #b6e8f3;
}
.banner {
width: 300px;
height: 300px;
background-color: pink;
margin: 200px auto;
position: relative;
overflow: hidden;
}
#ul1 {
position: absolute;
top: 0;
left: 0;
width: 1000%;
height: 100%;
}
#ul1 li {
float: left;
width: 10%;
height: 100%;
list-style-type: none;
}
#ul1 li img {
width: 100%;
height: 100%;
}
#ol1 {
position: absolute;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
}
#ol1 li {
float: left;
list-style-type: none;
width: 8px;
height: 8px;
border: 1px solid #ccc;
border-radius: 5px;
margin-right: 10px;
}
#arr {
display: none;
}
#arr #arrLeft {
position: absolute;
top: 50%;
left: 0;
transform: translateY(-50%);
width: 20px;
height: 40px;
background-color: #000;
opacity: .5;
z-index: 8;
}
#arrLeft span {
display: block;
width: 10px;
height: 10px;
border-top: 2px solid #fff;
border-right: 2px solid #fff;
margin: auto;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%) rotate(-135deg);
}
#arr #arrRight {
position: absolute;
top: 50%;
right: 0;
transform: translateY(-50%);
width: 20px;
height: 40px;
background-color: #000;
z-index: 8;
opacity: .5;
}
#arrRight span {
display: block;
width: 10px;
height: 10px;
border-top: 2px solid #fff;
border-right: 2px solid #fff;
margin: auto;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%) rotate(45deg);
}
.current {
background-color: #fff;
}
</style>
</head>
<body>
<div class="banner" id='box'>
<div id="screen">
<!-- 轮播图图片 -->
<ul id='ul1'>
<li><a href="#"><img src="./images/01.jpg" alt=""></a></li>
<li><a href="#"><img src="./images/02.jpg" alt=""></a></li>
<li><a href="#"><img src="./images/03.jpg" alt=""></a></li>
<li><a href="#"><img src="./images/04.jpg" alt=""></a></li>
<li><a href="#"><img src="./images/05.jpg" alt=""></a></li>
</ul>
<!-- 轮播图下方的小圆点 -->
<ol id='ol1'>
</ol>
</div>
<!-- 轮播图中的左右按钮 -->
<div id="arr">
<a href="javascript:;" id="arrLeft"><span></span></a>
<a href="javascript:;" id="arrRight"><span></span></a>
</div>
</div>
<script>
let box = document.getElementById('box');
let screen = document.getElementById('screen');
let unitWidth = screen.offsetWidth;
let ul1 = document.querySelector('#ul1');
let ulLis = document.querySelectorAll('#ul1>li');
let ol1 = document.querySelector('#ol1');
let arr = document.getElementById('arr');
let arrLeft = document.getElementById('arrLeft');
let arrRight = document.getElementById('arrRight');
let picNum = 0;
let timeId = null;
for (let i = 0; i < ulLis.length; i++) {
let liNew = document.createElement('li');
ol1.appendChild(liNew);
}
let olLis = ol1.children;
olLis[0].setAttribute('class', 'current');
for (let i = 0; i < olLis.length; i++) {
olLis[i].setAttribute('index', i);
olLis[i].onclick = function () {
for (let j = 0; j < olLis.length; j++) {
olLis[j].removeAttribute('class');
}
this.setAttribute('class', 'current');
let index = this.getAttribute('index');
let target = -index * unitWidth;
animate(ul1, target);
}
}
ul1.appendChild(ulLis[0].cloneNode(true));
box.onmouseover = function () {
arr.style.display = 'block';
clearInterval(timeId);
}
box.onmouseout = function () {
arr.style.display = 'none';
timeId = setInterval(clickRight, 2000);
}
arrRight.onclick = function () {
clickRight();
}
function clickRight() {
if (picNum == 5) {
picNum = 0;
ul1.style.left = 0 + 'px';
}
picNum++;
let target = -picNum * unitWidth;
animate(ul1, target);
for (let i = 0; i < olLis.length; i++) {
olLis[i].removeAttribute('class');
}
if (picNum == 5) {
olLis[0].setAttribute('class', 'current');
} else {
olLis[picNum].setAttribute('class', 'current');
}
}
arrLeft.onclick = function () {
if (picNum == 0) {
picNum = 5;
ul1.style.left = -picNum * unitWidth + 'px';
}
picNum--;
let target = -picNum * unitWidth;
animate(ul1, target);
for (let i = 0; i < olLis.length; i++) {
olLis[i].removeAttribute('class');
}
olLis[picNum].setAttribute('class', 'current');
}
timeId = setInterval(clickRight, 2000);
function animate(ele, target) {
clearInterval(ele.timeId)
ele.timeId = setInterval(function () {
let currentLeft = ele.offsetLeft;
let step = target > currentLeft ? 9 : -9;
currentLeft += step;
if (Math.abs(target - currentLeft) > Math.abs(step)) {
ele.style.left = currentLeft + 'px';
} else {
ele.style.left = target + 'px';
clearInterval(ele.timeId);
}
}, 30)
}
</script>
</body>
</html>
|