DOM

DOM

  • DOM是”Document Object Model“(文档对象模型)的首字母缩写。如果没有document,DOM也就无从谈起。当创建一个网页并把它加载到web浏览器中时,DOM就在幕后悄然而生。它将根据你编写的网页文档创建一个文档对象。
  • HTML DOM 定义了访问和操作HTML文档的标准方法
  • HTML DOM 把 HTML 文档呈现为带有元素、属性和文本的树结构(节点树)

DOM节点

一、节点类型

DOM 是这样规定的:

  • HTML 文档中的每个成分都是一个节点。
  • 文档节点: 整个文档是一个文档节点 document
  • 元素节点: 每个 HTML 标签是一个元素节点 element
  • 文本节点: 包含在 HTML 元素中的文本是文本节点 text
  • 属性节点: 每一个 HTML 属性是一个属性节点 attribute

二、节点关系

父(parent),子(child)和同胞(sibling)等术语用于描述这些关系。

  • 在节点树中,顶端节点被称为根(root)
  • 每个节点都有父节点、除了根(它没有父节点)
  • 一个节点可拥有任意数量的子节点
  • 同胞是拥有相同父节点的节点

三、节点属性

在文档对象模型(DOM)中,每一个节点都是一个对象。DOM节点有三个重要的属性:

  • nodeName属性:节点的名称,是只读
    • 元素节点的nodeName与标签名相同
    • 属性节点的nodeName与属性的名称相同
    • 文本节点的nodeName永远是#text
    • 文档节点的nodeName永远是#document
  • nodeValue属性:节点的值
    • 元素节点的 nodeValue 是 undefined 或 null
    • 文本节点的 nodeValue 是文本自身
    • 属性节点的 nodeValue 是属性的值
  • nodeType 属性: 节点的类型,是只读的。
元素类型节点类型
元素 1
属性 2
文本 3
注释 8
文档 9
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>节点属性</title>
</head>
<body>
    <div id="box">我是一个文本节点<!-- 我是注释 --></div>
    <script type="text/javascript">
        
        //attributes属性是获取到该节点对象上的所有属性的集合
        //childNodes属性是获取到该节点对象的所有子节点的集合
        
        // 1.获取元素节点
        var divNode = document.getElementById('box');
        console.log(divNode.nodeName + '|' + divNode.nodeValue + "/" + divNode.nodeType);
        // 2.获取属性节点
        var attrNode = divNode.attributes[0];
        console.log(attrNode.nodeName + '|' + attrNode.nodeValue + "/" + attrNode.nodeType);
        // 3.获取文本节点
        var textNode = divNode.childNodes[0];
        console.log(textNode.nodeName + '|' + textNode.nodeValue + "/" + textNode.nodeType);
        // 4.获取注释节点
        var commentNode = divNode.childNodes[1];
        console.log(commentNode.nodeName + '|' + commentNode.nodeValue + "/" + commentNode.nodeType);
        // 5.文档节点
        console.log(document.nodeName + '|' + document.nodeValue + "/" + document.nodeType);
    </script>
</body>
</html>
View Code

三、节点查找和节点操作

访问HTML元素等同于访问节点。注意:涉及到寻找元素,注意script标签的位置!

<script>
//=============================================获取元素节点的方式:

/*
document.getElementById()        //这个方法是与document对象相关联的函数。
document.getElementsByName()
document.getElementsByTagName()
document.getElementsByClassName()


导航节点:
parentElement           // 父节点标签元素
children                // 所有子标签
firstElementChild       // 第一个子标签元素
lastElementChild        // 最后一个子标签元素
nextElementtSibling     // 下一个兄弟标签元素
previousElementSibling  // 上一个兄弟标签元素
注意,js中没有办法找到所有的兄弟标签!
*/
var div1=document.getElementById("div1");
//支持局部查找;
var ele= div1.getElementsByTagName("p");
var ele2=div1.getElementsByClassName("div2");
//不支持局部查找
var ele3=div1.getElementById("div3");
var ele4=div1.getElementsByName("alex");





//=============================================节点操作:

/* 节点方法:
1.创建节点createElement(): //通过document调用
createElement()方法可创建元素节点。此方法可返回一个Element对象
var newNode = document.createElement(tagName);
tagName:字符传值,这个字符串用来指明创建元素的类型

注意:如果想获取节点对象的文本内容,可以直接调用innerText或者innerHTML属性来获取
var newNode = document.createElement('p');
console.log(newNode.nodeName);//P
newNode.innerText = 'hello';
console.log(newNode);//<p>hello</p>
newNode.innerHTML = '<a>hello</a>'

2.插入节点appendChild():
在指定的节点的最后一个子节点之后添加一个新的子节点
appendChild(newNode);

3.插入节点insertBefore():
insertBefore()方法可在已有的子节点前插入一个新的子节点
insertBefore(newNode,node);

4.删除节点removeChild():  //通过父元素调用
removeChild()方法从子节点列表中删除某个节点。如果删除成功,此方法可返回被删除的节点,如失败,则返回NULL
var x = oBox.removeChild(oBox.childNodes[0]);
注意:把删除的子节点赋值给x,这个子节点不在DOM树中,但是还存在内存中,可通过 x =null来删除对象。

5.替换元素节点replaceChild(): //通过父元素调用
replaceChild实现子节点(对象)的替换。返回被替换对象的引用
node.replaceChild(newnode,oldnew);

var oldnew = document.getElementById('text');
var newNode  = document.createElement('p');
newNode.innerHTML = 'Vue';
oldnew.parentNode.replaceChild(newNode,oldnew);

6.创建文本节点createTextNode: //通过document调用
createTextNode()方法创建新的文本节点,返回新创建的Text节点

var newNode = document.createElement('div');
var textNode  = document.createTextNode('我是一条文本信息');
newNode.appendChild(textNode);
document.body.appendChild(newNode);

*/


//=============================================节点属性操作:
/*
1、获取文本节点的值:innerText    innerHTML
2、attribute操作
    elementNode.setAttribute(name,value);
    elementNode.getAttribute(属性名);     elementNode.属性名(DHTML)
    elementNode.removeAttribute("属性名");
3、value获取当前选中的value值
    input
    select (selectedIndex)
    textarea
4、innerHTML 给节点添加html代码:
    该方法不是w3c的标准,但是主流浏览器支持
    tag.innerHTML = “<p>要显示内容</p>”;
5、关于class的操作:
    elementNode.className
    elementNode.classList.add
    elementNode.classList.remove
6、改变css样式:
    <p id="p2">Hello world!</p>
    document.getElementById("p2").style.color="blue";
    document.getElementById("p2").style.fontSize=48px
*/


//=============================================样式操作:
/*
1.动态设置样式
直接在想要动态设置样式的元素内部添加内联样式。这是用HTMLElement.style属性来实现。
这个属性包含了文档中每个元素的内联样式信息。你可以设置这个对象的属性直接修改元素样式
CSS样式的JavaSript属性版本以小驼峰式命名法书写,而CSS版本带连接符号(backgroundColor 对 background-color
var para = document.getElementById('box');
para.style.color = 'white';
para.style.backgroundColor = 'black';
para.style.padding = '10px';
para.style.width = '250px';
para.style.textAlign = 'center';

2.操作属性的类来控制样式(推荐)
使用HTML操作的常用方法 — Element.setAttribute() — 这里有两个参数,
你想在元素上设置的属性,你要为它设置的值。在这种情况下,我们在段落中设置类名为highlight:
var para = document.getElementById('box');
para.setAttribute('class','highlight');
*/



/* 节点属性:
childNodes属性:
访问选定元素节点下的所有子节点的列表,返回的值可以看作是一个数组,他具有length属性。

firstChild属性:
返回childNodes数组中的第一个子节点。如果选定的节点没有子节点,则该属性返回NULL。
node.firstChild与elementNode.childNodes[0]是同样的效果

lastChild属性:
返回childNodes数组中的最后一个子节点。如果选定的节点没有子节点,则该属性返回NULL。
node.lastChild与elementNode.childNodes[elementNode.childNodes.length-1]是同样的效果

parentNode属性:
获取指定节点的父节点:elementNode.parentNode  注意:父节点只能有一个
访问祖先节点:elementNode.parentNode.parentNode
访问弟弟节点:nextSiblings属性可返回某个节点之后紧跟的节点,如果无此节点,则该属性返回null  nodeObject.nextSibling
访问哥哥节点:previousSibling属性可返回节点之前紧跟的节点,如果无此节点,则该属性返回null   nodeObject.previousSibling
以上两个方法,在谷歌浏览器上获取出来的是空白文本节点(例如,换行符号)。
*/

// 文档中的每一个元素都对应着一个对象,找到元素后,就可以利用getAttribute()方法和setAttribute()方法对元素的属性值进行操作
var oP = document.getElementsByTagName('p')[0];
var title = oP.getAttribute('title');
console.log(title);

/*
setAttribute()方法做出的修改不会反映为文档本身的源码里。
这种“表里不一”的现象源自于DOM的工作模式:先加载文档的静态内容、再以动态方式对他们进行刷新,
动态刷新不影响文档的静态内容。这正是DOM的真正威力和诱人之处:对页面内容的刷新不需要最终用户在他们的浏览器里执行页面刷新操作就可以实现。
*/
var classList = document.getElementById('classList');
classList.setAttribute('title','这是我们最新的课程');
</script>
View Code

DOM Event(事件)

JavaScript操作css称为脚本化CSS,而JavaScript与HTML的交互是通过事件实现的。事件就是文档或浏览器窗口中发生的一些特定的交互瞬间,而事件流(又叫事件传播)描述的是从页面中接收事件的顺序。

  • 事件冒泡:
    • IE的事件流是事件冒泡流,而Netscape的事件流是事件捕获流
    • IE的事件流叫做事件冒泡(eventy bubbling),即事件开始时由最具体的元素(文档中嵌套层次最深的那个节点)接收,然后逐级向上传播到较为不具体的节点(文档)
    • 注意:所有现代浏览器都支持冒泡,但在具体实现还是有一些差别。IE9以上、Firfox、Chrome、safari 将事件一直冒泡到window对象
  • 事件捕获:
    • 事件捕获的思想是不太具体的节点应该更早接收到事件,而最具体的节点应该最后接收到事件。事件捕获的用意在于在事件到达预定目标之前捕获它
    • 注意:IE9、Firefox、Chrome、safari等现代浏览器都支持事件捕获,但从window对象开始获取
    • addEventListener(eventType,eventListener,useCapture)方法中的第三个参数设置为true时,即为事件捕获阶段
  • 事件流:
    • 事件流又称为事件传播,DOM2级事件规定的事件流包括三个阶段:事件捕获阶段(capture phase)、处于目标阶段(target phase)和事件冒泡阶段(bubbling phase)
    • 首先发生的是事件捕获,为截获事件提供了机会。然后是实际的目标接收到事件,最后一个阶段是冒泡阶段,可以在这个阶段对事件做出响应
<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title></title>
        <style type="text/css">
            #box{
                width: 200px;
                height: 200px;
                background-color: red;
            }
        </style>
    </head>
    <body>
        <div id="box">
        </div>
        <script type="text/javascript">
            var box = document.getElementById('box');
            box.onclick = function(){
                box.innerHTML += 'div\n';
            };
            document.body.onclick = function(){
                box.innerHTML += 'body\n';
            };
            document.documentElement.onclick = function(){
                box.innerHTML += 'html\n';
            };
            document.onclick = function(){
                box.innerHTML += 'body\n';
            };
            window.onclick = function(){
                box.innerHTML += 'window\n';
            };
        </script>
    </body>
</html>
事件冒泡

一、事件处理程序

事件处理程序又叫事件侦听器,实际上就是事件的绑定函数。事件发生时会执行函数中相应代码。事件处理程序:

1、绑定事件方式

  • HTML事件处理程序
  • DOM0级事件处理程序
  • DOM2级事件处理程序
  • IE事件处理程序
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title></title>
    <style type="text/css">
        #box1,#box2,#box3,#box4 {
            width: 200px;
            height: 200px;
            background-color: red;
        }
    </style>
</head>
<body>

<!--
一、HTML事件处理程序
缺点:耦合问题
​客户端编程的通用风格是保持HTML内容和javaScript行为分离,所以应该避免使用HTML事件处理程序属性,因为这些属性直接混合了javascript和HTML,且不易扩展
-->


<!--1、在事件处理程序函数内部,this等于事件的目标元素-->
<div id="box1" style="height:30px;width:200px;background-color:pink;" onclick="this.innerHTML+= '1';"></div>

<!--2、在HTML中定义的事件处理程序也可以调用在页面其它地方定义的脚本-->
<div id="box2" style="height:30px;width:200px;background-color:yellow;" onclick="test()"></div>
<script>
    function test() {
        document.getElementById('box').innerHTML += '1';
    }
</script>

<!--3、HTML事件处理程序会创建一个封装着元素属性值的函数。这个函数中有一个局部变量event,也就是事件对象。
通过event变量,可以直接访问事件对象,不用自己定义它,也不用从函数的参数列表中获取。-->
<div id="box3" style="height:30px;width:200px;background-color:red;"onclick = "this.innerHTML+= event.type;"></div>

<!--4、在事件处理程序函数内部,可以像访问局部变量一样访问document及该元素本身的成员。如此一来,事件处理程序要访问自己的属性就简单多了-->
<button id="box4" value="test" style="height:30px;width:200px;background-color:blue;"onclick = "this.innerHTML+= value;"></button>

</body>
</html>
HTML事件处理程序
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title></title>
    <style type="text/css">
        #box1,#box2,#box3,#box4 {
            width: 200px;
            height: 200px;
            background-color: red;
        }
    </style>
</head>
<body>

<!--
二、DOM0级事件处理程序
​通过javascript指定事件处理程序的传统方式,就是将一个函数赋值给一个事件处理程序属性。
这种为事件处理程序赋值的方法是在第四代Web浏览器中出现的,而且至今仍然为所有现代浏览器所支持。原因一是简单,二是具有跨浏览器的优势

每个元素都有自己的事件处理程序属性,这些属性通常全部小写,将这种属性的值设置为一个函数,就可以指定事件处理程序

注意:以DOM0级方式添加的事件处理程序会在事件流的冒泡阶段被处理

缺点:
围绕着每个事件目标对于每种事件类型只能添加一个事件处理程序

-->

<div id="box" style="height:30px;width:200px;background-color:pink;"></div>
<script>
document.getElementById('box').onclick = function(){this.innerHTML += '1';}
//可以通过将事件处理程序属性设置为null来删除事件处理程序  box.onclick = null;
</script>

