拖拽drag_[JS]面向对象的拖拽实现

本文是作者的学习笔记,详细记录了如何用JavaScript实现面向对象的拖拽功能。通过代码示例,逐步解释了拖拽效果的实现过程,欢迎读者在评论区交流指正,共同进步。
摘要由CSDN通过智能技术生成

bc2212f23ce0c194bd3d56326be9c125.png

这文章是我自己的学习记录,若文中有理解有误的地方,请在评论区指出,我再理解一下,更快进步,非常感谢!

  1. 直接上代码
//(我们的每个实例身上已经在down方法中携带了,但是在不同的作用域,需要使用实例对象将其联系起来,因为两者的this都是指向实例化对象的,故this.可以访问mouseToEle)

function Drag(ele){
    //封装了一个拖拽的构造函数,只要是new构造调用的实例就可以使用其中的特权方法,公有属性和方法
    //每一个new的实例元素都会被获取,故这是它们的公有属性,使用this.ele释放给实例对象,ele可以是id,标签名等
    this.ele = document.querySelector(ele);
    //每一个实例对象都要有点击按下的事件,故使用this进行释放这个特权方法,这个方法就是实例对象才有权利访问
    //为什么不将这个方法添加到原型对象上面去?
    //因为我们需要触发这个事件,此处触发的event对象只能是鼠标所以就把它设置成一个特权属性而不是一个公有属性,实例对象的特权方法,它们各自有自己的内存空间,只是它们长得'一样'罢了.   记得将mouse事件对象传入
    this.ele.onmousedown = function(e){
		//让每个实例对象执行它们的特权方法down(e)并传入参数
        //但是显然此时我们在一个新的作用域中,这个函数的this指向与外边的显然不同,但是我要让实例对象去调用这个公有方法,这样的话需要改变this的指向,这时候可以选择链式调用bind(this)绑定也可以使用变量接收,形成闭包,直至内层函数执行完毕再断开内层函数对外层变量的引用
        //使用bind的好处就是不会形成闭包,这样减少内存泄漏的风险
        this.down(e);
    }.bind(this);
}

//特权方法,要将参数进行接收
Drag.prototype.down = function(e){
    //这里比较有趣,我们先想一下对于任何一个实例对象,鼠标到盒子的距离当你在点击按下的时候已经获取到了,而且在本次按下释放之前,这个值是个恒定值,(你移动也不会改变,鼠标和盒子的相对位移是恒定的哦)只是每个实例的具体数据有差异而已,所以可以将这个属性设置成一个公有属性,这样的话所有的实例调用down方法的或获取到自己值便于计算元素的实际位移
    //注意的是offsetX和offsetY是鼠标到文档边缘的横纵向
    //放在对象里,便于使用
    this.mouseToEle = {
        x : e.offsetX,
        y : e.offsetY
    }
    //拖拽的时候是在文档中进行的,所以事件绑定的是给document,因为移动要有事件对象,所以记得要将参数进行传入
    &&&//注意这个就不是特权方法了,就是一个普通的事件绑定,你把函数当成普通的函数调用的时候,这个方法你有权可以访问和执行
    //但是函数没有return,默认返值是undefined,故直接调用默认的返值就是undefined
    document.onmousemove = function(e){
        //改变this执行biang调用公有方法
        this.move(e);
    }.bind(this);
    //若我要在鼠标按下的时候不拖拽弹起也可以实现弹起销毁事件,就要将销毁放置在按下里面进行回调
    //doucment事件对象,因为鼠标按键弹起的时候,前面的事件都会停止了,所以这时候就没必要传参数了,使用默认值就好
    //当弹起时候,将移动事件和弹起事件均释放,变成垃圾对象
    document.onmouseup = function(){
        //改变this指向
        this.up();
    }.bind(this);
}
​
Drag.prototype.move = function(e){
    //因为移动只是我们的一个move方法中才会完成的一种实现,所以为了不污染其他作用域,我将当前的元素移动的位置设置为当前作用域及其子作用域才可能访问的到的局部变量进行存储
    let nowEleLocation = {
        //鼠标坐标 - 鼠标相对于元素的边缘的距离 = 元素实际的位移量
        //(我们的每个实例身上已经在down方法中国携带了,但是在不同的作用域,需要使用实例对象将其联系起来,因为两者的this都是指向实例化对象的,故this.可以访问mouseToEle)
        x : e.clientX - this.mouseToEle.x,
        y : e.clientY - this.mouseToEle.y
    }; 
    //边界判断
    if (now.x <= 0) {
         now.x = 0;
    }
    if (now.x >= document.documentElement.clientWidth - this.ele.offsetWidth) {
         now.x = document.documentElement.clientWidth - this.ele.offsetWidth;
    }
    if (now.y <= 0) {
         now.y = 0;
     }
    if (now.y >= document.documentElement.clientHeight - this.ele.offsetHeight) {
         now.y = document.documentElement.clientHeight - this.ele.offsetHeight;
     }
​
    //为了使每个实例都拥有正常的页面表现,需要this
    this.ele.style.left = nowEleLocation.x + 'px';
    this.ele.style.top = nowEleLocation.y + 'px';
}
​
Drag.prototype.up = function(){
    //释放事件onmousedown
    document.onmousedown = null;
    //释放自己onmouseup 
    document.onmouseup = null;
}
​
new Drag('div');
new Drag('h1');
Drag();  //返回默认值 undefined

