Dom详细讲解

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.οnclick= 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值是一个undefinednode.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>我是列表项1li><li>我是列表项2li><li>我是列表项3li><li>我是列表项4li><li>我是列表项5li><li>我是列表项6li><li>我是列表项7li><li>我是列表项8li>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>我是列表项1li><li>我是列表项2li><li>我是列表项3li><li>我是列表项4li><li>我是列表项5li><li>我是列表项6li><li>我是列表项7li><li><span>我是列表项8span>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>我是列表项1li><li>我是列表项2li><li>我是列表项3li><li>我是列表项4li><li>我是列表项5li><li>我是列表项6li><li>我是列表项7li><li>我是列表项8li>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.οnmοuseοut= 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样式)
  • 当字符串中有标签时,会自动对标签进行转义
  • --> \
  • 低级浏览器也会正常显示

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>哈哈1li><li>哈哈2li><li>哈哈3li><li>哈哈4li><li>哈哈5li><li>哈哈6li>
ul>
var li_list = document.querySelectorAll("ul li");
for (var i = 0; i < li_list.length; i++) {// 给每一个对象都添加一个属性// 属性的名字叫做index  属性的值是ili_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');

父子关系

  1. 获取ul内部的所有子节点

    console.log(ul.childNodes);//拿到ul所有的子节点 (文本  元素 注释)
    
  2. 获取ul内部的所有子元素节点

    console.log(u.children);//拿到ul所有的子元素节点,低级浏览器还包含注释
    
  3. 获取ul的第一个子节点

    console.log(ul.firstChild);
    
  4. 获取ul的第一个子元素节点,但是只有高级浏览器认识

    console.log(ul.firstElementChild);
    
  5. 获取ul的最后一个子节点

    console.log(ul.lastChild);
    
  6. 获取ul的最后一个子元素节点,但是只有高级浏览器认识

    console.log(ul.lastElementChild);
    

兄弟关系

let liNode = document.quersalary(‘#single’)

  1. 获取li的上一个兄弟节点

    console.log(liNode.previousSibling);
    
  2. 获取li的上一个兄弟元素节点,但是只有高级浏览器认识

    console.log(liNode.previousElementSibling);
    
  3. 获取li的下一个兄弟节点

    console.log(liNode.nextSibling);
    
  4. 获取li的下一个兄弟元素节点,但是只有高级浏览器认识

    console.log(liNode.nextElementSibling);
    

兼容性封装函数

兼容性封装函数 实现获取ul元素的第一个子元素节点

高级浏览器可以正常使用firstElementChild

低级浏览器想办法去使用别的方式拿到

function getFirstElementChild(node){//如果有子元素节点就找到这个子元素节点,如果没有就返回nullif(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;
}

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>添加h1button>body>
html>
3.5.1 动态添加节点
<script type="text/javascript">window.onload = function(){var btn = document.querySelector('button');btn.onclick = function(){//第一种动态添加节点,元素的方式,以后不用,因为会覆盖原本有的元素document.write('

我是标题

'
); }} </script>
3.5.2 使用innerHTML

说明:几个特殊元素的获取方式

1、html document.documentElement

2、body document.body

3、head document.head

//直接写=会发生覆盖,因为它是把body里面的 内容修改为'

我是标题

'
//如果不想修改,必须使用+=才能添加元素 document.body.innerHTML += '

我是标题

'
; document.body.innerHTML = document.body.innerHTML + '

我是标题

'
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 = "
    ";for (let i = 0; i < arr.length; i++) {str += "
  • " + arr[i] + "
  • "
    ;} 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>战狼2li><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属性
  1. 第一种 直接通过元素的 style 来修改
