事件基础

来源:互联网 发布:sql怎么设置 identity 编辑:程序博客网 时间:2024/06/08 16:35
目录

1.什么是事件
2.事件对象及兼容处理
3.事件的传播机制
4.案例-鼠标跟随jQuery
5.案例-鼠标跟随JS版
6.鼠标跟随、深入理解事件的传播机制
7.事件委托/事件代理
8.案例-京东商城放大镜
9.案例-百度搜索框
10.案例-多级菜单JS版
11.案例-多级菜单jQuery版
12.拖拽demo实现基本的效果
13.拖拽demo解决鼠标丢失

1.什么是事件

事件分为两部分:

1.行为本身:浏览器天生就赋予其的行为。onclick、onmouseover(onmouserenter)、onmouseout(onmouseleave)、onmousemove、ommousemove、onmousedown、onmouseup、onmousewheel(鼠标滚轮滚动行为)、onscroll(滚动条滚动行为)、onresize(window.onresize 浏览器窗口大小改变事件)、onload、onunload、onfouse文本框获取焦点行为)、onblur(浏览器失去焦点)、onkeydown(键盘按下行为)、onkeyup……

哪怕没有给上述行为绑定方法,事件也存在。当点击这个盒子的时候,同样会触发它的onclick行为,只是什么事情都没做而已。

2.事件绑定:给元素的某一个行为绑定一个方法

//DOM0级事件绑定var oDiv = document.getElementById("div1");oDiv.onclick = function () {    //当触发oDiv的onclick行为的时候,会把绑定的这个函数执行};
//DOM2级事件绑定oDiv.addEventListener("click", function () {    console.log("ok");}, false);

onclick这个行为定义在当前元素的私有属性上;
addEventListener这个属性是定义在当前元素所属EventTarget这个类的原型上的

2.事件对象及兼容处理

oDiv.onclick = function () {};

把匿名函数定义的部分当做一个值赋值给oDiv的点击行为(函数表达式)
当触发div的点击行为的时候,会执行对应绑定上的方法
不仅仅把绑定的方法执行了,而且浏览器还默认的给这个方法传递了一个参数值:MouseEvent:鼠标事件对象。

  • MouseEvent是一个对象数据类型值,里面包含了很多的属性名和属性值,这些都是用来记录当前鼠标的相关信息的
  • MouseEvent -> UIEvent -> Event -> Object
  • MouseEvent记录的是页面中唯一一个鼠标每一次触发时候的相关信息,和到底是在哪个元素上触发的没有关系

关于事件对象(MouseEvent)的兼容性问题:

1、事件对象本身的获取存在兼容问题:标准浏览器中是浏览器给方法传递的参数,只需要定义形参e就可以获取到

oDiv.onclick = function (e) {    console.log(e);};

2、在IE6-8中,浏览器不会给方法传递参数,如果需要的话,需要到window.event中获取查找。
解决方法:

oDiv.onclick = function (e) {    e = e || window.event;    console.log(e);};

常用信息:

  • e.clientX/e.clientY:鼠标触发点距离当前屏幕左上角的坐标值
  • e.type:存储的是当前鼠标触发的行为类型,如“click”
  • e.target:事件源,当前鼠标触发的是哪个元素,那么它存储的就是哪个元素。存在兼容性问题,在IE6-8中不存在这个属性,即为undefined,可以使用e.srcElement来获取事件源。解决方法:e.target = e.target || e.srcElement;
  • e.preventDefault:阻止浏览器的默认行为。如a标签的默认行为就是跳转页面,但是有时候使用a标签,只是想应用它的特殊性,并不想点击的时候跳转。存在兼容性问题,在IE6-8中不存在这个属性,需要使用e.returnValue = false;来代替。
