思路
- 父盒子相對(duì)定位,子元素码耐,也就是被拖拽的元素絕對(duì)定位
- 當(dāng)鼠標(biāo)在子元素中按下時(shí)追迟,綁定鼠標(biāo)移動(dòng)事件,根據(jù)鼠標(biāo)位置改變?cè)匚恢?
- 設(shè)置鼠標(biāo)當(dāng)前位置(offsetX,offsetY,這時(shí)和父的相對(duì)位置)為元素的中心位置
- 移動(dòng)時(shí)改變位置css中的left為offsetX...的位置
- 當(dāng)鼠標(biāo)離開(kāi)時(shí)骚腥,解綁鼠標(biāo)移動(dòng)事件
實(shí)現(xiàn)過(guò)程(一)
css 部分
.decision-box{
position: relative;
width: 1500px;
height: 600px;
border: 1px solid #000;
border-radius: 6px;
/*margin-left: -40px;*/
}
.item{
position: absolute;
width: 50px;
height: 30px;
background: green;
border-radius: 6px;
text-align: center;
line-height: 30px;
cursor: pointer;
left: 50px
}
html 部分
<div class="decision-box decision_box">
<div class="item">1</div>
<div class="item">2</div>
<div class="item">3</div>
</div>
js 部分
//鼠標(biāo)按下敦间,要在移動(dòng)元素上按下
$(document).on('mousedown','.decision_box .item',function(e){
var ele = $(e.target);
$(document).on('mousemove','.decision_box',function(e){
//移動(dòng)鼠標(biāo)時(shí)改變?cè)匚恢? var x = e.offsetX,
y = e.offsetY;
ele.css({
left:x - 25 + 'px',
top:y - 15 + 'px'
});
e.stopPropagation();
});
e.stopPropagation();
});
//鼠標(biāo)放開(kāi)
$(document).on('mouseup',function(){
//解除鼠標(biāo)移動(dòng)事件
$(document).off('mousemove');
});
這時(shí),發(fā)生了錯(cuò)誤束铭,元素一閃一閃的廓块,位置不是一直跟著鼠標(biāo),在mousemove觸發(fā)函數(shù)里打印一下位置契沫,發(fā)現(xiàn)位置不一直是鼠標(biāo)位置带猴。原來(lái)是應(yīng)為鼠標(biāo)位置offsetX的原因。
關(guān)于鼠標(biāo)位置
- clientX 相對(duì)于可是窗口的距離
- offsetX 相對(duì)于e.target元素的位置
- pageX 相對(duì)于文檔的左邊緣
- screenX 相對(duì)于屏幕的位置
原來(lái)offsetX是相對(duì)于e.target元素的位置懈万。加入被拖拽元素寬高100px,當(dāng)我點(diǎn)擊100px,100px時(shí)拴清,元素的中心位置變?yōu)?00,100;此時(shí)offsetX又變?yōu)榱?0会通;這時(shí)offsetX又變回100口予;(以上數(shù)字只是數(shù)字,因?yàn)橛幸苿?dòng))涕侈。如上沪停,就形成了一閃一閃,之后鼠標(biāo)會(huì)超過(guò)元素范圍裳涛,這時(shí)木张,元素位置就在鼠標(biāo)相對(duì)于本身和鼠標(biāo)相對(duì)于父盒子之間切換。
那么怎么解決這個(gè)問(wèn)題呢调违?我的思路是:
- 使用其它鼠標(biāo)位置窟哺,當(dāng)點(diǎn)擊元素時(shí)獲取位置作為初始位置
- 當(dāng)移動(dòng)時(shí)獲取位置并求出相對(duì)位移泻轰,這個(gè)相對(duì)于位移也就是元素要移動(dòng)的距離技肩。
實(shí)現(xiàn)過(guò)程(二)
js 部分
//鼠標(biāo)按下,要在移動(dòng)元素上按下
$(document).on('mousedown','.decision_box .item',function(e){
console.log(parseInt($(e.target).css('left')))
var ele = $(e.target);
var initX = e.clientX,
initY = e.clientY,
itemX = parseInt(ele.css('left'));
itemY = parseInt(ele.css('top'));
$(document).on('mousemove','.decision_box',function(e){
//移動(dòng)鼠標(biāo)時(shí)改變?cè)匚恢? var curX = e.clientX,
curY = e.clientY;
ele.css({
left:itemX + (curX - initX) + 'px',
top:itemY + (curY - initY) + 'px'
});
e.stopPropagation();
});
e.stopPropagation();
});
//鼠標(biāo)放開(kāi)
$(document).on('mouseup',function(){
//解除鼠標(biāo)移動(dòng)事件
$(document).off('mousemove');
});
成功,可以拖動(dòng)了虚婿,這時(shí)又遇上了一個(gè)問(wèn)題旋奢,當(dāng)拖動(dòng)元素時(shí),有其它文本別選中時(shí)然痊,拖拽又出現(xiàn)了bug至朗,這時(shí)就要用到下面面這兩個(gè)屬性
onselectstart = "return false";
onselect = "return false";
- onselectstart事件不被input和textarea標(biāo)簽支持,而onselect事件只被input和textarea支持剧浸。
- Firefox/Opera不支持onselectstart事件Firefox中可以使用CSS "-moz-user-select:none"屬性來(lái)禁止文本選定
- webkit瀏覽器可以使用“-khtml-user-select”锹引,當(dāng)然也可以使用onselectstart事件來(lái)阻止用戶選定元素內(nèi)文本,如下
<div onselectstart="return false">accc</div>
這個(gè)屬性意思就是不讓文本被選中唆香。要做的就是當(dāng)點(diǎn)擊元素時(shí)嫌变,上這個(gè)屬性,當(dāng)放開(kāi)鼠標(biāo)時(shí)去掉這個(gè)屬性(改成return true)躬它;
最后代碼
//鼠標(biāo)按下腾啥,要在移動(dòng)元素上按下
$(document).on('mousedown','.decision_box .item',function(e){
$('body').attr('onselectstart','return false');
console.log(parseInt($(e.target).css('left')))
var ele = $(e.target);
var initX = e.clientX,
initY = e.clientY,
itemX = parseInt(ele.css('left'));
itemY = parseInt(ele.css('top'));
$(document).on('mousemove','.decision_box',function(e){
//移動(dòng)鼠標(biāo)時(shí)改變?cè)匚恢? var curX = e.clientX,
curY = e.clientY;
ele.css({
left:itemX + (curX - initX) + 'px',
top:itemY + (curY - initY) + 'px'
});
e.stopPropagation();
});
e.stopPropagation();
});
//鼠標(biāo)放開(kāi)
$(document).on('mouseup',function(){
$('body').attr('onselectstart','return true');
//解除鼠標(biāo)移動(dòng)事件
$(document).off('mousemove');
});
這時(shí),選中文本后再進(jìn)行拖拽還有問(wèn)題,(也可不解決)我暫時(shí)不知道冯吓;還有碰撞檢測(cè)什么的也沒(méi)加倘待。待續(xù)......