const btn = document.getElementById("btn")
const box1 = document.querySelector(".box1")
btn.onclick = function () {box1.className += " one"    // 注意类名前面的空格,因为一个元素类与类之间有一个空格  
}
  1. 第二种 通过 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>我是列表项1li><li>我是列表项2li><li>我是列表项3li><li>我是列表项4li><li>我是列表项5li><li>我是列表项6li><li>我是列表项7li><li><span>我是列表项8span>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 总结
  1. 元素的大小:宽和高的获取:以后我们拿元素的宽和高,先看元素有没有边框,如果没有边框,那么

    clientWidth和offsetWidth是一样的,如果有边框,看你需要不,需要的话就用offsetWidth

    不需要就用clientWidth; scrollWidth几乎不用

  2. 元素的位置(偏移量)的获取:以后需要获取元素的位置直接通过offsetLeft和offsetTop去获取,但是注意相对的参照元素是谁;(和绝对定位参照类似)

  3. 视口宽高求法(固定的)

    1. document.documentElement.clientWidth
    2. 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;}//第三步:把算出来的位置设置给boxbox.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 + '
'
; // content.innerHTML = content.innerHTML + i + '
'
}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 + '
'
; // content.innerHTML = content.innerHTML + i + '
'
}//设置滑块的高度 // 自定义滚动条的万能比例: // 滑块的高度 / 滑槽的高度 = 滑槽的高度 / 内容的高度 = 滑块滚动距离 / 内容的滚动距离 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 + '
'
; // content.innerHTML = content.innerHTML + i + '
'
}//设置滑块的高度 // 自定义滚动条的万能比例: // 滑块的高度 / 滑槽的高度 = 滑槽的高度 / 内容的高度 = 滑块滚动距离 / 内容的滚动距离 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/CHROMEbox.addEventListener('mousewheel',scrollMove);//fireFoxbox.addEventListener('DOMMouseScroll',scrollMove);//与其讲滚轮事件不如说在讲怎么区分滚轮是往下还是往上//兼容性去处理回调函数var flag = true;function scrollMove(e){e = e || window.event;if(e.wheelDelta){//ie或者chromeif(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 + '
'
;//content.innerHTML = content.innerHTML + i + '
'
}//设置滑块的高度// 自定义滚动条的万能比例:// 滑块的高度 / 滑槽的高度 = 滑槽的高度 / 内容的高度 = 滑块滚动距离 / 内容的滚动距离 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/CHROMEdocument.addEventListener('mousewheel', scrollMove);//fireFoxdocument.addEventListener('DOMMouseScroll', scrollMove);//与其讲滚轮事件不如说在讲怎么区分滚轮是往下还是往上//兼容性去处理回调函数var flag = true;function scrollMove(e) {e = e || window.event;if (e.wheelDelta) {//ie或者chromeif (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>

8. 轮播图

8.1 轮播图逻辑点击按钮

原始页面:

DOCTYPE html>
<html><head><meta charset="UTF-8"><title>title><style>*{margin: 0;padding: 0;}ul,li{list-style: none;}img{display: block;/*vertical-align: middle;*/}a{text-decoration: none;}input{outline: none;}.clearFix:after{content: '';display: table;clear: both;}#box{position: relative;width: 600px;height: 300px;margin: 50px auto;overflow: hidden;}#box .list{width: 3000px;height: 300px;}#box .list li{float: left;width: 600px;height: 300px;}#box .list li img{width: 600px;height: 300px;}#box span{position: absolute;top: 50%;transform: translateY(-50%);width: 50px;height: 100px;background-color: rgba(200,200,200,.7);font-size: 50px;text-align: center;line-height: 100px;color: white;opacity: 0;transition: opacity 2s;}#box .left{left: 0;}#box .right{right: 0;}#box .iconList{position: absolute;left: 50%;transform: translateX(-50%);bottom: 10px;overflow: hidden;}#box .iconList li{float: left;width: 40px;height: 40px;margin-right: 10px;border-radius: 50%;background-color: gray;}#box .iconList li.current{background-color: red;}style>head><body><div id="box"><ul class="list"><li><img src="img/1.jpg"/>li><li><img src="img/2.jpg"/>li><li><img src="img/3.jpg"/>li><li><img src="img/4.jpg"/>li><li><img src="img/5.jpg"/>li>ul><span class="left">  <  span><span class="right">  >  span><ul class="iconList"><li class="current">li><li>li><li>li><li>li><li>li>ul>div><script type="text/javascript">window.onload = function(){var box = document.getElementById('box');var spanNodes = document.querySelectorAll('#box span');//移入box.onmouseenter= function(){spanNodes[0].style.opacity = 1;spanNodes[1].style.opacity = 1;};//移出box.onmouseleave = function(){spanNodes[0].style.opacity = 0;spanNodes[1].style.opacity = 0;};}script>body>
html>
  • 手动点击更换图片
     //点击右侧按钮图片动起来spanNodes[1].onclick = function(){//可以求出目前ul所在的位置var startX = ulNode.offsetLeft;//也可以知道移动的距离差 -600var disX = -600;//我们就可以求出点击一次移动的最终位置var lastX = startX + disX;//把求出的最终位置设置给ul,这样点击就已经能轮播了,但是是瞬变轮播ulNode.style.left = lastX + 'px';}
  • 点击平滑切换
				var ulNode = document.querySelector('#box .list');var timeAll = 600;//点击一次移动一张图片的距离所需要的总时间var stepTime = 20;//每都一步所需要的的时间var timer = null;//点击右侧按钮图片动起来spanNodes[1].onclick = function(){//可以求出目前ul所在的位置var startX = ulNode.offsetLeft;//也可以知道移动的距离差 -600var disX = -600;//我们就可以求出点击一次移动的最终位置var lastX = startX + disX;//把求出的最终位置设置给ul,这样点击就已经能轮播了,但是是瞬变轮播//如果要变成滑动就不能这样做,我们得让这个-600慢慢一步一步走;