</body>
</html>
DOM0级事件处理程序
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title></title>
</head>
<body>
<!--
三、DOM2级事件处理程序
DOM2级事件处理程序定义了两个方法用于处理指定和删除事件处理程序的操作:addEventListener()和removeEventListener()
所有DOM节点中都包含这两个方法,并且它们都接受3个参数:要处理的事件名、作为事件处理程序的函数和一个布尔值。
最后的布尔值参数如果是true,表示在捕获阶段调用事件处理程序;如果是false,表示在冒泡阶段调用事件处理程序。若最后的布尔值不填写,则和false效果一样

注意: IE8浏览器不支持DOM2级事件处理程序

好处:可以添加多个事件处理程序,并按照他们添加的顺序触发

参数:如果希望向监听函数传递参数,可以用匿名函数包装一个监听函数

移除:通过addEventListener()添加的事件处理程序只能使用removeEventListener()来移除,
    移除时传入的参数与添加处理程序时使用的参数相同。这意味着,addEventListener()添加的匿名函数将无法移除。 
-->

<div id="box" style="height:30px;width:200px;background-color:pink;"></div>
<script>
    var box = document.getElementById('box');
    box.addEventListener('click',function(){this.innerHTML += '1'},false);
    box.addEventListener('click',function(){this.innerHTML += '2'},false);
</script>


<div id="box2" style="height:30px;width:200px;background-color:red;"></div>
<script>
    //参数:如果希望向监听函数传递参数,可以用匿名函数包装一个监听函数
    var box2 = document.getElementById('box2');
    box2.addEventListener("click",function(){
        test('123');
    },false);
    function test(x){box2.innerHTML += x;}
</script>


<div id="box3" style="height:30px;width:200px;background-color:blue;"></div>
<script>
    //无效: 移除时传入的参数与添加处理程序时使用的参数相同。这意味着,addEventListener()添加的匿名函数将无法移除。
    var box3 = document.getElementById('box3');
    box3.addEventListener("click",function(){
        this.innerHTML += '1'
    },false);

    box3.removeEventListener('click',function(){
        this.innerHTML += '1'
    },false);
</script>



<div id="box4" style="height:30px;width:200px;background-color:brown;"></div>
<script>
    //有效
    var box4 = document.getElementById('box4');
    var handle = function(){this.innerHTML += '1'};
    box4.addEventListener("click",handle,false);
    box4.removeEventListener('click',handle,false);
</script>



</body>
</html>
DOM2级事件处理程序
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title></title>
</head>
<body>
<!--
四、IE事件处理程序
IE实现了与DOM中类似的两个方法:attachEvent()和detachEvent()。
这两个方法接受相同的两个参数:事件处理程序名称与事件处理程序函数。由于IE8-浏览器只支持事件冒泡,
所以通过attachEvent()添加的事件处理程序都会被添加到事件冒泡阶段

attachEvent()方法的第一个参数是”onclick”,而非DOM的addEventListener()方法中的”click”

注意:attachEvent()方法只冒泡到document,且IE10-浏览器支持

this:与其他三个事件处理程序不同,IE事件处理程序的this指向了window,而非被绑定事件的元素。

顺序:使用attachEvent()方法添加的事件处理程序的触发顺序是有区别的。IE9、10浏览器是按正序执行的,而IE8-浏览器则是按倒序执行的 

移除:使用attachEvent()添加的事件可以通过detachEvent()来移除,条件是必须提供相同的参数。
    与DOM方法一样,这也意味着添加的匿名函数将不能被移除。
    不过,只要能够将对相同函数的引用传给detachEvent(),就可以移除相应的事件处理程序 

-->

<div id="box1" style="height:30px;width:200px;background-color:pink;"></div>
<script>
    var box1 = document.getElementById('box1');
    // box1.attachEvent('onclick',function(){this.innerHTML += '1';});
</script>


<!--<div>-->
<div id="box2" style="height:100px;width:300px;background-color:green;"
onclick = "console.log(this)"></div>



<div id="box3" style="height:100px;width:300px;background-color:brown;"></div>
<script>
    var box3 = document.getElementById('box3');
    box3.onclick= function(){
        console.log(this);//<div>
    }
</script>


<div id="box4" style="height:100px;width:300px;background-color:red;"></div>
<script>
    var box4 = document.getElementById('box4');
    box4.addEventListener('click',function(){
        console.log(this);//<div>
    });
</script>



<div id="box5" style="height:100px;width:300px;background-color:blue;"></div>
<script>
    var box5 = document.getElementById('box5');
    // box5.attachEvent('onclick',function(){
    //     console.log(this);//window
    // });
</script>



<div id="box6" style="height:30px;width:100px;background-color:pink;"></div>
<script>
    var box6 = document.getElementById('box6');
    box6.attachEvent('onclick',function(){
        box6.innerHTML += '1';
    });
    box6.attachEvent('onclick',function(){
        box6.innerHTML += '2';
    });
</script>



<div id="box7" style="height:30px;width:200px;background-color:red;"></div>
<script>
    //无效
    var box7 = document.getElementById('box7');
    box7.attachEvent("onclick",function(){
        box7.innerHTML += '1'
    },false);
    box7.detachEvent('onclick',function(){
        box7.innerHTML += '1'
    },false);
</script>



<div id="box8" style="height:30px;width:200px;background-color:pink;"></div>
<script>
//有效
var box8 = document.getElementById('box8');
var handle = function(){box.innerHTML += '1'};
box8.attachEvent("onclick",handle,false);
box8.detachEvent('onclick',handle,false);
</script>

<script>
//总结:
//由于IE8-浏览器不支持addEventListener()方法,所以需要配合attachEvent()方法来实现全浏览器的事件绑定兼容写法。
//同时,由于attachEvent()方法中的this指向window,所以需要对this进行显式修改。

function addEvent(target,type,handler){
    if(target.addEventListener){
        target.addEventListener(type,handler,false);
    }else{
        target.attachEvent('on'+type,function(event){
            return handler.call(target,event);
        });
    }
}
</script>







<div id="box" style="height:100px;width:100px;background:pink;" onclick = "this.innerHTML +='html\n'"></div>
<script>
//调用顺序:
//如果浏览器同时出现这四种事件处理程序,那么它们的调用顺序在各浏览器中表现并不一致 
    var box = document.getElementById('box');
    if(box.addEventListener){
        box.addEventListener('click',function(){this.innerHTML += 'DOM2级\n'})
    }
    if(box.attachEvent){
        box.attachEvent('onclick',function(){box.innerHTML +='IE\n'})
    }
    box.onclick = function(){
        this.innerHTML += 'DOM0级\n';
    }
</script>


<!--【相同点】-->

<!--  如果同时出现HTML事件处理程序和DOM0级事件处理程序,DOM0级会覆盖HTML事件处理程序-->

<!--【不同点】-->

<!--  chrome/safari/FF以及IE11浏览器结果为:DOM0级 DOM2级-->

<!--  IE9、10浏览器结果为:DOM0级 DOM2级 IE-->

<!--  IE8-浏览器结果为:DOM0级 IE-->



</body>
</html>
IE事件处理程序
<!--方式1:不推荐-->
<div id="div" onclick="foo(this)">点我呀</div>
<script>
    function foo(self){           // 形参不能是this;
        console.log("点你大爷!");
        console.log(self);
    }
</script>
<!--方式2:-->
<p id="abc">试一试!</p>
<script>
    var ele=document.getElementById("abc");
    function fc(){
        console.log("ok");
        console.log(this);    // this直接用
    };
    ele.onclick=fc;
</script>
<!--方式3:-->
<script>
/*
ie:obj.attachEvent(事件名称,事件函数);
    1.没有捕获
    2.事件名称有on
    3.事件函数执行的顺序:标准ie-》正序   非标准ie-》倒序
    4.this指向window
标准:obj.addEventListener(事件名称,事件函数,是否捕获);
    1.有捕获
    2.事件名称没有on
    3.事件执行的顺序是正序
    4.this触发该事件的对象
是否捕获 : 默认是false    false:冒泡 true:捕获
ie : obj.detachEvent(事件名称,事件函数);
标准 : obj.removeEventListener(事件名称,事件函数,是否捕获);
*/
function bind(obj, evname, fn) {
    if (obj.addEventListener) {
        obj.addEventListener(evname, fn, false);
    } else {
        obj.attachEvent('on' + evname, function() {
            fn.call(obj);
        });
    }
}
function fn1() {
    alert( this.id );
}
function fn2() {
    alert( this.id );
}
var oDiv1 = document.getElementById('div1');
bind(oDiv1, 'click', fn1);
bind(oDiv1, 'click', fn2);
</script>
绑定事件方式

2、事件对象

在触发DOM上的某个事件时,会产生一个事件对象event,这个对象中包含着所有与事件有关的信息。所有浏览器都支持event对象,但支持方式不同。

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title></title>
</head>
<body>
<!--
获取事件对象:
1. event对象是事件程序的第一个参数  注意: IE8 浏览器不支持
2. 另外一种方法是直接使用event变量  注意: Firefox浏览器不支持
-->

<!--IE8-浏览器输出undefined,其他浏览器则输出事件对象[object MouseEvent]-->
<div id="box" style="height:30px;width:200px;background:pink;"></div>
<script>
var box = document.getElementById('box');
box.onclick = function(e){
    box.innerHTML = e;
}
</script>

<!--firefox浏览器输出undefined,其他浏览器则输出事件对象[object MouseEvent] -->
<div id="box2" style="height:30px;width:200px;background:red;"></div>
<script>
var box2 = document.getElementById('box2');
box2.onclick = function(){
    box2.innerHTML = event;
}
</script>


<!--兼容:于是,获取事件对象的常见兼容性写法如下-->
<div id="box3" style="height:30px;width:200px;background:pink;"></div>
<script>
var box3 = document.getElementById('box3');
box3.onclick = function(e){
    e = e || event;
    box3.innerHTML = e;
}
</script>


<!--通过点击按tab键将焦点切换到button按钮上可以出发focus事件-->
<button id="box4" style="height:30px;width:200px;background:pink;"></button>
<script>
var box4 = document.getElementById('box4');
box4.onfocus = function(e){
    e = e || event;
    box4.innerHTML = e.type;  //focus
}
</script>

</body>
</html>
View Code

3、事件目标

  • 关于事件目标,共有currentTarget、target、srcElement这三个属性
  • currentTarget属性返回事件当前所在的节点,即正在执行的监听函数所绑定的那个节点 注意:IE8 浏览器不支持
  • currentTarget属性返回事件正在执行的监听函数所绑定的节点,而target属性返回事件的实际目标节点 注意:IE8 浏览器不支持
  • srcElement属性与target属性功能一致 注意:Firefox浏览器不支持
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title></title>
    <style>
        .in {
            height: 30px;
            background-color: lightblue;
            margin: 0 10px;
        }
        #box{background-color: lightblue;}
    </style>
</head>
<body>

<!--currentTarget属性返回事件当前所在的节点,即正在执行的监听函数所绑定的那个节点  IE8 浏览器不支持-->
<ul id="box">
    <li class="in">1</li>
    <li class="in">2</li>
</ul>
<script>
    var box = document.getElementById('box');
    box.onclick = function (e) {
        e = e || event;
        var tags = box.getElementsByTagName('li');
        tags[0].innerHTML = e.currentTarget;
        tags[1].innerHTML = (e.currentTarget === this);
    }
</script>




<!--currentTarget属性返回事件正在执行的监听函数所绑定的节点,而target属性返回事件的实际目标节点-->
<!--IE8 浏览器不支持-->
<!--以下代码中,点击该实际目标节点时,颜色变红;移出,颜色变浅蓝-->
<ul id="box2">
    <li class="in">1</li>
    <li class="in">2</li>
</ul>
<script>
    var box2 = document.getElementById('box2');
    box2.onclick = function(e){
        e = e || event;
        e.target.style.backgroundColor = 'pink';
    };
    box2.onmouseout = function(e){
        e = e || event;
        e.target.style.backgroundColor = 'lightblue';
    };
</script>


<!--srcElement-->
<!--​ srcElement属性与target属性功能一致-->
<!--注意:Firefox浏览器不支持-->
<ul id="box3">
    <li class="in">1</li>
    <li class="in">2</li>
</ul>
<script>
var box3 = document.getElementById('box3');
box3.onclick = function(e){
    e = e || event;
    e.srcElement.style.backgroundColor = 'pink';
};
box3.onmouseout = function(e){
    e = e || event;
    e.srcElement.style.backgroundColor = 'lightblue';
}
</script>




<script>
//兼容
var handler = function(e){
    e = e || event;
    var target = e.target || e.srcElement;
}
</script>
</body>
</html>
View Code

4、事件代理

  • 由于事件会在冒泡阶段向上传播到父节点,因此可以把子节点的监听函数定义在父节点上,由父节点的监听函数统一处理多个子元素的事件。这种方法叫做事件的代理(delegation),也叫事件委托   
  • 事件代理应用事件目标的target和srcElement属性完成。利用事件代理,可以提高性能及降低代码复杂度。
<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title></title>
        <style type="text/css">
            * {
                padding: 0;
                margin: 0;
            }
            ul {
                list-style: none;
            }
        </style>
    </head>
    <body>
        <ul id="box">
            <li>1</li>
            <li>2</li>
            <li>3</li>
            <li>4</li>
            <li>5</li>
        </ul>
        <script type="text/javascript">
            // 1.常规方法实现
            /* var lis = document.getElementsByTagName('li');
            for(var i = 0; i < lis.length; i ++){
                lis[i].onmouseover = function (){
                    this.style.backgroundColor = 'blue';
                }
                lis[i].onmouseout = function (){
                    this.style.backgroundColor = 'red';
                }
            } */
            // 2.事件代理方式实现
            ul.onmouseover = function(e) {
                e = e || event;
                var target = e.target || e.srcElement;
                target.style.backgroundColor = 'blue';
            }
        </script>
    </body>
