1. 程式人生 > >javascript動畫系列第四篇——拖拽改變元素大小

javascript動畫系列第四篇——拖拽改變元素大小

前面的話

  拖拽可以讓元素移動,也可以改變元素大小。本文將詳細介紹拖拽改變元素大小的效果實現

原理簡介

  拖拽讓元素移動,是改變定位元素的left和top值實現的。而拖拽改變元素大小,則還需要改變元素的寬高

範圍圈定

  我們把改變元素大小的範圍圈定在距離相應邊10px的範圍內

  左側邊界L = obj.offsetLeft + 10

  右側邊界R = obj.offsetLeft + obj.offsetWidth - 10

  上側邊界T = obj.offsetTop + 10

  下側邊界B = obj.offsetTop + obj.offsetHeight - 10

<div id="test" style="height: 100px;width: 100px;background-color: pink;">測試文字</div>
<script>
test.onmousemove = function(e){
    e = e || event;
    //元素邊界確定
    var L0 = this.offsetLeft;
    var R0 = this.offsetLeft + this.offsetWidth;
    var T0 = this.offsetTop;
    var B0 =
this.offsetTop + this.offsetHeight; //範圍邊界確定 var L = L0 + 10; var R = R0 - 10; var T = T0 + 10; var B = B0 - 10; //範圍確定 var areaL = e.clientX < L; var areaR = e.clientX > R; var areaT = e.clientY < T; var areaB = e.clientY > B; //左側範圍 if(areaL){
this.style.cursor = 'w-resize'; } //右側範圍 if(areaR){ this.style.cursor = 'e-resize'; } //上側範圍 if(areaT){ this.style.cursor = 'n-resize'; } //下側範圍 if(areaB){ this.style.cursor = 's-resize'; } //左上範圍 if(areaL && areaT){ this.style.cursor = 'nw-resize'; } //右上範圍 if(areaR && areaT){ this.style.cursor = 'ne-resize'; } //左下範圍 if(areaL && areaB){ this.style.cursor = 'sw-resize'; } //右下範圍 if(areaR && areaB){ this.style.cursor = 'se-resize'; } //中間範圍 if(!areaL && !areaR && !areaT && !areaB){ this.style.cursor = 'default'; } } </script>

大小改變

  處於左側範圍時,改變元素的left和width值

  處於右側範圍時,改變元素的left值

  處於上側範圍時,改變元素的top和height值

  處於下側範圍時,改變元素的height值

  [注意]元素改變前的狀態是指按下滑鼠的瞬時元素的狀態

<div id="test" style="height: 100px;width: 100px;background-color: pink;position:absolute;top:100px;left:200px;">測試文字</div>
<script>
function addEvent(target,type,handler){
    if(target.addEventListener){
        target.addEventListener(type,handler,false);
    }else{
        target.attachEvent('on'+type,function(event){
            return handler.call(target,event);
        });
    }
}
(function(){
    var x0,y0,x1,y1,EW,EH,isChanging;
    var ele = document.getElementById('test');
    var mousedownHandler = function(e){
        e = e || event;
        //獲取元素距離定位父級的x軸及y軸距離
        x0 = ele.offsetLeft;
        y0 = ele.offsetTop;
        //獲取此時滑鼠距離視口左上角的x軸及y軸距離
        x1 = e.clientX;
        y1 = e.clientY;
        //獲取此時元素的寬高
        EW = ele.offsetWidth;
        EH = ele.offsetHeight;        
        //按下滑鼠時,表示正在改變尺寸
        isChanging = true;
    }
    var mousemoveHandler = function(e){
        e = e || event;
        //元素邊界確定
        var L0 = ele.offsetLeft;
        var R0 = ele.offsetLeft + ele.offsetWidth;
        var T0 = ele.offsetTop;
        var B0 = ele.offsetTop + ele.offsetHeight;
        //範圍邊界確定
        var L = L0 + 10;
        var R = R0 - 10;
        var T = T0 + 10;
        var B = B0 - 10;
        //範圍確定
        var areaL = e.clientX < L;
        var areaR = e.clientX > R;
        var areaT = e.clientY < T;
        var areaB = e.clientY > B;
        //左側範圍
        if(areaL){ele.style.cursor = 'w-resize';}
        //右側範圍
        if(areaR){ele.style.cursor = 'e-resize';}
        //上側範圍
        if(areaT){ele.style.cursor = 'n-resize';}    
        //下側範圍
        if(areaB){ele.style.cursor = 's-resize';}    
        //左上範圍
        if(areaL && areaT){ele.style.cursor = 'nw-resize';}
        //右上範圍
        if(areaR && areaT){ele.style.cursor = 'ne-resize';}
        //左下範圍
        if(areaL && areaB){ele.style.cursor = 'sw-resize';}
        //右下範圍
        if(areaR && areaB){ele.style.cursor = 'se-resize';}
        //中間範圍    
        if(!areaL && !areaR && !areaT && !areaB){ele.style.cursor = 'default';}

        //獲取此時滑鼠距離視口左上角的x軸及y軸距離
        var x2 = e.clientX;
        var y2 = e.clientY;   
        //如果改變元素尺寸功能開啟
        if(isChanging){
            //處於左側範圍
            if(areaL){
                ele.style.left = x0 + (x2 - x1)  + 'px';
                ele.style.width = EW + (x1 - x2) + 'px'; 
            }
            //處於右側範圍
            if(areaR){ele.style.width = EW + (x2 - x1)+ 'px';}
            //處於上側範圍
            if(areaT){
                ele.style.top = y0 + (y2 - y1) + 'px';
                ele.style.height = EH + (y1 - y2) + 'px';
            }
            //處於下側範圍
            if(areaB){ele.style.height = EH + (y2 - y1) + 'px'; }               
        } 
    }
    var mouseupHandler = function(e){
        //滑鼠擡起時,表示停止運動
        isChanging = false;
    }
    addEvent(ele,'mousedown',mousedownHandler);
    addEvent(ele,'mousemove',mousemoveHandler);
    addEvent(ele,'mouseup',mouseupHandler)

})();
</script>    