//					ulNode.style.left = lastX + 'px';
//					用循环定时器模拟过度效果//求出每一步走的距离var stepDis = disX / (timeAll / stepTime);timer = setInterval(function(){var left = ulNode.offsetLeft + stepDis;//当慢慢移动到最后和瞬间移动到最后距离一样的时候,我们就清除定时器if(left === lastX){clearInterval(timer);}ulNode.style.left = left + 'px';},stepTime);}//点击左侧按钮spanNodes[0].onclick = function(){//可以求出目前ul所在的位置var startX = ulNode.offsetLeft;//也可以知道移动的距离差 -600var disX = 600;//我们就可以求出点击一次移动的最终位置var lastX = startX + disX;//把求出的最终位置设置给ul,这样点击就已经能轮播了,但是是瞬变轮播//如果要变成滑动就不能这样做,我们得让这个-600慢慢一步一步走;
//					ulNode.style.left = lastX + 'px';
//					用循环定时器模拟过度效果//求出每一步走的距离var stepDis = disX / (timeAll / stepTime);timer = setInterval(function(){var left = ulNode.offsetLeft + stepDis;//当慢慢移动到最后和瞬间移动到最后距离一样的时候,我们就清除定时器if(left === lastX){clearInterval(timer);}ulNode.style.left = left + 'px';},stepTime);}
  • 封装优化
				var ulNode = document.querySelector('#box .list');var timeAll = 600;//点击一次移动一张图片的距离所需要的总时间var stepTime = 20;//每都一步所需要的的时间var timer = null;//点击右侧按钮图片动起来spanNodes[1].onclick = function(){move(true);}//点击左侧按钮spanNodes[0].onclick = function(){move(false);}function move(flag){if(flag){var disX = -600;}else{var disX = 600;}//可以求出目前ul所在的位置var startX = ulNode.offsetLeft;//我们就可以求出点击一次移动的最终位置var lastX = startX + disX;//把求出的最终位置设置给ul,这样点击就已经能轮播了,但是是瞬变轮播//如果要变成滑动就不能这样做,我们得让这个-600慢慢一步一步走;//ulNode.style.left = lastX + 'px';//用循环定时器模拟过度效果//求出每一步走的距离var stepDis = disX / (timeAll / stepTime);timer = setInterval(function(){var left = ulNode.offsetLeft + stepDis;//当慢慢移动到最后和瞬间移动到最后距离一样的时候,我们就清除定时器if(left === lastX){clearInterval(timer);}ulNode.style.left = left + 'px';},stepTime);}

8.2 无限循环点击轮播