</html>
View Code
<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title></title>
        <style type="text/css">
            * {
                padding: 0;
                margin: 0;
            }
            ul {
                list-style: none;
            }
        </style>
    </head>
    <body>
        <ul id="box">
            <li>1</li>
            <li>2</li>
            <li>3</li>
            <li>4</li>
            <li>5</li>
        </ul>
        <script type="text/javascript">
            // 模拟未来的某个事件添加了对应的数据
            var ul = document.getElementById('box');
            setTimeout(function(){
                var item = document.createElement('li');
                item.innerHTML = '6';
                ul.appendChild(item);
            },100)
            /*
            //1.原生方式添加事件 不能触发未来添加元素的事件
            var lis = document.getElementsByTagName('li');
            for(var i = 0; i < lis.length; i ++){
                lis[i].onmouseover = function (){
                    this.style.backgroundColor = 'blue';
                }
                lis[i].onmouseout = function (){
                    this.style.backgroundColor = 'red';
                }
            }
            */
            // 2.事件代理方式实现,可以触发未来添加元素的事件
            ul.onmouseover = function(e) {
                e = e || event;
                var target = e.target || e.srcElement;
                target.style.backgroundColor = 'blue';
            }
        </script>
    </body>
</html>
View Code

5、事件冒泡

  • 事件冒泡是事件流的第三个阶段,通过事件冒泡可以在这个阶段对事件做出响应。
  • 关于冒泡,事件对象中包含bubbles、cancelBubble、stopPropagation()和stopImmediatePropagation()这四个相关的属性和方法。
  • bubbles属性返回一个布尔值,表示当前事件是否会冒泡。该属性为只读属性
  • 发生在文档元素上的大部分事件都会冒泡,但focus、blur和scroll事件不会冒泡。所以,除了这三个事件bubbles属性返回了false外,其它事件该属性都为true
  • stopPropagation()方法表示取消事件的进一步捕获或冒泡,无返回 注意:ie8 浏览器不支持
  • 使用stopPropagation()方法,可以阻止冒泡,但无法阻止同一事件的其他监听函数被调用
  • stopImmediatePropagation()方法不仅可以取消事件的进一步捕获或冒泡,而且可以阻止同一个事件的其他监听函数被调用,无返回值  [注意]IE8-浏览器不支持
  • 使用stopImmediatePropagation()方法,即可以阻止冒泡,也可以阻止同一事件的其他监听函数被调用
  • canceBubble属性只能用于阻止冒泡,无法阻止捕获阶段。该值可读写,默认值为false。当设置为true是,cancelBubble可以取消事件冒泡 [注意]该属性全浏览器支持,但并不是标准写法
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title></title>
</head>
<body>

<!--
bubbles属性返回一个布尔值:表示当前事件是否会冒泡。该属性为只读属性
发生在文档元素上的大部分事件都会冒泡,但focus、blur和scroll事件不会冒泡。所以,除了这三个事件bubbles属性返回了false外,其它事件该属性都为true
-->
<button id="test" style="height: 30px;width: 200px;"></button>
<script>
    //点击按钮时,按钮内容为true,说明click事件默认可冒泡
    var test = document.getElementById('test');
    test.onclick = function(e){
        test.innerHTML =e.bubbles;//true
    }
</script>


<div id="box" style="height: 50px;width: 200px;overflow:scroll;background:pink;line-height:60px;">内容</div>
<script>
    //滚动时,div内容变成false,说明scroll事件默认不可冒泡
    var box = document.getElementById('box');
    box.onscroll = function(e){
        test.innerHTML = e.bubbles;//false
    }
</script>



<!--
stopPropagation()方法表示取消事件的进一步捕获或冒泡,无返回   注意:ie8 浏览器不支持
​使用stopPropagation()方法,可以阻止冒泡,但无法阻止同一事件的其他监听函数被调用

stopImmediatePropagation()方法不仅可以取消事件的进一步捕获或冒泡,而且可以阻止同一个事件的其他监听函数被调用,无返回值  [注意]IE8-浏览器不支持
使用stopImmediatePropagation()方法,即可以阻止冒泡,也可以阻止同一事件的其他监听函数被调用

canceBubble属性只能用于阻止冒泡,无法阻止捕获阶段。该值可读写,默认值为false。当设置为true是,cancelBubble可以取消事件冒泡
[注意]该属性全浏览器支持,但并不是标准写法
-->
<button id="btn">触发</button>
<script type="text/javascript">
    var btn = document.getElementById('btn');
    btn.onclick = function (e){
        e = e || event;
        e.stopPropagation();  //stopPropagation()方法表示取消事件的进一步捕获或冒泡,无返回  注意:ie8 浏览器不支持
        this.innerText = '阻止冒泡';
    };
    document.body.onclick = function (e){
        alert('冒泡');
    };
</script>




<button id="btn1" style="width: 200px;">触发</button>
<script type="text/javascript">
    var btn1 = document.getElementById('btn1');
    // ​使用stopPropagation()方法,可以阻止冒泡,但无法阻止同一事件的其他监听函数被调用
    btn1.addEventListener('click',function (e){
        e = e || event;
        e.stopPropagation();
        this.innerHTML = '修改了';
    });
    btn1.addEventListener('click',function (e){
        e = e || event;
        this.style.backgroundColor = 'lightblue';
    });
    document.body.addEventListener('click',function (){
        alert('body');
    })
</script>




<button id="btn2" style="width: 200px;">触发</button>
<script type="text/javascript">
    var btn2 = document.getElementById('btn2');
    // 使用stopImmediatePropagation()方法,即可以阻止冒泡,也可以阻止同一事件的其他监听函数被调用
    btn2.addEventListener('click',function (e){
        e = e || event;
        e.stopImmediatePropagation();
        this.innerHTML = '修改了';
    });
    btn2.addEventListener('click',function (e){
        e = e || event;
        this.style.backgroundColor = 'lightblue';
    });
    document.body.addEventListener('click',function (){
        alert('body');
    })
</script>



<!--cancelBubble-->
<!--canceBubble属性只能用于阻止冒泡,无法阻止捕获阶段。该值可读写,默认值为false。当设置为true是,cancelBubble可以取消事件冒泡-->
<!--[注意]该属性全浏览器支持,但并不是标准写法-->
<button id="btn3">触发</button>
<script type="text/javascript">
    var btn3 = document.getElementById('btn3');
    btn3.onclick = function (e){
        e = e || event;
        e.cancelBubble = true;
        this.innerText = '阻止冒泡';
    };
    document.body.onclick = function (e){
        alert('冒泡');
    }
</script>


<script type="text/javascript">
//兼容    
var handler = function(e){
    e = e || event;
    if(e.stopPropagation){
        e.stopPropagation();
    }else{
        e.cancelBubble = true;
    }
}
</script>

</body>
</html>
View Code

6、事件流阶段

  • eventPhase属性返回一个整数值,表示事件目前所处的事件流阶段
  • 0表示事件没有发生,1表示捕获阶段,2表示目标阶段,3表示冒泡阶段   [注意]IE8-浏览器不支持
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title></title>
</head>
<body>

<button id="btn">
    事件流
</button>
<script type="text/javascript">
    var btn = document.getElementById('btn');
    btn.onclick = function (e){
        e =  e || event;
        this.innerHTML = e.eventPhase + '阶段';  //以下代码返回2,表示处于目标阶段
    }
</script>


<button id="btn2">
    事件流
</button>
<script type="text/javascript">
    var btn2 = document.getElementById('btn2');
    document.addEventListener('click',function(e){
        e = e || event;
        btn2.innerHTML += e.eventPhase +'阶段';   //以下代码返回1,表示处于捕获阶段
    },true);
</script>



<button id="btn3">
    事件流
</button>
<script>
    var btn3 = document.getElementById('btn3');
    document.addEventListener('click',function(e){
        e = e || event;
        btn3.innerHTML += e.eventPhase +'阶段';  //以下代码返回3,表示处于冒泡阶段
    },false);
</script>

</body>
</html>
View Code

7、取消默认行为

  • 常见的默认行为有点击链接后,浏览器跳转到指定页面;或者按一下空格键,页面向下滚动一段距离 ​
  • 关于取消默认行为的属性包括preventDefault()和returnValue
  • 在DOM0级事件处理程序中取消默认行为,使用returnValue、preventDefault()和return false都有效
  • 在DOM2级事件处理程序中取消默认行为,使用return false无效
  • 在IE事件处理程序中取消默认行为,使用preventDefault()无效
  • preventDefault()方法取消浏览器对当前事件的默认行为,无返回值 注意:IE8浏览器不支持
  • returnValue属性可读写,默认值是true,但将其设置为false就可以取消事件的默认行为,与preventDefault()方法的作用相同 注意: firebox和IE9浏览器不支持
  • 除了以上方法外,取消默认事件还可以使用return false
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title></title>
</head>
<body>
<a id="test" href="http://www.cnblogs.com">链接</a>
<script>
    var test = document.getElementById('test');
    test.onclick= function(e){
        e = e || event;
        e.preventDefault();   //preventDefault()方法取消浏览器对当前事件的默认行为,无返回值  注意:IE8浏览器不支持
    }
</script>


<a id="test2" href="http://www.cnblogs.com">链接</a>
<script>
    var test2 = document.getElementById('test2');
    test2.onclick= function(e){
        e = e || event;
        e.returnValue = false;
    }
</script>



<script>
//兼容
var handler = function(e){
    e = e || event;
    if(e.preventDefault){
        e.preventDefault();
    }else{
        e.returnValue = false;
    }
}
</script>



<a id="test3" href="http://www.cnblogs.com">链接</a>
<script>
    var test3 = document.getElementById('test3');
    test3.onclick= function(e){
        return false;  //​ 除了以上方法外,取消默认事件还可以使用return false
    }
</script>

</body>
</html>
View Code

8、事件对象属性

  • 在鼠标事件对象提供了丰富的信息 ​
  • 坐标位置: 关于坐标位置,事件对象提供了clientX/Y、pageX/Y、screenX/Y、x/y、offsetX/Y、layerX/Y这6对信息
  • clientX/Y与x/y: clientX/Y表示当鼠标事件发生时(不管是onclick,还是omousemove,onmouseover等),鼠标相对于浏览器(这里说的是浏览器的有效区域)x轴的位置和y轴的位置;。x/y与clientX/Y相同
  • screenX/Y: 当鼠标事件发生时,鼠标相对于显示器屏幕x轴的位置和y轴的距离;
  • pageX/Y: 表示相对于页面的水平和垂直坐标,它与clientX/clientY的区别是随滚动条的位置变化
  • offsetX与offsetY:当鼠标事件发生时,鼠标相对于事件源x轴的位置 offsetY:当鼠标事件发生时,鼠标相对于事件源y轴的位置
<!--clientX/Y表示当鼠标事件发生时(不管是onclick,还是omousemove,onmouseover等),
鼠标相对于浏览器(这里说的是浏览器的有效区域)x轴的位置和y轴的位置;。x/y与clientX/Y相同-->
    <body>
    <div id="box" style="width: 200px;height: 200px;background-color: red;"></div>
    <script type="text/javascript">
        var box = document.getElementById('box');
        box.onmousemove = function(e){
            e = e || event;
            // 鼠标指针相对于浏览器的水平和垂直坐标
            this.innerHTML = `clientX:${e.clientX};clientY:${e.clientY};clientY:${e.x};clientY:${e.y};`;
        }
    </script>
    </body>


<!--screenX/Y 当鼠标事件发生时,鼠标相对于显示器屏幕x轴的位置和y轴的距离;-->
<body>
    <div id="box2" style="width: 200px;height: 200px;background-color: red;"></div>
    <script type="text/javascript">
        var box2 = document.getElementById('box2');
        box2.onmousemove = function(e){
            e = e || event;
            // 鼠标指针在可视区域中的水平和垂直坐标
            this.innerHTML = `screenX:${e.screenX},screenY:${e.screenY}`;
        }
    </script>
</body>


<!--pageX/Y表示相对于页面的水平和垂直坐标,它与clientX/clientY的区别是随滚动条的位置变化-->
<body style="height: 2000px;">
<div id="box3" style="width: 200px;height: 200px;background-color: red;"></div>
    <div id="result"></div>
    <script type="text/javascript">
        var box3 = document.getElementById('box3');
        var result = document.getElementById('result');
        box3.onmousemove = function(e){
            e = e || event;
            result.innerHTML = `clientX:${e.clientX};clientY:${e.clientY}<br>pageX:${e.pageX},pageY:${e.pageY}`;
        }
    </script>
</body>


<!--offsetX与offsetY 当鼠标事件发生时,鼠标相对于事件源x轴的位置 offsetY:当鼠标事件发生时,鼠标相对于事件源y轴的位置-->
<body style="height: 2000px;">
<div id="box4" style="width: 200px;height: 200px;background-color: red;">
    </div>
    <div id="result4"></div>
    <script type="text/javascript">
        var box4 = document.getElementById('box4');
        var result4 = document.getElementById('result4');
        box4.onmousemove = function(e){
            e = e || event;
            this.innerHTML = `clientX:${e.clientX};clientY:${e.clientY};offsetX:${e.offsetX};offsetY:${e.offsetY};`;
        }
    </script>
</body>
View Code

二、事件类型

事件说明
onclick 鼠标单击事件
ondblclick 鼠标双击事件
onmouseover 鼠标经过事件
onmouseout 鼠标移开事件
onmousedown 鼠标按钮被按下
onmousemove 鼠标被移动
onmouseleave 鼠标从元素离开
onfocus 光标聚焦事件 练习:输入框
onblur 光标失焦事件 应用场景:用于表单验证,用户离开某个输入框时,代表已经输入完了,我们可以对它进行验证.
onchange 域的内容被改变。 应用场景:文本框内容改变事件,通常用于表单元素,当元素内容被改变时触发.(三级联动)
onselect 文本框内容被选中事件
onkeydown 某个键盘按键被按下。 应用场景: 当用户在最后一个输入框按下回车按键时,表单提交.
onkeypress 某个键盘按键被按下并松开。
onkeyup 某个键盘按键被松开。
onload 网页加载事件
onsubmit 确认按钮被点击

三、事件介绍

1、onload

  • 一般只给body元素加
  • 这个属性的触发标志着页面内容被加载完成.
  • 应用场景: 当有些事情我们希望页面加载完立刻执行,那么可以使用该事件属性.

2、onsubmit

  • 当表单在提交时触发. 该属性也只能给form元素使用.
  • 应用场景: 在表单提交前验证用户输入是否正确.如果验证失败.在该方法中我们应该阻止表单的提交.

3、onfocus,onblur,onselect

