原生JS拖拽模型(有限制范围的)

原生拖拽模型(有限制范围的)

思路:

确定盒子的移动的方式

​ 1、 定位的left top值可以让盒子移动

​ 2、直接margin 顶(在文档流中,不建议) 父元素的padding顶 (更加不建议)

​ 使用left来实现 ,需要设置定位。全部用 相对定位(叠加计算) 绝对定位都能实现(相对是谁,如果代码多,会很乱。),

这里我们使用 父相子绝(边界相对定位,移动的盒子绝对定位)

确定是否有边界

​ 移动的盒子不能超过设置的边界。

​ 判断边界有很多方法。可以使用移动盒子的四个角到视口的距离判断,也可以使用盒子能够移动的left来进行判断边界。

​ 这里我们使用 可以移动的最大值来判断。

横向可以移动的最大 就是边界宽 - 移动盒子的宽
纵向可以移动的最大top 就是边界的高 - 移动盒子的高

思考都触发了什么事件。

​ 盒子被拖动,首先需要 盒子被鼠标 按下不抬起(onmousedown), 然后是拖动(onmousemove),鼠标松开(onmouseup)

深度思考。 确保鼠标在触发鼠标按下不抬起的点,移动到终点的时候,点还在盒子的上相同位置。这个盒子该怎么样绘制。

我们这里使用的思路就是

盒子移动,需要知道鼠标 “点”在哪里 ,然后根据移动后的“点”再绘制盒子,这里通过为盒子设置的left和top值,让盒子移动,移动的left和top减去点在盒子上的距离。就可以保证点还在盒子的相同位置上。

​ 我们可以盒子的四个角来做运算,我们这里选择使用 左上角来计算 left值和top值。

扫描二维码关注公众号,回复: 8554813 查看本文章

这个时候我们又有了两种算法,left 可以相对于 父元素的边框,也可以根据上次移动的left 进行叠加。其实,这都是相对于父元素的边框。(注意,我们的盒子现在是绝对定位。)来一张丑陋的图。我们不用叠加。用简单,不走坑的,相对于大盒子的left。

在这里插入图片描述

​ 那么此时, 需要小盒子左边框的值到黑盒子,我们可以通过 左上角的点来算。

​ 点在哪里 使用只读属性 offsetX 和offsetY 得到鼠标的点在小盒子中的位置

​ 小黑盒子 : 点到视口的位置 clientX clientY 减去 点在小绿盒子的offsetX 和 offsetY

​ 再减去 大盒子 到视口的位置(pageX),大盒子到视口的位置可以选择使用 getComputedStyle(IE也不支持,我用的IE全指的是IE8,IE用的解析是currentStyle。可以做这么一个兼容) 浏览器解析之后的样式计算,也可以使用pageX,pageY 求得

​ 这里我们使用pageX和 pageY 来做图。(page是事件对象,并且IE不支持。下一遍原生js封装page函数,就可以调用page函数来实现,代码我们暂时先用getComputedStyle。想要兼容的小伙伴可以解析样式这里做一个兼容)。

在这里插入图片描述

​ 然后进去大盒子的边框。(这里我们使用clientLeft得到左边框)。然后就可以得到的 left 移动值, 相对于大黑盒子移动left。就可以达到相同的位置(展示)

​ 所以移动的left值就为

left值 = 移动后“点”的视口的x坐标 - 元素的偏移x坐标(offsetX) - 父元素到页面的距离(pageX) - 父元素的边框(clientLeft)。

1、 需要的事件 onmousedown、onmousemove、onmouseup

2、使用定位的left和top 来作为盒子移动。

3、边界的判断使用 可以移动的最大值

* {
    margin: 0;
    padding: 0;
}
#box {
    width: 500px;
    height: 500px;
    border: 1px solid red;
    margin: 0 auto;
    position: relative;
}
#move {
    width: 100px;
    height: 100px;
    background-color: orange;
    position: absolute;
    left: 0;
    top: 0;
}
<div id="box">
    <div id="move"></div>
</div>
var box = document.getElementById('box');
var move = document.getElementById('move');

// 最大可以移动距离
var maxLeft = parseFloat(getComputedStyle(box).width) - parseFloat(getComputedStyle(move).width);
var maxTop = parseFloat(getComputedStyle(box).height) - parseFloat(getComputedStyle(move).height);

// 获得盒子到 距离 视口 的宽和高
var leftt = getComputedStyle(box).marginLeft;   // 得到的是px 
var topp = getComputedStyle(box).top;


move.onmousedown = function(e) {
    // 兼容e
    var e = e || event; 
    // console.log('dd');
    // 获得点击位置的  元素偏移量  x y
    var ox = e.offsetX;
    var oy = e.offsetY;

    //  console.log(leftt);
    document.onmousemove = function(e) {
        var e = e || event; 

            //   点击 点 视口的 x y
        var cx = e.clientX;
        var cy = e.clientY;

        console.log(leftt);

        // 获得移动了的 left  和 height   再减外边盒子的边框
        var left = cx - ox - parseFloat(leftt);
        var top = cy - oy - parseFloat(topp);

        //  console.log(left);
        // console.log(cx- ox);
        // 因为有边界 ,所以  判断边界值
        /* 
            判断边界的方法   
                    1.   四个角的点   判断边界  
                    2.   可移动的长度进行  判断  
            */

            /* 用可移动的长度进行判断 */
            left = left < 0? 0: left;
            left = left > maxLeft? maxLeft: left;
            top = top < 0? 0: top;
            top = top > maxTop? maxTop: top;

        // console.log(max);
        //  css开始变
        move.style.left = left + 'px';
        move.style.top = top + 'px';
    }
}

// 鼠标抬起
document.onmouseup = function() {
    document.onmousemove = null;
}
发布了7 篇原创文章 · 获赞 1 · 访问量 218

猜你喜欢

转载自blog.csdn.net/qq_35898059/article/details/103661405