DOCTYPE html>
<html><head><meta charset="UTF-8"><title>title><style>*{margin: 0;padding: 0;}ul,li{list-style: none;}img{display: block;/*vertical-align: middle;*/}a{text-decoration: none;}input{outline: none;}.clearFix:after{content: '';display: table;clear: both;}#box{position: relative;width: 600px;height: 300px;margin: 50px auto;overflow: hidden;}#box .list{position: absolute;left: -600px;top: 0;width: 4200px;height: 300px;}#box .list li{float: left;width: 600px;height: 300px;}#box .list li img{width: 600px;height: 300px;}#box span{position: absolute;top: 50%;transform: translateY(-50%);width: 50px;height: 100px;background-color: rgba(200,200,200,.7);font-size: 50px;text-align: center;line-height: 100px;color: white;opacity: 0;transition: opacity 2s;}#box .left{left: 0;}#box .right{right: 0;}#box .iconList{position: absolute;left: 50%;transform: translateX(-50%);bottom: 10px;overflow: hidden;}#box .iconList li{float: left;width: 40px;height: 40px;margin-right: 10px;border-radius: 50%;background-color: gray;}#box .iconList li.current{background-color: red;}style>head><body><div id="box"><ul class="list"><li><img src="img/5.jpg"/>li><li><img src="img/1.jpg"/>li><li><img src="img/2.jpg"/>li><li><img src="img/3.jpg"/>li><li><img src="img/4.jpg"/>li><li><img src="img/5.jpg"/>li><li><img src="img/1.jpg"/>li>ul><span class="left">  <  span><span class="right">  >  span><ul class="iconList"><li class="current">li><li>li><li>li><li>li><li>li>ul>div><script type="text/javascript">window.onload = function(){var box = document.getElementById('box');var spanNodes = document.querySelectorAll('#box span');var ulNode = document.querySelector('#box .list');var timeAll = 600;//点击一次移动一张图片的距离所需要的总时间var stepTime = 20;//每都一步所需要的的时间var timer = null;//移入box.onmouseenter= function(){spanNodes[0].style.opacity = 1;spanNodes[1].style.opacity = 1;};//移出box.onmouseleave = function(){spanNodes[0].style.opacity = 0;spanNodes[1].style.opacity = 0;};//点击右侧按钮图片动起来spanNodes[1].onclick = function(){move(true);}//点击左侧按钮spanNodes[0].onclick = function(){move(false);}function move(flag){if(flag){var disX = -600;}else{var disX = 600;}//可以求出目前ul所在的位置var startX = ulNode.offsetLeft;//我们就可以求出点击一次移动的最终位置var lastX = startX + disX;//把求出的最终位置设置给ul,这样点击就已经能轮播了,但是是瞬变轮播//如果要变成滑动就不能这样做,我们得让这个-600慢慢一步一步走;
//					ulNode.style.left = lastX + 'px';
//					用循环定时器模拟过度效果//求出每一步走的距离var stepDis = disX / (timeAll / stepTime);timer = setInterval(function(){var left = ulNode.offsetLeft + stepDis;//当慢慢移动到最后和瞬间移动到最后距离一样的时候,我们就清除定时器if(left === lastX){clearInterval(timer);//无缝的逻辑if(left === -3600){left = -600;}else if(left === 0){left = -3000;}}ulNode.style.left = left + 'px';},stepTime);}}script>body>
html>

8.3 左右按钮联动小圆点变色