<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>无标题文档</title>
<script>
/*
焦点 : 使浏览器能够区分用户输入的对象,当一个元素有焦点的时候,那么他就可以接收用户的输入。
可以通过一些方式给元素设置焦点
    1.点击
    2.tab
    3.js
    不是所有元素都能够接收焦点的.能够响应用户操作的元素才有焦点
*/
window.onload = function() {
    var oText = document.getElementById('text1');
    //onfocus : 当元素获取到焦点的时候触发
    oText.onfocus = function() {
        if ( this.value == '请输入内容' ) {
            this.value = '';
        }
    }
    //onblur : 当元素失去焦点的时候触发
    oText.onblur = function() {
        if ( this.value.trim() == '' ) {
            this.value = '请输入内容';
        }
    }
    /*
        obj.focus() 给指定的元素设置焦点
        obj.blur() 取消指定元素的焦点
        obj.select() 选择指定元素里面的文本内容
    */
    oText.focus();
    var oBtn = document.getElementById('btn');
    oBtn.onclick = function() {
        oText.select();
    }
}
</script>
</head>
<body>
    <input type="text" id="text1" value="请输入内容" />
    <input type="button" value="选中文本" id="btn" />
</body>
</html>
View Code

4、onchange

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script type="text/javascript">
        function changetext() {
            console.log('内容改变了');
        }
    </script>
</head>
<body>
<input type="text" value="hello" onchange="changetext();">

<select name="" id="">
    <option value="">111</option>
    <option value="">222</option>
    <option value="">333</option>
</select>

<script>
    var ele=document.getElementsByTagName("select")[0];
    ele.onchange=function(){
          console.log(123);
    }
</script>

</body>
</html>
View Code

5、onkeydown

  • Event对象:代表事件的状态,比如事件在其中发生的元素、键盘按键的状态、鼠标的位置、鼠标按钮的状态。
  • 事件通常与函数结合使用,函数不会在事件发生前被执行!
  • event对象在事件发生时系统已经创建好了,并且会在事件函数被调用时传给事件函数.我们获得仅仅需要接收一下即可.
  • 比如onkeydown,我们想知道哪个键被按下了,需要问下event对象的属性,这里就时KeyCode.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<input type="text" id="t1"/>
<script type="text/javascript">
    var ele=document.getElementById("t1");
    ele.onkeydown=function(e){
        e=e||window.event;
        var keynum=e.keyCode;
        var keychar=String.fromCharCode(keynum);
        alert(keynum+'----->'+keychar);
    };
</script>
</body>
</html>
View Code

6、onmouseout与onmouseleave事件的区别:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<style>
        #container{
            width: 300px;
        }
        #title{
            cursor: pointer;
            background: #ccc;
        }
       #list{
           display: none;
           background:#fff;
       }

        #list div{
            line-height: 50px;
        }
        #list  .item1{
            background-color: green;
        }

         #list  .item2{
            background-color: rebeccapurple;
        }

         #list  .item3{
            background-color: lemonchiffon;
        }
    </style>
<body>


<p>先看下使用mouseout的效果:</p>
<div id="container">
        <div id="title">使用了mouseout事件↓</div>
        <div id="list">
                <div class="item1">第一行</div>
                <div class="item2">第二行</div>
                <div class="item3">第三行</div>
        </div>
</div>
<script>

// 1.不论鼠标指针离开被选元素还是任何子元素,都会触发 mouseout事件。
// 2.只有在鼠标指针离开被选元素时,才会触发 mouseleave 事件。

   var container=document.getElementById("container");
   var title=document.getElementById("title");
   var list=document.getElementById("list");

   title.onmouseover=function(){
       list.style.display="block";
   };

   container.onmouseleave=function(){  // 改为mouseout试一下
       list.style.display="none";
   };

    /*
    因为mouseout事件是会冒泡的,也就是onmouseout事件可能被同时绑定到了container的子元素title和list
    上,所以鼠标移出每个子元素时也都会触发我们的list.style.display="none";
    */

    // list.onmouseout=function(){
    //       list.style.display="none";
    // };
    /*
      为什么移出第一行时,整个list会被隐藏?
     其实是同样的道理,onmouseout事件被同时绑定到list和它的三个子元素item上,所以离开任何一个
     子元素同样会触发list.style.display="none";
    */





</script>
</body>
</html>
View Code

四、阻止事件

1、preventDefault

preventDefault它是事件对象(Event)的一个方法,作用是取消一个目标元素的默认行为。既然是说默认行为,当然是元素必须有默认行为才能被取消,如果元素本身就没有默认行为,调用当然就无效了。什么元素有默认行为呢?如链接<a>,提交按钮<input type=”submit”>等。当Event对象的cancelable为false时,表示没有默认行为,这时即使有默认行为,调用 preventDefault也是不会起作用的。

<script>
window.onload=function(){
    //阻止表单提交方式1().
    //onsubmit 命名的事件函数,可以接受返回值. 其中返回false表示拦截表单提交.其他为放行.
     var ele=document.getElementById("form");
     ele.onsubmit=function(event) {
    //    alert("验证失败 表单不会提交!");
    //    return false;
 
    // 阻止表单提交方式2 event.preventDefault(); ==>通知浏览器不要执行与事件关联的默认动作。
     alert("验证失败 表单不会提交!");
     event.preventDefault();
}
</script>
View Code

2、stopPropagation

stopPropagation也是事件对象(Event)的一个方法,作用是阻止目标元素的冒泡事件,但是会不阻止默认行为。什么是冒泡事件?如 在一个按钮是绑定一个”click”事件,那么”click”事件会依次在它的父级元素中被触发 。stopPropagation就是阻止目标元素的事件冒泡到父级元素。如:

<div id="abc_1" style="border:1px solid red;width:300px;height:300px;">
    <div id="abc_2" style="border:1px solid red;width:200px;height:200px;"></div>
</div>
<script type="text/javascript">
        document.getElementById("abc_1").onclick=function(){
            alert('111');
        };
        document.getElementById("abc_2").onclick=function(event){
            alert('222');
            event.stopPropagation(); //阻止事件向外层div传播.
        }
</script>
View Code

3、return false

现在很多js代码都直接使用jQuery来写,在jQuery中使用return false时,相当于同时使用event.preventDefault和event.stopPropagation,它会阻止冒泡也会阻止默认行为但是使用原生js写时,return false只会阻止默认行为。下面两段代码说明

使用原生js方法时,return false只能阻止默认行为,但却不能阻止冒泡

五、事件补充

1、事件参数e

当事件发生的时候,系统会自动的给事件处理函数传递一个参数,会提供事件相关的一些数据,事件参数e浏览器的兼容性检测: e = e || window.event

e.pageX和e.pageY
获取鼠标在页面中的位置(IE8中不支持pageX和pageY,支持window.event获取参数事件) pageX = clientX + 页面滚动出去的距离

2、target 和currentTarget

target 始终是点击的元素(IE8及之前是srcElement)
currentTarget 执行事件处理函数的元素
this 始终和currentTarget一样

3、事件冒泡

  • 用addEventListener注册事件的时候,第三个参数是false,即是冒泡。
  • 冒泡的好处 - 事件委托
<body>
<ul id="ul">
    <li>我是第1个li标签</li>
    <li>我是第2个li标签</li>
    <li>我是第3个li标签</li>
    <li>我是第4个li标签</li>
</ul>
<input type="button" value="insertLi" id="btn">
<script>
    var ul = document.getElementById("ul");
    var btn = document.getElementById("btn");
//把本来应该给li注册的事件,委托给ul,只需要给一个元素注册事件
//动态创建的li,也会执行预期的效果
    ul.addEventListener("click", test, false);     //注册点击事件
    btn.onclick = function () {     //点击同样会有alert
        var li = document.createElement("li");
        li.innerHTML = "我是新插入的li标签";
        ul.appendChild(li);
    };
//函数写在注册事件代码之外,提高性能
    function test(e) {
        alert(e.target.innerText);
    }
</script>
</body>
事件委托

4、阻止事件

阻止冒泡

e.stopPropagation( ) IE8及之前:   event.cancleBubble = true;

阻止默认行为

e.preventDefault() IE8及之前:  event.returnValue = false;
<body>
    <a href="http://www.baidu.com" id="link">百度</a>
<script>
    var link = document.getElementById("link");
    link.addEventListener("click", fn, false);
    function fn(e) {
        e.preventDefault();
        //若用return false; 不起作用,若用link.onclick = function();return false可以阻止
    }
</script>
</body>
阻止默认行为

5、鼠标事件的参数

e.type 事件的类型,如click,mouseover
事件的3个阶段 1 捕获阶段 2 目标阶段 3 冒泡阶段
e.eventPhase 事件阶段
shiftKey/ctrlKey/altKey 按下鼠标同时按下组合键
button 获取鼠标的按键
e.clientX和e.clientY 获取鼠标在可视区域的位置

6、键盘事件对象

方法 属性
keydown  按下时  
keypress  按下 keyCode  键盘码,只有数字和字母对应ASCII码
keyup  抬起时 charCode  对应ASCII码,只有在keypress中才生效(IE9+)

六、实例练习

左侧菜单

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        *{
            margin: 0;
            padding: 0;
        }
          .left{
              width: 20%;
              height: 500px;
              float: left;
              background-color: wheat;
          }

          .right{
              float: left;
              width: 80%;
              height: 500px;
              background-color: lightgray;

          }

           .title{
               text-align: center;
               line-height: 40px;
               background-color: #0e90d2;
               color: white;
           }
        .item{
            padding: 10px;
        }

        .hide{
            display: none;
        }
    </style>
</head>
<body>



<div class="outer">
      <div class="left">
           <div class="item">
               <div class="title">菜单一</div>
               <ul class="con">
                   <li>111</li>
                   <li>111</li>
                   <li>111</li>
               </ul>
           </div>
          <div class="item">
               <div class="title">菜单二</div>
               <ul class="con hide">
                   <li>222</li>
                   <li>222</li>
                   <li>222</li>
               </ul>
           </div>
          <div class="item">
               <div class="title">菜单三</div>
               <ul class="con hide">
                   <li>333</li>
                   <li>333</li>
                   <li>333</li>
               </ul>
           </div>
      </div>
      <div class="right"></div>
</div>


<script>

    var eles_title=document.getElementsByClassName("title");



    for (var i=0;i<eles_title.length;i++){
         eles_title[i].onclick=function(){

             this.nextElementSibling.classList.remove("hide");

             for(var j=0;j<eles_title.length;j++){

                 if (eles_title[j]!=this){
                     eles_title[j].nextElementSibling.classList.add("hide")
                 }

             }


         }

    }




</script>
</body>
</html>
View Code

全选反选

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<button class="select_all">全选</button>
<button class="select_reverse">反选</button>
<button class="cancel">取消</button>

<hr>

<table class="server_table" border="2px" cellspacing="2px">
    <tr>
        <td><input type="checkbox" class="item"></td>
        <td>111</td>
        <td>111</td>
        <td>111</td>
    </tr>
    <tr>
        <td><input type="checkbox" class="item"></td>
        <td>222</td>
        <td>222</td>
        <td>222</td>
    </tr>
    <tr>
        <td><input type="checkbox" class="item"></td>
        <td>333</td>
        <td>333</td>
        <td>333</td>
    </tr>
    <tr>
        <td><input type="checkbox" class="item"></td>
        <td>444</td>
        <td>444</td>
        <td>444</td>
    </tr>
</table>


<script>
/*
    var ele_all=document.getElementsByClassName("select_all")[0];
    var ele_reverse=document.getElementsByClassName("select_reverse")[0];
    var ele_cancel=document.getElementsByClassName("cancel")[0];
    var input_arr=document.getElementsByClassName("item");

    ele_all.onclick=function(){
          for(var i=0;i<input_arr.length;i++){
              console.log(input_arr[i]);
              var input=input_arr[i];
              input.checked=true;
          }
    };

     ele_cancel.onclick=function(){
          for(var i=0;i<input_arr.length;i++){
              console.log(input_arr[i]);
              var input=input_arr[i];
              input.checked=false;
          }
    };

    ele_reverse.onclick=function(){
          for(var i=0;i<input_arr.length;i++){
              console.log(input_arr[i]);
              var input=input_arr[i];
              if(input.checked){
                  input.checked=false;
              }
              else{
                  input.checked=true;
              }
          }
    };

*/


    var input_arr=document.getElementsByClassName("item");
    var button_arr=document.getElementsByTagName("button");

    for(var i=0;i<button_arr.length;i++){

        button_arr[i].onclick=function(){


            for (var j=0;j<input_arr.length;j++){
                 var inp=input_arr[j]
                 if(this.innerText=="全选"){
                     console.log("ok");
                 inp.checked=true;
             }
            else if(this.innerText=="取消"){
                  inp.checked=false;
             }
            else {
                 if(inp.checked){
                     inp.checked=false;
                 }else {
                     inp.checked=true;
                 }
             }
                
            }
        }

    }
</script>
</body>
</html>
View Code

select移动

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

    <style>
        .outer{
            margin: 0 auto;
            background-color: darkgray;
            width: 80%;
            height: 600px;margin-top: 30px;
            word-spacing: -5px;

        }

        #left{
            display: inline-block;
            width: 100px ;
            height: 140px;
            background-color: wheat;
            text-align: center;


        }

        #choice{
            display: inline-block;
            height: 140px;
            background-color: darkolivegreen;

            vertical-align: top;
            padding:0 5px;


        }

        #choice button{
            margin-top: 20px;
        }

         #right{
            display: inline-block;
            width: 100px ;
            height: 140px;
            background-color: wheat;
            text-align: center;
            line-height: 140px;

        }

    </style>
</head>
<body>



<div class="outer">

    <select multiple="multiple" size="5" id="left">
    <option>红楼梦</option>
    <option>西游记</option>
    <option>水浒传</option>
    <option>JinPingMei</option>
    <option>三国演义</option>
</select>




<span id="choice">
    <button id="choose_move"> > </button><br>
    <button id="all_move"> >> </button>
</span>



<select multiple="multiple" size="10" id="right">
    <option>放风筝的人</option>
</select>


</div>




<script>

    var choose_move=document.getElementById("choose_move");
    var all_move=document.getElementById("all_move");

    var right=document.getElementById("right");
    var left=document.getElementById("left");
    var options=left.options;



    choose_move.onclick=function(){

        for (var i=0; i<options.length;i++){

             var option=options[i];
             if(option.selected==true){

                   // var news=option.cloneNode(true);
                   // console.log(news);

                   right.appendChild(option);
                   i--;
             }
         }
    };

    all_move.onclick=function(){

        for (var i=0; i<options.length;i++){

             var option=options[i];

                   right.appendChild(option);
                   i--;

         };
    };




    /*
   var buttons=document.getElementsByTagName("button");
   for(var i=0;i<buttons.length;i++) {
        buttons[i].onclick = function () {

            for (var i = 0; i < options.length; i++) {

                var option = options[i];

                if (this.innerText == ">") {
                    if (option.selected == true) {

                        // var news=option.cloneNode(true);
                        // console.log(news);

                        right.appendChild(option);
                        i--;
                    }
                } else {
                    right.appendChild(option);
                    i--;
                }
            }
        };
    }


   */