程式碼優化

  與拖拽移動元素一樣,拖拽改變元素大小也存在同樣的問題

  問題一:文字及圖片具有原生的拖放行為,通過取消預設行為可解決。IE8-瀏覽器不支援,使用全域性捕獲來實現IE相容

  問題二:拖放過快,滑鼠移動速度快於mousemove觸發速度時,滑鼠脫離元素,使後續事件無法發生。把mousemove事件加在document上,即可解決

  問題三:元素大小改變需要有範圍限制

<div id="test" style="height: 100px;width: 100px;background-color: pink;position:absolute;top:100px;left:200px;">測試文字</div>
<script>
function addEvent(target,type,handler){
    if(target.addEventListener){
        target.addEventListener(type,handler,false);
    }else{
        target.attachEvent('on'+type,function(event){
            return handler.call(target,event);
        });
    }
}
(function(){
    var x0,y0,x1,y1,EW,EH,isChanging;
    var ele = document.getElementById('test');
    var mousedownHandler = function(e){
        e = e || event;
        //獲取元素距離定位父級的x軸及y軸距離
        x0 = ele.offsetLeft;
        y0 = ele.offsetTop;
        //獲取此時滑鼠距離視口左上角的x軸及y軸距離
        x1 = e.clientX;
        y1 = e.clientY;
        //獲取此時元素的寬高
        EW = ele.offsetWidth;
        EH = ele.offsetHeight;        
        //按下滑鼠時,表示正在改變尺寸
        isChanging = true;
    }
    var mousemoveHandler = function(e){
        e = e || event;
        //元素邊界確定
        var L0 = ele.offsetLeft;
        var R0 = ele.offsetLeft + ele.offsetWidth;
        var T0 = ele.offsetTop;
        var B0 = ele.offsetTop + ele.offsetHeight;
        //範圍邊界確定
        var L = L0 + 10;
        var R = R0 - 10;
        var T = T0 + 10;
        var B = B0 - 10;
        //範圍確定
        var areaL = e.clientX < L;
        var areaR = e.clientX > R;
        var areaT = e.clientY < T;
        var areaB = e.clientY > B;
        //左側範圍
        if(areaL){ele.style.cursor = 'w-resize';}
        //右側範圍
        if(areaR){ele.style.cursor = 'e-resize';}
        //上側範圍
        if(areaT){ele.style.cursor = 'n-resize';}    
        //下側範圍
        if(areaB){ele.style.cursor = 's-resize';}    
        //左上範圍
        if(areaL && areaT){ele.style.cursor = 'nw-resize';}
        //右上範圍
        if(areaR && areaT){ele.style.cursor = 'ne-resize';}
        //左下範圍
        if(areaL && areaB){ele.style.cursor = 'sw-resize';}
        //右下範圍
        if(areaR && areaB){ele.style.cursor = 'se-resize';}
        //中間範圍    
        if(!areaL && !areaR && !areaT && !areaB){ele.style.cursor = 'default';}

        //獲取此時滑鼠距離視口左上角的x軸及y軸距離
        var x2 = e.clientX;
        var y2 = e.clientY;   
        //<