DOCTYPE html>
<html><head><meta charset="UTF-8"><title>title><style>*{margin: 0;padding: 0;}ul,li{list-style: none;}img{display: block;/*vertical-align: middle;*/}a{text-decoration: none;}input{outline: none;}.clearFix:after{content: '';display: table;clear: both;}#box{position: relative;width: 600px;height: 300px;margin: 50px auto;overflow: hidden;}#box .list{position: absolute;left: -600px;top: 0;width: 4200px;height: 300px;}#box .list li{float: left;width: 600px;height: 300px;}#box .list li img{width: 600px;height: 300px;}#box span{position: absolute;top: 50%;transform: translateY(-50%);width: 50px;height: 100px;background-color: rgba(200,200,200,.7);font-size: 50px;text-align: center;line-height: 100px;color: white;opacity: 0;transition: opacity 2s;}#box .left{left: 0;}#box .right{right: 0;}#box .iconList{position: absolute;left: 50%;transform: translateX(-50%);bottom: 10px;overflow: hidden;}#box .iconList li{float: left;width: 40px;height: 40px;margin-right: 10px;border-radius: 50%;background-color: gray;}#box .iconList li.current{background-color: red;}style>head><body><div id="box"><ul class="list"><li><img src="img/9.jpg"/>li><li><img src="img/17.jpg"/>li><li><img src="img/2.jpg"/>li><li><img src="img/3.jpg"/>li><li><img src="img/7.jpg"/>li><li><img src="img/9.jpg"/>li><li><img src="img/17.jpg"/>li>ul><span class="left">  <  span><span class="right">  >  span><ul class="iconList"><li class="current">li><li>li><li>li><li>li><li>li>ul>div><script type="text/javascript">window.onload = function(){var box = document.getElementById('box');var spanNodes = document.querySelectorAll('#box span');var ulNode = document.querySelector('#box .list');var iconItems = document.querySelectorAll('#box .iconList li');var timeAll = 600;//点击一次移动一张图片的距离所需要的总时间var stepTime = 20;//每都一步所需要的的时间var timer = null;//移入box.onmouseenter= function(){spanNodes[0].style.opacity = 1;spanNodes[1].style.opacity = 1;};//移出box.onmouseleave = function(){spanNodes[0].style.opacity = 0;spanNodes[1].style.opacity = 0;};//点击右侧按钮图片动起来spanNodes[1].onclick = function(){move(true);}//点击左侧按钮spanNodes[0].onclick = function(){move(false);}function move(flag){if(flag){var disX = -600;}else{var disX = 600;}//可以求出目前ul所在的位置var startX = ulNode.offsetLeft;//我们就可以求出点击一次移动的最终位置var lastX = startX + disX;//把求出的最终位置设置给ul,这样点击就已经能轮播了,但是是瞬变轮播//如果要变成滑动就不能这样做,我们得让这个-600慢慢一步一步走;
//					ulNode.style.left = lastX + 'px';
//					用循环定时器模拟过度效果//求出每一步走的距离var stepDis = disX / (timeAll / stepTime);timer = setInterval(function(){var left = ulNode.offsetLeft + stepDis;//当慢慢移动到最后和瞬间移动到最后距离一样的时候,我们就清除定时器if(left === lastX){clearInterval(timer);//无缝的逻辑if(left === -3600){left = -600;}else if(left === 0){left = -3000;}}ulNode.style.left = left + 'px';},stepTime);//小圆点变色//排它//先让所有的小圆点变灰for(var i = 0; i < iconItems.length; i++){iconItems[i].className = '';}//让对应的小圆点变红//要求对应的小圆点,其实就是要求出对应的小圆点的下标//想要求小圆点的下标,我们可以转而求要显示的图片的下标,//图片下标 - 1就是我们要的小圆点下标var index = lastX / -600 - 1;if(index > 4){index = 0;}else if(index < 0){index = 4;}iconItems[index].className = 'current';			}	}script>body>
html>

8.4 点击小圆点切换变色

