手记

QQ面板的下拉状态栏选择

   本文为《DOM事件探秘》课程中第四章“QQ面板在浏览器窗口的拖曳效果及状态列表选择”的代码实现。
   本文及js代码demo为笔者在课后实现,代码中有详细注释,解说了上课视频中老师的代码功能及实现思想。读者可以复制本文代码作为笔记进行参考。
   核心代码为drag.js文件中的JavaScript实现,重点内容包含:

1、封装函数实现通过className和父元素Id实现元素目标的获取;
2、建立拖曳函数(包含鼠标按住事件、鼠标移动事件、松开按钮事件);
3、关闭面板
4、点击切换函数
4.1、点击状态区展示状态栏
4.2、鼠标经过改变列表背景颜色、鼠标移开列表改变背景颜色
4.3、鼠标点击选项时:1、将列表内容传入状态区;2、将状态列表隐藏
5、点击其他区域隐藏状态列表
6、在显示状态列表和隐身状态列表时注意修改浏览器默认的事件冒泡

面板的**效果图**:


界面描述demo:

<!DOCTYPE html>
<head>
    <title>拖动</title>
    <link href="css/main.css" rel="stylesheet" />
    <script src="js/drag.js"></script>
</head>
<body>
    <!-- 整个主板区 -->
    <div class="loginPanel" id="loginPanel">
        <!-- 描述关闭按钮 -->
        <div >
            <div class="ui_boxyClose" id="ui_boxyClose"></div>
        </div>

        <!-- LOGO部分鼠标点击可以拖动区域 -->
        <div class="login_logo_webqq"></div>

        <!-- 账号输入区 -->
        <div class="inputs">
            <div class="sign-input"><span>帐 号:</span><span><input autocomplete="on" name="u" id="u" type="text"  class="input01" tabindex="1" value="QQ号码或Email帐号" onFocus="if (value =='QQ号码或Email帐号'){value =''}" onBlur="if (value ==''){value='QQ号码或Email帐号';}" /></span></div>
            <div class="sign-input"><span>密 码:</span><span><input name="p" id="p" maxlength="16" type="password" class="input01" tabindex="2" /></span></div>
        </div>

        <!-- 状态选择区 -->
        <div class="bottomDiv">
            <div class="btn" ></div>
            <div>
                <div id="loginState" class="login-state-trigger login-state-trigger2 login-state" title="选择在线状态">

                    <div id="loginStateShow" class="login-state-show online">状态</div>
                    <div class="login-state-down">下</div>
                    <div class="login-state-txt" id="login2qq_state_txt">在线</div>

            <ul id="loginStatePanel" class="statePanel login-state" >
                <li id="online" class="statePanel_li">
                    <div class="stateSelect_icon online"></div>
                    <div class="stateSelect_text">我在线上</div>
                </li>
                <li id="callme" class="statePanel_li">
                    <div class="stateSelect_icon callme"></div>
                    <div class="stateSelect_text">Q我吧</div>
                </li>
                <li id="away" class="statePanel_li">
                    <div class="stateSelect_icon away"></div>
                    <div class="stateSelect_text">离开</div>
                </li>
                <li id="busy" class="statePanel_li">
                    <div class="stateSelect_icon busy"></div>
                    <div class="stateSelect_text">忙碌</div>
                </li>
                <li id="silent" class="statePanel_li">
                    <div class="stateSelect_icon silent"></div>
                    <div class="stateSelect_text">请勿打扰</div>
                </li>
                <li id="hidden" class="statePanel_li">
                    <div class="stateSelect_icon hidden"></div>
                    <div class="stateSelect_text">隐身</div>
                </li>
            </ul>
                </div>

            </div>

        </div>

    </div>

