原生拖拽模型(有限制范围的)
思路:
确定盒子的移动的方式
1、 定位的left top值可以让盒子移动
2、直接margin 顶(在文档流中,不建议) 父元素的padding顶 (更加不建议)
使用left来实现 ,需要设置定位。全部用 相对定位(叠加计算) 绝对定位都能实现(相对是谁,如果代码多,会很乱。),
这里我们使用 父相子绝(边界相对定位,移动的盒子绝对定位)
确定是否有边界
移动的盒子不能超过设置的边界。
判断边界有很多方法。可以使用移动盒子的四个角到视口的距离判断,也可以使用盒子能够移动的left来进行判断边界。
这里我们使用 可以移动的最大值来判断。
横向可以移动的最大 就是边界宽 - 移动盒子的宽
纵向可以移动的最大top 就是边界的高 - 移动盒子的高
思考都触发了什么事件。
盒子被拖动,首先需要 盒子被鼠标 按下不抬起(onmousedown), 然后是拖动(onmousemove),鼠标松开(onmouseup)
深度思考。 确保鼠标在触发鼠标按下不抬起的点,移动到终点的时候,点还在盒子的上相同位置。这个盒子该怎么样绘制。
我们这里使用的思路就是
盒子移动,需要知道鼠标 “点”在哪里 ,然后根据移动后的“点”再绘制盒子,这里通过为盒子设置的left和top值,让盒子移动,移动的left和top减去点在盒子上的距离。就可以保证点还在盒子的相同位置上。
我们可以盒子的四个角来做运算,我们这里选择使用 左上角来计算 left值和top值。
这个时候我们又有了两种算法,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;
}