</script>


</body>
</html>
View Code

二级联动

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

</head>
<body>

<select id="province">
    <option>请选择省:</option>
</select>

<select id="city">
    <option>请选择市:</option>
</select>


<script>
    data={"河北省":["廊坊","邯郸"],"北京":["朝阳区","海淀区"]};


      var p=document.getElementById("province");
      var c=document.getElementById("city");

    for(var i in data){
        var option_pro=document.createElement("option");

        option_pro.innerHTML=i;

        p.appendChild(option_pro);
    }
     p.onchange=function(){

            pro=(this.options[this.selectedIndex]).innerHTML;
            citys=data[pro];

         c.options.length=0;

         for (var i in citys){
             var option_city=document.createElement("option");
             option_city.innerHTML=citys[i];
             c.appendChild(option_city);
         }

        }
</script>


</body>
</html>
View Code

跑马灯与tab切换

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>tab</title>
  <style>
    *{margin:0; padding:0; list-style:none;}
    body{
        font-family: "Helvetica Neue", "Hiragino Sans GB", "Microsoft YaHei", "\9ED1\4F53", Arial, sans-serif;
    }
    h3{
        text-align: center;
        color:darkcyan;
        margin-top: 30px;
        letter-spacing: 5px;
    }
    .box{
      width: 1000px;
      margin:50px auto 0px;
    }
    #title{
      line-height: 40px;
      background-color: rgb(247,247,247);
      font-size: 16px;
      font-weight: bold;
      color: rgb(102,102,102);
    }
    #title span{
      float: left;
      width: 166px;
      text-align: center;
    }
    #title span:hover{
      /*color: black;*/
      cursor: pointer;
    }
    #content{
      margin-top: 20px;
    }
    #content li{
      width: 1050px;
      display: none;
      background-color: rgb(247,247,247);
    }
    #content li div{
      width: 156px;
      margin-right: 14px;
      float: left;
      text-align: center;
    }
    #content li div a{
      font-size: 14px;
      color: black;
      line-height: 14px;
    /*  float: left;*/
    display: inline-block;
      margin-top: 10px;
    }
    #content li a:hover{
      color: #B70606;
    }
    #content li div span{
        font-size: 16px;
        line-height: 16px;
        /*float: left;*/
        display: block;
        color: rgb(102,102,102);
        margin-top: 10px;
      }
    #content img{
      float: left;
      width: 155px;
      height: 250px;
    }
    #title .select{
      background-color: #2459a2;
      color: white;
        border-radius: 10%;
    }
    #content .show{
      display: block;
    }

    .show span{
        color: red!important;
        font-size: 30px;
    }
  </style>
</head>

<body>
    <h3 id="wel">京东商城欢迎您</h3>
    <!--  direction="right up down left" -->
<!--  behavior:滚动方式(包括3个值:scroll、slide、alternate) -->
<!--  说明:scroll:循环滚动,默认效果;slide:只滚动一次就停止;alternate:来回交替进行滚动。 -->
<!--  scrollamount="5" 滚动速度 -->

<marquee behavior="scroll" direction="right">欢迎您苑昊先生</marquee>
    <script>

    function test(){

        var mywel = document.getElementById("wel");
        var content = mywel.innerText;

        var f_content = content.charAt(0);
        var l_content = content.substring(1,content.length);

        var new_content = l_content + f_content;
        mywel.innerText = new_content;

    }

    // setInterval("test();", 500);
</script>
    <div class="box">
      <p id="title">
        <span class="select">家用电器</span>
        <span>家具</span>
        <span>汽车</span>
        <span>食品</span>
        <span>女鞋</span>
        <span>医疗保健</span>
      </p>

      <ul id="content">
        <li class="show">

          <div><img src="https://img10.360buyimg.com/n1/s450x450_jfs/t4786/325/2470647304/119102/9e1a4ed5/59005841Nd786a8df.jpg" alt="冰箱"><a href="#">容声(Ronshen)冰箱</a><span>价格:5600</span></div>
          <div><img src="https://img12.360buyimg.com/n1/s450x450_jfs/t3037/347/1290968859/201366/7c1028a0/57c00194N9d0a54c6.jpg" alt="洗衣机"><a href="#">海尔洗衣机</a><span>价格:5400</span></div>
          <div><img src="https://img11.360buyimg.com/n1/jfs/t3289/128/2393835119/236360/af1d283b/57e0f300N53dde603.jpg" alt="电饭煲"><a href="#">福库(CUCKOO)电饭煲</a><span>价格:3999</span></div>
          <div><img src="https://img13.360buyimg.com/n1/jfs/t3235/137/2361713777/152258/a6908440/57e098c2N44a90a5d.jpg" alt="智能电视"><a href="#">三星智能电视</a><span>价格:8999</span></div>
          <div><img src="https://img10.360buyimg.com/n1/jfs/t2053/101/1391591157/215066/572e131b/5696ee9bN2376492d.jpg" alt="净水器"><a href="#">净水器</a><span>价格:1300</span></div>
          <div><img src="https://img14.360buyimg.com/n1/jfs/t3175/78/2357430273/262835/9a8e7f65/57e0a3e9Nbda39dd2.jpg" alt="空气净化器"><a href="#">空气净化器</a><span>价格:5300</span></div>
        </li>

        <li>

          <div><img src="https://img12.360buyimg.com/n1/jfs/t1948/172/2877517581/556924/682eb107/56f63dc8Naddf77e5.jpg" alt="沙发"><a href="#">沙发</a><span>价格:2900</span></div>
          <div><img src="https://img12.360buyimg.com/n1/jfs/t1948/172/2877517581/556924/682eb107/56f63dc8Naddf77e5.jpg" alt="沙发"><a href="#">沙发</a><span>价格:2900</span></div>
          <div><img src="https://img12.360buyimg.com/n1/jfs/t1948/172/2877517581/556924/682eb107/56f63dc8Naddf77e5.jpg" alt="沙发"><a href="#">沙发</a><span>价格:2900</span></div>
          <div><img src="https://img12.360buyimg.com/n1/jfs/t1948/172/2877517581/556924/682eb107/56f63dc8Naddf77e5.jpg" alt="沙发"><a href="#">沙发</a><span>价格:2900</span></div>
          <div><img src="https://img12.360buyimg.com/n1/jfs/t1948/172/2877517581/556924/682eb107/56f63dc8Naddf77e5.jpg" alt="沙发"><a href="#">沙发</a><span>价格:2900</span></div>
          <div><img src="https://img12.360buyimg.com/n1/jfs/t1948/172/2877517581/556924/682eb107/56f63dc8Naddf77e5.jpg" alt="沙发"><a href="#">沙发</a><span>价格:2900</span></div>

        </li>
        <li>
          <div><img src="http://img11.360buyimg.com/n1/jfs/t4969/76/45396935/144539/347153d4/58d9cff4N36872ad6.jpg" alt="长安汽车"><a href="#">长安汽车</a><span>价格:12900</span></div>
          <div><img src="http://img11.360buyimg.com/n1/jfs/t4969/76/45396935/144539/347153d4/58d9cff4N36872ad6.jpg" alt="长安汽车"><a href="#">长安汽车</a><span>价格:12900</span></div>
          <div><img src="http://img11.360buyimg.com/n1/jfs/t4969/76/45396935/144539/347153d4/58d9cff4N36872ad6.jpg" alt="长安汽车"><a href="#">长安汽车</a><span>价格:12900</span></div>
          <div><img src="http://img11.360buyimg.com/n1/jfs/t4969/76/45396935/144539/347153d4/58d9cff4N36872ad6.jpg" alt="长安汽车"><a href="#">长安汽车</a><span>价格:12900</span></div>
          <div><img src="http://img11.360buyimg.com/n1/jfs/t4969/76/45396935/144539/347153d4/58d9cff4N36872ad6.jpg" alt="长安汽车"><a href="#">长安汽车</a><span>价格:12900</span></div>
          <div><img src="http://img11.360buyimg.com/n1/jfs/t4969/76/45396935/144539/347153d4/58d9cff4N36872ad6.jpg" alt="长安汽车"><a href="#">长安汽车</a><span>价格:12900</span></div>
        </li>
        <li>

          <div><img src="https://img14.360buyimg.com/n1/jfs/t4414/110/2582917360/207971/b7e129ad/58f0ee1fN94425de1.jpg" alt="嘉兴粽子"><a href="#">嘉兴粽子</a><span>价格:1</span></div>
          <div><img src="https://img14.360buyimg.com/n1/jfs/t4414/110/2582917360/207971/b7e129ad/58f0ee1fN94425de1.jpg" alt="嘉兴粽子"><a href="#">嘉兴粽子</a><span>价格:1</span></div>
          <div><img src="https://img14.360buyimg.com/n1/jfs/t4414/110/2582917360/207971/b7e129ad/58f0ee1fN94425de1.jpg" alt="嘉兴粽子"><a href="#">嘉兴粽子</a><span>价格:1</span></div>
          <div><img src="https://img14.360buyimg.com/n1/jfs/t4414/110/2582917360/207971/b7e129ad/58f0ee1fN94425de1.jpg" alt="嘉兴粽子"><a href="#">嘉兴粽子</a><span>价格:1</span></div>
          <div><img src="https://img14.360buyimg.com/n1/jfs/t4414/110/2582917360/207971/b7e129ad/58f0ee1fN94425de1.jpg" alt="嘉兴粽子"><a href="#">嘉兴粽子</a><span>价格:1</span></div>
          <div><img src="https://img14.360buyimg.com/n1/jfs/t4414/110/2582917360/207971/b7e129ad/58f0ee1fN94425de1.jpg" alt="嘉兴粽子"><a href="#">嘉兴粽子</a><span>价格:1</span></div>


        </li>
        <li>

          <div><img src="https://img14.360buyimg.com/n1/jfs/t3079/298/5759209435/92674/14818594/587f1c33N53e5d2a9.jpg" alt="星期六"><a href="#">星期六</a><span>价格:439</span></div>
          <div><img src="https://img14.360buyimg.com/n1/jfs/t3079/298/5759209435/92674/14818594/587f1c33N53e5d2a9.jpg" alt="星期六"><a href="#">星期六</a><span>价格:439</span></div>
          <div><img src="https://img14.360buyimg.com/n1/jfs/t3079/298/5759209435/92674/14818594/587f1c33N53e5d2a9.jpg" alt="星期六"><a href="#">星期六</a><span>价格:439</span></div>
          <div><img src="https://img14.360buyimg.com/n1/jfs/t3079/298/5759209435/92674/14818594/587f1c33N53e5d2a9.jpg" alt="星期六"><a href="#">星期六</a><span>价格:439</span></div>
          <div><img src="https://img14.360buyimg.com/n1/jfs/t3079/298/5759209435/92674/14818594/587f1c33N53e5d2a9.jpg" alt="星期六"><a href="#">星期六</a><span>价格:439</span></div>
          <div><img src="https://img14.360buyimg.com/n1/jfs/t3079/298/5759209435/92674/14818594/587f1c33N53e5d2a9.jpg" alt="星期六"><a href="#">星期六</a><span>价格:439</span></div>

        </li>
        <li>

          <div><img src="https://img12.360buyimg.com/n1/jfs/t5755/127/1139389729/356866/99d4e869/5923e410Nb2983f70.jpg" alt="汇仁 肾宝片"><a href="#">汇仁 肾宝片</a><span>价格:322</span></div>
          <div><img src="https://img12.360buyimg.com/n1/jfs/t5755/127/1139389729/356866/99d4e869/5923e410Nb2983f70.jpg" alt="汇仁 肾宝片"><a href="#">汇仁 肾宝片</a><span>价格:322</span></div>
          <div><img src="https://img12.360buyimg.com/n1/jfs/t5755/127/1139389729/356866/99d4e869/5923e410Nb2983f70.jpg" alt="汇仁 肾宝片"><a href="#">汇仁 肾宝片</a><span>价格:322</span></div>
          <div><img src="https://img12.360buyimg.com/n1/jfs/t5755/127/1139389729/356866/99d4e869/5923e410Nb2983f70.jpg" alt="汇仁 肾宝片"><a href="#">汇仁 肾宝片</a><span>价格:322</span></div>
          <div><img src="https://img12.360buyimg.com/n1/jfs/t5755/127/1139389729/356866/99d4e869/5923e410Nb2983f70.jpg" alt="汇仁 肾宝片"><a href="#">汇仁 肾宝片</a><span>价格:322</span></div>
          <div><img src="https://img12.360buyimg.com/n1/jfs/t5755/127/1139389729/356866/99d4e869/5923e410Nb2983f70.jpg" alt="汇仁 肾宝片"><a href="#">汇仁 肾宝片</a><span>价格:322</span></div>

        </li>


      </ul>
    </div>

    <script>
      var title=document.getElementById('title');
      var content=document.getElementById('content');
      var category=title.getElementsByTagName('span');
      var item=content.getElementsByTagName('li');

      for (var i = 0; i < category.length; i++) {

          category[i].index=i;

          category[i].onclick=function(){

            for (var j = 0; j < category.length; j++) {
              category[j].className='';
              item[j].className='';
            }
            this.className='select';
            item[this.index].className='show';
          }


      }

    </script>
</body>
</html>
View Code
<!DOCTYPE html>
<html>
    <head>
        <meta charset='utf-8' >
        <title>欢迎blue shit莅临指导&nbsp;&nbsp;</title>
        <script type='text/javascript'>
            function Go(){
                var content = document.title;
                var firstChar = content.charAt(0)
                var sub = content.substring(1,content.length)
                document.title = sub + firstChar;
            }
            setInterval('Go()',1000);
        </script>
    </head>
    <body>    
    </body>
</html>
跑马灯
<!DOCTYPE html>
<html>
    <head>
        <meta charset='utf-8' />
        <title></title>
        
        <style>
            .gray{
                color:gray;
            }
            .black{
                color:black;
            }
        </style>
        <script type="text/javascript">
            function Enter(){
               var id= document.getElementById("tip")
               id.className = 'black';
               if(id.value=='请输入关键字'||id.value.trim()==''){
                    id.value = ''
               }
            }
            function Leave(){
                var id= document.getElementById("tip")
                var val = id.value;
                if(val.length==0||id.value.trim()==''){
                    id.value = '请输入关键字'
                    id.className = 'gray';
                }else{
                    id.className = 'black';
                }
            }
        </script>
    </head>
    <body>
        <input type='text' class='gray' id='tip' value='请输入关键字' onfocus='Enter();'  onblur='Leave();'/>
    </body>
