DOM
概念
所谓DOM,全称 Docuemnt Object Model 文档对象模型
DOM 为文档提供了结构化表示,并定义了如何通过脚本来访问文档结构。目的其实就是为了能让js操作html元素而制定的一个规范。
解析过程
HTML加载完毕,渲染引擎会在内存中把HTML文档,生成一个DOM树,getElementById是获取内中DOM上的元素节点。然后操作的时候修改的是该元素的属性。
DOM树(一切皆是节点)
在HTML当中,一切都是节点:
- 元素节点:HMTL标签。
- 文本节点:标签中的文字(比如标签之间的空格、换行)
- 属性节点::标签的属性
整个html文档就是一个文档节点。所有的节点都是Object。
DOM可以做什么
- 找对象(元素节点)
- 设置元素的属性值
- 设置元素的样式
- 动态创建和删除元素
- 事件的触发响应:事件源、事件、事件的驱动程序
清楚DOM的结构
- 获取文档对象:document
- 获取html:document.documentElement
- 获取body: document.body
获取其它DOM(事件源)的三种方式
var oDiv1 = document.getElementById("box1"); //方式一:通过id获取单个标签 var oDiv2 = document.getElementsByTagName("div")[0]; //方式二:通过 标签名 获得 标签数组,所以有s var oDiv3 = document.getElementsByClassName("box")[0]; //方式三:通过 类名 获得 标签数组,所以有s
事件
JS是事件驱动为核心的一门语言
事件的三要素:事件源、事件、事件驱动程序
谁引发的后续事件,谁就是事件源
-
代码书写步骤如下:
-
(1)获取事件源:
document.getElementById(“box”);
//类似与ios语言的UIButton *adBtn = [UIButton buttonWithType:UIButtonTypeCustom];
-
(2)绑定事件: 事件源box.事件onclick = function(){ 事件驱动程序 };
-
(3)书写事件驱动程序:关于DOM的操作
常用事件:
绑定事件的方式
直接绑定匿名函数
var oDiv = document.getElementById("box"); //绑定事件的第一种方式 oDiv.onclick = function () { alert("我是弹出的内容"); };
先单独定义函数,再绑定
var oDiv = document.getElementById("box"); //绑定事件的第二种方式 oDiv.onclick = fn; //注意,这里是fn,不是fn()。fn()指的是返回值。 //单独定义函数 function fn() { alert("我是弹出的内容"); };
行内绑定
<!--行内绑定--> <div id="box" onclick="fn()"></div> <script type="text/javascript"> function fn() { alert("我是弹出的内容"); } </script>
JavaScript入口函数 window.onload()
此函数调用,是当页面加载完毕(文档和图片)的时候,触发onload()函数,文档先加载,图片资源后加载
<script type="text/javascript"> window.onload = function () { console.log("alex"); //等页面加载完毕时,打印字符串 } </script>
js的加载是和html同步加载的,把使用元素的代码放在onload里,加载完html后再执行。
样式属性操作
对style标签中的属性进行操作,并且通过js控制盒模型的属性
(width,height等),控制盒子的显示隐藏(display:none|block),控制盒子的颜色切换(background:red|green)等等
<div id='box'></div> <script> window.onload = function(){ //1.获取事件源(事件对象,在文档中一切的标签都是对象) var oDiv = docuement.getElementById('box'); //2.事件 oDiv.onclick = function(){ //3.事件驱动程序 ps:记得 所有的style中使用的像margin-left 在js操作时都是用marginLeft属性进行赋值 oDiv.style.backgroundColor = 'yellow'; } }; </script>
值的操作
所谓值的操作,就是对前闭合标签和后闭合标签中间的文本内容的设置和获取。
- 双闭合标签: innerText或者innerHTML
- 单闭合标签:除了img标签,就剩input了,使用value进行赋值
<div id='box'></div> <input type='text' value = 'alex' id='user'> <script> window.onload = function(){ //1.获取事件源(事件对象,在文档中一切的标签都是对象) var oDiv = docuement.getElementById('box'); var oInput = docuement.getElementById('user'); //2.事件 oDiv.onclick = function(){ //3.事件驱动程序 oDiv.innerText = 'alex';//仅仅设置文本内容 oDiv.innerHTML = '<h1>alex</h1>';//将标签和文本内容一起解析 }; //2.事件 oInput.onclick = function(){ //3.事件驱动程序 只有有value属性的 才能使用value赋值和设置值 oInput.value = 'wusir'; } }; </script>
标签属性操作
所谓标签属性,就是对标签中(字面上看到的)属性的操作。比如像每个标签中id,class,title、img
标签的src属性和alt属性、a标签的href属性、input标签中的name、type属性等等
<script> //window.onload页面加载完毕以后再执行此代码 window.onload = function () { //需求:鼠标放到img上,更换为另一张图片,也就是修改路径(src的值)。 //步骤: //1.获取事件源 //2.绑定事件 //3.书写事件驱动程序 //1.获取事件源 var oImg = document.getElementById("box"); //2.绑定事件(悬停事件:鼠标进入到事件源中立即出发事件) oImg.onmouseover = function () { //3.书写事件驱动程序(修改src) img.src = "image/jd2.png"; // this.src = "image/jd2.png"; } //2.绑定事件(悬停事件:鼠标进入到事件源中立即出发事件) oImg.onmouseout = function () { //3.书写事件驱动程序(修改src) img.src = "image/jd1.png"; } } </script>
元素显示和隐藏的两种方式
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style type="text/css"> #box{ 100px; height:200px; background-color:red; } .active{ display:none; } </style> </head> <body> <buttom id="btn">隐藏</buttom> <div id="box" class="box active"></div> <script type="text/javascript"> window.onload = function(){ function $(id){ return document.getElementById(id); } var isShow = true; $('btn').onclick = function(){ if(isShow){ //通过控制样式属性的display 属性来对盒子的显示与隐藏 $('box').style.display = 'none'; isShow = false; this.innerText = '显示'; }else{ $('box').style.display = 'block'; this.innerText = '隐藏'; isShow = true; } } //方案二:切换初始化时会有渲染开销,网页中频繁切换,建议使用这种方式 // 在js 中设置类,需要用className var isShow = true; $('btn').onclick = function () { if (isShow){ $('box').className += ' active'; this.innerText = '显示'; isShow = false; }else{ $('box').className='box'; this.innerText = '隐藏'; isShow = true; } } } </script> </body> </html>
节点的操作
创建节点
新的标签(元素节点) = document.createElement("标签名");
比如,如果我们想创建一个li标签,或者是创建一个不存在的adbc标签,可以这样做:
<script type="text/javascript"> var a1 = document.createElement("li"); //创建一个li标签 var a2 = document.createElement("adbc"); //创建一个不存在的标签 console.log(a1); console.log(a2); console.log(typeof a1); console.log(typeof a2); </script>
插入节点
插入节点有两种方式,它们的含义是不同的。
方式1:
父节点.appendChild(新的子节点);
解释:父节点的最后插入一个新的子节点。
方式2:
父节点.insertBefore(新的子节点,作为参考的子节点);
- 在参考节点前插入一个新的节点。
- 如果参考节点为null,那么他将在父节点最后插入一个子节点。
删除节点
父节点.removeChild(子节点);
解释:用父节点删除子节点。必须要指定是删除哪个子节点。
自己删除自己
$('btn').onclick = function(){ this.parentNode.removeChild(this); }
DOM相关案例
1.模态框案例
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>模态框案例</title> <style type="text/css"> *{ margin:0; padding:0; } html,body{ 100%; height:100%; } #bg{ position:relative; top:0; left:0; 100%; height:100%; background-color:rgba(0,0,0,.3) } #login{ 300px; height:300px; border-radius: 3px; background-color: #fff; line-height:300px; text-align: center; margin:0 auto; position:relative; } #close{ position:absolute; right:0; top:0; 20px; height:20px; background-color: red; line-height:20px; text-align:center; color:green; cursor:pointer; } </style> </head> <body> <buttom id="btn">登录</buttom> <!--需求:打开页面,点击登录 显示一个背景图,中心弹出一个登录框,登录框右上角有关闭按钮 点击关闭;关闭登录框--> <script type="text/javascript"> function $(id) { return document.getElementById(id); } //1.点击登录按钮,弹出登录框 // 背景 var oBg = document.createElement('div'); //登录框 var oLogin = document.createElement('p'); //关闭按钮 var oClose = document.createElement('span'); oBg.id = 'bg'; oLogin.id = 'login'; oClose.id='close'; oClose.innerText = 'X'; oLogin.innerHTML = '登录成功弹出'; //追加 oBg.appendChild(oLogin); oLogin.appendChild(oClose); $('btn').onclick = function () { this.parentNode.appendChild(oBg); this.style.display = 'none'; //移除登录的字样 // this.parentNode.removeChild(this); }; oClose.onclick = function () { oBg.parentNode.removeChild(oBg); $('btn').style.display='inline-block'; } </script> </body> </html>
模拟hover选项卡
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style type="text/css"> button{ margin:10px; 100px; height:40px; cursor:pointer; } button.active{ background-color:green; } </style> </head> <body> <button class="active">按钮1</button> <button>按钮2</button> <button>按钮3</button> <button>按钮4</button> <button>按钮5</button> <script type="text/javascript"> //需求:鼠标悬浮哪个button上,该button变成绿色背景(添加类 active) var oBtns = document.getElementsByTagName('button'); for (var i = 0;i<oBtns.length;i++){ oBtns[i].onmouseover = function () { //重要:排它思想 //先把所有按钮的className设置为空,然后把(this)当前这个按钮的className 设置为active for(var j=0;j<oBtns.length;j++){ oBtns[j].className = ''; } this.className='active'; } } for(var i = 0;i<oBtns.length;i++){ oBtns[i].onmouseout = function () { this.className=''; } } </script> </body> </html>
tab栏选项卡
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style type="text/css"> *{ padding:0; margin:0; } ul{ list-style: none; } #tab{ 480px; margin:20px auto; border:1px solid red; } ul{ 100%; overflow: hidden; } #tab ul li{ float:left; 160px; height:60px; text-align: center; background-color: #ccc; } #tab ul li a{ 100%; height:100%; color:black; display: block; text-decoration: none; } #tab ul li.active{ background-color: red; } #tab p{ display:none; height:200px; text-align: center; line-height:200px; background-color:red; } #tab p.active{ display:block; } </style> </head> <body> <div id="tab"> <ul> <li class="active"> <a href="javascript:void(0)">首页</a> </li> <li > <a href="javascript:void(0)">新闻</a> </li> <li > <a href="javascript:void(0)">图片</a> </li> </ul> <p class="active">首页内容</p> <p>新闻内容</p> <p>图片</p> </div> <script type="text/javascript"> //需求:鼠标放上面,li上 li变色(添加类)对应下面的p也显示出来(添加类) //思路:1.点亮上面的盒子 2.利用索引值来显示下面的盒子 //esc6中使用let声明块级作用域 { let a = 10;//使用let后 作用域只在这个括号中有效 console.log(a); } var tabLi = document.getElementsByTagName('li'); var tabP = document.getElementsByTagName('p'); for(let i = 0;i<tabLi.length;i++){ tabLi[i].onclick = function(){ for(var j = 0;j <tabLi.length;j++){ tabLi[j].className=''; tabP[j].className=''; } this.className='active'; // tabP[i].className='active'; console.log(i); tabP[i].className='active'; } } </script> </body> </html>
client、offset、scroll系列
他们的作用主要与计算盒模型、盒子的偏移量和滚动有关
clientTop 内容区域到边框顶部的距离 ,边框的高度 clientLeft 内容区域到边框左部的距离,边框的宽度 clientWidth 内容区域+左右padding 可视宽度 clientHeight 内容区域+ 上下padding 可视高度
屏幕的可视区域
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> </head> <body> </body> <script type="text/javascript"> // 屏幕的可视区域 window.onload = function(){ // document.documentElement 获取的是html标签 console.log(document.documentElement.clientWidth); console.log(document.documentElement.clientHeight); // 窗口大小发生变化时,会调用此方法 window.onresize = function(){ console.log(document.documentElement.clientWidth); console.log(document.documentElement.clientHeight); } } </script> </html>
offset:偏移量
offsetWidth占位宽 内容+padding+border
offsetHeight占位高
offsetTop: 如果盒子没有设置定位 到body的顶部的距离,如果盒子设置定位,那么是以父辈为基准的top值
offsetLeft: 如果盒子没有设置定位 到body的左部的距离,如果盒子设置定位,那么是以父辈为基准的left值
<html> <head> <meta charset="UTF-8"> <title></title> <style type="text/css"> *{ padding: 0; margin: 0; } </style> </head> <body style="height: 2000px"> <div> <div class="wrap" style=" 300px;height: 300px;background-color: green"> <div id="box" style=" 200px;height: 200px;border: 5px solid red;position: absolute;top:50px;left: 30px;"> </div> </div> </div> </body> <script type="text/javascript"> window.onload = function(){ var box = document.getElementById('box'); /* offsetWidth占位宽 内容+padding+border offsetHeight占位高 offsetTop: 如果盒子没有设置定位 到body的顶部的距离,如果盒子设置定位,那么是以父辈为基准的top值 offsetLeft: 如果盒子没有设置定位 到body的左部的距离,如果盒子设置定位,那么是以父辈为基准的left值 * */ // console.log(box.offsetTop); console.log(box.offsetLeft); console.log(box.offsetWidth); console.log(box.offsetHeight); } </script> </html>
scroll
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> <style type="text/css"> *{padding: 0;margin: 0;} </style> </head> <body style=" 2000px;height: 2000px;"> <div style="height: 200px;background-color: red;"></div> <div style="height: 200px;background-color: green;"></div> <div style="height: 200px;background-color: yellow;"></div> <div style="height: 200px;background-color: blue;"></div> <div style="height: 200px;background-color: gray;"></div> <div id = 'scroll' style=" 200px;height: 200px;border: 1px solid red;overflow: auto;padding: 10px;margin: 5px 0px 0px 0px;"> <p>学习新技能,达成人生目标,开始用自己的力量影响世界学习新技能,达成人生目标,开始用自己的力量影响世界学习新技能,达成人生目标,开始用自己的力量影响世界学习新技能,达成人生目标,开始用自己的力量影响世界学习新技能,达成人生目标,开始用自己的力量影响世界学习新技能,达成人生目标,开始用自己的力量影响世界学习新技能,达成人生目标,开始用自己的力量影响世界学习新技能,达成人生目标,开始用自己的力量影响世界学习新技能,达成人生目标,开始用自己的力量影响世界学习新技能,达成人生目标,开始用自己的力量影响世界学习新技能,达成人生目标,开始用自己的力量影响世界学习新技能,达成人生目标,开始用自己的力量影响世界 </p> </div> </body> <script type="text/javascript"> window.onload = function(){ //实施监听滚动事件 触动此方法,这个宽度包含border的宽度 window.onscroll = function(){ // console.log(1111) // console.log('上'+document.documentElement.scrollTop) // console.log('左'+document.documentElement.scrollLeft) // console.log('宽'+document.documentElement.scrollWidth) // console.log('高'+document.documentElement.scrollHeight) }; var s = document.getElementById('scroll'); s.onscroll = function(){ // scrollHeight : 内容的高度+padding 不包含边框 console.log('上'+s.scrollTop); console.log('左'+s.scrollLeft); console.log('宽'+s.scrollWidth); console.log('高'+s.scrollHeight); } } </script> </html>
定时器
在js中有两种定时器:
-
一次性定时器:setTimeout()
-
周期性循环定时器: setInterval()
setTimeout()
只在指定的时间后执行一次
/定时器 异步运行 function hello(){ alert("hello"); } //使用方法名字执行方法 var t1 = window.setTimeout(hello,1000); var t2 = window.setTimeout("hello()",3000);//使用字符串执行方法 window.clearTimeout(t1);//去掉定时器
setInterval()
在指定时间为周期循环执行
/实时刷新 时间单位为毫秒 setInterval('refreshQuery()',8000); /* 刷新查询 */ function refreshQuery(){ console.log('每8秒调一次') }
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style type="text/css"> #box{ 100px; height:100px; background-color: yellow; } </style> </head> <body> <div id="box">我的盒子</div> <button id ="animate">动画吧</button> <button id="clear">清除定时器</button> <script type="text/javascript"> /*console.log('开始'); //一次性定时器 2秒之后会执行回调函数,setTimeout()可以做异步操作 //如果对于数据的请求 出现数据阻塞的问题,那么可以考虑使用 setTime //来做异步操作 setTimeout(function () { console.log('走到尽头了'); },2000); console.log(22222);*/ //周期循环定时器 var oDiv = document.getElementById('box'); var oAnimate = document.getElementById('animate'); var num=0; let timer; oAnimate.onclick = function () { //用定时器时 先清定时器,再开定时器,页面不会出现时间叠加的问题 clearInterval(timer); timer = setInterval(function () { //控制盒子的步伐 num+=3; console.log(num); oDiv.style.marginLeft = num+'px'; },100); }; //clearInterval(handle?:long) //clearTimeout(handle?:long) var oClear = document.getElementById('clear'); oClear.onclick = function () { clearInterval(timer); } </script> </body> </html>