DOCTYPE html>
<html><head><meta charset="UTF-8"><title>title><style>*{margin: 0;padding: 0;}ul,li{list-style: none;}img{display: block;/*vertical-align: middle;*/}a{text-decoration: none;}input{outline: none;}.clearFix:after{content: '';display: table;clear: both;}#box{position: relative;width: 600px;height: 300px;margin: 50px auto;overflow: hidden;}#box .list{position: absolute;left: -600px;top: 0;width: 4200px;height: 300px;}#box .list li{float: left;width: 600px;height: 300px;}#box .list li img{width: 600px;height: 300px;}#box span{position: absolute;top: 50%;transform: translateY(-50%);width: 50px;height: 100px;background-color: rgba(200,200,200,.7);font-size: 50px;text-align: center;line-height: 100px;color: white;opacity: 0;transition: opacity 2s;}#box .left{left: 0;}#box .right{right: 0;}#box .iconList{position: absolute;left: 50%;transform: translateX(-50%);bottom: 10px;overflow: hidden;}#box .iconList li{float: left;width: 40px;height: 40px;margin-right: 10px;border-radius: 50%;background-color: gray;}#box .iconList li.current{background-color: red;}style>head><body><div id="box"><ul class="list"><li><img src="img/9.jpg"/>li><li><img src="img/17.jpg"/>li><li><img src="img/2.jpg"/>li><li><img src="img/3.jpg"/>li><li><img src="img/7.jpg"/>li><li><img src="img/9.jpg"/>li><li><img src="img/17.jpg"/>li>ul><span class="left">  <  span><span class="right">  >  span><ul class="iconList"><li class="current">li><li>li><li>li><li>li><li>li>ul>div><script type="text/javascript">window.onload = function(){var box = document.getElementById('box');var spanNodes = document.querySelectorAll('#box span');var ulNode = document.querySelector('#box .list');var iconItems = document.querySelectorAll('#box .iconList li');var timeAll = 600;//点击一次移动一张图片的距离所需要的总时间var stepTime = 20;//每都一步所需要的的时间var timer = null;//移入box.onmouseenter= function(){spanNodes[0].style.opacity = 1;spanNodes[1].style.opacity = 1;};//移出box.onmouseleave = function(){spanNodes[0].style.opacity = 0;spanNodes[1].style.opacity = 0;};//点击右侧按钮图片动起来spanNodes[1].onclick = function(){move(true);}//点击左侧按钮spanNodes[0].onclick = function(){move(false);}//点击小圆点移动for(var i = 0; i < iconItems.length; i++){iconItems[i].index = i;iconItems[i].onclick = function(){//点击小圆点后的逻辑//和小圆点变色求小圆点的下标  刚好相反//点击哪个小圆点,可以获取到点击的这个小圆点的下标//根据小圆点的下标可以求出要显示的图片的下标//就可以求出要显示的图片对应的最终位置//把最终位置传到move可以求出点击小圆点后的距离差//点击按钮和点击小圆点逻辑是一样的,只是距离差不同move((this.index + 1)* -600);}}function move(flag){if(typeof flag === "boolean"){//证明点击的是按钮if(flag){var disX = -600;}else{var disX = 600;}}else{//证明点击的是小圆点进来的flag不是布尔值var disX = flag - ulNode.offsetLeft;}//可以求出目前ul所在的位置var startX = ulNode.offsetLeft;//我们就可以求出点击一次移动的最终位置var lastX = startX + disX;//把求出的最终位置设置给ul,这样点击就已经能轮播了,但是是瞬变轮播//如果要变成滑动就不能这样做,我们得让这个-600慢慢一步一步走;
//					ulNode.style.left = lastX + 'px';
//					用循环定时器模拟过度效果//求出每一步走的距离var stepDis = disX / (timeAll / stepTime);timer = setInterval(function(){var left = ulNode.offsetLeft + stepDis;//当慢慢移动到最后和瞬间移动到最后距离一样的时候,我们就清除定时器if(left === lastX){clearInterval(timer);//无缝的逻辑if(left === -3600){left = -600;}else if(left === 0){left = -3000;}}ulNode.style.left = left + 'px';},stepTime);//小圆点变色//排它//先让所有的小圆点变灰for(var i = 0; i < iconItems.length; i++){iconItems[i].className = '';}//让对应的小圆点变红//要求对应的小圆点,其实就是要求出对应的小圆点的下标//想要求小圆点的下标,我们可以转而求要显示的图片的下标,//图片下标 - 1就是我们要的小圆点下标var index = lastX / -600 - 1;if(index > 4){index = 0;}else if(index < 0){index = 4;}iconItems[index].className = 'current';}}script>body>
html>

8.5 定时器叠加问题

发生情况:连续点击 定时器执行的时间的间隔很短