</html>

搜索框
搜索框

client、offset、scroll系列

他们的作用主要与计算盒模型、盒子的偏移量和滚动有关

一、offset偏移大小

偏移量(offset dimension)是javascript中的一个重要的概念。涉及到偏移量的主要是offsetLeft、offsetTop、offsetHeight、offsetWidth这四个属性。当然,还有一个偏移参照——定位父级offsetParent。

1、定位父级

  • 人们并没有把offsetParent翻译为偏移父级,而是翻译成定位父级,很大原因是offsetParent与定位有关
  • 定位父级offsetParent的定义是:与当前元素最近的经过定位(position不等于static)的父级元素,主要分为下列几种情况:
    • 元素自身有fixed定位,offsetParent的结果为null 注意:firefox浏览器有兼容性问题返回body
    • 元素自身无fixed定位,且父元素都没有设置定位,offsetParent的结果为body
    • 元素自身无fixed定位,且父级元素存在经过定位的元素,offsetParent的结果为离自身元素最近的经过定位的父级元素
    • body元素的offsetParent是null
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div id="test" style="position:fixed"></div>
<script>
var test = document.getElementById('test');
console.log(test.offsetParent); //返回null  注意:firefox并没有考虑固定定位的问题,返回<body>
</script>


<div id="test2" ></div>
<script>
var test2 = document.getElementById('test2');
console.log(test2.offsetParent); //返回<body>
</script>


<div id="grandfather" style="position: relative;">
    <div id="father" >
        <div id="test3"></div>
    </div>
</div>
<script type="text/javascript">
    var test3 = document.getElementById('test3');
    // 距离该子元素最近的进行过定位的父元素,如果其父元素不存在定位则offsetParent为:body元素;
    console.log(test3.offsetParent); // 返回 <div id="grandfather" style="position: relative;">
</script>


<script type="text/javascript">
    console.log(document.body.offsetParent);//null    <body>元素的offsetParent是null
</script>

</body>
</html>
View Code

2、偏移量

  • 偏移量共包括了offsetHeight、offsetWidth、offsetLeft、offsetTop这四个属性
  • offsetWidth表示元素在水平方向上占用的空间大小,无单位(以像素px计) offsetWidth = border-left-width + padding-left + width + padding-right + border-right-width;
  • offsetHeight表示元素在垂直方向上占用的空间大小,无单位(以像素px计) offsetHeight = border-top-width + padding-top + height + padding-bottom + border-bottom-width
  • body元素的offsetParent是null
  • 注意:如果想修改盒子的大小,请使用xxx.style.width进行设置。
  • offsetTop表示元素的上外边框至offsetParent元素的上内边框之间的像素距离
  • offsetLeft表示元素的左外边框至offsetParent元素的左内边框之间的像素距离
  • 总结:相对于父元素(看父元素是否有定位,如果有定位,以父元素为基础,如果没有继续往上寻找,如果一直没有找到,则以body为基准)的左边距和上边距
  • offsetHeight、offsetWidth、offsetLeft、offsetTop是只读属性.
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <style>
            #box {
                width: 200px;
                height: 150px;
                background-color: red;
                padding: 10px;
                border: 5px solid #ddd;
                margin: 10px;
            }
        </style>
    </head>
    <body>
        <div id="box" style="width: 100px;height: 100px;"></div>
        <script>
            var box = document.getElementById('box');
            //offsetHeight = 内容高 + 上下内边距 + 边框
            console.log(box.offsetWidth,box.offsetHeight); //130  130
            console.log(box.offsetLeft,box.offsetTop);  //18  10
            console.log(box.style.width, box.style.height);//100px 100px
            // 可以设置大小
            box.style.width = 500 + 'px';
            box.style.height = 500 + 'px';
            
            // 不可以设置大小
            box.offsetWidth = 100 + 'px';
            box.offsetHeight = 100 + 'px';
            box.offsetLeft = 100 + 'px';
            box.offsetTop = 100 + 'px';

            console.log(box.offsetWidth,box.offsetHeight); //530  530
            console.log(box.offsetLeft,box.offsetTop);  //18  10
            console.log(box.style.width, box.style.height);//500px 500px

        </script>
    </body>
</html>
View Code
<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title></title>
        <style type="text/css">
            *{
                padding: 0;
                margin: 0;
            }
            #father{
                width: 400px;
                height: 400px;
                background-color: red;
                /* position: relative; */
                margin: 40px;
            }
            #son {
                width: 200px;
                height: 100px;
                background-color: green;
                padding: 10px;
                border: 5px solid #DA70D6;
                margin-left: 20px;
            }
        </style>
    </head>
    <body>
        <div id="father">
            <div id="son"></div>
        </div>
        <script type="text/javascript">
            var box = document.getElementById('son');
            //总结:相对于父元素(看父元素是否有定位,如果有定位,以父元素为基础,如果没有继续往上寻找,如果一直没有找到,则以body为基准)的左边距和上边距
            //如果有父级定位元素: 结果为离自身元素最近的经过定位的父级元素
            console.log(box.offsetLeft);//20
            console.log(box.offsetTop); //0
            //如果无父级定位元素
            console.log(box.offsetLeft);//60
            console.log(box.offsetTop); //40
        </script>
    </body>
</html>
View Code
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title></title>
</head>
<body>
<div style="padding: 20px;border:1px solid black;position:absolute;">
    <div id="test" style="width:100px; height:100px; margin:10px;background-color: red;"></div>
</div>
<script type="text/javascript">
    var test = document.getElementById('test');
    console.log(getElementLeft(test)); //39px
    console.log(getElementTop(test)); // 39px

    /*
      求出当前元素的页面偏移量:
​      要知道某个元素在页面上的偏移量,将这个元素的offsetLeft和offsetTop与其offsetParent的相同属性相加,
      并加上offsetParent的相应方向的边框,如此循环直到根元素,就可以得到元素到页面的偏移量
    */

    function getElementLeft(ele) {
        var actualLeft = ele.offsetLeft;
        var parent = ele.offsetParent;
        while (parent != null) {
            actualLeft = actualLeft + parent.offsetLeft + parent.clientLeft;
            parent = parent.offsetParent;
        }
        return actualLeft + 'px';
    }

    function getElementTop(ele) {
        var actualTop = ele.offsetTop;
        var parent = ele.offsetParent;
        while (parent != null) {
            actualTop = actualTop + parent.offsetTop + parent.clientTop;
            parent = parent.offsetParent;
        }
        return actualTop + 'px';
    }
</script>
</body>
</html>
元素到页面的偏移量

offsetWidth和offsetHeight
offsetHeight的构成
offsetHeight = height + padding + border
offsetWidth相同
 
offsetHeight和style.height的区别
1. demo.style.height只能获取行内样式,否则无法获取到
2. .style.height是字符串(有单位px), offsetHeight是数值(无单位)
3. .style.height可以设置行内样式,但offsetHeight是只读属性,不可设置
所以:demo.style.height获取 某元素的真实高度/宽度,用.style.height来设置高度/宽度
offsetLeft和offsetTop
offsetLeft的构成
1,到距离自身最近的(带有定位的)父元素的 左侧/顶部
2,如果所有父级元素都没有定位,则以body为准
3,offsetLeft是自身border左侧到父级padding左侧的距离
 
offsetLeft和style.left的区别
1,style.left只能获取行内样式
2,offsetLeft只读,style.left可读可写
3,offsetLeft是数值,style.left是字符串并且有单位px
4,如果没有定位,style.left获取的数值可能是无效的
5,最大的区别:offsetLeft以border左上角为基准, style.left以margin左上角为基准
offsetParent
构成
1. 返回该对象距离最近的带有定位的父级元素
2. 如果当前元素的所有父级元素都没有定位(position为absolute或relative),那么offsetParent为body
3. offsetLeft获取的就是相对于offsetParent的距离
 
与parentNode的区别
parentNode始终指向的是当前元素的最近的父元素,无论定位与否

二、scroll滚动大小

1、滚动宽高

  • scrollHeight表示元素的总高度,包括由于溢出而无法展示在网页的不可见部分
  • scrollWidth表示元素的总宽度,包括由于溢出而无法展示在网页的不可见部分
  • 没有滚动条时,scrollHeight与clientHeight属性结果相等,scrollWidth与clientWidth属性结果相等
  • 存在滚动条时,但元素设置宽高大于等于元素内容宽高时,scroll和client属性的结果相等
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div id="test" style="width: 100px;height: 100px;padding: 10px;margin: 10px;border: 1px solid black;"></div>
<script>
    var test = document.getElementById('test');
    console.log(test.scrollHeight, test.scrollWidth); //120 120
    console.log(test.clientHeight, test.clientWidth);//120 120
</script>

</body>
</html>
View Code

2、滚动长度

  • scrollTop属性表示被隐藏在内容区域上方的像素数。元素未滚动时,scrollTop的值为0,如果元素被垂直滚动了,scrollTop的值大于0,表示元素上方不可见内容的像素高度
  • scrollLeft属性表示被隐藏在内容区域左侧的像素数。元素未滚动时,scrollLeft的值为0,如果元素被水平滚动了,scrollLeft的值大于0,且表示元素左侧不可见内容的像素宽度
  • 当滚动条滚动到内容底部时,符合以下等式 scrollHeight = scrollTop + clientHight
  • 与scrollHeight和scrollWidth属性不同的是,scrollLeft和scrollTop是可写的
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div id="test" style="width: 100px;height: 100px;padding: 10px;margin: 10px;border: 1px solid black;overflow:scroll;font-size:20px;line-height:200px;">
    内容<br>内容<br>
</div>
<button id="btn1">向下滚动</button>
<button id="btn2">向上滚动</button>
<script type="text/javascript">
    var test = document.getElementById('test');
    // scrollLeft和scrollTop是可读写的
    var btn1 = document.getElementById('btn1');
    var btn2 = document.getElementById('btn2');
    btn1.onclick =  function (){
        test.scrollTop += 10;
    };
    btn2.onclick =  function (){
        test.scrollTop -= 10;
    };
</script>

</body>
</html>
View Code

3、页面滚动

  • 理论上,大部分的浏览器通过document.documentElement.scrollTop和scrollLeft可以反映和控制页面的滚动;safari浏览器是通过document.body.scrollTop和scrollLeft来控制的
  • 页面的滚动高度兼容写法是: var docScrollTop = document.documentElement.scrollTop || document.body.scrollTop
    var docScrollLeft = document.documentElement.scrollLeft || document.body.scrollLeft
<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title></title>
    </head>
    <body style="height: 2000px;">
        <button id="backTop" style="position: fixed;">回到顶部</button>
        <script type="text/javascript">
            var backTop = document.getElementById('backTop');
            backTop.onclick = scrollTop;
            function scrollTop(){
                //兼容性写法
                if(document.documentElement.scrollTop || document.body.scrollTop){
                    document.documentElement.scrollTop = document.body.scrollTop = 0;
                }
            }
        </script>
    </body>
</html>
回到顶部

4、滚动方法scrollTo(x,y)

  • scrollTo(x,y)方法滚动当前window中显示的文档,让文档中由坐标x和y指定
  • 回到顶部: window.scrollTo(0,0);
  • 回到底部: window.scrollTo(0,document.body.scrollHeight);
<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title></title>
    </head>
   <body style="height: 2000px;">
    <button id="backTop" style="position: fixed;">回到顶部</button>

    <script type="text/javascript">
        //scrollTo(x,y)方法滚动当前window中显示的文档,让文档中由坐标x和y指定的点位于显示区域的左上角
        var backTop = document.getElementById('backTop');
        backTop.onclick = scrollTop;
        function scrollTop(){
            scrollTo(0,0);
        }
    </script>
</body>
</html>
View Code
scrollHeight和scrollWidth 对象内部的实际内容的高度/宽度(不包括border)
scrollTop和scrollLeft 被卷去部分的顶部/左侧 到 可视区域 顶部/左侧 的距离
onscroll事件 滚动条滚动触发的事件
页面滚动坐标 var scrollTop = window.pageYoffset || document.documentElement.scrollTop || document.body.scrollTop || 0;

三、client客户区大小

  • 客户区大小client:指的是元素内容及其内边距所占据的空间大小
  • clientHeight属性返回元素节点的客户区高度 clientHeight = padding-top + height + padding-bottom
  • clientWidth属性返回元素节点的客户区宽度 clientWidth = padding-left + width + padding-right
  • clientLeft属性返回左边框的宽度
  • clientTop属性返回上边框的宽度
  • 页面大小:常用document.documentElement的client属性来表示页面大小(不包含滚动条宽度)document.documentElement.clientWidth; document.documentElement.clientHeight;
  • 如果给元素设置了display:none,则客户区client属性都为0
  • 每次访问客户区client属性都需要重新计算,重复访问需要耗费大量的性能,所以要尽量避免重复访问这些属性。如果需要重复访问,则把它们的值保存在变量中,以提高性能
  • 所有的client属性都是只读的
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <div id="test" style="width: 100px;height: 100px;padding: 10px;margin: 10px;border: 1px solid black;"></div>
<script>
    var test = document.getElementById('test');
    console.log(test.clientHeight);  //120
    //静态失败了
    test.clientHeight = 10;
    console.log(test.clientHeight);  //120

    console.log(test.clientWidth);  //120
    console.log(test.clientLeft);  //1
    console.log(test.clientTop);  //1
</script>


<div id="test2" style="width: 100px;height: 100px;padding: 10px;margin: 10px;border: 1px solid black;display:none;"></div>
<script>
    var test2 = document.getElementById('test2');
    console.log(test2.clientHeight);  //0
    console.log(test2.clientWidth);  //0
    console.log(test2.clientLeft);  //0
    console.log(test2.clientTop);  //0
</script>



<div id="test3" style="width: 100px;height: 100px;padding: 10px;margin: 10px;border: 1px solid black;"></div>
<script>
    var test3 = document.getElementById('test3');
    console.time("time");
    for(var i = 0; i < 100000; i++){
        var a = test3.clientHeight;
    }
    console.timeEnd('time');//time: 26.02685546875ms
</script>


    
<div id="test4" style="width: 100px;height: 100px;padding: 10px;margin: 10px;border: 1px solid black;"></div>
<script>
    var test4 = document.getElementById('test4');
    console.time("time");
    var a = test4.clientHeight;
    for(var i = 0; i < 100000; i++){
        var b = a;
    }
    console.timeEnd('time');// time: 1.602294921875ms
