赞
踩
JavaScript = ECMAScript(JS基础) + DOM +BOM
本文旨在介绍DOM (Document Object Model) 和 BOM (Browser Object Model) 的基本概念和相关操作,以及如何利用它们来实现动态交互效果和特效开发。
在DOM部分中,我们将详细介绍节点操作,包括如何访问元素节点、节点之间的关系、如何改变元素节点的内容,以及节点的创建、移除和克隆等操作。我们还将介绍如何使用事件监听来处理各种事件,并探讨事件传播和事件对象的相关知识。
另外,我们将深入讨论定时器和延时器的用法,以及如何利用它们来实现动画效果。我们还会介绍一些常用的BOM对象,如window对象、Navigator对象、History对象和Location对象,以及如何利用它们来实现一些特效开发。
通过阅读本文,你将掌握DOM和BOM的基本概念和操作方法,了解如何利用它们来制作动态交互和特效效果,提升网页的用户体验和交互性。
请你继续阅读,深入了解DOM和BOM的精彩世界。
DOM(Document Object Model,文档对象模型)是JavaScript操作HTML文档的接口,使文档操作变得非常优雅、简便。
DOM最大的特点就是将文档表示为节点树
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Document</title> </head> <body> <h1>DOM基本概念</h1> <div> <h2>程序员的梦工厂</h2> <img src="logo.png"> <div class="box"> DOM节点树 </div> </div> </body> </html>
什么是document对象 ?
- document对象是DOM中最重要的东西,几乎所有DOM的功能都封装在了document对象中
- document对象也表示整个HTML文档,它是DOM节点树的根
- document对象的nodeType.属性值是9
<div id="box">我是一个盒子</div>
var oBox = document.getElementById('box'); //参数就是元素节点的id,注意不要写#号
<p> 我是段落1 </p>
<p> 我是段落2 </p>
<p> 我是段落3 </p>
var ps = document.getElementsByTagName('p'); //得到p标签的数组
var p2 = ps.getElementsByTagName('p')[1]; //得到第二个p标签
<div class="spec">
<p class="para"> 我是段落 </p>
<p> 我是段落 </p>
</div>
var spec_divs = document.getElementsByClassName('spec');//注意不要写.号
var p1 = spec.getElementsByClassName('para');
<div id="box">
<p>我是段落</p>
<p class="spec para">我是段落</p>
</div>
var the_p = document.querySelector('#box .spec');
<ul id="list1">
<li>我是li</li>
<li>我是li</li>
<li>我是li</li>
<li>我是li</li>
<li>我是li</li>
</ul>
<ul id="list2">
<li>我是li</li>
<li>我是li</li>
<li>我是li</li>
<li>我是li</li>
<li>我是li</li>
</ul>
var list1 = document.querySelectorAll('#list1 li'); //得到list1中li的内容
<div id="box">
<p>我是段落A</p>
<p>我是段落a</p>
<p id="para">我是段落B
<span>1</span>
<span id="sp">2</span>
<span>3</span>
</p>
<p>我是段落b</p>
<p>我是段落C</p>
<p>我是段落c</p>
</div>
var box = document.getElementById('box'); var para = document.getElementById('para'); // 1.封装第一个函数,这个函数可以返回元素的所有子元素节点(兼容到IE6) function getChildren(node){ // 结果数组 var children = []; // 遍历node这个节点的所有子节点,判断每一个子节点的nodeType的值 // 如果是1,就推入数组 for( var i =0; i < node.childNodes.length; i++){ if(node.childNodes[i].nodeType == 1){ children.unshift(node.childNodes[i]); } } return children; } console.log(getChildren(box)); console.log(getChildren(para)); // 2.封装第二个函数,这个函数可以返回元素的前一个元素兄弟节点(兼容到IE6),类似previousElementSibling的功能 function getElementPrevSibling(node){ var o = node; //使用while语句 while(o.previousSibling != null){ if(o.previousSibling.nodeType == 1){ //结束循环,找到了 return o.previousSibling; } // 让o成为它的前一个节点 o = o.previousSibling; } return null; } console.log(getElementPrevSibling(para)); console.log(getElementPrevSibling(sp)); // 3.封装第三个函数,这个函数可以返回元素的所有元素兄弟节点 function getAllElementSilbling(node){ // 前面的元素兄弟节点 var prevs = []; // 后面的元素兄弟节点 var nexts = []; var o = node; //遍历node前面的节点 while(o.previousSibling != null){ if(o.previousSibling.nodeType == 1){ prevs.push(o.previousSibling); } o = o.previousSibling; } //遍历node后面的节点 o = node; while (o.nextSibling != null){ if(o.nextSibling.nodeType == 1){ nexts.push(o.nextSibling); } o = o.nextSibling } return prevs.concat(nexts); } console.log(getAllElementSilbling(para));
<div id="box"></div>
oBox.innerHTML = 'innerHTML学习'; //输出innerHTML学习
oBox.innerHTML = '<ul><li>牛奶</li><li>咖啡</li></ul>'; //输出·牛奶 ·咖啡
oBox.innerText = 'innerText学习' ;//输出 innerText学习
oBox.innerText = '<ul><li>牛奶</li><li>咖啡</li></ul>' ; //输出<ul><li>牛奶</li><li>咖啡</li></ul>
document.createElement0方法用于创建一个指定tagname的HTML元素
新创建出的节点是“孤儿节点”,这意味着它并没有被挂载到DOM树上,我们无法看见它
必须继续使用appendChild()或insertBefore()方法将孤儿节点插入到DOM树上
appendChild():
父节点.appendChild(孤儿节点);
insertBefore():
父节点.insertBefore(孤儿节点,标杆节点);
示例:
<div id="box">
<p>我是原本的段落0</p>
<p>我是原本的段落1</p>
<p>我是原本的段落2</p>
</div>
//访问需要添加的节点(父节点)
var oBox = document.getElementById('box');
// 第一步: 创建孤儿节点
var oP = document.createElement('p');
//设置内部文字
oP.innerText = '我是新来的';
// 第二步: 上树 appendChild()方法
oBox.appendChild(oP);
// 第二步: 上树 insertBefore()方法
var oPs = oBox.getElementsByTagName('p');
oBox.insertBefore(oP.oPs[0]);
如果将已经挂载到DOM树上的节点成为appendChild()或者insertBefore()的参数,这个节点将会被移动
新父节点.appendChild(已经有父亲的节点);
新父节点.insertBefore(已经有父亲的节点,标杆子节点);
这意味着一个节点不能同时位于DOM树的两个位置
示例:
<div id="box1">
<p id="para">我是段落</p>
</div>
<div id="box2">
<p>我是box2的原有p1标签</p>
<p>我是box2的原有p2标签</p>
</div>
var box2 = document.getElementById('box2');
var para = document.getElementById('para');
var ps_box2 = box2.getElementsByTagName('p');
// box2.appendChild(para);
box2.insertBefore(para,ps_box2[1]);//将para插到box2的p2之前
removeChild()方法从DOM中删除一个子节点
节点不能主动删除自己,必须由父节点删除它
父节点.removeChild(要删除的节点);
box1.removeChild(para);
var 孤儿节点 = 老节点.cloneNode();
//相当于falsevar 孤儿节点 = 老节点.cloneNode(true);
oBox.style.cssText = "background-color: red; font-size: 32px;";
标准W3C属性,如src、href等,只需要打点进行更改即可
oImg.src = 'imgages/pic.jpg';
不符合W3C标准的属性,要使用setAttribute()和getAttribute()来设置、读取
bBox.setAttribute('data-n',10); //设置 (更改)
var n = oBox.getAttribute('data-n'); //读取
alert(n); //弹出10
事件 : 用户与网页的交互动作
监听 : 为了随时能够发现这个事件发生了,而执行预先编写的一些程序
最简单的设置事件监听的方法——设置它们的onxxx属性:
oBox.onclick = function(){
// 点击盒子时,将执行这里的语句
}
addEventListener()方法 addEventListener(type,listener,useCapture)
oBox.addEventListener('click',function(){
// 点击盒子时,将执行这里的语句
},true);
研究: 当盒子嵌套时事件监听的执行顺序 ? (鼠标点击中间盒子)
事件的传播顺序 : 先从外到内,再从内到外
事件捕获:当一个事件触发后,从window对象触发,不断经过下级的节点,直到目标节点,在事件到达目标节点之前的过程就是捕获过程,所有经过的节点,都会触发对应的事件.
事件冒泡:当事件到达目标节点后,会沿着捕获阶段的路线原路返回,同样所有经过的节点都会触发对应的事件.
结果2: 先捕获(box1 -> box2 -> box3) -> 再冒泡(box3 -> box2 -> box1) (√)
onxxx这样的写法只能监听冒泡阶段,捕获阶段需要用 addEventListener() 方法
注意事项:
oBox.onmousemove = function(e){}; //对象e就是这次事件的"事件对象"
e.clientX
e.preventDefault();
e.stopPropagation();
优点
原理
事件委托实现
e.target属性: 事件源元素,返回事件的目标节点
oBox.addEventListener('click',function(e){
e.target.style.backgroundColor = 'red'; //点击盒子时,盒子将变红
})
标准浏览器用 ev.target, IE浏览器用event.srcElement
e.currentTarget: 事件处理程序附加到的元素
使用场景
适用事件委托的事件
注意事项
setInterval()函数可以重复调用一个函数,在每次调用之间有固定的时间间隔
函数的参数
setInterval(function (a,b){
// 形式参数a的值是88,形式参数b的值是66
},2000,88,66);
具名函数也可以传入setInterval()
var a = 0
function fun(){
console.log(++a);
}
setInterval(fun,2000);//具名函数当中第一个参数,注意这里没有()
clearInterval()函数可以清除一个定时器
var a = 0;
//设置定时器,并且用变量timer接受这个定时器
var timer = setInterval(function(){
clearInterval(timer); //设表先关
console.log(++a);
},2000);
//点击按钮时,清除定时器
oBtn.onclick = function(){
clearInterval(timer); //清除定时器时,要传入定时器变量
}
设表先关 : 在多次点击按钮时会导致定时器叠加,数字会快速增加, 为了防止定时器叠加,我们应该在设置定时器时,也要清除之前的定时器
var timer = setTimeout(function(){ //这个函数会再两秒后执行一次 },2000);
clearInterval(timer);
setInterval() 和 setTimeout() 是两个异步语句
异步(asynchronous): 不会阻塞CPU继续执行其他语句,当异步完成时,会执行"回调函数"(callback)
使用定时器实现动画较为不便:
oList.innerHTML += oList.innerHTML;
var left = 0;
left = 0
,JS+CSS3结合实现动画
<a href="javascript:;" ></a>
点击a时不会刷新页面var idx = 0
,每触发一次点击事件,让idx++或者idx–),如果是,就要瞬间跳转到缓冲图片上,然后再过渡到真正要显示的下一张图片 oList.style.transition = 'none';
函数节流:一个函数执行一次后,只有大于设定的执行周期后才允许执行第二次,需要借助setTimeout()延时器
BOM(Browser Object Model,浏览器对象模型)是JS与浏览器窗口交互的接口
一些与浏览器改变尺寸、滚动条滚动相关的特效,都要借助BOM技术
window对象是当前JS脚本运行所处的窗口,而这个窗口中包含DOM结构,window.document属性就是document对象
在有标签页功能的浏览器中,每个标签都拥有自己的window对象;也就是说,同一个窗口的标签页之间不会共享一个window对象
全局变量会成为window对象的属性
内置函数普遍是window的方法
多个js文件之间是共享全局作用域的,即JS文件没有作用域隔离功能
窗口尺寸相关属性
document.documentElement.clientWidth
resize事件
在窗口大小改变之后,就会触发resize事件,可以用window.onresize或者window.addEventLinstener(‘resize’)来绑定事件处理函数
window.onresize = function (){
console.log('窗口宽度事件被触发了'+ window.innerWidth); //窗口宽度事件被触发了1613
}
已卷动高度
window.scrollY属性表示在垂直方向已滚动的像素值 (只读)
document.documentElement.scrollTop属性也表示窗口卷动高度(不是只读的)
var scrollTop = window.scrollY || document.documentElement.scrollTop; //提高网页兼容性的一种方式
scroll事件
在窗口被卷动之后,就会触发scroll事件,可以使用window.onscroll或者window.addEventListener(‘scroll’)来绑定事件处理函数
window.onscroll = function(){
console.log('窗口卷动事件被触发了'+window.scrollY); //窗口事件被触发了888
}
window.navigator属性可以检索navigator对象,它内部含有用户此次活动的浏览器的相关属性和表标识
console.log('浏览器官方名称:' + navigator.appName);//浏览器官方名称:Netscape
console.log('浏览器版本:' + navigator.appVersion);//浏览器版本:5.0
console.log('用户代理:' + navigator.userAgent); //用户代理:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36
console.log('用户操作系统:' + navigator.platform);//用户操作系统:Win32
history.back() 同于点击浏览器的回退按钮
<a href="javascript:history.back();">回退</a>
history.go(-1) 等同于history.back();
btn.onclick = function (){
history.go(-1);
}
window.location = 'https://www.csdn.net/';
window.location.reload(true);
*{ margin: 0; padding: 0; } .content-part{ width: 1200px; margin: 0 auto; margin-bottom: 30px; background-color: #aeaeae; font-size: 50px; padding: 20px; } .floornav{ position: fixed; right: 40px; top: 50%; margin-top: -120px; height: 240px; width:80px; background-color: greenyellow; } .floornav ul { list-style: none; } .floornav ul li{ width: 80px; height: 40px; font-size: 26px; line-height: 40px; text-align: center; cursor:pointer; } .floornav ul li.current{ background-color: pink; color:white;; }
<nav class="floornav" id="floornav"> <ul id="list"> <li data-n = '体育' class="current">体育</li> <li data-n = '科技'>科技</li> <li data-n = '视频'>视频</li> <li data-n = '娱乐'>娱乐</li> <li data-n = '新闻'>新闻</li> <li data-n = '美食'>美食</li> </ul> </nav> <section class="content-part" style="height: 400px" data-n = '体育'>体育栏目</section> <section class="content-part" style="height: 200px" data-n = '科技'>科技栏目</section> <section class="content-part" style="height: 300px" data-n = '视频'>视频栏目</section> <section class="content-part" style="height: 500px" data-n = '娱乐'>娱乐栏目</section> <section class="content-part" style="height: 600px" data-n = '新闻'>新闻栏目</section> <section class="content-part" style="height: 400px" data-n = '美食'>美食栏目</section>
// 使用事件委托给li添加监听 let list = document.getElementById('list'); let current = document.querySelector('.current'); let contenParts = document.querySelectorAll('.content-part'); let lis = document.querySelectorAll('#list li'); list.onclick = function (e){ if(e.target.tagName.toLowerCase() === 'li'){ // getAttribute表示得到标签身上的某个属性值 var n = e.target.getAttribute('data-n'); // 可以用属性选择器(就是方括号选择器)来寻找带有相同data-n的content-part let contentPart = document.querySelector('.content-part[data-n='+n+']'); //让页面的卷动自动成为这个盒子的offsetTop值 document.documentElement.scrollTop = contentPart.offsetTop; } } // 在页面加载好之后,将所有的content-part盒子的offsetTop值推入数组 var offsetTopArr = []; // 遍历所有的contentPart,将他们的净位置推入数组 for( var i= 0;i < contenParts.length; i++){ offsetTopArr.push(contenParts[i].offsetTop); } console.log(offsetTopArr); // 为了最后一项可以方便比较,我们可以推入一个无穷大 offsetTopArr.push(Infinity); //当前楼层 var nowfloor =-1; // 窗口的卷动 window.onscroll = function (){ // 遍历offsetTopArr数组,看看当前的scrollTop值在哪两个楼层之间 for(var i = 0;i<offsetTopArr.length;i++){ var scrolltop = document.documentElement.scrollTop; if(scrolltop >= offsetTopArr[i] && scrolltop < offsetTopArr[i+1]){ break; } } // 退出循环的时候,i是几,就表示当前楼层是几 console.log(i); // 如果当前所在楼层不是i,表示环楼了(也是一种节流机制) if(nowfloor !== i){ // 让全局变量改变为这个楼层号 nowfloor = i; //设置下标为i的项有current for (var j=0;j<lis.length;j++){ if(j===i){ lis[j].className = 'current'; }else{ lis[j].className = ''; } } } };
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。