2. 接着上结构

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>手写面向对象的拖拽</title>
    <style>
        div{
            width: 300px;
            height: 300px;
            background-color: #95dc84;
            position: absolute;
            /*不要忘记这里的position一定要有!,否则不起作用,而且js的style设置的是行内样式,层级更高*/
        }
​
        h1 {
            width: 200px;
            height: 40px;
            background-color: #ea4a36;
            position: absolute;
            cursor: pointer;
        }
    </style>
</head>
<body>
    <div></div>
    <h1>你拖拽我呀!</h1>
</body>
</html>
​

3.最后没注释的版本如下:

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>手写面向对象的拖拽</title>
    <style>
        div{
            width: 300px;
            height: 300px;
            background-color: #95dc84;
            position: absolute;
        }
​
        h1 {
            width: 200px;
            height: 40px;
            background-color: #ea4a36;
            position: absolute;
            cursor: pointer;
        }
    </style>
</head>
<body>
    <div></div>
    <h1>你拖拽我呀!</h1>
    <script>
        function Drag(ele) {
            this.ele = document.querySelector(ele);
            this.ele.onmousedown = function (e) {
                this.down(e);
            }.bind(this);
        }
​
        Drag.prototype.down = function (e) {
            this.mouseToBox = {
                x : e.offsetX,
                y : e.offsetY
            };
​
            document.onmousemove = function (e) {
                this.move(e);
            }.bind(this);
​
            document.onmouseup = function () {
                this.up();
            }.bind(this);
        };
​
        Drag.prototype.move = function (e) {
            let mouseLocation = {
                x : e.clientX - this.mouseToBox.x,
                y : e.clientY - this.mouseToBox.y,
            };
            if (now.x <= 0) {
                now.x = 0;
            }
            if (now.x >= document.documentElement.clientWidth - this.ele.offsetWidth) {
                now.x = document.documentElement.clientWidth - this.ele.offsetWidth;
            }
            if (now.y <= 0) {
                now.y = 0;
            }
            if (now.y >= document.documentElement.clientHeight - this.ele.offsetHeight) {
                now.y = document.documentElement.clientHeight - this.ele.offsetHeight;
            }
​
            this.ele.style.left = mouseLocation.x + 'px';
            this.ele.style.top = mouseLocation.y + 'px';
        };
​
        Drag.prototype.up = function () {
            document.onmousemove = null;
            document.onmouseup = null;
        };
​
        new Drag('div');
        new Drag('h1');
    </script>
</body>
</html>

上述完成了一个拖拽的效果!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值