a.onclick = function (e) {    e = e || window.event;    e.preventDefault ? e.preventDefault() : e.returnValue = false;    //或者:return false;    //或者:见下};
<li><a href="javascript:;"></a></li>/*直接在HTML结构上阻止或者:href="javascript:void 0;"href="javascript:void 1;"*/
  • e.pageX/e.pageY:当前鼠标触发点距离body左上角(页面第一屏幕最左上角)的x/y轴的坐标。存在兼容性问题,在IE6-8中不存在这个属性,即为undefined,解决方法:
e.pageX = e.pageX || (e.clientX + (document.documentElement.scrollLeft || document.body.scrollLeft));e.pageY = e.pageY || (e.clientY + (document.documentElement.scrollTop || document.body.scrollTop));
  • e.stopPropagation:阻止事件的冒泡传播,在IE6-8中不存在这个属性,解决方法如下:
e.stopPropagation ? e.stopPropagation() : e.cancelBubble = true;
  • e.keycode:当前键盘上每一个键对应的值,如:空格:32;回退键:8;回车键:13;delete:46;左:37;上:38;右:39;下:40
3.事件的传播机制

有以下代码:

<body><div id="outer">    <div id="inner">        <div id="center"></div>    </div></div><script type="text/javascript">    var outer = document.getElementById("outer"),        inner = document.getElementById("inner"),        center = document.getElementById("center");    document.body.onclick = function () {        console.log("body");    };    outer.onclick = function () {        console.log("outer");    };    inner.onclick = function () {        console.log("inner");    };    center.onclick = function () {        console.log("center");    };</script></body>

点击时,控制台会输出:center、inner、outer、body,这就涉及到了事件的默认传播机制。

事件的默认传播机制分为三个阶段:

  • 捕获阶段:从外向里依次查找元素
  • 目标阶段:当前事件源本身的操作
  • 冒泡阶段:从内到外依次触发相关的行为

最常用的就是冒泡阶段。

用DOM0级事件绑定给元素的某一个行为绑定的方法,都是在行为触发后的冒泡阶段把方法执行的。如图:

冒泡阶段:

  • 当前center的click行为被触发,如果给其绑定了方法,首先把center对应的方法执行(目标阶段)
  • 不仅仅center的click行为被触发了,它所有的父级元素的click行为也会被触发。inner的click行为触发->如果给inner也绑定了方法,inner对应的方法也会执行
  • 同理依次查找outer、body、html、document

注意:每个浏览器传播到的最顶层是不一样的。谷歌中可以到document,IE中只能传播到HTML。

document.body.addEventListener("click", function () {    console.log("body");}, false); //第一个参数是行为的类型,第二个参数是给当前的行为绑定的方法,第三个参数是控制在哪个阶段发生,true是捕获阶段发生,false是冒泡阶段发生outer.addEventListener("click", function () {    console.log("outer");}, true);inner.addEventListener("click", function () {    console.log("inner");}, false);

点击center的div,输出:outer、inner、body

4.案例-鼠标跟随jQuery

效果图:

HTML代码:

<div id="box" class="box">    <img src="img/1.jpg" bigImg="img/11.jpg"/>    <img src="img/2.jpg" bigImg="img/22.jpg"/>    <img src="img/3.jpg" bigImg="img/33.jpg"/>    <img src="img/4.jpg" bigImg="img/44.jpg"/>    <div id="mark">        <img src="img/11.jpg"/>    </div></div>

CSS代码:

body, div, ing {    margin: 0;    padding: 0;}img {    display: block;    border: none;}.box {    width: 450px;    margin: 20px auto;    position: relative;}.box img {    width: 100px;    border: 1px solid #777777;    float: left;    margin-left: 10px;}#mark {    position: absolute;    top: 0px;    left: 0;    width: 384px;    height: 216px;    border: 1px solid #5bc0de;    z-index: 10;    display: none;}#mark img {    border: none;    float: none;    margin-left: 0px;    width: 100%;    height: 100%;}

JavaScript代码(jQuery):

$(function () {    var $box = $("#box"),        $mark = $("#mark"),        $boxOffset = $box.offset(); //获取当前元素距离body的偏移    $box.children("img").mouseover(function (e) {        e = e || window.event;        e.target = e.target || e.srcElement;        var left = e.clientX - $boxOffset.left + 10;        var top = e.clientY - $boxOffset.top + 10;        $mark.stop().show(100).css({left: left, top: top}).find("img").attr("src", e.target.getAttribute("bigImg"));    }).bind("mousemove", function (e) {        e = e || window.event;        e.target = e.target || e.srcElement;        var left = e.clientX - $boxOffset.left + 10;        var top = e.clientY - $boxOffset.top + 10;        $mark.css({left: left, top: top});    }).bind("mouseout", function (e) {        $mark.stop().hide(100);    });});
5.案例-鼠标跟随JS版

效果图:

HTML代码:

<div id="box">    <!--<div id="mark"></div>--></div>

CSS代码:

body, div {    margin: 0;    padding: 0;}#box {    position: relative;    margin: 20px auto;    width: 300px;    height: 300px;    background: #5bc0de;}#mark {    position: absolute;    top: 0;    left: 0;    width: 100px;    height: 100px;    background: #FFAAAA;}

JS代码:

var box = document.getElementById("box");box.onmouseover = function (e) {    e = e || window.event;    var mark = document.createElement("div");    mark.id = "mark";    this.appendChild(mark);    mark.style.left = e.clientX - this.offsetLeft + 5 + "px";    mark.style.top = e.clientY - this.offsetTop + 5 + "px";};box.onmousemove = function (e) {    e = e || window.event;    var mark = document.getElementById("mark");    if (mark) {        mark.style.left = e.clientX - this.offsetLeft + 5 + "px";        mark.style.top = e.clientY - this.offsetTop + 5 + "px";    }};

以上代码会出现一个问题:当鼠标移动过快的时候会进入到mark盒子,触发到它的mouseover行为,由于事件的冒泡传播机制,导致box的mouseover会重新触发,导致盒子一直被触发
解决方法:阻止mark盒子的onmouseover行为的冒泡传播

如果增加onmouseout事件,依然有问题,鼠标快速移动,首先会到mark上,此时浏览器在计算mark的位置,计算完成,mark到达指定的位置,此时鼠标又重新回到box上,触发了box的mouseover,也触发了mark的mouseout,mark的mouseout被触发,也会传播到box的mouseout上,会把mark先删除,然后再创建……

box.onmouseout = function (e) {    e = e || window.event;    var mark = document.getElementById("mark");    if (mark) {        this.removeChild(mark);    }};

onmouseenter和onmouseover的区别:
都是鼠标滑上去的行为,但是onmouseenter默认阻止了浏览器的冒泡传播,即:mark的mouseenter行为触发,不会传播到box。而onmouseover是存在冒泡传播的,想要阻止的话只能自己写代码阻止。
onmouseleave和onmouseout同理。

所以代码可以写成:

var box = document.getElementById("box");box.onmouseenter = function (e) {    e = e || window.event;    var mark = document.createElement("div");    mark.id = "mark";    this.appendChild(mark);    mark.style.left = e.clientX - this.offsetLeft + 5 + "px";    mark.style.top = e.clientY - this.offsetTop + 5 + "px";};box.onmousemove = function (e) {    e = e || window.event;    var mark = document.getElementById("mark");    if (mark) {        mark.style.left = e.clientX - this.offsetLeft + 5 + "px";        mark.style.top = e.clientY - this.offsetTop + 5 + "px";    }};box.onmouseleave = function (e) {    e = e || window.event;    var mark = document.getElementById("mark");    if (mark) {        this.removeChild(mark);    }};
6.鼠标跟随、深入理解事件的传播机制

效果图:鼠标滑到粉盒子上时,蓝盒子出现,在蓝盒子上时,不消失。
代码如下:

<!DOCTYPE html><html><head>    <meta charset="UTF-8">    <title>Title</title>    <style type="text/css">        body, div {            margin: 0;            padding: 0;        }        #box {            position: relative;            width: 100px;            height: 30px;            background: #FFAAAA;        }        #mark {            position: absolute;            left: 0;            top: 30px;            width: 300px;            height: 100px;            background: #5bc0de;            display: none;        }    </style></head><body><div id="box">    <div id="mark"></div></div><script type="text/javascript">    var box = document.getElementById("box");    var mark = document.getElementById("mark");    box.onmouseenter = function () {        mark.style.display = "block";    };    box.onmouseleave = function () {        mark.style.display = "none";    };</script></body></html>
7.事件委托、事件代理

利用事件的冒泡传播机制,即触发当前元素的某个行为,它父级所有元素的相关行为都会被触发。利用这个机制,如果容器中有很多元素都需要绑定点击事件,没有必要一个个的绑定,只需要给最外层容器绑定一个点击事件即可,在这个方法执行的时候,通过事件源(e.target)的区分来进行不同的操作。

事件委托的简单应用

效果图:

说明:
点击购物车,出现粉色框,点击粉色框不消失,点击购物车消失,点击空白处消失。
代码如下:

<!DOCTYPE html><html><head>    <meta charset="UTF-8">    <title>Title</title>    <style type="text/css">        body, div, span {            margin: 0;            padding: 0;            font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;            font-size: 14px;        }        html,body {            width: 100%;            height: 100%;            overflow: hidden;        }        #box {            position: relative;            left: 50%;            top: 50px;            margin-left: -50px;            width: 100px;            height: 30px;            border: 1px solid #9783b9;            line-height: 30px;            text-align: center;            cursor: pointer;        }        #mark {            position: absolute;            top: 30px;            left: -1px;            width: 300px;            height: 100px;            line-height: 100px;            text-align: center;            background: #FFAAAA;            border: 1px solid #9783b9;        }    </style></head><body><div id="box">    <span>购物车</span>    <div id="mark" style="display: none">查看购物车的详细信息</div></div><script type="text/javascript">    var mark = document.getElementById("mark");    document.body.onclick = function (e) {        console.log("111");        e = e || window.event;        e.target = e.target || e.srcElement;        //如果点击的是box或者#box下的span,判断mark是否显示,显示就隐藏,反之显示        if (e.target.id === "box" || (e.target.tagName.toLowerCase() === "span" && e.target.parentNode.id === "box")) {            if (mark.style.display === "none") {                mark.style.display = "block";            } else {                mark.style.display = "none";            }            return;        }        //如果事件源是#mark,不进行任何操作        if (e.target.id === "mark") {            return;        }        //以上都不是,直接让#mark隐藏        mark.style.display = "none";    };</script></body></html>
8.案例-京东商城放大镜

效果图:

代码如下:

<!DOCTYPE html><html><head>    <meta charset="UTF-8">    <title>Title</title>    <style type="text/css">        body, div, img {            margin: 0;            padding: 0;        }        img {            display: block;            border: none;        }        #box {            position: absolute;            top: 20px;            left: 20px;            width: 350px;            height: 350px;            border: 1px;            box-shadow: 3px 3px 10px 0 #111;        }        #box img {            width: 350px;            height: 350px;        }        #mark {            position: absolute;            top: 0;            left: 0;            width: 175px;            height: 175px;            background: #000;            opacity: 0.5;            filter: alpha(opacity=50);            cursor: move;            display: none;        }        #boxRight {            display: none;            position: absolute;            width: 350px;            height: 350px;            top: 20px;            left: 440px;            overflow: hidden;        }        /*右侧图片大小是左边2倍*/        #boxRight img {            position: absolute;            width: 700px;            height: 700px;            top: 0;            left: 0;        }    </style></head><body><div id="box">    <img src="img/jd.jpg"/>    <div id="mark"></div></div><div id="boxRight">    <img src="img/jd.jpg"/></div><script type="text/javascript">    //放大镜原理:    //mark横向是box的一半,纵向也是box的一半,那么右侧大图的横向和纵向应该是左边小图的二倍    var box = document.getElementById("box"),        mark = document.getElementById("mark"),        boxRight = document.getElementById("boxRight");    //设置mark盒子的位子信息    function setPosition(e) {        //正常情况下获取的top/left,但是需要做边界判断        var top = e.clientY - box.offsetTop - (mark.offsetHeight / 2);        var left = e.clientX - box.offsetLeft - (mark.offsetWidth / 2);        //边界判断:        var tempL = 0, tempT = 0;        var minL = 0, minT = 0, maxL = box.offsetWidth - mark.offsetWidth, maxT = box.offsetHeight - mark.offsetHeight;        if (left < minL) {            mark.style.left = minL + "px";            tempL = minL;        } else if (left > maxL) {            mark.style.left = maxL + "px";            tempL = maxL;        } else {            mark.style.left = left + "px";            tempL = left;        }        if (top < minT) {            mark.style.top = minT + "px";            tempT = minT;        } else if (top > maxT) {            mark.style.top = maxT + "px";            tempT = maxT;        } else {            mark.style.top = top + "px";            tempT = top;        }        //让右侧的图片跟着运动        var oImg = boxRight.getElementsByTagName("img")[0];        oImg.style.left = -tempL * 2 + "px";        oImg.style.top = -tempT * 2 + "px";    }    box.onmouseenter = function (e) {        e = e || window.event;        mark.style.display = "block";        setPosition(e);        boxRight.style.display = "block";    };    box.onmousemove = function (e) {        e = e || window.event;        setPosition(e);    };    box.onmouseleave = function (e) {        e = e || window.event;        mark.style.display = "none";        boxRight.style.display = "none";    };</script></body></html>
9.案例-百度搜索框

效果图:

分析:
显示时情况:

  • 文本框获取焦点,并且文本框中有内容的时候
  • 在文本框中输入或者删除内容时,如果内容没有清空就显示,否则就隐藏

隐藏时情况:

  • 点击页面中其余的位置(除文本框和searchList里面的每一行),都隐藏
  • 点击searchList中的列表隐藏,但是还要把列表中的内容放到文本框中

代码如下:

<!DOCTYPE html><html><head>    <meta charset="UTF-8">    <title>Title</title>    <style type="text/css">        body, divinput, ul, li {            margin: 0;            padding: 0;            font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;            font-size: 14px;        }        input {            display: block;            outline: none; /*清除彩色边框*/        }        a {            display: block;            text-decoration: none;            color: #000;        }        a:hover, a:active, a:target {            text-decoration: none;            color: #000;        }        ul, li {            list-style: none;        }        .box {            width: 500px;            position: absolute;            top: 20px;            left: 50%;            margin-left: -250px;        }        .box input {            width: 300px;            height: 35px;            padding: 0 10px;            border: 1px solid #888;        }        .box ul {            display: none;            border: 1px solid #888;            position: relative;            top: -1px;        }        .box ul li, .box ul a {            height: 30px;            line-height: 35px;        }        .box ul a {            padding: 0 10px;        }        .box ul a:hover {            background: #eee;        }    </style></head><body><div class="box">    <input type="text" id="searchInp"/>    <ul id="searchList">        <li><a href="javascript:;">冰箱</a></li>        <li><a href="javascript:;">彩电</a></li>        <li><a href="javascript:;">洗衣机</a></li>        <li><a href="javascript:;">废品</a></li>        <li><a href="javascript:;">废塑料</a></li>    </ul></div><script type="text/javascript">    var searchInp = document.getElementById("searchInp"),        searchList = document.getElementById("searchList");    //不管是获取焦点还是在里面编辑内容,都是有内容显示,没内容隐藏    searchInp.onfocus = searchInp.onkeyup = function () {        var val = this.value.replace(/(^ +| +$)/g, ""); //获取文本框中的内容,并且去除它的首尾空格        searchList.style.display = val.length > 0 ? "block" : "none";    };    document.body.onclick = function (e) {        e = e || window.event;        e.target = e.target || e.srcElement;        //如果点击的事件源是searchList下的a标签,让searchList隐藏,并且把当前点击的内容放到文本框中        if (e.target.tagName.toLowerCase() === "a" && e.target.parentNode.parentNode.id === "searchList") {            searchList.style.display = "none";            searchInp.value = e.target.innerHTML;            return;        }        //如果事件源是文本框还需要单独处理//        if(e.target.id==="searchInp"){//            return;//        }        searchList.style.display = "none";    };    //可以阻止一个容器中某些特殊性的元素,让其不在委托的范围内,只需要把这些不需要委托的事件阻止即可    searchInp.onclick = function (e) {        e = e || window.event;        e.stopPropagation ? e.stopPropagation() : e.cancelBubble = true;    };</script></body></html>
10.案例-多级菜单JS版

效果图:

完整代码如下:

<!DOCTYPE html><html><head>    <meta charset="UTF-8">    <title>Title</title>    <style type="text/css">        * {            margin: 0;            padding: 0;            font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;            font-size: 14px;        }        ul, li {            list-style: none;        }        .box {            width: 300px;            margin: 10px;            padding: 10px;            border: 1px dashed #5bc0de;            /*渐进增强:首先设置一个纯色的背景,对于不兼容css3的浏览器来说会使用纯色,对于兼容的浏览器来说,下面再额外的增加一些渐变色,这样的话会把纯色的覆盖掉*/            background: #FFAAAA;            background: -webkit-linear-gradient(top left, #5bc0de, #bce8f1);        }        .box li {            position: relative;            line-height: 30px;        }        .box em {            position: absolute;            width: 16px;            height: 16px;            background: #777777;            top: 7px;            left: 0;            cursor: pointer;        }        .box em.open {            background: #333;        }        .box span {            display: block;            padding-left: 20px;        }        .box .two {            margin-left: 20px;        }        .box .three {            margin-left: 40px;        }        .box .four {            margin-left: 60px;        }        .box .two, .box .three, .box .four {            display: none;        }    </style></head><body><div class="box" id="box">    <ul>        <li>            <em></em><span>第一级第一个</span>            <ul class="two">                <li><span>第二级第一个</span></li>                <li>                    <em></em><span>第二级第二个</span>                    <ul class="three">                        <li><span>第三级第一个</span></li>                        <li><span>第三级第二个</span></li>                        <li>                            <em></em><span>第三级第三个</span>                            <ul class="four">                                <li><span>第四级第一个</span></li>                                <li><span>第四级第二个</span></li>                                <li><span>第四级第三个</span></li>                            </ul>                        </li>                    </ul>                </li>                <li>                    <em></em><span>第二级第三个</span>                    <ul class="three">                        <li><span>第三级第一个</span></li>                        <li><span>第三级第二个</span></li>                        <li><span>第三级第三个</span></li>                    </ul>                </li>            </ul>        </li>        <li>            <em></em><span>第一级第二个</span>            <ul class="two">                <li><span>第二级第一个</span></li>                <li>                    <em></em><span>第二级第二个</span>                    <ul class="three">                        <li><span>第三级第一个</span></li>                        <li><span>第三级第二个</span></li>                        <li>                            <em></em><span>第三级第三个</span>                            <ul class="four">                                <li><span>第四级第一个</span></li>                                <li><span>第四级第二个</span></li>                                <li><span>第四级第三个</span></li>                            </ul>                        </li>                    </ul>                </li>                <li>                    <em></em><span>第二级第三个</span>                    <ul class="three">                        <li><span>第三级第一个</span></li>                        <li><span>第三级第二个</span></li>                        <li><span>第三级第三个</span></li>                    </ul>                </li>            </ul>        </li>    </ul></div><script type="text/javascript" src="utils.js"></script><script type="text/javascript">    var box = document.getElementById("box");    //把列表中的span(前面带em的)设置一个cursor: pointer;的样式    var spanList = box.getElementsByTagName("span");    for (var i = 0; i < spanList.length; i++) {        var curSpan = spanList[i];        var curPre = utils.prev(curSpan); //获取当前span的上一个哥哥元素节点        if (curPre && curPre.tagName.toLowerCase() === "em") {            curSpan.style.cursor = "pointer";        }    }    //使用事件委托实现操作    box.onclick = function (e) {        e = e || window.event;        var tar = e.target || e.srcElement;        //只有点击的是em/span标签才进行展开或者收缩的操作        if (/^(em|span)$/i.test(tar.tagName)) {            var parent = tar.parentNode; //获取父亲            var oEm = utils.children(parent, "em")[0];            var firstUl = utils.children(parent, "ul")[0];//获取父亲子集中第一个ul            if (firstUl) { //只有存在才进行相关的操作                //这个ul当前是隐藏让其显示,否则隐藏                var isBlock = utils.css(firstUl, "display") === "block" ? true : false;                if (isBlock) { //当前是显示的                    firstUl.style.display = "none";                    oEm ? utils.removeClass(oEm, "open") : null;                    //当外层的收起,里层所有的ul都隐藏,并且所有的em都要移除open样式                    var allUl = parent.getElementsByTagName("ul"), allEm = parent.getElementsByTagName("em");                    for (var i = 0; i < allEm.length; i++) {                        allUl[i].style.display = "none";                        utils.removeClass(allEm[i], "open");                    }                } else { //当前是隐藏的                    firstUl.style.display = "block";                    oEm ? utils.addClass(oEm, "open") : null;                }            }        }    };</script></body></html>

utils.js见:http://blog.csdn.net/ruirui_1996/article/details/78116836

11.案例-多级菜单jQuery版
var $box = $("#box");$box.find("span").each(function () {    //$(this) 每一次循环当前循环的这个元素    var $pre = $(this).prev();    if ($pre[0] && $pre[0].tagName.toLowerCase() === "em") {        $(this).css("cursor", "pointer");    }});function fn() {    var $par = $(this).parent();    var $ul = $($par.children("ul")[0]);    var $em = $($par.children("em")[0]);    if ($ul.length > 0) {        var isBlock = $ul.css("display") === "block" ? true : false;        $ul.slideToggle();        $em.toggleClass("open");        //当前如果是收缩,需要把子子孙孙中所有的ul/em都隐藏和移除open样式        if (isBlock) {            $par.find("ul").css("display", "none");            $par.find("em").removeClass("open");        }    }}$box.delegate("em", "click", fn); //给$box绑定点击事件,如果当前的事件源是em的话执行fn$box.delegate("span", "click", fn);
12.拖拽demo实现基本的效果

原理:
当鼠标在盒子上按下的时候开始拖拽(给盒子绑定onmousemove和onmouseup)。当鼠标移动的时候,计算盒子的最新位置,当鼠标抬起的时候,拖拽已经结束了,move和up就没用了,再把move和up移除。
这里写图片描述
开始记录一下鼠标的开始位置strX/strY和盒子的开始位置strListrT。
当鼠标移动的过程中,获取最新的鼠标位置,用现有的位置减起始位置等于鼠标移动的距离A
当前盒子的位置=盒子的起始位置+鼠标移动的距离A

<!DOCTYPE html><html><head>    <meta charset="UTF-8">    <title>Title</title>    <style type="text/css">        * {            margin: 0;            padding: 0;        }        html, body {            width: 100%;            height: 100%;        }        #box {            position: absolute;            /*top: 50%;*/            /*left:50%;*/            /*margin: -100px 0 0 -100px;*/            /*或者:*/            /*position: absolute;*/            /*top: 0;*/            /*left: 0;*/            /*right: 0;*/            /*bottom: 0;*/            /*margin: auto;*/            /*IE下兼容不好 主要用于移动端的开发*/            width: 200px;            height: 200px;            background: #5bc0de;            cursor: move;        }    </style></head><body><div id="box"></div><script type="text/javascript">    var box = document.getElementById("box");    box.style.top = ((document.documentElement.clientHeight || document.body.clientHeight) - box.offsetHeight) / 2 + "px";    box.style.left = ((document.documentElement.clientWidth || document.body.clientWidth) - box.offsetWidth) / 2 + "px";    box.onmousedown = down;    function down(e) {        e = e || window.event;        //记录开始位置的信息        this["strX"] = e.clientX;        this["strY"] = e.clientY;        this["strL"] = parseFloat(this.style.left);        this["strT"] = parseFloat(this.style.top);        //给元素绑定移动和抬起的事件        this.onmousemove = move;        this.onmouseup = up;    }    function move(e) {        e = e || window.event;        var curL = e.clientX - this["strX"] + this["strL"];        var curT = e.clientY - this["strY"] + this["strT"];        console.lo        //边界判断        var minL = 0, minT = 0,            maxL = (document.documentElement.clientWidth || document.body.clientWidth) - this.offsetWidth,            maxT = (document.documentElement.clientHeight || document.body.clientHeight) - this.offsetHeight;        curL = curL < minL ? minL : (curL > maxL ? maxL : curL);        curT = curT < minT ? minT : (curT > maxT ? maxT : curT);        this.style.left = curL + "px";        this.style.top = curT + "px";    }    function up(e) {        this.onmousemove = null;        this.onmouseup = null;    }</script></body></html>
13.拖拽demo解决鼠标丢失

鼠标焦点丢失:
当鼠标移动过快的时候,鼠标会脱离盒子,导致盒子的mouseup和mousemove事件都移除不掉。
在IE和火狐中,可以使用setCapture()方法将鼠标和盒子绑在一起,用releaseCapture()解绑,但是在谷歌下不兼容。
谷歌下解决方法:
鼠标始终在文档中,把mousemove和mouseup绑定给document

优化后JS代码:

<script type="text/javascript">    var box = document.getElementById("box");    box.style.top = ((document.documentElement.clientHeight || document.body.clientHeight) - box.offsetHeight) / 2 + "px";    box.style.left = ((document.documentElement.clientWidth || document.body.clientWidth) - box.offsetWidth) / 2 + "px";    box.onmousedown = down;    function down(e) {        e = e || window.event;        //记录开始位置的信息        this["strX"] = e.clientX;        this["strY"] = e.clientY;        this["strL"] = parseFloat(this.style.left);        this["strT"] = parseFloat(this.style.top);        //给元素绑定移动和抬起的事件        if (this.setCapture) { //把当前鼠标和this绑定在一起            this.setCapture();            this.onmousemove = move;            this.onmouseup = up;        } else {            var _this = this; //_this是#box            document.onmousemove = function (e) {                // move(e); //move中的方法为window                move.call(_this,e);            };            document.onmouseup = function (e) {                up.call(_this,e);            };        }    }    function move(e) {        e = e || window.event;        var curL = e.clientX - this["strX"] + this["strL"];        var curT = e.clientY - this["strY"] + this["strT"];        //边界判断        var minL = 0, minT = 0,            maxL = (document.documentElement.clientWidth || document.body.clientWidth) - this.offsetWidth,            maxT = (document.documentElement.clientHeight || document.body.clientHeight) - this.offsetHeight;        curL = curL < minL ? minL : (curL > maxL ? maxL : curL);        curT = curT < minT ? minT : (curT > maxT ? maxT : curT);        this.style.left = curL + "px";        this.style.top = curT + "px";    }    function up(e) {        if (this.releaseCapture) {//把当前的鼠标和this解绑            this.releaseCapture();            this.onmousemove = null;            this.onmouseup = null;        } else {            document.onmousemove = null;            document.onmouseup = null;        }    }</script>

原创粉丝点击