</script>


</html>
View Code

function client() {
            return {
                        clientWidth: window.innerWidth || document.body.clientWidth || document.documentElement.clientWidth || 0;
                        clientHeight: window.innerHeight || document.body.clientHeitght || document.documentElement.clientHeight || 0;
            };
}
获得页面可视区域的大小
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
        <style type="text/css">
        body{ margin:0; padding:0}
            .box{
                width: 200px;
                height: 200px;
                position: absolute;
                border: 20px solid red;
                /*margin: 10px 0px 0px 0px;*/
                margin:100px;
                padding: 80px;
            }
        </style>
    </head>
    <body  style="height: 2000px">
        <div class="box">
            专业丰富的课程体系,博学多闻的实力讲师以及风趣生动的课堂,在路飞,不是灌输知识,而是点燃你的学习火焰。专业丰富的课程体系,博学多闻的实力讲师以及风趣生动的课堂,在路飞,不是灌输知识,而是点燃你的学习火焰。专业丰富的课程体系,博学多闻的实力讲师以及风趣生动的课堂,在路飞,不是灌输知识,而是点燃你的学习火焰。专业丰富的课程体系,博学多闻的实力讲师以及风趣生动的课堂,在路飞,不是灌输知识,而是点燃你的学习火焰。
        </div>
        
        
      <div id="box" style="width: 200px;height: 200px;border: 5px solid red;position: absolute;top:200px;left: 600px; padding:10px" >            
      </div>
  
    
     <div class="wrap" style=" position:absolute; left:500px; top:300px; width: 300px;height: 300px;background-color: green">
           <div id="box2" style="width: 200px;height: 200px;border: 5px solid red;position: absolute;top:50px;left: 30px; padding:10px" >            
           </div>
     </div>
        
        
    </body>
    <script type="text/javascript">
        /*
         *      clientTop 内容区域到边框顶部的距离 ,说白了,就是边框的高度
         *      clientLeft 内容区域到边框左部的距离,说白了就是边框的宽度
         *      clientWidth 内容区域+左右padding   可视宽度
         *      clientHeight 内容区域+ 上下padding   可视高度
         * */

        var oBox = document.getElementsByClassName('box')[0];
        console.log(oBox.clientTop);   //20
        console.log(oBox.clientLeft);  //20
        console.log(oBox.clientWidth); //360
        console.log(oBox.clientHeight); //360
    
        // 屏幕的可视区域(就是窗口大小)
        window.onload = function(){
            
            // document.documentElement 获取的是html标签
            
            console.log(document.documentElement.clientWidth);  //1903
            console.log(document.documentElement.clientHeight); //406
            // 窗口大小发生变化时,会调用此方法
            window.onresize = function(){    
                console.log(document.documentElement.clientWidth);  //1205
                console.log(document.documentElement.clientHeight); //309
            }    
            
            
            //
            var box = document.getElementById('box')
            var box2 = document.getElementById('box2')
            /*
             offsetWidth占位宽  内容+padding+border
             offsetHeight占位高 
             offsetTop: 如果盒子没有设置定位 到body的顶部的距离,如果盒子设置定位,那么是以父辈为基准的top值
             offsetLeft: 如果盒子没有设置定位 到body的左部的距离,如果盒子设置定位,那么是以父辈为基准的left值
             * */
            console.log(box.offsetTop) //200
            console.log(box.offsetLeft) // 600
            console.log(box.offsetWidth) //230
            console.log(box.offsetHeight) //230
            
            
            //不管父标签是position:absolute还是position:relative都一样
            console.log(box2.offsetTop) //50
            console.log(box2.offsetLeft) // 30
            console.log(box2.offsetWidth) //230
            console.log(box2.offsetHeight) //230
            
            
        }
    
        
        //window.scrollTo(0,document.body.scrollHeight)

    </script>

</html>
client,offset
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
        <style type="text/css">
            *{padding: 0;margin: 0;}
        </style>
    </head>
    <body style="width: 2000px;height: 2000px;">
        <div style="height: 200px;background-color: red;"></div>
        <div style="height: 200px;background-color: green;"></div>
        <div style="height: 200px;background-color: yellow;"></div>
        <div style="height: 200px;background-color: blue;"></div>
        <div style="height: 200px;background-color: gray;"></div>
        <div id = 'scroll' style="width: 200px;height: 200px;border: 1px solid red;overflow: auto;padding: 10px;margin: 5px 0px 0px 0px;">
            <p>学习新技能,达成人生目标,开始用自己的力量影响世界学习新技能,达成人生目标,开始用自己的力量影响世界学习新技能,达成人生目标,开始用自己的力量影响世界学习新技能,达成人生目标,开始用自己的力量影响世界学习新技能,达成人生目标,开始用自己的力量影响世界学习新技能,达成人生目标,开始用自己的力量影响世界学习新技能,达成人生目标,开始用自己的力量影响世界学习新技能,达成人生目标,开始用自己的力量影响世界学习新技能,达成人生目标,开始用自己的力量影响世界学习新技能,达成人生目标,开始用自己的力量影响世界学习新技能,达成人生目标,开始用自己的力量影响世界学习新技能,达成人生目标,开始用自己的力量影响世界
            </p>

        </div>


    </body>
    <script type="text/javascript">

        window.onload = function(){
            
            //window.scrollTo(0,document.body.scrollHeight)

            //实施监听滚动事件
            window.onscroll = function(){
               console.log(''+document.documentElement.scrollTop)
               console.log(''+document.documentElement.scrollLeft)
               console.log(''+document.documentElement.scrollWidth)
               console.log(''+document.documentElement.scrollHeight)
            }

            var s = document.getElementById('scroll');
            s.onscroll = function(){
//              scrollHeight : 内容的高度+padding  不包含边框
                console.log(''+s.scrollTop)
                console.log(''+s.scrollLeft)
                console.log(''+s.scrollWidth)
                console.log(''+s.scrollHeight)
            }
        }

    </script>
</html>
scroll

四、获得计算后样式的方法

w3c标准 window.get ComputedStyle(element, null)[属性]
IE浏览器 element.currentStyle[属性]
封装浏览器兼容性函数
function getStyle(element, attr) {
        if(window.getComputedStyle) {
            return window.getComputedStyle(element, null)[attr];
        } else {
            return element.currentStyle[attr];
        }
    }

五、运动

  • 匀速运动:让一个元素在页面中运动起来很简单,设置定时器,改变定位元素的left和top值即可
  • 缓冲运动: 速度 = (结束值-起始值) * 缓动系数。缓动系数为0到1之间的数。举个例子,比如火车在进站的时候,速度是由快到慢的过程,而火车在离站的时候是由慢到快的过程。
  • 透明度动画:透明度是一个比较特殊的样式,因为IE8浏览器不支持opacity,只能通过滤镜的方式写成filter:alpha(opacity=透明值)
  • 多物体动画:如果在页面中有多个元素利用运动函数进行运动。由于定时器返回值在不同元素上是不同的返回值。所以要将全局的定时器挂载到当前的元素之上。
  • 链式动画:物体的多个属性可能是同时运动,也可能是一个属性运动完成之后,另一个属性再运动。如果要完成这种效果,就需要用到回调函数。
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <style>
            * {
                padding: 0;
                margin: 0;
            }
            #box {
                position: relative;
                width: 200px;
                height: 200px;
                background-color: red;
                left: -200px;
            }
            #box span {
                position: absolute;
                width: 40px;
                height: 60px;
                background-color: #000;
                color: #fff;
                right: -40px;
                top: 50%;
                margin-top: -30px;
                line-height: 60px;
                text-align: center;
            }
        </style>
    </head>
    <body>
        <div id="box">
            <span>拉开</span>
        </div>
        <script>
            window.onload = function() {
                var oDiv = document.getElementById('box');
                var timer = null;
                oDiv.onmouseover = function() {
                    //1.先清除定时器,再开启定时器
                   // clearInterval(timer);
                    //2.当定时器未停止时,不允许开启新定时器
                   //注意:由于定时器开启时,其返回值是一个不为0的整数,所以可以通过判断其返回值,来确定是否使用return语句
                    if(timer) return;
                    timer = setInterval(function() {
                        if (oDiv.offsetLeft == 500) {
                            clearInterval(timer);
                        } else {
                            oDiv.style.left = oDiv.offsetLeft + 5 + 'px';
                        }
                    }, 30)
                }
            }
        </script>
    </body>
</html>        
清除定时器的两种方式
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <style>
            * {
                padding: 0;
                margin: 0;
            }
            #box {
                position: relative;
                width: 200px;
                height: 200px;
                background-color: red;
                left: -200px;
            }
            #box span {
                position: absolute;
                width: 40px;
                height: 60px;
                background-color: #000;
                color: #fff;
                right: -40px;
                top: 50%;
                margin-top: -30px;
                line-height: 60px;
                text-align: center;
            }
        </style>
    </head>
    <body>
        <div id="box">
            <span>拉开</span>
        </div>
        <script>
            window.onload = function() {
                var oDiv = document.getElementById('box');
                var timer = null;
                oDiv.onmouseover = function() {
                    //先清除定时器 再开启定时器
                    clearInterval(timer);
                    timer = setInterval(function() {
                        //设置边界,清除定时器
                        if (oDiv.offsetLeft === 0) {
                            clearInterval(timer);
                        } else {
                            oDiv.style.left = oDiv.offsetLeft + 5 + 'px';
                        }
                    }, 30)
                };
                oDiv.onmouseout = function() {
                    //先清除定时器 再开启定时器
                    clearInterval(timer);
                    timer = setInterval(function() {
                        console.log(oDiv.offsetLeft);
                        //设置边界,清除定时器
                        if (oDiv.offsetLeft === -200) {
                            clearInterval(timer);
                        } else {
                            oDiv.style.left = oDiv.offsetLeft - 5 + 'px';
                        }
                    }, 30)
                }
            }
        </script>


<script>
        window.onload = function () {
            var oDiv = document.getElementById('box');
            oDiv.onmouseover = function () {
                //匀速运动开始
                startMove(this,0)
            };
            oDiv.onmouseout = function () {
                //匀速运动开始
                startMove(this,-200)
            }
        };
        var timer = null,speed = 0;
        /**
         * @param {Object} oDiv 当前目标对象
         * @param {Object} target 运动到的目标位置
         */
        function startMove(oDiv,target) {
            //先清除定时器 再开启定时器
            clearInterval(timer);
            timer = setInterval(function () {
                //我们要求盒子既能向前又能向后,那么我们的步长就得有正有负
                //目标值如果大于当前值取正,目标值如果小于当前值取负
                speed  = target > oDiv.offsetLeft ? 10 : -10;
                //设置边界,清除定时器
                if(oDiv.offsetLeft === target){
                    clearInterval(timer);
                }else{
                 oDiv.style.left = oDiv.offsetLeft + speed + 'px';
                }
            },30)
        }
    </script>


    </body>
</html>
匀速运动--分享到
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <style>
            * {
                padding: 0;
                margin: 0;
            }
            #box {
                position: relative;
                width: 200px;
                height: 200px;
                background-color: red;
                left: -200px;
            }
            #box span {
                position: absolute;
                width: 40px;
                height: 60px;
                background-color: #000;
                color: #fff;
                right: -40px;
                top: 50%;
                margin-top: -30px;
                line-height: 60px;
                text-align: center;
            }
        </style>
    </head>
    <body>
        <div id="box">
            <span>拉开</span>
        </div>
        <script>
            window.onload = function() {
                var oDiv = document.getElementById('box');
                var timer = null,target = 0,target1 = -200;
                console.log(oDiv.offsetLeft);

                oDiv.onmouseover = function() {
                    clearInterval(timer);
                    timer = setInterval(function() {
                        speed = (target-oDiv.offsetLeft) / 8;
                        speed=speed>0?Math.ceil(speed):Math.floor(speed);
                        if (oDiv.offsetLeft == target) {
                            clearInterval(timer);
                        } else {
                            oDiv.style.left = oDiv.offsetLeft + speed + 'px';
                        }
                    }, 30)
                };
                oDiv.onmouseout= function() {
                    clearInterval(timer);
                    timer = setInterval(function() {
                        speed = (target1-oDiv.offsetLeft) / 8;
                        speed=speed>0?Math.ceil(speed):Math.floor(speed);
                        if (oDiv.offsetLeft == target1) {
                            clearInterval(timer);
                        } else {
                            oDiv.style.left = oDiv.offsetLeft + speed + 'px';
                        }
                    }, 30)
                }
            }
        </script>



    <script>
            window.onload = function() {
                //获取标签
                var oDiv = document.getElementById('box');
                //定时器变量设置全局,后面要处理
                var timer = null;
                oDiv.onmouseover = function() {
                    slowMove(this,0);
                };

                oDiv.onmouseout= function() {
                    slowMove(this,-200);
                };
                function slowMove(obj,target){
                    clearInterval(timer);
                    timer = setInterval(function() {
                        speed = (target-obj.offsetLeft) / 20;
                        //如果速度是大于0,说明是往右走,向上取整。速度小于0,说明往左走,向下取整
                        speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed);
                        if (obj.offsetLeft == target) {
                            clearInterval(timer);
                        } else {
                            obj.style.left = obj.offsetLeft + speed + 'px';
                        }
                    }, 30)
                }
            }
        </script>
    

    </body>
</html>
缓冲运动
<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title></title>
        <style type="text/css">
            #box{
                width: 200px;
                height: 200px;
                background-color: red;
                opacity: 0.3;
                filter: alpha(opactity:30);
            }
        </style>
    </head>
    <body>
    
    <!--与物体运动不同的是,透明度的变化时改变的opacity值的变化。css属性中没有像offsetAlpha类似的值。-->
    <!--所以我们在全局定义一个初始的alpha = 30的变量,来控制当前透明度数值的变化。-->
    
        <div id="box"></div>
        <script type="text/javascript">
            window.onload = function (){
                var box = document.getElementById('box');
                box.onmouseover = function (){
                    opacityAnimation(box,100);
                };
                box.onmouseout = function (){
                    opacityAnimation(box,30);
                };
                var alpha = 30,timer = null,speed = 0;
                function opacityAnimation(ele,target){
                    clearInterval(timer);
                    timer = setInterval(function(){
                        // 如果目标值大于当前变化的值,表示为真值,透明度在增大,反之亦然
                        speed = target > alpha ? 10 : -10;
                        // 当前变化的值等于了目标值,清除定时器
                        if(alpha == target){
                            clearInterval(timer);
                        }else{
                            // 否则,透明度变化
                            alpha+=speed;
                            ele.style.filter = 'alpha(opactity:'+alpha+')';
                            ele.style.opacity = alpha / 100;
                        }
                    },30)
                }
            }
        </script>
    </body>