DOCTYPE html>
<html><head><meta charset="UTF-8"><title>title><style>*{margin: 0;padding: 0;}ul,li{list-style: none;}img{display: block;/*vertical-align: middle;*/}a{text-decoration: none;}input{outline: none;}.clearFix:after{content: '';display: table;clear: both;}#box{position: relative;width: 600px;height: 300px;margin: 50px auto;overflow: hidden;}#box .list{position: absolute;left: -600px;top: 0;width: 4200px;height: 300px;}#box .list li{float: left;width: 600px;height: 300px;}#box .list li img{width: 600px;height: 300px;}#box span{position: absolute;top: 50%;transform: translateY(-50%);width: 50px;height: 100px;background-color: rgba(200,200,200,.7);font-size: 50px;text-align: center;line-height: 100px;color: white;opacity: 0;transition: opacity 2s;}#box .left{left: 0;}#box .right{right: 0;}#box .iconList{position: absolute;left: 50%;transform: translateX(-50%);bottom: 10px;overflow: hidden;}#box .iconList li{float: left;width: 40px;height: 40px;margin-right: 10px;border-radius: 50%;background-color: gray;}#box .iconList li.current{background-color: red;}style>head><body><div id="box"><ul class="list"><li><img src="img/9.jpg"/>li><li><img src="img/17.jpg"/>li><li><img src="img/2.jpg"/>li><li><img src="img/3.jpg"/>li><li><img src="img/7.jpg"/>li><li><img src="img/9.jpg"/>li><li><img src="img/17.jpg"/>li>ul><span class="left">  <  span><span class="right">  >  span><ul class="iconList"><li class="current">li><li>li><li>li><li>li><li>li>ul>div><script type="text/javascript">window.onload = function(){var box = document.getElementById('box');var spanNodes = document.querySelectorAll('#box span');var ulNode = document.querySelector('#box .list');var iconItems = document.querySelectorAll('#box .iconList li');var timeAll = 600;//点击一次移动一张图片的距离所需要的总时间var stepTime = 20;//每都一步所需要的的时间var timer = null;var isMove = false;//移入box.onmouseenter= function(){spanNodes[0].style.opacity = 1;spanNodes[1].style.opacity = 1;};//移出box.onmouseleave = function(){spanNodes[0].style.opacity = 0;spanNodes[1].style.opacity = 0;};//点击右侧按钮图片动起来spanNodes[1].onclick = function(){move(true);}//点击左侧按钮spanNodes[0].onclick = function(){move(false);}//点击小圆点移动for(var i = 0; i < iconItems.length; i++){iconItems[i].index = i;iconItems[i].onclick = function(){move((this.index + 1)* -600);}}function move(flag){//第二次开始的时候去判断开关状态;if(isMove){return;}//第一次点击的时候isMove = true;if(typeof flag === "boolean"){//证明点击的是按钮if(flag){var disX = -600;}else{var disX = 600;}}else{//证明点击的是小圆点进来的flag不是布尔值var disX = flag - ulNode.offsetLeft;}//可以求出目前ul所在的位置var startX = ulNode.offsetLeft;//我们就可以求出点击一次移动的最终位置var lastX = startX + disX;var stepDis = disX / (timeAll / stepTime);timer = setInterval(function(){var left = ulNode.offsetLeft + stepDis;//当慢慢移动到最后和瞬间移动到最后距离一样的时候,我们就清除定时器if(left === lastX){clearInterval(timer);//无缝的逻辑if(left === -3600){left = -600;}else if(left === 0){left = -3000;}//在特定的条件下,让isMove再次变为false,为了后期也能动,否则后期点击就不动了isMove = false;}ulNode.style.left = left + 'px';},stepTime);//小圆点变色//排它//先让所有的小圆点变灰for(var i = 0; i < iconItems.length; i++){iconItems[i].className = '';}var index = lastX / -600 - 1;if(index > 4){index = 0;}else if(index < 0){index = 4;}iconItems[index].className = 'current';}}script>body>
html>

8.6 自动轮播

