1.Dom的基本介绍
1.1 什么是DOM
文档对象模型,英文全称为Document Object Model,它提供了对文档的结构化的表述,并定义了一种方式可以使从程序中对该结构进行访问,从而改变文档的结构,样式和内容。
D:Document,文档,表示的整个Html的网页文档
O:Object, 对象,将网页的每一部分(标签)转换为每一个对象
M:Model,模型,使用模型来表示对象之间的关系,方便我们获取。
DOM 将文档解析为一个由节点和对象(包含属性和方法的对象)组成的结构集合。简言之,它会将web页面和脚本或程序语言连接起来,让脚本来操作页面,使用js代码将页面的样式,内容,结构修改。
通过一些js的方法来获取标签的对象(documet.getElementById()),然后调用属性和方法修改原来标签的样式和内容,结构。
1.2 DOM树
- 将HTMl文档以树状结构直观的表现出来,我们称之为
文档树或DOM树 - 作用:文档树直观的体现了标签与标签之间的关系
| document | 文档 | html页面代码 所有的html结构 |
|---|---|---|
| object | 对象 | 将html中每一个标签 都变成一个对象 |
| model | 模型 | 用另一种形式展示 |
-
window是浏览器窗口对象,所有东西都被当作是window的子对象
-
文档对象document 是window下的一个属性 代表整个DOM文档对象
-
根元素(root) html标签
-
文档树(dom树) 以HTML为根节点 形成的一棵倒立的树状结构,我们称作DOM树;这个树上所有的东西都叫节点,节点有很多类(节点共12类)
-
元素节点 标签
-
属性节点 属性
-
文本节点 内容
-
注释节点 注释
这些节点如果我们通过DOM方法去获取或者其它的操作去使用的话,就叫DOM对象
-
1.3 DOM对象如何创建的?
- 浏览器根据html标签生成的 JS 对象 (DOM对象)
- DOM的核心就是把内容当**
对象**来处理
1.4 Dom0,Dom1,Dom2,Dom3区别
前言:DOM(Document Object Model,文档对象模型)是针对HTML文档和XML(可扩展的标记语言)文档的一个API。DOM描绘了一个层次化的节点树,允许开发人员添加、移出和修改页面的某一部分,DOM脱胎于Netscape及微软公司创始的DHTML(动态HTML)。但现在它已经成为表现和操作页面标记的真正跨平台、语言中立的方式。
- Dom0
- Dom0级事件具有极好的跨浏览器优势,会以最快的速度绑定。
- 为某一个元素的同一个行为绑定不同的方法在行内会分别执行
- 为某一个元素的同一个行为绑定不同的方法在script标签中后面的方法会覆盖前面的方法
- 删除Dom0事件处理程序,只要将对应事件的属性设置为null即可
- Dom1
- Dom1一般只有设计规范没有具体实现,企业级应用无
- Dom2
- Dom2级事件是通过addEventListener绑定的事件,IE下的Dom2事件通过attachEvent绑定
- 可以给某个元素的同一个行为绑定不同的方法在行内会分别执行
- 删除Dom2事件处理程序通过removeEventListener
- Dom3
- Dom3级事件在Dom2级事件的基础上添加了更多的事件类型
- 允许开发人员自定义一些事件
2. Dom0事件绑定和解绑
-
不可以同时添加同一类事件多次,如果添加后面覆盖前面
-
dom0事件解绑 本质上就是把事件回调函数和事件对象的事件属性断开指向
box.onclick= null
3. Dom2事件绑定和解绑
前言:dom2事件添加和解绑高低浏览器使用的方法是不同的
高级浏览器才可以使用
-
事件的解绑
dom2事件解绑的时候,参数必须和绑定的时候一模一样
box.addEventListener('click',fn); btn.onclick = function(){ box.removeEventListener('click',fn); } -
低级浏览器
-
添加事件监听1
box.attachEvent('onclick',function(){}) //如果添加多个时间,那么也会依次执行,只不过执行顺序和高级浏览器相反 } -
添加事件监听2
function fn1(){ console.log('嘿嘿'); } box.attachEvent('onclick',fn1); -
解绑方式
function fn1(){ console.log('嘿嘿'); } box.attachEvent('onclick',fn1); btn.onclick = function(){ box.detachEvent('onclick',fn1); }
-
-
封装绑定事件
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> <style> *{ margin: 0; padding: 0; } #box{ width: 200px; height: 200px; background-color: red; } </style> </head> <body> <div id="box"></div> <button id="btn">点击解绑</button> <script type="text/javascript"> window.onload = function(){ var box = document.getElementById('box'); var btn = document.getElementById('btn'); //兼容封装高低浏览器添加事件绑定 //dom2事件高级浏览器用的是高级浏览器的添加方式 //低级浏览器用的是低级浏览器的添加方式 function addEvent(node,eventType,callBack){ if(node.addEventListener){ //高级浏览器node.addEventListener值是一个函数数据 node.addEventListener(eventType,callBack); }else{ //低级浏览器node.addEventListener值是一个undefined node.attachEvent('on' + eventType,callBack); } } function fn2(){ console.log('兼容成功'); } addEvent(box,'click',fn2); } </script> </body> </html> -
练习:封装解绑事件
4. 事件流
事件流:发生了事件之后的各个盒子的顺序
- 捕获事件流(网景) 最终很少用几乎不用
- 冒泡事件流(ie) 最终我们所用的事件传播都是冒泡
- 标准DOM事件流 这个是我们现用的标准事件流,里面包含三个阶段: 有捕获 再去获取目标元素 最后冒泡,这个三个阶段当中的捕获和冒泡可以由程序员自己选择。但是通常情况我们都是使用默认 (冒泡)
4.1 Dom0事件的事件流
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style>
*{
margin: 0;
padding: 0;
}
.laoda{
position: relative;
width: 500px;
height: 500px;
background-color: red;
}
.laoer{
position: absolute;
/*left: 0;
right: 0;
bottom: 0;
top: 0;
margin: auto;*/
left: 50%;
top: 50%;
transform: translate(-50%,-50%);
/*left: 50%;
top: 50%;
margin-left: -150px;
margin-top: -150px;*/
width: 300px;
height: 300px;
background-color: green;
}
.laomo{
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%,-50%);
width: 100px;
height: 100px;
background-color: blue;
}
</style>
</head>
<body>
<div class="laoda">
<div class="laoer">
<div class="laomo">
</div>
</div>
</div>
<script type="text/javascript">
window.onload = function(){
var laoda = document.querySelector('.laoda');
var laoer = document.querySelector('.laoer');
var laomo = document.querySelector('.laomo');
//dom0事件的事件流都是冒泡,没有捕获
//事件的事件流是客观存在的,和事件监听没关系;
laoda.onclick = function(){
console.log('我是老大');
};
laoer.onclick = function(){
console.log('我是老二');
};
laomo.onclick = function(){
console.log('我是老末');
};
}
</script>
</body>
</html>
4.2 事件流整体流程
window.onload = function(){
var laoda = document.querySelector('.laoda');
var laoer = document.querySelector('.laoer');
var laomo = document.querySelector('.laomo');
//dom0事件的事件流都是冒泡,没有捕获
//事件的事件流是客观存在的,和事件监听没关系;
laoda.onclick = function(){
console.log('我是老大');
};
laoer.onclick = function(){
console.log('我是老二');
};
laomo.onclick = function(event){
console.log('我是老末');
};
document.body.onclick = function(){
console.log('我是body');
};
document.documentElement.onclick = function(){
console.log('我是html');
};
document.onclick = function(){
console.log('我是祖宗');
}
}
4.3 Dom2事件的事件流
Dom2事件冒泡
- 高级浏览器:
window.onload = function(){
var laoda = document.querySelector('.laoda');
var laoer = document.querySelector('.laoer');
var laomo = document.querySelector('.laomo');
laoda.addEventListener('click',function(){
console.log('我是老大');
},false);
laoer.addEventListener('click',function(){
console.log('我是老二');
},false);
laomo.addEventListener('click',function(){
console.log('我是老末');
},false);
}
- 低级浏览器
- 样式有的版本会丢失,暂时不做过多关注
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style>
*{
margin: 0;
padding: 0;
}
#laoda{
position: relative;
width: 500px;
height: 500px;
background-color: red;
}
#laoer{
position: absolute;
/*left: 0;
right: 0;
bottom: 0;
top: 0;
margin: auto;*/
left: 50%;
top: 50%;
transform: translate(-50%,-50%);
/*left: 50%;
top: 50%;
margin-left: -150px;
margin-top: -150px;*/
width: 300px;
height: 300px;
background-color: green;
}
#laomo{
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%,-50%);
width: 100px;
height: 100px;
background-color: blue;
}
</style>
</head>
<body>
<div id="laoda">
<div id="laoer">
<div id="laomo">
</div>
</div>
</div>
<script type="text/javascript">
window.onload = function() {
var laoda = document.getElementById('laoda');
var laoer = document.getElementById('laoer');
var laomo = document.getElementById('laomo');
laoda.attachEvent('onclick', function() {
console.log('laoda');
});
laoer.attachEvent('onclick', function() {
console.log('laoer');
});
laomo.attachEvent('onclick', function() {
console.log('laomo');
})
}
</script>
</body>
</html>
Dom2事件捕获
window.onload = function(){
var laoda = document.querySelector('.laoda');
var laoer = document.querySelector('.laoer');
var laomo = document.querySelector('.laomo');
laoda.addEventListener('click',function(){
console.log('我是老大');
},true);
laoer.addEventListener('click',function(){
console.log('我是老二');
},true);
laomo.addEventListener('click',function(){
console.log('我是老末');
},true);
}
总结:dom0事件及低级浏览器的dom2事件(没有第三个参数)都是只有冒泡,以后我们用的最多的也是冒泡,捕获几乎不用,高级浏览器的dom2事件可以根据第三个参数选择是捕获还是冒泡,一般我们都不写,默认是冒泡
4.4 阻止冒泡
- Dom0阻止冒泡
<script type="text/javascript">
window.onload = function(){
var laoda = document.querySelector('.laoda');
var laoer = document.querySelector('.laoer');
var laomo = document.querySelector('.laomo');
//dom0事件的事件流都是冒泡,没有捕获
//事件的事件流是客观存在的,和事件监听没关系;
laoda.onclick = function(e){
console.log('我是老大');
e.stopPropagation();
};
laoer.onclick = function(e){
console.log('我是老二');
e.stopPropagation();
};
laomo.onclick = function(e){
console.log('我是老末');
e.stopPropagation();
};
}
</script>
- Dom2高级浏览器阻止冒泡
window.onload = function() {
var laoda = document.querySelector('.laoda');
var laoer = document.querySelector('.laoer');
var laomo = document.querySelector('.laomo');
laoda.addEventListener('click', function(e) {
console.log('我是老大');
e.stopPropagation();
}, false);
laoer.addEventListener('click', function(e) {
console.log('我是老二');
e.stopPropagation();
}, false);
laomo.addEventListener('click', function(e) {
console.log('我是老末');
e.stopPropagation();
}, false);
}
- Dom2低级浏览器阻止冒泡
<script type="text/javascript">
window.onload = function(){
var laoda = document.getElementById('laoda');
var laoer = document.getElementById('laoer');
var laomo = document.getElementById('laomo');
laoda.attachEvent('onclick',function(e){
console.log('laoda');
// e.stopPropagation();
e.cancelBubble = true;
});
laoer.attachEvent('onclick',function(e){
console.log('laoer');
// e.stopPropagation();
e.cancelBubble = true;
});
laomo.attachEvent('onclick',function(e){
console.log('laomo');
// e.stopPropagation();
e.cancelBubble = true;
})
}
</script>
5. 事件委派
5.1 什么是事件委派
- 事件委派过程当中依赖了事件冒泡
- 事件冒泡的好处就是可以进行事件委派(事件委托,事件代理);把子元素的事件监听添加给父(祖先)元素,把子元素发生的事件委托给父元素进行处理
5.2 事件委派用法
-
什么时候用?
- 当一个元素内部子元素(儿子)很多,并且每个子元素(儿子)都要添加相同的事件的时候,我们可以使用事件委派来提高效率
- 出现新添加的东西,并且新添加的东西要和老的拥有同样的行为;此时我们就想事件委派;不用事件委派,老的身上会有想要的行为,而新添加的没有
-
用法?
- 事件委派的做法: 给父元素添加事件监听,不给元素本身添加,事件发生后通过event的target属性去找真正发生事件的目标元素进行处理
-
好处?
- 事件委派的好处:可以大大降低内存的占用,并且可以提高效率。
-
总结
事件委派其实是借用事件冒泡去做的,因为事件冒泡导致内部所有的元素发生事件都会冒泡到祖先身上,我们不在子元素身上去添加事件监听和处理,而是在共同的祖先身上去添加,让祖先去处理子元素发生的事件;祖先去处理其实就是通过事件对象当中的target 去获取到真正发生事件的子元素;对子元素进行处理
-
事件委派1
- 普通移入变色
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> </head> <body> <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> </ul> <script type="text/javascript"> window.onload = function() { var liNodes = document.querySelectorAll('li'); for (var i = 0; i < liNodes.length; i++) { liNodes[i].onmouseover = function() { this.style.backgroundColor = 'hotpink'; }; liNodes[i].onmouseout = function() { this.style.backgroundColor = 'white'; }; } } </script> </body> </html>- 事件委派变色
window.onload = function(){ //2、事件委派写法(子元素(儿子)很多) //事件监听添加给共有的父(祖先)元素 //事件发生在子元素(儿子)身上的时候,会自动冒泡到父元素(爹)身上 //父元素(爹)感受到事件发生后,再回过头去找到发生事件的子元素(儿子) // 进行处理 var ulNode = document.querySelector('ul'); ulNode.onmouseover = function(e){ //找到真正发生事件的儿子 目标元素 //目标元素是藏在事件对象当中的 //事件对象当中target属性就是发生事件的目标元素 // (代表的是最内部的一个) console.log(e); if(e.target.nodeName === 'LI'){//不加if有可能拿到的就是爹 //这个判断事件委派一般都会有,为了确保目标元素是我们找到的那个元素 e.target.style.backgroundColor = 'hotpink'; } }; ulNode.onmouseout = function(e){ if(e.target.nodeName === 'LI'){ e.target.style.backgroundColor = 'white'; } }; }- 移入标签不是最内层标签
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> </head> <body> <ul> <li>我是列表项1</li> <li>我是列表项2</li> <li>我是列表项3</li> <li>我是列表项4</li> <li>我是列表项5</li> <li>我是列表项6</li> <li>我是列表项7</li> <li><span>我是列表项8</span></li> </ul> <script type="text/javascript"> window.onload = function(){ var ulNode = document.querySelector('ul'); ulNode.onmouseover = function(e){ //找到真正发生事件的儿子 目标元素 //目标元素是藏在事件对象当中的 //事件对象当中target属性就是发生事件的目标元素(代表的是最内部的一个) console.log(e); if(e.target.nodeName === 'LI'){//不加if有可能拿到的就是爹 //这个判断事件委派一般都会有,为了确保目标元素是我们找到的那个元素 e.target.style.backgroundColor = 'hotpink'; }else if(e.target.parentElement.nodeName === 'LI'){ e.target.parentElement.style.backgroundColor = 'hotpink'; } }; ulNode.onmouseout = function(e){ if(e.target.nodeName === 'LI'){ e.target.style.backgroundColor = 'white'; }else if(e.target.parentElement.nodeName === 'LI'){ e.target.parentElement.style.backgroundColor = 'white'; } }; } </script> </body> </html> -
事件委派2
- 普通使用
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> </head> <body> <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> </ul> <button>点击添加</button> <script type="text/javascript"> window.onload = function(){ //本来有一些,然后还可能去动态添加一些新的 //老的和新的都要有相同的行为效果 //此时就想事件委派 // //1、先让原来的li可以移入变色 var liNodes = document.querySelectorAll('li'); var btn = document.querySelector('button'); var ulNode = document.querySelector('ul'); for(var i = 0; i < liNodes.length; i++){ liNodes[i].onmouseover = function(){ this.style.backgroundColor = 'hotpink'; }; liNodes[i].onmouseout = function(){ this.style.backgroundColor = 'white'; }; } //2、点击按钮添加新的 btn.onclick = function(){ var liNode = document.createElement('li'); liNode.innerHTML = '我是新的'; ulNode.appendChild(liNode); liNode.onmouseover = function(){ this.style.backgroundColor = 'hotpink'; }; liNode.onmouseout = function(){ this.style.backgroundColor = 'white'; }; } } </script> </body> </html>- 事件委派
<script type="text/javascript"> window.onload = function(){ //本来有一些,然后还可能去动态添加一些新的 //老的和新的都要有相同的行为效果 //此时就想事件委派 // //1、先让老的可以移入变色 var liNodes = document.querySelectorAll('li'); var btn = document.querySelector('button'); var ulNode = document.querySelector('ul'); //事件委派的写法 btn.onclick = function(){ var liNode = document.createElement('li'); liNode.innerHTML = '我是新的'; ulNode.appendChild(liNode); } ulNode.onmouseover= function(e){ if(e.target.nodeName === 'LI'){ e.target.style.backgroundColor = 'hotpink'; } }; ulNode.onmouseout = function(e){ if(e.target.nodeName === 'LI'){ e.target.style.backgroundColor = 'white'; } }; } </script>
6. 两对移入移出区别
-
onmouseover/onmouseout如果涉及到事件切换或者冒泡必须使用双o如果是一个父子元素模型,对父元素添加移入和移出,当鼠标移入父元素里面的子元素的时候,事件会移出然后再移入。也就是说事件元素会有切换;事件委派的时候,必须使用这一对,大部分的时候我们使用的事件流都是冒泡,冒泡一定会涉及到事件的切换,所以我们常用双o事件;
-
onmouseenter/onmouseleave如果是一个父子元素模型,对父元素添加移入和移出,当鼠标移入父元素里面的子元素的时候, 事件并没有移出然后再移入。也就是说事件元素没有切换;
-
企业级开发中大部分使用的是onmouseenter/onmouseleave 因为不会发生事件切换 不会影响动态效果
使用双o在部分浏览器下会发生卡顿现象。如果使用冒泡必须使用双o
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style>
*{
margin: 0;
padding: 0;
}
#box{
width: 300px;
height: 300px;
background-color: red;
}
#box1{
width: 150px;
height: 150px;
background-color: green;
}
</style>
</head>
<body>
<div id="box">
<div id="box1"></div>
</div>
<script type="text/javascript">
window.onload = function(){
var box = document.getElementById('box');
//如果从外部元素移入到内部元素有事件切换,可以区分出不同元素的
// box.onmouseover = function(){
// console.log('移入')
// };
//
// box.onmouseout= function(){
// console.log('移出')
// };
//如果从外部元素移入到内部元素没有事件切换,认为内部元素和外部元素就是同一个
box.onmouseenter = function(){
console.log('移入')
};
box.onmouseleave= function(){
console.log('移出')
};
}
</script>
</body>
</html>
2. Dom的基本使用
2.1 window.onload
window.onload window.onload是一个事件,在文档加载完成后能立即触发
window.onload = function () {
var div = document.getElementById("d");
div.style.color = "red";
};
2.2 事件三要素
| 事件源 | 事件的源头 是由谁触发的 btn |
|---|---|
| 事件类型 | 发生了什么事情 onclick |
| 事件的回调函数 | 函数没有调用就执行了 我们称之为回调函数 function |
事件三要素
- 事件源 (承受事件的对象)
- 事件类型onclick
- 事件处理回调函数 回调函数就是不需要调用就自己执行的函数
事件处理三大步
- 获取事件源DOM对象
- 添加对应事件监听(onclick)
- 书写处理回调
事件写好之后可以重复触发执行;
2.3 获取DOM对象的6种方式
2.3.1 返回一个对象
- document.getElementById
- document.querySelector
2.3.2 返回多个对象
- document.getElementsByTagName
- document.getElementsByClassName
- document.getElementsByName
- document.querySelectorAll
2.3.3 className
className 可以用来获取/修改类名
<p class="p1" id="pp">雨下整夜,我的爱如溢出就像雨水</p>
<button id="btn">按钮</button>
var pp = document.getElementById("pp");
var btn = document.getElementById("btn");
btn.onclick = function () {
pp.className = "p2";
};
2.3.4 checked (disabled)
<!-- 默认情况下是不选中 -->
<input type="checkbox" id="inp" />
<input type="checkbox" checked="checked" />
<input type="checkbox" checked="a" /> -->
<button id="btn">按钮</button>
<script>
var btn = document.getElementById("btn");
btn.onclick = function () {
// 当属性名字和属性值一致的时候 我们有很多种写的方式
// 所以呢为了规范书写
// 当属姓名和属性值一致的时候 eg: checked = "checked"
// 我们使用true和false的boolean来定义
var inp = document.getElementById("inp");
inp.checked = true; // 选中用true,不选中用false
};
disabled设置禁用(btn.disabled = "")设置为空字符串 , 如果不设置(任意字符都可以)
2.4 innerHtml&&innerText&&textContent
修改文本的三个属性
element.textContent 获取或修改元素中的文本内容
- 获取的是标签中的内容,不会考虑css样式 可以获取隐藏的内容
- 低级浏览器返回undefined
innerText获取内容时,会考虑css样式
- 通过innerText去读取CSS样式,会触发网页的重排(计算CSS样式)
- 当字符串中有标签时,会自动对标签进行转义
- --> \<li\>
- 低级浏览器也会正常显示
element.innerHTML 获取或修改元素中的html代码
可以直接向元素中添加html代码
innerHTML插入内容时,有被xss注入的风险
2.4.1 封装innerText&&textContent
// innerText
// textContent
function getOrsetContent(node, content) {
if (arguments.length == 1) {
return node.textContent || node.innerText;
} else if (arguments.length == 2) {
return node.textContent
? (node.textContent = content)
: (node.innerText = content);
}
}
var p = document.getElementById("pp");
getOrsetContent(p);
2.5 排他思想
2.5.1 解决策略1
<ul>
<li>重庆</li>
<li>成都</li>
<li>武汉</li>
<li>长沙</li>
<li>南京</li>
<li>杭州</li>
</ul>
var li_list = document.querySelectorAll("li");
// console.log(li_list);
// li_list.forEach((item, index, arr) => {
// item.addEventListener("click", function () {
// arr.forEach((item) => (item.innerHTML = "嘿嘿"));
// this.innerHTML = "哈哈";
// });
// });
for (var i = 0; i < li_list.length; i++) {
li_list[i].onclick = function () {
li_list.forEach((item) => (item.innerHTML = "嘿嘿"));
li_list[i].innerHTML = "哈哈";
};
}
2.5.2 解决策略2
<ul>
<li>哈哈1</li>
<li>哈哈2</li>
<li>哈哈3</li>
<li>哈哈4</li>
<li>哈哈5</li>
<li>哈哈6</li>
</ul>
var li_list = document.querySelectorAll("ul li");
for (var i = 0; i < li_list.length; i++) {
// 给每一个对象都添加一个属性
// 属性的名字叫做index 属性的值是i
li_list[i].index = i;
li_list[i].onclick = function () {
for (var j = 0; j < li_list.length; j++) {
li_list[j].innerHTML = "嘿嘿";
}
// 如果想在点击事件内部使用时间外部的i
// 那就可以使用这种策略
li_list[this.index].innerHTML = "666";
};
}
2.6 开关思想
使用flag,赋一个布尔值来改变 true | false
div {
width: 200px;
height: 200px;
margin: 100px auto;
border-radius: 50%;
border: 1px solid yellowgreen;
}
var flag = true;
var div = document.querySelector("div");
div.onclick = function () {
if (flag) {
this.style.backgroundColor = "yellow";
} else {
this.style.backgroundColor = "white";
}
flag = !flag;
};
2.7 鼠标事件
- onclick
- ondblclick
- oncontextmenu
- onmousemove
- onmouseover/onmouseout
- onmouseenter/onmouseleave
- onmousedown/onmouseup
2.8 键盘事件
- onkeyup
- onkeydown
- onfocus
- onblur
2.9 事件对象
event 事件
事件对象
- 事件对象是有浏览器在事件触发时所创建的对象,这个对象中封装了事件相关的各种信息
- 通过事件对象可以获取到事件的详细信息 比如:鼠标的坐标、键盘的按键..
- 浏览器在创建事件对象后,会将事件对象作为响应函数的参数传递, 所以我们可以在事件的回调函数中定义一个形参来接收事件对象
const box1 = document.getElementById("box1")
// box1.onmousemove = event => {
// console.log(event)
// }
box1.addEventListener("mousemove", event => {
console.log(event.clientX, event.clientY) // 获取鼠标坐标
box1.textContent = event.clientX + "," + event.clientY
})
2.10 冒泡
在DOM中存在着多种不同类型的事件对象
-
多种事件对象有一个共同的祖先 Event
-
event.target 触发事件的对象
-
event.currentTarget 绑定事件的对象(同this)
-
event.stopPropagation() 停止事件的传导
-
event.preventDefault() 取消默认行为
-
-
事件的冒泡(bubble) - 事件的冒泡就是指事件的向上传到 - 当元素上的某个事件被触发后,其祖先元素上的相同事件也会同时被触发 - 冒泡的存在大大的简化了代码的编写,但是在一些场景下我们并不希望冒泡存在 不希望事件冒泡时,可以通过事件对象来取消冒泡
<div id="box1"></div>
<div id="box2"></div>
#box1 {
width: 100px;
height: 100px;
background-color: greenyellow;
border-radius: 50%;
position: absolute;
}
#box2 {
width: 500px;
height: 500px;
background-color: orange;
}
/* 使小绿球可以跟随鼠标一起移动
事件的冒泡和元素的样式无关,之和结构相关 */
const box1 = document.getElementById("box1")
const box2 = document.getElementById("box2")
document.addEventListener("mousemove", (event) => {
box1.style.left = event.x + "px" // 注意拼接单位
box1.style.top = event.y + "px"
})
box2.addEventListener("mousemove", event => {
event.stopPropagation()
})
3. Dom节点操作
3.1 节点的概念
-
什么是节点
文档树所有包含的东西都可以称作节点;最关注的节点是元素(就是我们平时所说的标签)节点(head body title hr td tr。。)
-
常用的节点分类
- 元素节点--标签
- 文本节点--标签的内容
- 属性节点--标签的属性
- 注释节点--注释
3.2 节点类型
nodeType nodeName nodeValue
文本节点 3 #text 文本内容
元素节点 1 元素名大写 null
注释节点 8 #comment 注释内容
3.2.1 子节点和子元素节点
-
childNodes 拿到的是某个元素的子节点:包括子元素节点和文本子节点,如果有注释还有注释节点;
-
children 拿到的是某个元素的子元素节点
-
子节点:childNodes (儿子节点):
- 高级浏览器: 元素,文本(文本,空格,换行),注释
- 低版本浏览器: 元素,文本(不包括空格和换行),注释 (注释前后的空格是计算的,最后标签和结束标签之间的空格)
-
子元素节点: children(儿子元素):
- 高级浏览器:元素
- 低版本浏览器:元素,注释
3.3 获取节点的方式
<ul>
<li></li>
<li id='single'></li>
<li></li>
<ul>
let ul = document.querSelector('ul');
父子关系
-
获取ul内部的所有子节点
console.log(ul.childNodes);//拿到ul所有的子节点 (文本 元素 注释) -
获取ul内部的所有子元素节点
console.log(u.children);//拿到ul所有的子元素节点,低级浏览器还包含注释 -
获取ul的第一个子节点
console.log(ul.firstChild); -
获取ul的第一个子元素节点,但是只有高级浏览器认识
console.log(ul.firstElementChild); -
获取ul的最后一个子节点
console.log(ul.lastChild); -
获取ul的最后一个子元素节点,但是只有高级浏览器认识
console.log(ul.lastElementChild);
兄弟关系
let liNode = document.quersalary('#single')
-
获取li的上一个兄弟节点
console.log(liNode.previousSibling); -
获取li的上一个兄弟元素节点,但是只有高级浏览器认识
console.log(liNode.previousElementSibling); -
获取li的下一个兄弟节点
console.log(liNode.nextSibling); -
获取li的下一个兄弟元素节点,但是只有高级浏览器认识
console.log(liNode.nextElementSibling);
兼容性封装函数
兼容性封装函数 实现获取ul元素的第一个子元素节点
高级浏览器可以正常使用firstElementChild
低级浏览器想办法去使用别的方式拿到
function getFirstElementChild(node){
//如果有子元素节点就找到这个子元素节点,如果没有就返回null
if(node.firstElementChild){
//高级
return node.firstElementChild;
}else{
//低级
var result = node.firstChild;
while(result !== null && result.nodeType !== 1){
//如果前面不去判断null,result如果拿到是一个null,result.nodeType就会报错
result = result.nextSibling;//如果找到最后都没找到,会返回一个null
}
return result;
}
}
console.log(getFirstElementChild(ulNode));
3.4 二级菜单
* {
margin: 0;
padding: 0;
}
li {
list-style: none;
}
a {
text-decoration: none;
color: #666;
}
.list {
position: relative;
width: 200px;
height: 150px;
border: 1px solid #000;
margin: 100px;
}
.list > li {
width: 200px;
height: 50px;
line-height: 50px;
text-align: center;
background-color: aquamarine;
}
.list > li:nth-child(2n) {
border-bottom: 1px solid #000;
border-top: 1px solid #000;
box-sizing: border-box;
}
.list .listIn {
display: none;
}
.listIn {
position: absolute;
width: 200px;
height: 150px;
border: 1px solid #000;
left: 200px;
top: -1px;
}
.listIn li {
width: 200px;
height: 50px;
background-color: skyblue;
}
.listIn li:nth-child(2n) {
border-bottom: 1px solid #000;
border-top: 1px solid #000;
box-sizing: border-box;
}
.ling {
position: absolute;
left: 200px;
top: 0;
display: none;
}
<ul class="list">
<li>
<a href="#">男歌手</a>
<ul class="listIn">
<li>
<a href="#">汪苏泷</a>
<ul class="ling">
<li>123</li>
<li>123</li>
<li>123</li>
</ul>
</li>
<li><a href="#">李易峰</a></li>
<li><a href="#">林俊杰</a></li>
</ul>
</li>
<li>
<a href="#">女歌手</a>
<ul class="listIn">
<li><a href="#">ci_ci</a></li>
<li><a href="#">旺仔小乔</a></li>
<li><a href="#">王心凌</a></li>
</ul>
</li>
<li>
<a href="#">组合</a>
<ul class="listIn">
<li><a href="#">牛奶咖啡</a></li>
<li><a href="#">。。。</a></li>
<li><a href="#">。。。</a></li>
</ul>
</li>
</ul>
let list = document.querySelectorAll(".list > li");
let listIn_list = document.querySelectorAll(".list .listIn");
let ling_list = document.querySelectorAll('.listIn .ling');
for (var i = 0; i < list.length; i++) {
list[i].index = i;
list[i].onmouseenter = function () {
listIn_list[this.index].style.display = "block";
};
list[i].onmouseleave = function () {
listIn_list[this.index].style.display = "none";
};
}
for(var i = 0; i < ling_list.length; i++) {
listIn_list[i].index = i;
listIn_list[i].onmouseenter = function() {
console.log(ling_list[this.index]);
ling_list[this.index].style.display = 'block';
}
}
3.5 创建节点的三种方式
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<p>我是一个段落</p>
<button>添加h1</button>
</body>
</html>
3.5.1 动态添加节点
<script type="text/javascript">
window.onload = function(){
var btn = document.querySelector('button');
btn.onclick = function(){
//第一种动态添加节点,元素的方式,以后不用,因为会覆盖原本有的元素
document.write('<h1>我是标题</h1>');
}
}
</script>
3.5.2 使用innerHTML
说明:几个特殊元素的获取方式
1、html
document.documentElement2、body
document.body3、head
document.head
//直接写=会发生覆盖,因为它是把body里面的 内容修改为'<h1>我是标题</h1>'
//如果不想修改,必须使用+=才能添加元素
document.body.innerHTML += '<h1>我是标题</h1>';
document.body.innerHTML = document.body.innerHTML + '<h1>我是标题</h1>'
3.5.3 使用方法创建节点
//1、创建一个你想添加的元素 dom对象,但是创建好的这个对象并不在页面上
var h1Node = document.createElement('h1');
//2、把创建好的h1标签写内容
h1Node.innerHTML = '我是标题';
//3、经历完前两步,h1标签就已经准备好了,然后页面上想要看到,必须把h1添加给页面上已经存在的元素
document.body.appendChild(h1Node);//追加的意思就是末尾加
3.6 创建列表添加
3.6.1 获取列表渲染页面1
let arr = ["孙悟空", "猪八戒", "沙和尚", "白骨精", "唐僧", "玉兔公主"];
let str = "<ul>";
for (let i = 0; i < arr.length; i++) {
str += "<li>" + arr[i] + "</li>";
}
document.body.innerHTML = str;
3.6.2 获取列表渲染页面2
let arr = ["孙悟空", "猪八戒", "沙和尚", "白骨精", "唐僧", "玉兔公主"];
let ul = document.createElement('ul');
for(let i = 0; i < arr.length; i++) {
let li = document.createElement('li');
li.innerHTML = arr[i];
ul.append(li);
}
document.body.append(ul);
3.7 节点的增删改
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<ul>
<li>战狼2</li>
<li>黑客帝国</li>
<li>变形金刚</li>
<li>金刚狼</li>
<li>蜘蛛侠</li>
</ul>
</body>
</html>
3.7.1 添加
//从末尾加 追加
var ulNode = document.querySelector('ul');
var liNode = document.createElement('li');
liNode.innerHTML = '上海堡垒';
ulNode.appendChild(liNode);
//从其他位置加
var ulNode = document.querySelector('ul');
var liNode = document.createElement('li');
liNode.innerHTML = '上海堡垒';
var liNodeOld = document.querySelector('li:nth-child(4)');
ulNode.insertBefore(liNode,liNodeOld);
3.7.2 修改
var ulNode = document.querySelector('ul');
var liNodeOld = document.querySelector('li:nth-child(4)');
var liNode = document.createElement('li');
liNode.innerHTML = '钢铁侠';
ulNode.replaceChild(liNode,liNodeOld);
3.7.3 删除
//删除节点
var ulNode = document.querySelector('ul');
var liNodeOld = document.querySelector('li:nth-child(4)');
ulNode.removeChild(liNodeOld);
//删除整个ul 下面两种方式都可以
document.body.removeChild(ulNode);
ulNode.parentNode.removeChild(ulNode);
3.8 克隆
cloneNode() 方法对节点进行复制时,它会复制节点的所有特点包括各种属性
这个方法默认只会复制当前节点,而不会复制节点的子节点 可以传递一个 true 作为参数,这样该方法也会将元素的子节点一起复制
/* 点击按钮后,将id为l1的元素添加list2中 */
const list2 = document.getElementById("list2")
const l1 = document.getElementById("l1")
const btn01 = document.getElementById("btn01")
btn01.onclick = function () {
const newL1 = l1.cloneNode(true) // 用来对节点进行复制的
/*
使用 cloneNode() 方法对节点进行复制时,它会复制节点的所有特点包括各种属性
这个方法默认只会复制当前节点,而不会复制节点的子节点
可以传递一个true作为参数,这样该方法也会将元素的子节点一起复制
*/
newL1.id = "newL1"
list2.appendChild(newL1)
}
3.9 元素 css属性的操作
3.9.1 获取css属性
getComputedStyle 返回的结果都是带单位的,要修改需要使用parseInt或Number把单位去掉
const btn = document.getElementById("btn")
const box1 = document.querySelector(".box1")
btn.onclick = function () {
/*
getComputedStyle()
- 它会返回一个对象,这个对象中包含了当前元素所有的生效的样式
- 参数:
1. 要获取样式的对象
2. 要获取的伪元素
- 返回值:
返回的一个对象,对象中存储了当前元素的样式
- 注意:
样式对象中返回的样式值,不一定能来拿来直接计算
所以使用时,一定要确保值是可以计算的才去计算
*/
const styleObj = getComputedStyle(box1)
console.log(styleObj.width)
console.log(styleObj.left)
// console.log(parseInt(styleObj.width) + 100)
// box1.style.width = parseInt(styleObj.width) + 100 + "px"
// console.log(styleObj.backgroundColor)
const beforeStyle = getComputedStyle(box1, "::before") // 伪类需要使用两个参数的写法
// console.log(beforeStyle.color)
console.log(box1.firstElementChild)
}
最为常用的获取样式方法
clientHeight clientWidth 获取元素内部的宽度和高度(包括内容区和内边距)
offsetHeight offsetWidth 获取元素的可见框的大小(包括内容区、内边距和边框)
offsetLeft offsetTop 获取元素相对于其定位父元素的偏移量
offsetParent 获取元素的定位父元素 如果所有的元素都没有开启定位则返回body
scrollWidth scrollHeight 获取元素滚动区域的大小(一般是子盒子超出父盒子出现了滚动条,获取父元素的scrollWidth属性来获取滚动区域的大小)
scrollLeft scrollTop 获取或设置元素滚动条的偏移量
const btn = document.getElementById("btn");
const box1 = document.getElementById("box1");
btn.onclick = function () {
// console.log(box2.clientWidth);
// console.log(box2.clientHeight);
// console.log(box2.offsetWidth);
// console.log(box2.offsetHeight);
// console.log(box2.scrollWidth);
// console.log(box2.scrollHeight);
// console.log(box1.clientWidth);
// console.log(box1.clientHeight);
// console.log(box1.offsetWidth);
// console.log(box1.offsetHeight);
// console.log(box1.scrollHeight)
// console.log(box1.scrollWidth)
// console.log(box1.offsetParent)
// console.log(box1.offsetLeft);
// console.log(box1.offsetTop)
// console.log(box1.scrollTop)
};
3.9.2 修改css属性
- 第一种 直接通过元素的 style 来修改
const btn = document.getElementById("btn")
const box1 = document.querySelector(".box1")
btn.onclick = function () {
box1.className += " one" // 注意类名前面的空格,因为一个元素类与类之间有一个空格 <div class="one two"></div>
}
- 第二种 通过 classList (推荐)
classList
- add 添加
- remove 移除
- toggle 切换 (无则加,有则删)
- replace 替换
- contains 判断是否包含
let div = document.querySelector(".one");
let btn = document.querySelector('#btn');
btn.addEventListener('click', function() {
// div.className += ' two';
// div.classList.add('two'); // 添加
// div.classList.toggle('two'); // 切换
// div.classList.remove('one'); // 删除
// div.classList.replace('one', 'three'); // 替换
// console.log(div.classList.contains('one')); // 判断是否包含
})
3.10 综合案例
触发回车之后,把表单的内容动态创建li标签,所有的li标签移入变色
<input type="text" id="inp" />
let inp = document.querySelector("#inp");
function AddColor() {
this.style.backgroundColor = "pink";
}
function RemoveColor() {
this.style.backgroundColor = "";
}
inp.onkeyup = function (event) {
if (event.keyCode == 13) {
if (this.value.trim()) {
var ul = document.createElement("ul");
var li = document.createElement("li");
li.onmouseenter = AddColor;
li.onmouseleave = RemoveColor;
li.textContent = this.value;
ul.append(li);
document.body.append(ul);
}
}
};
4. event对象
onclick 鼠标事件 ondbclick 左键双击 oncontextmenu 右键单机 onmousemove 鼠标移动 onmouseenter 鼠标移入 onmouseleave 鼠标移出 onmouseover 鼠标移入 onmouseout 鼠标移出 onmousedown 按下 oncroll 滚轮
4.1 event概念,作用
系统给我们封装的,任何事件都会有这个event对象,这个对象当中封装了和这个事件相关的一切信息
4.2 event兼容性处理
如果是高级浏览器去调用函数的回调函数,它会把事件对象封装好传给回调函数的第一个形参;
如果是低版本浏览器去调用,它会把事件对象封装好作为window的一个属性 window.event;所以我们在去拿事件对象的时候,要兼容性去拿
event = event || window.event;
4.3 目标元素节点兼容处理
event.target|| event.srcElement
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<ul>
<li>我是列表项1</li>
<li>我是列表项2</li>
<li>我是列表项3</li>
<li>我是列表项4</li>
<li>我是列表项5</li>
<li>我是列表项6</li>
<li>我是列表项7</li>
<li><span>我是列表项8</span></li>
</ul>
<script type="text/javascript">
window.onload = function(){
var ulNode = document.querySelector('ul');
ulNode.onmouseover = function(e){
e = e || window.event;//兼容高低浏览器事件对象写法
var target = e.target || e.srcElement;
if(target.nodeName === 'LI'){//不加if有可能拿到的就是爹
target.style.backgroundColor = 'hotpink';
}else if(target.parentElement.nodeName === 'LI'){
target.parentElement.style.backgroundColor = 'hotpink';
}
};
ulNode.onmouseout = function(e){
e = e || window.event;
var target = e.target || e.srcElement;
if(target.nodeName === 'LI'){
target.style.backgroundColor = 'white';
}else if(target.parentElement.nodeName === 'LI'){
target.parentElement.style.backgroundColor = 'white';
}
};
}
</script>
</body>
</html>
5. 鼠标的三种位置
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style>
*{
margin: 0;
padding: 0;
}
#box{
width: 300px;
height: 300px;
margin: 50px;
background-color: red;
}
body{
height: 4000px;
}
</style>
</head>
<body>
<div id="box">
</div>
<script type="text/javascript">
var box = document.getElementById('box');
box.onclick = function(e) {
//鼠标的位置也是存在于事件对象当中
e = e || window.event;
console.log(e);
}
</script>
</body>
</html>
总结:
-
offsetX offsetY
拿的是鼠标相对自身元素的水平距离和垂直距离 相对的是自身元素左上角(以自身元素左上角为原点)
-
clientX& clientY
拿的是鼠标相对视口的 水平距离和垂直距离 相对的是视口的左上角(以视口左上角为原点)
-
pageX pageY
拿的是鼠标相对**页面(第一屏)**的水平距离和垂直距离 相对的是页面的左上角(以页面左上角为原点)
6. 鼠标跟随移动
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style>
*{
margin: 0;
padding: 0;
}
img{
position: absolute;
left: 0;
top: 0;
display: block;
width: 100px;
height: 50px;
}
</style>
</head>
<body>
<img src="img/1.jpg" alt="" />
<script type="text/javascript">
window.onload = function(){
//鼠标移动事件,移动一下,移动事件触发的次数是n次
//必须通过console打印去确定事件触发了多少次
var imgNode = document.querySelector('img');
document.onmousemove = function(e){
// console.log('移动')
// 鼠标的位置和图片定位相对的都是视口的原点位置
//拿到鼠标的位置,就是图片要移动的位置
e = e || window.event;
imgNode.style.left = e.clientX + 'px';
imgNode.style.top = e.clientY + 'px';
}
}
</script>
</body>
</html>
7. 定时器
-
单次定时器(延迟定时)
一般用来做延迟效果 定时炸弹
- 案例:求出结果延迟5秒打印
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<button>点击清除定时器</button>
<script type="text/javascript">
window.onload = function(){
//延迟定时器就是用来做延迟效果的
var a = 10;
var b = 20;
var c = a + b;
// console.log(c);
//5秒之后再去打印这个结果
//设置延迟定时器
var timer = setTimeout(function(){
console.log(c);
},5000);//延迟的时间以毫秒为单位,定时器返回的都是定时器设置的编号,这个编号对清除定时器有用
// console.log(timer);
//清除延迟定时器
var btn = document.querySelector('button');
btn.onclick = function(){
clearTimeout(timer);//参数代表的是设置定时器返回的定时器编号
}
}
</script>
</body>
</html>
-
循环定时器的设置和删除
和循环类似都是为了重复去做一件事 闹钟
-
案例:每隔3秒打印 老马
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> </head> <body> <button>点击清除</button> <script type="text/javascript"> var timer = setInterval(function(){ console.log('i love you~'); },2000); //循环定时器清除 var btn = document.querySelector('button'); btn.onclick = function(){ clearInterval(timer); } //无论是延迟定时器还是循环定时器,清除的时候都需要保存设置定时器的编号 //定义保存定时器的编号的变量,一定要定义成全局变量 //定时器编号的变量必须是全局变量,否则某些场合没办法清除定时器 </script> </body> </html> -
案例2:打印10次大哥之后清除定时器
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> </head> <body> <button>点击清除</button> <script type="text/javascript"> //设置循环定时器 //当打印次数10次,然后就不打印了 var n = 0; var timer = null; timer = setInterval(function(){ console.log('老马~'); n++; if(n === 10){ clearInterval(timer); } },2000); </script> </body> </html>
-
-
万年历
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<span></span>
<script type="text/javascript">
window.onload = function(){
function getDateAndTimeNow(){
var date = new Date();
var year = date.getFullYear();
var month = date.getMonth() + 1;
var day = date.getDate();
var time = date.toLocaleTimeString();
return '现在是:' + year + '年' + month + '月' + day + '日 '+ time;
}
var spanNode = document.querySelector('span');
setInterval(function(){
spanNode.innerHTML = getDateAndTimeNow();
},1000);
}
</script>
</body>
</html>
- 阅读协议
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<input type="button" value="确认(5s)" disabled="disabled"/>
<script type="text/javascript">
window.onload = function(){
var n = 5;
var inputNode = document.querySelector('input');
var timer = null;
timer = setInterval(function(){
n--;
if(n <= 0){
clearInterval(timer);
inputNode.value = '确认';
inputNode.disabled = false;
}else{
inputNode.value = '确认('+ n +'s)';
}
},1000);
}
</script>
</body>
</html>
- 定时器有时候是不准的(同步和异步)
- 单线程
- JavaScript是一门单线程的语言,因此,JavaScript在同一个时间只能做一件事,单线程意味着,如果在同个时间有多个任务的话,这些任务就需要进行排队,前一个任务执行完,才会执行下一个任务
- 为什么js设计是单线程
- JavaScript的单线程,与它的用途是有很大关系,我们都知道,JavaScript作为浏览器的脚本语言,主要用来实现与用户的交互,利用JavaScript,我们可以实现对DOM的各种各样的操作,如果JavaScript是多线程的话,一个线程在一个DOM节点中增加内容,另一个线程要删除这个DOM节点,那么这个DOM节点究竟是要增加内容还是删除呢?这会带来很复杂的同步问题,因此,JavaScript是单线程的
- 同步任务
- 同步任务是指在主线程上排队执行的任务,只有前一个任务执行完毕,才能继续执行下一个任务,当我们打开网站时,网站的渲染过程,比如元素的渲染,其实就是一个同步任务
- 异步任务
- 异步任务是指不进入主线程,而进入任务队列的任务,只有任务队列通知主线程,某个异步任务可以执行了,该任务才会进入主线程,当我们打开网站时,像图片的加载,音乐的加载,其实就是一个异步任务
- 定时器管理模块
- 队列
- 单线程
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<script type="text/javascript">
var a = 100;
console.log('赛马');
setTimeout(function(){
console.log('老马');
},4000)
for(var i = 0; i < 50000; i++){
for(var j = 0; j < 50000; j++){
a++;
}
}
</script>
</body>
</html>
面试题:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<script type="text/javascript">
var a = 100;
console.log('赛马');
setTimeout(function(){
console.log('老马');
},4000)
setTimeout(function(){
console.log('中马');
},2000)
for(var i = 0; i < 50000; i++){
for(var j = 0; j < 50000; j++){
a++;
}
}
</script>
</body>
</html>
4 js获取style中的样式
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<style type="text/css">
#box {
position: absolute;
left: 100px;
top: 100px;
width: 200px;
height: 200px;
background-color: red;
}
</style>
</head>
<body>
<div id="box">
</div>
<script>
var d = document.getElementById('box');
console.log(d.style.width);
console.log(d.style.backgroundColor);
</script>
</body>
</html>
4.1 Client系列 只读
- **clientWidth **拿的是盒子 内容 + padding的宽
- clientHeight拿的是盒子 内容 + padding的高
- clientLeft 拿的是盒子左边框大小
- clientTop 拿的是盒子上边框大小
4.2 Offset系列 只读
- offsetWidth
- 拿的是盒子 内容 + padding + border的宽
- offsetHeight
- 拿的是盒子 内容 + padding + border的高
- offsetLeft
- 拿的是元素的偏移量:可以认为就是拿的绝对定位left值
- 切记如果进行offsetLeft的值进行加法运算不允许添加px
- offsetTop
- 拿的是元素的偏移量:可以认为就是拿的绝对定位top值
4.3 Scroll系列
- scrollWidth 只读
- 当内容比盒子小的时候,拿的是盒子的clientWidth
- 当内容比盒子大的时候,拿的是内容的offsetWidth + 盒子的一侧内边距
- document.documentElement.scrollWidth
- scrollHeight 只读
- 当内容比盒子小的时候,拿的是盒子的clientHeight
- 当内容比盒子大的时候,拿的是内容的offsetHeight + 盒子的一侧内边距
- document.documentElement.scrollHeight
- scrollTop可读可写
- 拿的是盒子内容向上滚动的距离
- document.documentElement.scrollTop
- scrollLeft可读可写
- 拿的是盒子内容向左滚动的距离
- document.documentElement.scrollLeft
4.4 总结
-
元素的大小:宽和高的获取:以后我们拿元素的宽和高,先看元素有没有边框,如果没有边框,那么
clientWidth和offsetWidth是一样的,如果有边框,看你需要不,需要的话就用offsetWidth
不需要就用clientWidth; scrollWidth几乎不用
-
元素的位置(偏移量)的获取:以后需要获取元素的位置直接通过offsetLeft和offsetTop去获取,但是注意相对的参照元素是谁;(和绝对定位参照类似)
-
视口宽高求法(固定的)
- document.documentElement.clientWidth
- document.documentElement.clientHeight
4.5 案例
- 导航栏跟随
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style>
*{
margin: 0;
padding: 0;
}
#box{
width: 100%;
height: 60px;
background-color: red;
}
body{
height: 4000px;
}
</style>
</head>
<body>
<div id="box"></div>
<script type="text/javascript">
window.onload = function(){
var box = document.getElementById('box');
window.onscroll = function(){
//系统滚动的事件
//求视口的高度
//求内容往上滚动的距离
var H = document.documentElement.clientHeight;//求出视口的高度
//系统的内容滚动,有些浏览器认为滚动的是html的内容,有些浏览器认为滚动的是body的内容
//这里我们要兼容写法
var scrollDis = document.documentElement.scrollTop || document.body.scrollTop;
if(scrollDis >= H){
//如果内容滚动的距离大于等于视口的高度,那么就跟随
box.style.position = 'fixed';
box.style.left = 0;
box.style.top = 0;
}else{
//如果不大于就不跟随
box.style.position = 'static';
box.style.left = 0;
box.style.top = 0;
}
}
}
</script>
</body>
</html>
- 盒子来回移动
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style>
*{
margin: 0;
padding: 0;
}
#box{
position: absolute;
left: 0;
top: 0;
width: 100px;
height: 80px;
background-color: red;
}
</style>
</head>
<body>
<div id="box"></div>
<script type="text/javascript">
//求出盒子最新的位置,设置给盒子的left 就能让盒子动
// 盒子的新位置 = 盒子的原始位置 + 盒子要移动的距离差
var box = document.getElementById('box');
// setTimeout(function(){
// //第一步:拿到盒子原来的位置
// var eleX = box.offsetLeft;
// //第二步:求出现在准备要走的位置
// var lastX = eleX + 50;
// //第三步:把算出来的位置设置给box
// box.style.left = lastX + 'px';
//
// },3000)
var step = 3;
setInterval(function(){
//第一步:拿到盒子原来的位置
var eleX = box.offsetLeft;
//第二步:求出现在准备要走的位置
var lastX = eleX + step;
//在判定临界值,当达到左右临界的时候,往相反方向去走
if(lastX > document.documentElement.clientWidth - box.offsetWidth){
lastX = document.documentElement.clientWidth - box.offsetWidth;
step = -3;
}else if(lastX < 0){
lastX = 0;
step = 3;
}
//第三步:把算出来的位置设置给box
box.style.left = lastX + 'px';
},16)
</script>
</body>
</html>
5. 初始包含块
页面的第一屏
- 思考:子绝父不相的结果? body? html? 视口?
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style>
*{
margin: 0;
padding: 0;
}
#box{
position: absolute;
left: 0;
top: 0;
width: 200px;
height: 200px;
background-color: blue;
}
</style>
</head>
<body>
<div id="box"></div>
</body>
</html>
- 思考:html的某些特殊属性作用的位置
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style>
*{
margin: 0;
padding: 0;
}
html{
width: 500px;
height: 500px;
margin-left: 100px;
border: 10px solid black;
background-color: red;
/*html比较特殊,特殊原因它的部分属性作用的不是自己 而是document*/
/*doucument是网页最外层的元素,html文档当中没有任何标签表示它*/
}
</style>
</head>
<body>
<div id="box"></div>
</body>
</html>
- 思考:body某些特殊属性作用的位置
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style>
*{
margin: 0;
padding: 0;
}
html{
width: 500px;
height: 500px;
margin-left: 100px;
/* background-color: red; */
/*html比较特殊,特殊原因它的部分属性作用的不是自己 而是document*/
/*doucument是网页最外层的元素,html文档当中没有任何标签标示它*/
}
body{
width: 300px;
height: 3000px;
border: 10px solid yellow;
background-color: red;
/*body比较特殊,单独的给Body设置某些属性,作用的不是自己 而是document*/
/*doucument是网页最外层的元素,html文档当中没有任何标签表示它*/
}
</style>
</head>
<body>
<div id="box"></div>
</body>
</html>
- html和body同时拥有backgroundColor的时候
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style>
*{
margin: 0;
padding: 0;
}
html{
width: 500px;
height: 500px;
margin-left: 100px;
border: 10px solid black;
background-color: red;
/*html比较特殊,特殊原因它的部分属性作用的不是自己 而是document*/
/*doucument是网页最外层的元素,html文档当中没有任何标签标示它*/
}
body{
width: 300px;
height: 3000px;
border: 10px solid yellow;
background-color: blue;
/*body比较特殊,单独的给Body设置某些属性,作用的不是自己 而是document
如果html和body都设置了,那么html作用在document上,body作用自己身上
*/
/*doucument是网页最外层的元素,html文档当中没有任何标签标示它*/
}
</style>
</head>
<body>
<div id="box"></div>
</body>
</html>
- 观察初始包含块
- 初始包含块相对于浏览器第一屏大小一致的块状结构
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style>
*{
margin: 0;
padding: 0;
}
html{
width: 500px;
height: 500px;
margin-left: 100px;
border: 10px solid black;
background-color: red;
/*html比较特殊,特殊原因它的部分属性作用的不是自己 而是document*/
/*doucument是网页最外层的元素,html文档当中没有任何标签标示它*/
}
body{
width: 300px;
height: 3000px;
border: 10px solid yellow;
background-color: blue;
/*body比较特殊,单独的给Body设置某些属性,作用的不是自己 而是document*/
/*doucument是网页最外层的元素,html文档当中没有任何标签标示它*/
}
#box{
position: absolute;
left: 0;
top: 0;
width: 200px;
height: 200px;
background-color: red;
}
/*初始包含块:和浏览器第一屏大小一致的一个块状结构,称作初始包含块,元素子绝父不相的时候
其实相对的是初始包含块去做的定位,不是body也不是html也不是视口
* */
/*
以后,打开浏览器最外层的结构,首先是document,接着是初始包含块 , HTML , body
*/
</style>
</head>
<body>
<div id="box"></div>
</body>
</html>
6. 系统滚动条的控制
html和body这两个元素overflow的scroll属性,控制着系统的滚动条,系统的滚动条有两个,一个是body身上的,一个是document身上的。我们平时看到的那个滚动条是document身上的。如果我们想要控制系统滚动条哪个显示哪个关闭分以下情况:
- 单独的给body或者html 设置overflow:scroll 滚动条打开的全部都是document的
- 如果两个元素同时设置overflow属性,body设置的是scroll,html设置是hidden,那么document的滚动条被关闭,body身上的滚动条会打开,相反,body身上被关闭,document身上的被打开
- 如果两个元素同时设置overflow:hidden;那么系统的两个滚动条全部被关闭
- 如果两个都设置overflow:scroll,那么html会打开document身上的,而body会打开自己身上的滚动条
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style>
*{
margin: 0;
padding: 0;
}
html{
width: 500px;
height: 500px;
border: 10px solid black;
overflow: scroll;
}
body{
width: 300px;
height: 300000px;
border: 10px solid blue;
overflow: scroll;
}
/* 企业级开发中常用写法
html,body{
height:100%;
overflow:hidden;
}
*/
</style>
</head>
<body>
<div id="box">
<div id="box1"></div>
</div>
</body>
</html>
7. 鼠标拖拽基础
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style>
*{
margin: 0;
padding: 0;
}
#box{
position: absolute;
left: 0;
top: 0;
width: 150px;
height: 80px;
background-color: red;
}
</style>
</head>
<body>
<div id="box"></div>
<script type="text/javascript">
window.onload = function(){
var box = document.getElementById('box');
box.onmousedown = function(e){
e = e || window.event;
//按下的时候获取元素的初始位置和鼠标的初始位置
var eleX = box.offsetLeft;
var eleY = box.offsetTop;
var startX = e.clientX;
var startY = e.clientY;
box.onmousemove = function(e){
e = e || window.event;
//可以获取鼠标的结束位置
var endX = e.clientX;
var endY = e.clientY;
//求出鼠标的距离差
var disX = endX - startX;
var disY = endY - startY;
//求出元素移动的最终位置 = 元素的初始位置 + 鼠标的距离差
var lastX = eleX + disX;
var lastY = eleY + disY;
//把求出来的最终位置设置给元素
box.style.left = lastX + 'px';
box.style.top = lastY + 'px';
};
box.onmouseup = function(){
box.onmousemove = box.onmouseup = null;
}
}
}
</script>
</body>
</html>
基础拖拽问题:
- 鼠标拖动过快,会跑出元素,元素就不动
因为计算机跟不上你的速度,跑出盒子,盒子不动,因为事件添加在盒子身上,跑出去后事件就不在盒子身上触发了。包括在外部鼠标抬起,也是解绑不了盒子上的事件的,因为鼠标抬起也是在盒子身上添加的;解决:移动事件和抬起事件,最好添加给document
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style>
*{
margin: 0;
padding: 0;
}
#box{
position: absolute;
left: 0;
top: 0;
width: 150px;
height: 80px;
background-color: red;
}
</style>
</head>
<body>
<div id="box"></div>
<script type="text/javascript">
window.onload = function(){
var box = document.getElementById('box');
box.onmousedown = function(e){
e = e || window.event;
//按下的时候获取元素的初始位置和鼠标的初始位置
var eleX = box.offsetLeft;
var eleY = box.offsetTop;
var startX = e.clientX;
var startY = e.clientY;
document.onmousemove = function(e){
e = e || window.event;
//可以获取鼠标的结束位置
var endX = e.clientX;
var endY = e.clientY;
//求出鼠标的距离差
var disX = endX - startX;
var disY = endY - startY;
//求出元素移动的最终位置 = 元素的初始位置 + 鼠标的距离差
var lastX = eleX + disX;
var lastY = eleY + disY;
//把求出来的最终位置设置给元素
box.style.left = lastX + 'px';
box.style.top = lastY + 'px';
};
document.onmouseup = function(){
box.onmousemove = box.onmouseup = null;
}
}
}
</script>
</body>
</html>
-
在盒子当中写上文字,拖拽先选中文字,在拖拽,文字跟着走,盒子不动,放手盒子会瞬间到放手的位置
因为浏览器有默认行为,拖拽文字就是一个默认行为。解决:取消浏览器的默认行为
取消浏览器默认行为根据事件添加方式不同而不同
- dom0事件,那么在事件回调当中写上return false;
- dom2事件, 在事件回调当中添加e.preventDefault();
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style>
*{
margin: 0;
padding: 0;
}
#box{
position: absolute;
left: 0;
top: 0;
width: 150px;
height: 80px;
background-color: red;
}
</style>
</head>
<body>
<div id="box">张三</div>
<script type="text/javascript">
window.onload = function(){
var box = document.getElementById('box');
box.onmousedown = function(e){
e = e || window.event;
//按下的时候获取元素的初始位置和鼠标的初始位置
var eleX = box.offsetLeft;
var eleY = box.offsetTop;
var startX = e.clientX;
var startY = e.clientY;
document.onmousemove = function(e){
e = e || window.event;
//可以获取鼠标的结束位置
var endX = e.clientX;
var endY = e.clientY;
//求出鼠标的距离差
var disX = endX - startX;
var disY = endY - startY;
//求出元素移动的最终位置 = 元素的初始位置 + 鼠标的距离差
var lastX = eleX + disX;
var lastY = eleY + disY;
//把求出来的最终位置设置给元素
box.style.left = lastX + 'px';
box.style.top = lastY + 'px';
};
document.onmouseup = function(){
box.onmousemove = box.onmouseup = null;
}
return false;
}
}
</script>
</body>
</html>
-
在低版本浏览器当中在盒子当中写上文字,拖拽先选中文字,在拖拽会出现禁止拖拽的现象
因为低版本浏览器专门有这样的行为,禁止拖拽是低版本浏览器专属,解决:使用全局捕获,把鼠标后续的事件,强制拉回作用在元素身上,以后鼠标就只能作用在元素身上了,全局捕获有捕获就有释放,否则后果自负
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style>
*{
margin: 0;
padding: 0;
}
#box{
position: absolute;
left: 0;
top: 0;
width: 150px;
height: 80px;
background-color: red;
}
</style>
</head>
<body>
<div id="box">张三丰</div>
<script type="text/javascript">
window.onload = function(){
var box = document.getElementById('box');
box.onmousedown = function(e){
e = e || window.event;
//按下的时候获取元素的初始位置和鼠标的初始位置
var eleX = box.offsetLeft;
var eleY = box.offsetTop;
var startX = e.clientX;
var startY = e.clientY;
//全局捕获
box.setCapture&&box.setCapture();//只有低版本浏览器才会用到全局捕获
document.onmousemove = function(e){
e = e || window.event;
//可以获取鼠标的结束位置
var endX = e.clientX;
var endY = e.clientY;
//求出鼠标的距离差
var disX = endX - startX;
var disY = endY - startY;
//求出元素移动的最终位置 = 元素的初始位置 + 鼠标的距离差
var lastX = eleX + disX;
var lastY = eleY + disY;
//把求出来的最终位置设置给元素
box.style.left = lastX + 'px';
box.style.top = lastY + 'px';
};
document.onmouseup = function(){
document.onmousemove = document.onmouseup = null;
box.releaseCapture&&box.releaseCapture();//低版本浏览器释放全局捕获
}
return false;
}
}
</script>
</body>
</html>
7.1. 鼠标拖拽添加临界值
window.onload = function(){
var box = document.getElementById('box');
box.onmousedown = function(e){
e = e || window.event;
//按下的时候获取元素的初始位置和鼠标的初始位置
var eleX = box.offsetLeft;
var eleY = box.offsetTop;
var startX = e.clientX;
var startY = e.clientY;
//全局捕获
box.setCapture&&box.setCapture();//只有低版本浏览器才会用到全局捕获
document.onmousemove = function(e){
e = e || window.event;
//可以获取鼠标的结束位置
var endX = e.clientX;
var endY = e.clientY;
//求出鼠标的距离差
var disX = endX - startX;
var disY = endY - startY;
//求出元素移动的最终位置 = 元素的初始位置 + 鼠标的距离差
var lastX = eleX + disX;
var lastY = eleY + disY;
//添加临界值
if(lastX > document.documentElement.clientWidth - box.offsetWidth){
lastX = document.documentElement.clientWidth - box.offsetWidth
}else if(lastX < 0){
lastX = 0;
}
if(lastY > document.documentElement.clientHeight - box.offsetHeight){
lastY = document.documentElement.clientHeight - box.offsetHeight
}else if(lastY < 0){
lastY = 0;
}
//把求出来的最终位置设置给元素
box.style.left = lastX + 'px';
box.style.top = lastY + 'px';
};
document.onmouseup = function(){
document.onmousemove = document.onmouseup = null;
box.releaseCapture&&box.releaseCapture();//低版本浏览器释放全局捕获
}
return false;
}
}
7.2 鼠标拖拽吸附效果
window.onload = function(){
var box = document.getElementById('box');
box.onmousedown = function(e){
e = e || window.event;
//按下的时候获取元素的初始位置和鼠标的初始位置
var eleX = box.offsetLeft;
var eleY = box.offsetTop;
var startX = e.clientX;
var startY = e.clientY;
//全局捕获
box.setCapture&&box.setCapture();//只有低版本浏览器才会用到全局捕获
document.onmousemove = function(e){
e = e || window.event;
//可以获取鼠标的结束位置
var endX = e.clientX;
var endY = e.clientY;
//求出鼠标的距离差
var disX = endX - startX;
var disY = endY - startY;
//求出元素移动的最终位置 = 元素的初始位置 + 鼠标的距离差
var lastX = eleX + disX;
var lastY = eleY + disY;
//添加临界值
if(lastX > document.documentElement.clientWidth - box.offsetWidth - 50){
lastX = document.documentElement.clientWidth - box.offsetWidth
}else if(lastX < 50){
lastX = 0;
}
if(lastY > document.documentElement.clientHeight - box.offsetHeight - 50){
lastY = document.documentElement.clientHeight - box.offsetHeight
}else if(lastY < 50){
lastY = 0;
}
//把求出来的最终位置设置给元素
box.style.left = lastX + 'px';
box.style.top = lastY + 'px';
};
document.onmouseup = function(){
document.onmousemove = document.onmouseup = null;
box.releaseCapture&&box.releaseCapture();//低版本浏览器释放全局捕获
}
return false;
}
}
7.3 添加碰撞效果
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style>
*{
margin: 0;
padding: 0;
}
#box{
position: absolute;
left: 0;
top: 0;
width: 150px;
height: 80px;
background-color: red;
}
img{
position: absolute;
left: 0;
top: 0;
bottom: 0;
right: 0;
margin: auto;
width: 200px;
height: 100px;
}
</style>
</head>
<body>
<div id="box">老马</div>
<img src="img/1.jpg" alt="" />
<script type="text/javascript">
window.onload = function(){
var box = document.getElementById('box');
var imgNode = document.querySelector('img');
box.onmousedown = function(e){
e = e || window.event;
//按下的时候获取元素的初始位置和鼠标的初始位置
var eleX = box.offsetLeft;
var eleY = box.offsetTop;
var startX = e.clientX;
var startY = e.clientY;
//全局捕获
box.setCapture&&box.setCapture();//只有低版本浏览器才会用到全局捕获
document.onmousemove = function(e){
e = e || window.event;
//可以获取鼠标的结束位置
var endX = e.clientX;
var endY = e.clientY;
//求出鼠标的距离差
var disX = endX - startX;
var disY = endY - startY;
//求出元素移动的最终位置 = 元素的初始位置 + 鼠标的距离差
var lastX = eleX + disX;
var lastY = eleY + disY;
//添加临界值
if(lastX > document.documentElement.clientWidth - box.offsetWidth - 50){
lastX = document.documentElement.clientWidth - box.offsetWidth
}else if(lastX < 50){
lastX = 0;
}
if(lastY > document.documentElement.clientHeight - box.offsetHeight - 50){
lastY = document.documentElement.clientHeight - box.offsetHeight
}else if(lastY < 50){
lastY = 0;
}
//把求出来的最终位置设置给元素
box.style.left = lastX + 'px';
box.style.top = lastY + 'px';
//设置元素位置之后,然后判断是否发生碰撞
var boxL = lastX + box.offsetWidth;//求盒子在图片左侧的位置+自身宽度
var imgL = imgNode.getBoundingClientRect().left;//专门求元素相对视口的位置
var boxT = lastY + box.offsetHeight;
var imgT = imgNode.getBoundingClientRect().top;
var boxR = lastX;
var imgR = imgNode.getBoundingClientRect().left + imgNode.offsetWidth;
var boxB = lastY;
var imgB = imgNode.getBoundingClientRect().top + imgNode.offsetHeight;
if(boxL < imgL || boxT < imgT || boxR > imgR || boxB > imgB){
//碰不到
imgNode.src = 'img/1.jpg';
}else{
//碰到了
imgNode.src = 'img/2.jpg';
}
};
document.onmouseup = function(){
document.onmousemove = document.onmouseup = null;
box.releaseCapture&&box.releaseCapture();//低版本浏览器释放全局捕获
}
return false;
}
}
</script>
</body>
</html>
7.4 添加自定义滚动条
我们的页面架构首先要清楚
页面的最外层是document,紧接着是初始包含块,html, body,其次是我们的元素,我们禁止了系统的滚动条,(因为各大浏览器的系统滚动条风格不一,有可能会影响我们的页面布局),所以在body当中我们一般会有最外的一个盒子模拟body区域,在这个盒子的右侧会定位一个盒子模拟滚动条
- 原始页面
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style>
*{
margin: 0;
padding: 0;
}
html,body{
height: 100%;
overflow: hidden;
}
#wrap{
position: relative;
width: 100%;
height: 100%;
overflow: hidden;
}
#wrap .scrollBar{
position: absolute;
right: 0;
top: 0;
width: 30px;
height: 100%;
background-color: hotpink;
border-left: 1px solid greenyellow;
border-right: 1px solid greenyellow;
}
#wrap .scrollBar .scrollIn{
position: absolute;
left: 50%;
transform: translateX(-50%);
top: 0;
width: 26px;
height: 100px;
background-color: deepskyblue;
}
</style>
</head>
<body>
<div id="wrap">
<div class="scrollBar">
<div class="scrollIn"></div>
</div>
</div>
<script type="text/javascript">
</script>
</body>
</html>
- js实现
<script type="text/javascript">
//让滚动条滑块先动起来
window.onload = function(){
var scrollIn = document.querySelector('#wrap .scrollBar .scrollIn');
scrollIn.onmousedown = function(e){
e = e || window.event;
//按下的时候获取元素的初始位置和鼠标的初始位置
var eleY = scrollIn.offsetTop;
var startY = e.clientY;
//全局捕获
scrollIn.setCapture&&scrollIn.setCapture();//只有低版本浏览器才会用到全局捕获
document.onmousemove = function(e){
e = e || window.event;
//可以获取鼠标的结束位置
var endY = e.clientY;
//求出鼠标的距离差
var disY = endY - startY;
//求出元素移动的最终位置 = 元素的初始位置 + 鼠标的距离差
var lastY = eleY + disY;
//添加临界值
if(lastY > document.documentElement.clientHeight -scrollIn.offsetHeight){
lastY = document.documentElement.clientHeight - scrollIn.offsetHeight
}else if(lastY < 0){
lastY = 0;
}
//把求出来的最终位置设置给元素
scrollIn.style.top = lastY + 'px';
};
document.onmouseup = function(){
document.onmousemove = document.onmouseup = null;
scrollIn.releaseCapture&&scrollIn.releaseCapture();//低版本浏览器释放全局捕获
}
return false;
}
}
</script>
7.5 滚动条带内容移动
- 设置内容
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style>
*{
margin: 0;
padding: 0;
}
html,body{
height: 100%;
overflow: hidden;
}
#wrap{
position: relative;
width: 100%;
height: 100%;
overflow: hidden;
}
#wrap .content{
position: absolute;
left: 0;
top: 0;
}
#wrap .scrollBar{
position: absolute;
right: 0;
top: 0;
width: 30px;
height: 100%;
background-color: hotpink;
border-left: 1px solid greenyellow;
border-right: 1px solid greenyellow;
}
#wrap .scrollBar .scrollIn{
position: absolute;
left: 50%;
transform: translateX(-50%);
top: 0;
width: 26px;
height: 100px;
background-color: deepskyblue;
}
</style>
</head>
<body>
<div id="wrap">
<div class="content"></div>
<div class="scrollBar">
<div class="scrollIn"></div>
</div>
</div>
<script type="text/javascript">
//让滚动条滑块先动起来
window.onload = function(){
var scrollIn = document.querySelector('#wrap .scrollBar .scrollIn');
var content = document.querySelector('#wrap .content');
//模拟内容,给网页上写点内容
for(var i = 0; i < 200; i++){
content.innerHTML += i + '<br>';
// content.innerHTML = content.innerHTML + i + '<br>'
}
scrollIn.onmousedown = function(e){
e = e || window.event;
//按下的时候获取元素的初始位置和鼠标的初始位置
var eleY = scrollIn.offsetTop;
var startY = e.clientY;
//全局捕获
scrollIn.setCapture&&scrollIn.setCapture();//只有低版本浏览器才会用到全局捕获
document.onmousemove = function(e){
e = e || window.event;
//可以获取鼠标的结束位置
var endY = e.clientY;
//求出鼠标的距离差
var disY = endY - startY;
//求出元素移动的最终位置 = 元素的初始位置 + 鼠标的距离差
var lastY = eleY + disY;
//添加临界值
if(lastY > document.documentElement.clientHeight - scrollIn.offsetHeight){
lastY = document.documentElement.clientHeight - scrollIn.offsetHeight
}else if(lastY < 0){
lastY = 0;
}
//把求出来的最终位置设置给元素
scrollIn.style.top = lastY + 'px';
};
document.onmouseup = function(){
document.onmousemove = document.onmouseup = null;
scrollIn.releaseCapture&&scrollIn.releaseCapture();//低版本浏览器释放全局捕获
}
return false;
}
}
</script>
</body>
</html>
- 滚动条长度设置(注意样式中原本定死的滚动条)
- 自定义滚动条的万能比例: 滑块的高度 / 滑槽的高度 = 滑槽的高度 / 内容的高度 = 滑块滚动距离 / 内容的滚动距离
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style>
*{
margin: 0;
padding: 0;
}
html,body{
height: 100%;
overflow: hidden;
}
#wrap{
position: relative;
width: 100%;
height: 100%;
overflow: hidden;
}
#wrap .content{
position: absolute;
left: 0;
top: 0;
}
#wrap .scrollBar{
position: absolute;
right: 0;
top: 0;
width: 30px;
height: 100%;
background-color: hotpink;
border-left: 1px solid greenyellow;
border-right: 1px solid greenyellow;
}
#wrap .scrollBar .scrollIn{
position: absolute;
left: 50%;
transform: translateX(-50%);
top: 0;
width: 26px;
/*height: 100px;*/
background-color: deepskyblue;
}
</style>
</head>
<body>
<div id="wrap">
<div class="content"></div>
<div class="scrollBar">
<div class="scrollIn"></div>
</div>
</div>
<script type="text/javascript">
//让滚动条滑块先动起来
window.onload = function(){
var scrollIn = document.querySelector('#wrap .scrollBar .scrollIn');
var content = document.querySelector('#wrap .content');
//模拟内容,给网页上写点内容
for(var i = 0; i < 100; i++){
content.innerHTML += i + '<br>';
// content.innerHTML = content.innerHTML + i + '<br>'
}
//设置滑块的高度
// 自定义滚动条的万能比例:
// 滑块的高度 / 滑槽的高度 = 滑槽的高度 / 内容的高度 = 滑块滚动距离 / 内容的滚动距离
var scale = document.documentElement.clientHeight / content.offsetHeight;
var scrollHeight = document.documentElement.clientHeight * scale;
scrollIn.style.height = scrollHeight + 'px';
scrollIn.onmousedown = function(e){
e = e || window.event;
//按下的时候获取元素的初始位置和鼠标的初始位置
var eleY = scrollIn.offsetTop;
var startY = e.clientY;
//全局捕获
scrollIn.setCapture&&scrollIn.setCapture();//只有低版本浏览器才会用到全局捕获
document.onmousemove = function(e){
e = e || window.event;
//可以获取鼠标的结束位置
var endY = e.clientY;
//求出鼠标的距离差
var disY = endY - startY;
//求出元素移动的最终位置 = 元素的初始位置 + 鼠标的距离差
var lastY = eleY + disY;
//添加临界值
if(lastY > document.documentElement.clientHeight - scrollIn.offsetHeight){
lastY = document.documentElement.clientHeight - scrollIn.offsetHeight
}else if(lastY < 0){
lastY = 0;
}
//把求出来的最终位置设置给元素
scrollIn.style.top = lastY + 'px';
};
document.onmouseup = function(){
document.onmousemove = document.onmouseup = null;
scrollIn.releaseCapture&&scrollIn.releaseCapture();//低版本浏览器释放全局捕获
}
return false;
}
}
</script>
</body>
</html>
- 滚动条和内容联动(注意方向)
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style>
*{
margin: 0;
padding: 0;
}
html,body{
height: 100%;
overflow: hidden;
}
#wrap{
position: relative;
width: 100%;
height: 100%;
overflow: hidden;
}
#wrap .content{
position: absolute;
left: 0;
top: 0;
}
#wrap .scrollBar{
position: absolute;
right: 0;
top: 0;
width: 30px;
height: 100%;
background-color: hotpink;
border-left: 1px solid greenyellow;
border-right: 1px solid greenyellow;
}
#wrap .scrollBar .scrollIn{
position: absolute;
left: 50%;
transform: translateX(-50%);
top: 0;
width: 26px;
/*height: 100px;*/
background-color: deepskyblue;
}
</style>
</head>
<body>
<div id="wrap">
<div class="content"></div>
<div class="scrollBar">
<div class="scrollIn"></div>
</div>
</div>
<script type="text/javascript">
//让滚动条滑块先动起来
window.onload = function(){
var scrollIn = document.querySelector('#wrap .scrollBar .scrollIn');
var content = document.querySelector('#wrap .content');
//模拟内容,给网页上写点内容
for(var i = 0; i < 200; i++){
content.innerHTML += i + '<br>';
// content.innerHTML = content.innerHTML + i + '<br>'
}
//设置滑块的高度
// 自定义滚动条的万能比例:
// 滑块的高度 / 滑槽的高度 = 滑槽的高度 / 内容的高度 = 滑块滚动距离 / 内容的滚动距离
var scale = document.documentElement.clientHeight / content.offsetHeight;
var scrollHeight = document.documentElement.clientHeight * scale;
scrollIn.style.height = scrollHeight + 'px';
scrollIn.onmousedown = function(e){
e = e || window.event;
//按下的时候获取元素的初始位置和鼠标的初始位置
var eleY = scrollIn.offsetTop;
var startY = e.clientY;
//全局捕获
scrollIn.setCapture&&scrollIn.setCapture();//只有低版本浏览器才会用到全局捕获
document.onmousemove = function(e){
e = e || window.event;
//可以获取鼠标的结束位置
var endY = e.clientY;
//求出鼠标的距离差
var disY = endY - startY;
//求出元素移动的最终位置 = 元素的初始位置 + 鼠标的距离差
var lastY = eleY + disY;
//添加临界值
if(lastY > document.documentElement.clientHeight - scrollIn.offsetHeight){
lastY = document.documentElement.clientHeight - scrollIn.offsetHeight
}else if(lastY < 0){
lastY = 0;
}
//把求出来的最终位置设置给元素
scrollIn.style.top = lastY + 'px';
//添加内容滚动逻辑
// 滑槽的高度 / 内容的高度 = 滑块滚动距离 / 内容的滚动距离
var contentDis = lastY / scale;
content.style.top = -contentDis + 'px';
};
document.onmouseup = function(){
document.onmousemove = document.onmouseup = null;
scrollIn.releaseCapture&&scrollIn.releaseCapture();//低版本浏览器释放全局捕获
}
return false;
}
}
</script>
</body>
</html>
7.6 滚轮事件基础
区分上下
- ie/chrome : mousewheel(dom2的标准模式)
event.wheelDelta
上:120
下:-120
上和下指的是滚轮的方向
- firefox: DOMMouseScroll(dom2的标准模式)
event.detail
上:-3
下:3
上和下指的是滚轮的方向
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style>
*{
margin: 0;
padding: 0;
}
#box{
width: 300px;
height: 300px;
background-color: red;
}
</style>
</head>
<body>
<div id="box"></div>
<script type="text/javascript">
window.onload = function(){
var box = document.getElementById('box');
//IE/CHROME
box.addEventListener('mousewheel',scrollMove);
//fireFox
box.addEventListener('DOMMouseScroll',scrollMove);
//与其讲滚轮事件不如说在讲怎么区分滚轮是往下还是往上
//兼容性去处理回调函数
var flag = true;
function scrollMove(e){
e = e || window.event;
if(e.wheelDelta){
//ie或者chrome
if(e.wheelDelta > 0){
//往上
flag = true;
}else{
//往下
flag = false;
}
}else if(e.detail){
//火狐
if(e.detail > 0){
//往下
flag = false;
}else{
//往上
flag = true;
}
}
if(flag){
//不管什么浏览器,一定是往上滚的
box.style.height = box.offsetHeight - 10 + 'px';
}else{
//不管什么浏览器,一定是往下滚的
box.style.height = box.offsetHeight + 10 + 'px';
}
}
}
</script>
</body>
</html>
7.7 自定义滚动条添加滚轮事件
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style>
*{
margin: 0;
padding: 0;
}
html,body{
height: 100%;
overflow: hidden;
}
#wrap{
position: relative;
width: 100%;
height: 100%;
overflow: hidden;
}
#wrap .content{
position: absolute;
left: 0;
top: 0;
}
#wrap .scrollBar{
position: absolute;
right: 0;
top: 0;
width: 30px;
height: 100%;
background-color: hotpink;
border-left: 1px solid greenyellow;
border-right: 1px solid greenyellow;
}
#wrap .scrollBar .scrollIn{
position: absolute;
left: 50%;
transform: translateX(-50%);
top: 0;
width: 26px;
/*height: 100px;*/
background-color: deepskyblue;
}
</style>
</head>
<body>
<div id="wrap">
<div class="content"></div>
<div class="scrollBar">
<div class="scrollIn"></div>
</div>
</div>
<script type="text/javascript">
//让滚动条滑块先动起来
window.onload = function() {
var scrollIn = document.querySelector('#wrap .scrollBar .scrollIn');
var content = document.querySelector('#wrap .content');
//模拟内容,给网页上写点内容
for (var i = 0; i < 200; i++) {
content.innerHTML += i + '<br>';
//content.innerHTML = content.innerHTML + i + '<br>'
}
//设置滑块的高度
// 自定义滚动条的万能比例:
// 滑块的高度 / 滑槽的高度 = 滑槽的高度 / 内容的高度 = 滑块滚动距离 / 内容的滚动距离
var scale = document.documentElement.clientHeight / content.offsetHeight;
var scrollHeight = document.documentElement.clientHeight * scale;
scrollIn.style.height = scrollHeight + 'px';
//拖拽滑块相关的
scrollIn.onmousedown = function(e) {
e = e || window.event;
//按下的时候获取元素的初始位置和鼠标的初始位置
var eleY = scrollIn.offsetTop;
var startY = e.clientY;
//全局捕获
scrollIn.setCapture && scrollIn.setCapture(); //只有低版本浏览器才会用到全局捕获
document.onmousemove = function(e) {
e = e || window.event;
//可以获取鼠标的结束位置
var endY = e.clientY;
//求出鼠标的距离差
var disY = endY - startY;
//求出元素移动的最终位置 = 元素的初始位置 + 鼠标的距离差
var lastY = eleY + disY;
//添加临界值
if (lastY > document.documentElement.clientHeight - scrollIn.offsetHeight) {
lastY = document.documentElement.clientHeight - scrollIn.offsetHeight
} else if (lastY < 0) {
lastY = 0;
}
//把求出来的最终位置设置给元素
scrollIn.style.top = lastY + 'px';
//添加内容滚动逻辑
//滑槽的高度 / 内容的高度 = 滑块滚动距离 / 内容的滚动距离
var contentDis = lastY / scale;
content.style.top = -contentDis + 'px';
};
document.onmouseup = function() {
document.onmousemove = document.onmouseup = null;
scrollIn.releaseCapture && scrollIn.releaseCapture(); //低版本浏览器释放全局捕获
}
return false;
}
//滚动滚轮相关的
//IE/CHROME
document.addEventListener('mousewheel', scrollMove);
//fireFox
document.addEventListener('DOMMouseScroll', scrollMove);
//与其讲滚轮事件不如说在讲怎么区分滚轮是往下还是往上
//兼容性去处理回调函数
var flag = true;
function scrollMove(e) {
e = e || window.event;
if (e.wheelDelta) {
//ie或者chrome
if (e.wheelDelta > 0) {
//往上
flag = true;
} else {
//往下
flag = false;
}
} else if (e.detail) {
//火狐
if (e.detail > 0) {
//往下
flag = false;
} else {
//往上
flag = true;
}
}
if (flag) {
//不管什么浏览器,一定是往上滚的
//往上滚 滑块往上跑 内容往下跑
//滑槽的高度 / 内容的高度 = 滑块滚动距离 / 内容的滚动距离
var lastY = scrollIn.offsetTop - 10;
if (lastY < 0) {
lastY = 0;
}
scrollIn.style.top = lastY + 'px';
var contentDis = -scrollIn.offsetTop / scale;
content.style.top = contentDis + 'px';
} else {
//不管什么浏览器,一定是往下滚的
//往下滚 滑块往吓跑 内容往上跑
var lastY = scrollIn.offsetTop + 10;
if (lastY > document.documentElement.clientHeight scrollIn.offsetHeight) {
lastY = document.documentElement.clientHeight - scrollIn.offsetHeight
}
scrollIn.style.top = lastY + 'px';
var contentDis = -scrollIn.offsetTop / scale;
content.style.top = contentDis + 'px';
}
}
}
</script>
</body>
</html>