</html>
透明度动画
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title></title>
    <style type="text/css">
        #box, #box2 {
            width: 200px;
            height: 200px;
            background-color: red;
            border: 1px solid #000;
        }
    </style>
</head>
<body>
<div id="box2"></div>
<script type="text/javascript">
    window.onload = function () {
        var oBox2 = document.getElementById('box2');
        console.log(oBox2.offsetWidth);
        move2(oBox2);
    };
    //offsetWidth的坑
    /*
    * alert(obj.offsetWidth);。会发现得到的结果是202。那obj.style.width = obj.offsetWidth - 1 + 'px';得到的width为201px。
    * 是要比之前一开始css样式中的width增大了1px。这是因为offsetWidth = border-left-width + padding-left + width + padding-right + border-right-width;
    * 所以我们不能通过offsetWidth来获取当前盒子的宽度。
    * */
    function move2(obj) {
        setInterval(function () {
            obj.style.width = obj.offsetWidth - 1 + 'px';
        }, 30)
    }

</script>

<div id="box"></div>
<script type="text/javascript">
    window.onload = function () {
        var oBox = document.getElementById('box');
        move(oBox);
    };

    function move(obj) {
        setInterval(function () {
            obj.style.width = parseInt(getStyle(obj, 'width')) - 1 + 'px';
        }, 30)
    }

    //两种办法解决
    // 1.给当前盒子设置行内样式的宽度,并通过obj.style.width来获取当前盒子的宽度。(不推荐)
    // 2.封装自己的获取属性样式函数


    function getStyle(obj, attr) {
        /**
         * @param {Object} obj 哪个对象
         * @param {Object} attr 什么属性
         */
        if (obj.currentStyle) {
            // 针对IE浏览器
            return obj.currentStyle[attr];
        } else {
            // 针对于Firefox浏览器
            return getComputedStyle(obj, null)[attr];
        }
    }
</script>


</body>
</html>
offsetWidth的坑
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title></title>
    <style>
        * {
            padding: 0;
            margin: 0;
        }

        ul {
            list-style: none;
        }

        ul li {
            margin: 20px 0;
            width: 300px;
            height: 150px;
            background-color: yellowgreen;
            border: 4px solid #000;
        }
    </style>
    <script type="text/javascript">
        window.onload = function () {
            var allLis = document.getElementsByTagName('li');
            for (var i = 0; i < allLis.length; i++) {
                allLis[i].onmouseover = function () {
                    /**
                     * 第一个参数为当前的对象,第二个参数为目标值
                     */
                    startMove(this, 600);
                };
                allLis[i].onmouseout = function () {
                    startMove(this, 300);
                }
            }
            var speed = 0;

            function startMove(ele, target) {
                //1.先关闭定时器 再开启定时器
                clearInterval(ele.timer);
                ele.timer = setInterval(function () {
                    // 1.1 获取样式属性
                    var cur = parseInt(getStyle(ele, 'width'));
                    // 1.2.求出步长
                    speed = (target - cur) * 0.5;
                    // 1.3 判断speed的正负
                    speed = target > cur ? Math.ceil(speed) : Math.floor(speed);
                    //1.4 临界值判断
                    if (cur == target) {
                        clearInterval(ele.timer);
                    } else {
                        // 1.5 运动起来
                        ele.style.width = cur + speed + 'px';
                    }
                }, 30)
            }

            function getStyle(obj,attr){
                if(obj.currentStyle){
                    // 针对IE浏览器
                    return obj.currentStyle[attr];
                }else{
                    // 针对于Firefox浏览器
                    return getComputedStyle(obj,null)[attr];
                }
            }

        }
    </script>
</head>
<body>
<ul>
    <li></li>
    <li></li>
    <li></li>
</ul>
</body>
</html>
多物体运动-单值
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title></title>
    <style>
        * {
            padding: 0;
            margin: 0;
        }

        ul {
            list-style: none;
        }

        ul li {
            margin: 20px 0;
            width: 300px;
            height: 150px;
            background-color: yellowgreen;
            border: 4px solid #000;
            opacity: 0.3;
            filter: alpha(opacity:30);
        }
    </style>
    <script type="text/javascript">
        window.onload = function () {
            var allLis = document.getElementsByTagName('li');
            for (var i = 0; i < allLis.length; i++) {
                allLis[i].onmouseover = function () {
                    /**
                     * 第一个参数为当前的对象,第二个参数为目标值
                     */
                    startMove(this, 600);
                };
                allLis[i].onmouseout = function () {
                    startMove(this, 300);
                }
            }


            function getStyle(obj, attr) {
                if (obj.currentStyle) {
                    // 针对IE浏览器
                    return obj.currentStyle[attr];
                } else {
                    // 针对于Firefox浏览器
                    return getComputedStyle(obj, null)[attr];
                }
            }


            var speed = 0;

            function startMove(ele, attr, target) {
                //1.先关闭定时器 再开启定时器
                clearInterval(ele.timer);
                ele.timer = setInterval(function () {
                    // 1.1 获取样式属性 处理透明度的问题
                    var cur = 0;
                    if (attr === 'opacity') {
                        cur = Math.round(parseFloat(getStyle(ele, attr)) * 100);
                    } else {
                        cur = parseInt(getStyle(ele, attr));
                    }
                    // 1.2.求出步长
                    speed = (target - cur) * 0.5;
                    // 1.3 判断speed的正负
                    speed = target > cur ? Math.ceil(speed) : Math.floor(speed);
                    //1.4 临界值判断
                    if (cur == target) {
                        clearInterval(ele.timer);
                    } else {
                        if (attr === 'opacity') {
                            ele.style[attr] = 'alpha(opacity:' + (cur + speed) + ')';
                            ele.style[attr] = (cur + speed) / 100;
                        } else {
                            // 1.5 运动起来
                            ele.style[attr] = cur + speed + 'px';
                        }
                    }
                }, 30)
            }

        };

// 第一版:
/* 单值
            function startMove(ele, target) {
                //1.先关闭定时器 再开启定时器
                clearInterval(ele.timer);
                ele.timer = setInterval(function () {
                    // 1.1 获取样式属性
                    var cur = parseInt(getStyle(ele, 'width'));
                    // 1.2.求出步长
                    speed = (target - cur) * 0.5;
                    // 1.3 判断speed的正负
                    speed = target > cur ? Math.ceil(speed) : Math.floor(speed);
                    //1.4 临界值判断
                    if (cur == target) {
                        clearInterval(ele.timer);
                    } else {
                        // 1.5 运动起来
                        ele.style.width = cur + speed + 'px';
                    }
                }, 30)
            }
*/



// 第二版:
/* 多值:将属性当做形参放到封装的函数中。
   调用时:startMove(this,'width',600);  startMove(this,'height',150);
   不能处理透明度动画

function startMove(ele, attr, target) {
    //1.先关闭定时器 再开启定时器
    clearInterval(ele.timer);
    ele.timer = setInterval(function () {
        // 1.1 获取样式属性
        var cur = parseInt(getStyle(ele, attr));                 //1、==========opacity是小数,获取出来的值转成了整型
        // 1.2.求出步长
        speed = (target - cur) * 0.5;
        // 1.3 判断speed的正负
        speed = target > cur ? Math.ceil(speed) : Math.floor(speed);
        //1.4 临界值判断
        if (cur == target) {
            clearInterval(ele.timer);
        } else {
            // 1.5 运动起来
            ele.style[attr] = cur + speed + 'px';               //2、==========opacity是没有单位的,加了px
        }
    }, 30)
}

*/


//最终版:
//透明度样式处理:
// 注意:由于透明度涉及小数计算,如0.07*100=> 7.000000000000001,所以需要用Math.round()去掉尾巴
function startMove(ele, attr,target) {
    //1.先关闭定时器 再开启定时器
    clearInterval(ele.timer);
    ele.timer = setInterval(function() {
        // 1.1 获取样式属性 处理透明度的问题
        var cur = 0;
        if(attr === 'opacity'){
            cur = Math.round(parseFloat(getStyle(ele,attr))*100);
        }else{
            cur = parseInt(getStyle(ele,attr));
        }
        // 1.2.求出步长
        speed = (target - cur) * 0.5;
        // 1.3 判断speed的正负
        speed = target > cur ? Math.ceil(speed) : Math.floor(speed);
        //1.4 临界值判断
        if (cur == target) {
            clearInterval(ele.timer);
        } else {
            if(attr === 'opacity'){
                ele.style[attr]  = 'alpha(opacity:'+(cur+speed)+')';
                ele.style[attr] = (cur + speed)/100;
            }else{
                // 1.5 运动起来
                ele.style[attr] = cur + speed + 'px';
            }
        }
    }, 30)
}


</script>
</head>
<body>
<ul>
    <li></li>
    <li></li>
    <li></li>
</ul>
</body>
</html>
多物体运动-多值
var speed = 0;
/**
 * @param {Object} ele 当前元素
 * @param {Object} attr 当前元素的某个属性
 * @param {Object} target 目标
 */
function startMove(ele, attr, target,fn) {
    //1.先关闭定时器 再开启定时器
    clearInterval(ele.timer);
    ele.timer = setInterval(function() {
        // 1.1 获取样式属性
        var cur = 0;
        if (attr === 'opacity') {
            cur = Math.round(parseFloat(getStyle(ele, attr)) * 100);
        } else {
            cur = parseInt(getStyle(ele, attr));
        }
        // 1.2.求出步长
        speed = (target - cur) * 0.5;
        // 1.3 判断speed的正负
        speed = target > cur ? Math.ceil(speed) : Math.floor(speed);
        //1.4 临界值判断
        if (cur == target) {
            clearInterval(ele.timer);
            //修改的地方
            // 结束的时候做判断,调用fn
            if(fn){
                fn();
            }
        } else {
            if (attr === 'opacity') {
                ele.style[attr] = 'alpha(opacity:' + (cur + speed) + ')';
                ele.style[attr] = (cur + speed) / 100;
            } else {
                // 1.5 运动起来
                ele.style[attr] = cur + speed + 'px';
            }
        }
    }, 30)
}
/**
 * @param {Object} obj 哪个对象
 * @param {Object} attr 什么属性
 */
function getStyle(obj, attr) {
    if (obj.currentStyle) {
        // 针对IE浏览器
        return obj.currentStyle[attr];
    } else {
        // 针对于Firefox浏览器
        return getComputedStyle(obj, null)[attr];
    }
}
js/myAnimation.js--一先一后
<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title></title>
        <style type="text/css">
            #box{
                width: 200px;
                height: 200px;
                background-color: red;
                border: 1px solid #000;
                opacity: 0.3;
                filter: alpha(opacity: 30);
            }
        </style>
    </head>
    <body>
        <div id="box"></div>


    <!--1.先引入外部的模块-->
<script src="js/myAnimation.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
    window.onload = function() {
        //2.获取元素
        var oBox = document.getElementById('box');
        //3.监听事件
        oBox.onmouseover = function() {
           //小心回调函数中this的指向。在回调函数中this的指向指向了window对象
            var that = this;
            //3.运动
            startMove(this, 'width', 500,function(){
                startMove(that,'height',400);
            });
        };
        oBox.onmouseout = function() {
            var that = this;
            startMove(this, 'height', 200,function(){
                startMove(that,'width',200);
            });
        }
    }
    </script>


    </body>
</html>
链式动画--一先一后
var speed = 0;
/**
 * @param {Object} ele 当前元素
 * @param {Object} json 当前元素数值键值对 json数据
 * @param {Object} fn 当前回调函数
 */
function startMove(ele, json, fn) {
    //1.先关闭定时器 再开启定时器
    clearInterval(ele.timer);
    ele.timer = setInterval(function() {
        // 做个标杆,如果为true,证明所有的属性已到达终点值
        var flag = true;
        for (var attr in json) {
            // console.log(attr,json[attr]);
            // 1.1 获取样式属性
            var cur = 0;
            if (attr === 'opacity') {
                cur = Math.round(parseFloat(getStyle(ele, attr)) * 100);
            } else {
                cur = parseInt(getStyle(ele, attr));
            }
            // 1.2.求出步长
            speed = (json[attr] - cur) / 20;
            // 1.3 判断speed的正负
            speed = json[attr] > cur ? Math.ceil(speed) : Math.floor(speed);

            // 1.4 如果所有的属性没到达终点值。继续执行下面的代码, 所有属性都到达终点才清除定时器
            if(cur !== json[attr]){
                flag = false;
            }

            //1.5 处理属性名为opacity
            if (attr === 'opacity') {
                //1.5.1 兼容IE
                ele.style[attr] = 'alpha(opacity:' + (cur + speed) + ')';
                //1.5.2 w3c浏览器
                ele.style[attr] = (cur + speed) / 100;
            } else {
                // 1.6 运动起来
                ele.style[attr] = cur + speed + 'px';
            }
        }
        // 1.6 如果flag是成立的,证明所有的属性都到达终点,此时清除定时器,执行回调函数
        if (flag) {
            clearInterval(ele.timer);
            if (fn) {
                fn();
            }
        }
    }, 30)
}
/**
 * @param {Object} obj 哪个对象
 * @param {Object} attr 什么属性
 */
function getStyle(obj, attr) {
    if (obj.currentStyle) {
        // 针对IE浏览器
        return obj.currentStyle[attr];
    } else {
        // 针对于Firefox浏览器
        return getComputedStyle(obj, null)[attr];
    }
}
js/myAnimation.js同时运动
<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title></title>
        <style type="text/css">
            #box{
                width: 200px;
                height: 200px;
                background-color: red;
                border: 1px solid #000;
                opacity: 0.3;
                filter: alpha(opacity: 30);
            }
        </style>
    </head>
    <body>
        <div id="box"></div>


    <!--1.先引入外部的模块-->
<script src="js/myAnimation.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
    window.onload = function() {
        var oBox = document.getElementById('box');
        oBox.onmouseover = function() {
            startMove(oBox,{"width":400,"height":400,'opacity': 100})
        };
        oBox.onmouseout = function() {
            startMove(oBox,{"width":200,"height":200,'opacity': 30})
        }
    }
</script>


    </body>
</html>
链式运动--同时运动

 

posted @ 2018-12-23 22:38  silencio。  阅读(437)  评论(0编辑  收藏  举报