DOCTYPE html>
<html><head><meta charset="UTF-8"><title>title><style>*{margin: 0;padding: 0;}ul,li{list-style: none;}img{display: block;/*vertical-align: middle;*/}a{text-decoration: none;}input{outline: none;}.clearFix:after{content: '';display: table;clear: both;}#box{position: relative;width: 600px;height: 300px;margin: 50px auto;overflow: hidden;}#box .list{position: absolute;left: -600px;top: 0;width: 4200px;height: 300px;}#box .list li{float: left;width: 600px;height: 300px;}#box .list li img{width: 600px;height: 300px;}#box span{position: absolute;top: 50%;transform: translateY(-50%);width: 50px;height: 100px;background-color: rgba(200,200,200,.7);font-size: 50px;text-align: center;line-height: 100px;color: white;opacity: 0;transition: opacity 2s;}#box .left{left: 0;}#box .right{right: 0;}#box .iconList{position: absolute;left: 50%;transform: translateX(-50%);bottom: 10px;overflow: hidden;}#box .iconList li{float: left;width: 40px;height: 40px;margin-right: 10px;border-radius: 50%;background-color: gray;}#box .iconList li.current{background-color: red;}style>head><body><div id="box"><ul class="list"><li><img src="img/9.jpg"/>li><li><img src="img/17.jpg"/>li><li><img src="img/2.jpg"/>li><li><img src="img/3.jpg"/>li><li><img src="img/7.jpg"/>li><li><img src="img/9.jpg"/>li><li><img src="img/17.jpg"/>li>ul><span class="left">  <  span><span class="right">  >  span><ul class="iconList"><li class="current">li><li>li><li>li><li>li><li>li>ul>div><script type="text/javascript">window.onload = function(){var box = document.getElementById('box');var spanNodes = document.querySelectorAll('#box span');var ulNode = document.querySelector('#box .list');var iconItems = document.querySelectorAll('#box .iconList li');var timeAll = 600;//点击一次移动一张图片的距离所需要的总时间var stepTime = 20;//每都一步所需要的的时间var timer = null;var isMove = false;var autoTimer = null;//移入box.onmouseenter= function(){spanNodes[0].style.opacity = 1;spanNodes[1].style.opacity = 1;clearInterval(autoTimer);};//移出box.onmouseleave = function(){spanNodes[0].style.opacity = 0;spanNodes[1].style.opacity = 0;autoRun();};//点击右侧按钮图片动起来spanNodes[1].onclick = function(){move(true);}//点击左侧按钮spanNodes[0].onclick = function(){move(false);}//点击小圆点移动for(var i = 0; i < iconItems.length; i++){iconItems[i].index = i;iconItems[i].onclick = function(){//点击小圆点后的逻辑//和小圆点变色求小圆点的下标  刚好相反//点击哪个小圆点,可以获取到点击的这个小圆点的下标//根据小圆点的下标可以求出要显示的图片的下标//就可以求出要显示的图片对应的最终位置//把最终位置传到move可以求出点击小圆点后的距离差//点击按钮和点击小圆点逻辑是一样的,只是距离差不同move((this.index + 1)* -600);}}//自动轮播autoRun();function autoRun(){autoTimer = setInterval(function(){move(true);},2000);}function move(flag){//第二次开始的时候去判断开关状态;if(isMove){return;}//第一次点击的时候isMove = true;if(typeof flag === "boolean"){//证明点击的是按钮if(flag){var disX = -600;}else{var disX = 600;}}else{//证明点击的是小圆点进来的flag不是布尔值var disX = flag - ulNode.offsetLeft;}//可以求出目前ul所在的位置var startX = ulNode.offsetLeft;//我们就可以求出点击一次移动的最终位置var lastX = startX + disX;//把求出的最终位置设置给ul,这样点击就已经能轮播了,但是是瞬变轮播//如果要变成滑动就不能这样做,我们得让这个-600慢慢一步一步走;
//					ulNode.style.left = lastX + 'px';
//					用循环定时器模拟过度效果//求出每一步走的距离var stepDis = disX / (timeAll / stepTime);timer = setInterval(function(){var left = ulNode.offsetLeft + stepDis;//当慢慢移动到最后和瞬间移动到最后距离一样的时候,我们就清除定时器if(left === lastX){clearInterval(timer);//无缝的逻辑if(left === -3600){left = -600;}else if(left === 0){left = -3000;}isMove = false;}ulNode.style.left = left + 'px';},stepTime);//小圆点变色//排它//先让所有的小圆点变灰for(var i = 0; i < iconItems.length; i++){iconItems[i].className = '';}var index = lastX / -600 - 1;if(index > 4){index = 0;}else if(index < 0){index = 4;}iconItems[index].className = 'current';}}script>body>
html>


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部