</body>
</html>
**界面样式代码(main.css文件):**
  .loginPanel {
            width: 380px;
            height: 247px;
            left: 400px;
            top: 120px;
            position: absolute;
            border: 1px solid #ccc;
            background: #f6f6f6;
            -moz-border-radius: 10px;
            -webkit-border-radius: 10px;
            border-radius: 10px;
            -moz-box-shadow: 0 0 8px #000;
            -webkit-box-shadow: 0 0 8px #000;
            box-shadow: 0 0 8px #000;
        }

        .login_logo_webqq {
            background: url('../images/login_window_logo.png') no-repeat -210px -0px;
            margin-left: 100px;
            margin-top: 10px;
            width: 200px;
            height: 44px;
            cursor: move;
        }

        .inputs {
            font: bold 15px arial;
            margin-left: 80px;
            margin-top: 30px;
        }

            .inputs .sign-input {
                padding-bottom: 20px;
            }

                .inputs .sign-input input {
                    width: 170px;
                    border: 1px #ccc solid;
                    color: #868686;
                    font-size: 16px;
                    padding: 2px;
                    -moz-border-radius: 10px;
                    -webkit-border-radius: 10px;
                    -khtml-border-radius: 10px;
                    -border-radius: 10px;
                    outline: none;
                }

        .btn {
            background: url("../images/login_btn.png") no-repeat -111px 0;
            width: 111px;
            height: 36px;
            border: 0;
            text-align: center;
            line-height: 20px;
            color: #0C4E7C;
            cursor: pointer;
            margin-left: 14px;
        }

        .login-state-trigger {
            cursor: pointer;
            display: block;
            float: left;
            height: 16px;
            overflow: hidden;
            width: 120px;
            margin: 4px 0 0 0;
        }

        .login-state-trigger2 {
            margin: 10px 0 0 20px;
        }

        .login-state-down {
            background: url("../images/ptlogin.png") no-repeat scroll 0 -22px transparent;
            float: left;
            height: 6px;
            margin-top: 5px;
            overflow: hidden;
            text-indent: -999em;
            width: 7px;
        }

        .login-state-show {
            float: left;
            height: 14px;
            overflow: hidden;
            text-indent: -999em;
            width: 14px;
            margin: 1px 4px 0 0;
        }

        .login-state-txt {
            float: left;
            margin-left: 5px;
            font-size: 12px;
            >line-height:18px!important;
        }

        .login-state .callme {
            background: url("../images/ptlogin.png") -72px 0 no-repeat;
        }

        .login-state .online {
            background: url("../images/ptlogin.png") 0 0 no-repeat;
        }

        .login-state .away {
            background: url("../images/ptlogin.png") -18px 0 no-repeat;
        }

        .login-state .busy {
            background: url("../images/ptlogin.png") -36px 0 no-repeat;
        }

        .login-state .silent {
            background: url("../images/ptlogin.png") -108px 0 no-repeat;
        }

        .login-state .hidden {
            background: url("../images/ptlogin.png") -54px 0 no-repeat;
        }

        .statePanel {
            display: none;
            position: absolute;
            right: 68px;
            top: 193px;
            z-index: 10;
            margin: 0;
            border-width: 1px;
            border-style: solid;
            border-color: #ccc #6a6a6a #666 #cdcdcd;
            padding: 0;
            width: 100px;
            height: 133px;
            overflow: hidden;
            background: white;
            font-size: 12px;
            line-height: 1.5;
        }

            .statePanel .statePanel_li {
                display: block;
                float: left;
                margin: 0;
                padding: 3px 0;
                width: 100px;
                height: 16px;
                line-height: 16px;
                overflow: hidden;
                zoom: 1;
                cursor: pointer;
            }

        .stateSelect_icon {
            float: left;
            margin: 2px 0 0 5px;
            width: 14px;
            height: 14px;
            overflow: hidden;
        }

        .stateSelect_text {
            margin: 0 0 0 22px;
        }

        .bottomDiv {
            margin-left: 70px;
        }

        .ui_boxyClose{
            width:28px;
            height:28px;
            position:absolute;
            top:-10px;
            right:-10px;
            cursor:pointer;
            background:url('../images/boxy_btn.png') no-repeat;
            z-index:1
        }
        .ie6_0 
        .ui_boxyClose{
            background:0;
            filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='boxy_btn.png',sizingMethod='scale')
        }
**JS代码实现(drag.js文件):**
/*document.getElementsByClassName()方法在IE10以前的浏览器都是不支持的*/
//先封装一个方法用来获取相关class属性元素对象
//思路:通过对应className和它的父元素ID定位这个className的元素
function getByClass(clasName, parent){
    //如果有传父元素过来,让它不要传父元素这个对象而是传父元素的ID,如果没有传父元素过来那么我们就传document
    var oParent = parent?document.getElementById(parent):document;
    var eles=[];
    //获取该父元素下的所有Tag元素elements
    var elements = oParent.getElementsByTagName('*');
    //把父元素数组中的所有Tag元素取出来挨个遍历一遍,看看各元素的className和传进来的clasName是不是一样的
    //如果一样则把找到的这个元素加进eles[]数组
    for(var i=0,l=elements.length; i<l; i++){    
        if(elements[i].className==clasName){
            eles.push(elements[i]);
        }
    }
    //alert(eles.length);
    return eles; //最后返回eles数组
}

//初始化页面加载
window.onload = drag;

