原生javascript实现QQ面板拖动、下拉
1、index.html(html页面)
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>QQ面板拖动、下拉</title>
<link href="css/main.css" rel="stylesheet" />
<script class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="js/domUtil.js"></script>
<script class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="js/eventUtil.js"></script>
<script class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="js/drag.js"></script>
</head>
<body>
<div class="loginPanel" id="loginPanel">
<div style="position: relative; z-index: 1;">
<div class="ui_boxyClose" id="ui_boxyClose"></div>
</div>
<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" style="ime-mode: disabled" 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" style="float: left"></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" style="display: none">
<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>
2、css/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')}
3、js/domUtil.js(获取节点相关操作)
//封装获取dom的相关操作,解决浏览器兼容性问题
var domUtil = {
//由于多次使用document.getElementById,所以进行封装
getById:function(id){
return document.getElementById(id);
},
/*由于document.getElementsByClassName在IE10以下不兼容,所以进行封装
思路:将class与parent下面的所有元素(parent.getElementsByTagName('*'))的className进行对比,匹配上压入数组
*/
getByClass:function(clsName,parentID){
var oParent = parentID?this.getById(parentID):document,
eles = [],//返回的元素数组
allChilds = oParent.getElementsByTagName('*');//oParent下面的所有子孙元素
for (var i = 0; i < allChilds.length; i++) {
if(clsName==allChilds[i].className){
eles.push(allChilds[i]);
}
}
return eles;
},
getWindowWidth:function(){
return document.documentElement.clientWidth || document.body.clientWidth;//页面宽度
},
getWindowHeight:function(){
return document.documentElement.clientHeight || document.body.clientHeight;//页面高度
}
}
4、js/eventUtil.js(事件操作程序相关封装)
//使用变量,类似JSON类型的js对象方式进行事件处理程序的相关逻辑封装,主要解决了浏览器兼容性问题
//单独写进js中,便于html多次进行调运
var eventUtil = {
//添加事件
addEventHandle:function(element,eventType,fn){
if(element.addEventListener){//非IE
element.addEventListener(eventType,fn,false);
}else if(element.attachEvent){//IE
element.attachEvent('on'+eventType,fn);//这里拼接上'on',调运的时候不要加on,使用click等。
}else{//不支持DOM2级,使用DOM0级方式
element['on'+eventType] = fn;//这里使用[]方式实现对象的属性添加,相当于.的作用
}
},
//删除事件
removeEventHandle:function(element,eventType,fn){
if(element.removeEventListener){//非IE,不带'on'
element.removeEventListener(eventType,fn,false);//这里传入fn,是因为DOM2级或DOM0级都可以一次给一个元素的同一个事件绑定多个程序,所以需要传入具体的程序fn进行删除
}else if(element.detachEvent){//IE,带'on'
element.detachEvent('on'+eventType,fn);
}else{//不支持DOM2级,使用DOM0级方式
element['on'+eventType] = fn;
}
},
//获取事件对象
getEvent:function(event){
return event?event:window.event;
},
//获取事件类型
getType:function(event){
return event.type;
},
//获取执行事件的目标元素
getTarget:function(event){
return event.target||event.srcElement;
},
//禁用默认行为
preventDefault:function(event){
if(event.preventDefault){
event.preventDefault();//非IE
}else{
event.returnValue = false;//针对IE
}
},
//阻止传播冒泡
stopPropagation:function(event){
if(event.stopPrapagation){
event.stopPrapagation();//非IE
}else{
event.cancelBubble = true;//针对IE
}
}
}
5、js/drag.js(页面逻辑)
window.onload = drag;//页面加载完成以后,此时是能够拿到所有的dom节点的
function drag(){
var oDown = domUtil.getByClass('login_logo_webqq','loginPanel')[0];
//拖曳
oDown.onmousedown=fnDown;
//关闭窗口
var oClose = domUtil.getById('ui_boxyClose');
oClose.onclick = function(){
domUtil.getById('loginPanel').style.display = 'none';
};
//切换状态
var oState = domUtil.getById('loginState'),//状态最终显示的目标区域,这个区域用于点击展开状态列表,同时接收显示最终选择的状态
oStateImg = domUtil.getById('loginStateShow'),//状态显示样式,例如图标
oStateTxt = domUtil.getById('login2qq_state_txt'),//状态文本信息
oStatePanel = domUtil.getById('loginStatePanel'),//状态面板ul,状态元素的外层
oStateLis = oStatePanel.getElementsByTagName('li');//所有的状态元素数组
//显示状态面板,事件需要阻止冒泡,因为后面document的onclick需要隐藏状态面板,这里不阻止的话,会冒泡,导致先显示,后隐藏的逻辑
oState.onclick = function(){
eventUtil.stopPropagation(event);
oStatePanel.style.display = 'block';
};
//页面所有地方点击,都要关闭状态面板
document.onclick = function(){
oStatePanel.style.display = 'none';
};
//每一个状态的元素添加移入、移出、点击事件
for (var i = 0; i < oStateLis.length; i++) {
var oStateLi = oStateLis[i];
oStateLi.onmouseover = function(event){
this.style.background='#567';
};
oStateLi.onmouseout = function(event){
this.style.background='#fff';
};
//点击状态元素:
//1、隐藏状态面板;注意下面也要阻止冒泡,因为上层的oState的onclick需要显示状态面板
//2、替换当前状态id值(id值在css里面有同名的class)到loginStateShow元素的class上去,保证图标的显示
//3、替换当前文本到login2qq_state_txt的文本
oStateLi.onclick = function(event){
eventUtil.stopPropagation(event);
oStatePanel.style.display = 'none';//1
oStateImg.className = 'login-state-show '+this.id;//2
oStateTxt.innerHTML = domUtil.getByClass('stateSelect_text',this.id)[0].innerHTML;//这里不要用innerText,因为firefox不存在innerText属性
};
}
}
/*鼠标在区域内按下动作 执行逻辑
1、鼠标变成+形状,这个由css设置
2、面板在整个页面内跟随移动,需要为document注册onmousemove事件
3、在鼠标松开情况下,面板停止移动,为document注册onmouseup事件
因为不考虑同一事件注册多个程序的情况,所以我们使用DOM0级方式即可。
*/
function fnDown(event){
event = eventUtil.getEvent(event);//获取事件对象,此时为鼠标按下事件
var oDrag = domUtil.getById('loginPanel'),//需要拖曳的面板对象
dx = event.clientX-oDrag.offsetLeft,//光标与面板之间的x距离
dy = event.clientY-oDrag.offsetTop;//光标与面板之间的y距离
document.onmousemove = function(event){
event = eventUtil.getEvent(event);
fnMove(oDrag,event,dx,dy);
};
document.onmouseup = function(){
document.onmousemove = null;
}
}
//需要根据光标位置和光标相对面板的距离,为面板设置left和top,而且为了保证面板能够完全在页面显示,需要对每个临界点进行特殊处理
//临界点有四个:
//1、面板向左不能小于0
//2、面板向右:不能大于屏幕宽度-10-面板宽度(还是考虑关闭图标右边额外占用的10px)
//3、面板向上不能小于10(因为关闭图标在上面、右边分别额外占用了10px,得考虑进来)
//4、面板向下:不能大于屏幕高度-面板高度
function fnMove(element,event,disX,disY){
var l = event.clientX-disX,//移动后的面板left
t = event.clientY-disY,//移动后的面板top
winW = domUtil.getWindowWidth(),//页面宽度
winH = domUtil.getWindowHeight(),//页面高度
maxL = winW -10-element.offsetWidth,//面板最大left
maxT = winH-element.offsetHeight;//面板最大top
if(l<0){
l = 0;
}else if(l>maxL){
l = maxL;
}
if(t<10){
t = 10;
}else if(t>maxT){
t = maxT;
}
element.style.left = l+'px';
element.style.top = t+'px';
}
点击查看更多内容
5人点赞
评论
共同学习,写下你的评论
评论加载中...
作者其他优质文章
正在加载中
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