本文为《DOM事件探秘》课程中第四章“QQ面板在浏览器窗口中拖曳效果”的代码实现。
本文及js代码demo为笔者在课后实现,代码中有详细注释,解说了上课视频中老师的代码功能及实现思想。读者可以复制本文代码作为笔记进行参考。
核心代码为drag.js文件中的JavaScript实现,重点内容包含:
1、封装函数实现通过className和父元素Id实现元素目标的获取;
2、建立拖曳函数(包含鼠标按住事件、鼠标移动事件、松开按钮事件);
3、关闭面板
面板在窗口边框的效果图:
界面描述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">LOGO头部</div>
<!-- 账号输入区 -->
<div class="inputs">
账户信息输入区
</div>
<!-- 状态选择区 -->
<div class="bottomDiv">
登录 及
状态选择区
</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;
}
/***********************************************************/
/*
//定义fnDown函数:鼠标按下时让对象跟随鼠标坐标(clientX, clientY)
function fnDown(){
//在页面中移动
var oDrag=document.getElementById("loginPanel");
//鼠标按下后 > 在整个页面移动(整个页面用document表示)
//onmousemove 当鼠标指针在元素内部移动时重复触发函数
document.onmousemove = function(event){//因为鼠标位置信息都是保存在“事件”的clientX和clientY属性中,所以函数中需要传入一个代表事件的变量
//event接收鼠标位置信息
//非IE浏览器直接使用event,IE浏览器得用到window.event
event = event || window.event;
//测试:用title接收位置信息
document.title = event.clientX+','+event.clientY;
oDrag.style.left = event.clientX+"px";
oDrag.style.top = event.clientY+"px";
}
}
*/
/************************************************************/
//鼠标按下函数
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";
}