//建立拖曳事件函数:
//思路:在标题区域按下 > 要在页面中移动 > 释放鼠标时停止移动
function drag(){
  //1、获取点击拖动的位置:标题区域
    //通过标题的className和标题的父元素id定位这个标题元素对象集,并取第一个作为作用对象
    var oTitle = getByClass('login_logo_webqq','loginPanel')[0];
  //2、拖曳功能
    //给oTitle绑定一个事件onmousedown:在鼠标按下任何按钮时触发
    oTitle.onmousedown = fnDown;//在鼠标按下时调用fnDown函数

  //3、关闭
    var oClose = document.getElementById("ui_boxyClose");
    oClose.onclick = close;
    /*---------------------------*/
    //切换状态
    var loginState = document.getElementById("loginState");
    var stateList = document.getElementById("loginStatePanel");
    var lis = stateList.getElementsByTagName("li");
    var stateTxt = document.getElementById("login2qq_state_txt");
    var loginStateShow = document.getElementById("loginStateShow");
    //鼠标点击状态时显示整个状态栏
    loginState.onclick = function(e){
        //为了避免和点击其他区域隐藏状态列表函数冲突,这里要阻止事件冒泡
        e = e || window.event;
        //做个浏览器兼容的判断
        if(e.stopPropagation){ //非IE浏览器
            e.stopPropagation();
        }else{ //IE8版本下
            e.cancelBubble = true; 
        }
        stateList.style.display = "block";
    }
    //鼠标滑过、离开、点击状态栏列表选项
    for(var i=0; i<lis.length; i++){
        lis[i].onmouseover = function(){
            this.style.backgroundColor = "#567";
        }
        lis[i].onmouseout = function(){
            this.style.backgroundColor = "#fff";
        }
        //点击列表选项
        lis[i].onclick = function(e){//针对事件捕获行为需要添加一个事件变量
            var lis_id = this.id; //获取被选中的li的id
            //1、把选项列表的id传入状态区的class中,把选项列表文字内容传入状态区
            stateTxt.innerHTML = getByClass("stateSelect_text",lis_id)[0].innerHTML;
            loginStateShow.className = "login-state-show "+lis_id;

            //2、点击列表选项时整个状态栏隐藏
              //注:因为代码45已经对loginState点击事件显示状态列表
              //    因为浏览器默认事件冒泡,点击stateList的同时也作用了loginState,两个函数之间冲突
                //将默认的事件冒泡改为事件捕获
                e = e || window.event;
                //做个浏览器兼容的判断
                if(e.stopPropagation){ //非IE浏览器
                    e.stopPropagation();
                }else{ //IE8版本下
                    e.cancelBubble = true; 
                }
                //改为事件捕获后,使得点击stateList时不冒泡作用loginState,实现statList隐身
            stateList.style.display = "none";
        }
    }
    //点击外面隐藏列表
    document.onclick = function(e){

        stateList.style.display = "none";   
        //注:document点击事件比前面stateList级别更高,在前面做点击显示状态列表时要阻止事件冒泡
    }

}
//鼠标按下函数
function fnDown(event){
    event = event || window.event;
    var oDrag = document.getElementById("loginPanel");
    //定义光标按下时在面板区内部的左、上距离
    var disX = event.clientX-oDrag.offsetLeft,//光标的x坐标 - 面板在窗口左边的距离
        disY = event.clientY-oDrag.offsetTop;
    //移动事件
    document.onmousemove = function(event){
        event = event || window.event;
        fnMove(event,disX,disY); //在鼠标移动时调用移动函数fnMove()
    }
    //鼠标松开按键时释放移动函数
    document.onmouseup = function(event){
      //当鼠标释放就说明onmousemove什么都没有做
        document.onmousemove = null;
        //切忌不要改 fnMove = null;
    }
}
//鼠标移动函数
function fnMove(event,X,Y){
    var oDrag = document.getElementById("loginPanel");
    //定义面板在浏览器窗口的坐标
    var dleft = event.clientX-X, //主板左边距离=事件在窗口中坐标-光标在面板中占据的宽和高
        dtop = event.clientY-Y;
    //定义浏览器窗口的宽高(兼容不同版本浏览器)
    var winW = document.documentElement.clientWidth || document.body.clientWidth,//获取窗口宽
        winH = document.documentElement.clientHeight || document.body.clientHeight;//获取窗口高
    //定义面板在窗口中移动的最大范围
    var maxW = winW - oDrag.offsetWidth, //offsetWidth用来获取这个盒子的宽
        maxH = winH - oDrag.offsetHeight;
    //测试,发现当面板移动到边缘后还是会继续移动,这里就需要强制处理
    //document.title = dleft+","+dtop;
    if(dleft<0){
        oDrag.style.left = 0+"px";
    }else if(dleft>maxW){
        oDrag.style.left = maxW-10+"px";
    }else{
        oDrag.style.left = dleft+"px";  
    }
    if(dtop<0){
        oDrag.style.top = 10+"px";
    }else if(dtop>maxH){
        oDrag.style.top = maxH+"px";
    }else{
        oDrag.style.top = dtop+"px";
    }
}
//关闭函数
function close(){
    var oTab = document.getElementById("loginPanel");
    oTab.style.display = "none";
}

相关图标:
注:图标放在“images”文件夹下,drag.js放在“js”文件夹下,main.css放在“css”文件夹下。
不能上传文件真是蛋疼o(*≧▽≦)ツ┏━┓

21人推荐
随时随地看视频
慕课网APP