事件基础

本文详细介绍了JavaScript中的事件,包括事件基础、事件对象的兼容处理、事件传播机制、鼠标跟随和事件委托等实战案例,讲解了如鼠标事件、键盘事件的相关属性和方法,并提供了事件阻止和事件冒泡的解决方案。
摘要由CSDN通过智能技术生成
目录

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>

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值