为什么我的改进没有让这个 JS 拖放脚本停止滞后?

问题描述 投票:0回答:1

我有这个脚本效果很好,它做我想做的......但唯一的问题是它在快速移动div时滞后。

我在互联网上花了几个小时试图找到解决方案,比如添加 pointermove、使用 translate3d、使用 RequestAnimationFrame、css as will-change 等...但没有任何效果

请参阅下面我尝试改进的代码

box-medling.js

(function ($) {
    $.fn.boxModeling = function (options) {

        const settings = $.extend({
            boxSelector: 'box',
            handlerClass: 'resize-handler',
            minWidth: 40,
            minHeight: 40,
            resize: true,
            rotate: true,
            move: true,
        raf: false,
        startX: false,
        startY: false,
        deltaX: false,
        deltaY: false,
        initX: false,
        initY: false,


        }, options);
        
         


        const boxHandlers =
            '<div class="box-handlers">' +
            '<div class="' + settings.handlerClass + ' resize left-top" style="top: -5px;left: -5px;"></div>' +
            '<div class="' + settings.handlerClass + ' resize left-mid" style="left: -5px;top: calc(50% - 5px);"></div>' +
            '<div class="' + settings.handlerClass + ' resize left-bot" style="bottom: -5px;left: -5px;"></div>' +
            '<div class="' + settings.handlerClass + ' resize center-top" style="top: -5px;left: calc(50% - 5px);"></div>' +
            '<div class="' + settings.handlerClass + ' resize center-bot" style="bottom: -5px;left: calc(50% - 5px);"></div>' +
            '<div class="' + settings.handlerClass + ' resize right-top" style="top: -5px;right: -5px;"></div>' +
            '<div class="' + settings.handlerClass + ' resize right-mid" style="right: -5px;top: calc(50% - 5px);"></div>' +
            '<div class="' + settings.handlerClass + ' resize right-bot" style="bottom: -5px;right: -5px;"></div>' +
            '<div class="' + settings.handlerClass + ' rotate" style="top: -30px;left: calc(50% - 5px);"></div>' +
            '</div>';

        return $(this).each(function () {

            const box = this;

            // $(box).css('transform', $(box).css('transform') + 'translate(-50%, -50%)');

            let initX, initY, mousePressX, mousePressY, initW, initH, initRotate;

            $(box).append(boxHandlers);

            const hLeftTop = $(box).find('.' + settings.handlerClass + '.left-top');
            const hLeftMid = $(box).find('.' + settings.handlerClass + '.left-mid');
            const hLeftBot = $(box).find('.' + settings.handlerClass + '.left-bot');
            const hCenterTop = $(box).find('.' + settings.handlerClass + '.center-top');
            const hCenterBot = $(box).find('.' + settings.handlerClass + '.center-bot');
            const hRightTop = $(box).find('.' + settings.handlerClass + '.right-top');
            const hRightMid = $(box).find('.' + settings.handlerClass + '.right-mid');
            const hRightBot = $(box).find('.' + settings.handlerClass + '.right-bot');
            const hRotate = $(box).find('.' + settings.handlerClass + '.rotate');


            


            function repositionElement(x, y) {
                //alert(settings.deltaX);
                
                //$(box).css('backface-visibility', 'hidden'); 
                //$(box).css({'-webkit-transform': 'translateX(' + x + 'px) translateY(' + y + 'px)', 'transform': 'translateX(' + x + 'px) translateY(' + y + 'px)' });
                
                
                
                 $(box).css('left', x+ 'px');    // <=
                 //initX + (event.clientX - mousePressX)
                 $(box).css('top', y + 'px');     // <=
                 
                 // box.style.transform = "translate3d("+settings.deltaX+"px,"+settings.deltaY+"px, 0px)";
                  // once the paint job is done we 'release' animation frame variable to allow next paint job:
                  settings.raf = null;
                
                //console.dirxml(box);
            }

            function resize(w, h) {
                $(box).css('width', w + 'px');
                $(box).css('height', h + 'px');
                //console.log('box : '+$(box).attr("data-id")+' wh : '+h+'-'+h);
            }

            function getRotation(e) {
                const st = window.getComputedStyle(e, null);
                const tm = st.getPropertyValue("-webkit-transform") ||
                    st.getPropertyValue("-moz-transform") ||
                    st.getPropertyValue("-ms-transform") ||
                    st.getPropertyValue("-o-transform") ||
                    st.getPropertyValue("transform") ||
                    "none";
                if (tm !== "none") {
                    const values = tm.split('(')[1].split(')')[0].split(',');
                    const angle = Math.round(Math.atan2(Number.parseFloat(values[1]), Number.parseFloat(values[0])) * (180 / Math.PI));
                    
                    return (angle < 0 ? angle + 360 : angle);
                    
                }
                return 0;
            }

            function rotateBox(deg) {
                $(box).css('transform', 'translate(-50%, -50%) rotate(' + deg + 'deg)');      // <=
                //console.log('box : '+$(box).attr("data-id")+' angle : '+(deg < 0 ? deg + 360 : deg));
            }

            function dragSupport(event) {
                if ($(event.target).hasClass(settings.handlerClass)) {
                    return;
                }

                initX = box.offsetLeft;         // <=
                initY = box.offsetTop;          // <=
                mousePressX = event.clientX;
                mousePressY = event.clientY;
                 
                function eventMoveHandler(event) {
                    
                      if (!settings.raf) {
 
                        x=initX + (event.clientX - mousePressX);
                        y=initY + (event.clientY - mousePressY);
                        let functionWithZeroParams = () => {
                            repositionElement(x,y)
                        }


                        settings.raf = requestAnimationFrame(functionWithZeroParams);
                      }
                    //console.log(event.clientX+"-"+event.clientY);

                   // repositionElement(initX + (event.clientX - mousePressX), initY + (event.clientY - mousePressY));
                }
                 
                box.addEventListener('pointermove', eventMoveHandler, { passive: true });         // <=
                
                
                ["pointerup", "pointercancel"].forEach((event) => {
                window.addEventListener('pointerup', function eventEndHandler() {
                    
                      if (settings.raf) {
                        cancelAnimationFrame(settings.raf);
                        settings.raf = null;
                      };
  
                    showObjectState()
                    box.removeEventListener('pointermove', eventMoveHandler);  // <=
                    window.removeEventListener('pointerup', eventEndHandler);
                },  { passive: true });
                })
                
                
            }
            function showObjectState() {
                
                var gcss ='transform :translate(-50%, -50%) rotate('+getRotation(box)+'deg); left : '+$(box).css('left')+' ;top : '+$(box).css('top')+' ;width : '+$(box).css('width')+' ;height : '+$(box).css('height')+';';
                console.log(gcss) 
                if($(box).attr("data-id")!="popup") {
                $('#selectedboxid').val($(box).attr("data-id"));
                $(".box").css("border", "black dashed 10px");
                $("#popup").css("border", "solid red 10px");
                
                $(box).css("border", "red dashed 10px");

                 $.post( "manage.php", { action:'location', boxid: $(box).attr("data-id"), projectid:1, css:gcss  })
                  .done(function( data ) {
                     
                  });
                 
                }

            }
            function resizeHandler(event, left, top, xResize, yResize) {
                initX = box.offsetLeft;         // <=
                initY = box.offsetTop;          // <=
                mousePressX = event.clientX;
                mousePressY = event.clientY;

                initW = box.offsetWidth;
                initH = box.offsetHeight;

                initRotate = getRotation(box);      // <=

                const initRadians = initRotate * Math.PI / 180;
                const cosFraction = Math.cos(initRadians);
                const sinFraction = Math.sin(initRadians);

                function eventMoveHandler(event) {
                    const wDiff = (event.clientX - mousePressX);
                    const hDiff = (event.clientY - mousePressY);
                    let rotatedWDiff = cosFraction * wDiff + sinFraction * hDiff;
                    let rotatedHDiff = cosFraction * hDiff - sinFraction * wDiff;

                    let newW = initW, newH = initH, newX = initX, newY = initY;

                    if (xResize) {
                        if (left) {
                            newW = initW - rotatedWDiff;
                            if (newW < settings.minWidth) {
                                newW = settings.minWidth;
                                rotatedWDiff = initW - settings.minWidth;
                            }
                        } else {
                            newW = initW + rotatedWDiff;
                            if (newW < settings.minWidth) {
                                newW = settings.minWidth;
                                rotatedWDiff = settings.minWidth - initW;
                            }
                        }
                        newX += 0.5 * rotatedWDiff * cosFraction;
                        newY += 0.5 * rotatedWDiff * sinFraction;
                    }

                    if (yResize) {
                        if (top) {
                            newH = initH - rotatedHDiff;
                            if (newH < settings.minHeight) {
                                newH = settings.minHeight;
                                rotatedHDiff = initH - settings.minHeight;
                            }
                        } else {
                            newH = initH + rotatedHDiff;
                            if (newH < settings.minHeight) {
                                newH = settings.minHeight;
                                rotatedHDiff = settings.minHeight - initH;
                            }
                        }
                        newX -= 0.5 * rotatedHDiff * sinFraction;
                        newY += 0.5 * rotatedHDiff * cosFraction;
                    }

                    resize(newW, newH);
                    
                    
                    repositionElement(newX, newY);
                }

                // window addEventListener
                window.addEventListener('mousemove', eventMoveHandler,  { passive: true });
                window.addEventListener('mouseup', function eventEndHandler() {
                    showObjectState()
                    window.removeEventListener('mousemove', eventMoveHandler, false);
                    window.removeEventListener('mouseup', eventEndHandler);
                }, false);
            }

            function rotate(event) {
                 
                initX = box.offsetLeft;             // <=
                initY = box.offsetTop;              // <=
                mousePressX = event.clientX;
                mousePressY = event.clientY;

                const arrowRects = box.getBoundingClientRect();
                const arrowX = arrowRects.left + arrowRects.width / 2;
                const arrowY = arrowRects.top + arrowRects.height / 2;

                function eventMoveHandler(event) {
                    const angle = Math.atan2(event.clientY - arrowY, event.clientX - arrowX) + Math.PI / 2;
                    rotateBox(angle * 180 / Math.PI);
                }

                window.addEventListener('mousemove', eventMoveHandler, false);
                window.addEventListener('mouseup', function eventEndHandler() {
                    showObjectState()
                    window.removeEventListener('mousemove', eventMoveHandler, false);
                    window.removeEventListener('mouseup', eventEndHandler);
                }, false);
            }

            function editingStyle(event) {
                console.dir(event);
                $('.' + settings.handlerClass).hide();
                $(box).css('z-index', getComputedStyle(document.body).getPropertyValue('--zi-' + $(box).data('id')) );      // <= <=

                if ($(event.target).hasClass(settings.boxSelector)) {
                    $(event.target).find('.' + settings.handlerClass).show();
                    $(event.target).css('z-index', '1000');         // <=
                } else if ($(event.target).hasClass(settings.handlerClass)) {
                    $(event.target).show();
                    $(event.target).siblings('.' + settings.handlerClass).show();
                    $(event.target).parents('.' + settings.boxSelector).css('z-index', '1000');         // <=
                }

                if (!settings.resize) {
                    $($(event.target).parents().find('.' + settings.handlerClass + '.resize').hide());
                }
                if (!settings.rotate) {
                    $($(event.target).parents().find('.' + settings.handlerClass + '.rotate').hide());
                }
$("#popup").css("z-index", "99999");
$(".ck").css("z-index", "99999");
            }
            
            function popup(event) {
                 $("#popup").show();
                $("#popup").css("left", ((parseInt($(box).css('left'))-parseInt($(box).css('width')))-14)+'px');
                $("#popup").css("top", $(box).css('top'));
                $("#popup").css("z-index", "99999");
                
                
                
            }

                //box.addEventListener('dblclick', function (event) { if(event.target.role!="textbox") {return popup(event);} }, false); 
                
            // listeners
            if (settings.move) {
                
                 
                box.addEventListener('mousedown', function (event) { if(event.target.role!="textbox") { return dragSupport(event);} }, false);
                
                
            }

            if (settings.resize) {
                hLeftTop.mousedown(function (event) { return resizeHandler(event, true, true, true, true); });
                hLeftMid.mousedown(function (event) { return resizeHandler(event, true, false, true, false); });
                hLeftBot.mousedown(function (event) { return resizeHandler(event, true, false, true, true); });
                hCenterTop.mousedown(function (event) { return resizeHandler(event, false, true, false, true); });
                hCenterBot.mousedown(function (event) { return resizeHandler(event, false, false, false, true); });
                hRightTop.mousedown(function (event) { return resizeHandler(event, false, true, true, true); });
                hRightMid.mousedown(function (event) { return resizeHandler(event, false, false, true, false); });
                hRightBot.mousedown(function (event) { return resizeHandler(event, false, false, true, true); });
            }

            if (settings.rotate) {
                
                hRotate.get(0).addEventListener('mousedown', function (event) {  return rotate(event); }, false);
                
            }

            $(document).mousedown(function (event) { return editingStyle(event); });
            
            
        


        });

    };
}(jQuery));

index.html

 

<!DOCTYPE html>
<html lang="">
    <head>
 
<script src="https://code.jquery.com/jquery-3.6.0.js"></script>
<script src="https://code.jquery.com/ui/1.13.2/jquery-ui.js"></script>
        <style>
        
        
@font-face {
  font-family: 'Virgil';
  src:  url('Virgil.woff2') format('woff2'),
         
}
body {
  font-family: 'Virgil', Fallback, sans-serif;
}
         
.lead { font-size: 1.5rem; font-weight: 300; }
.container { margin: 150px auto; max-width: 960px; }
 body { background: #fafafa; }
 .box {
         position: absolute;
         user-select: none;
         transform: translate(-50%, -50%);
     will-change: transform, left, top;
         contain: layout;
      }

            .resize-handler {
                height: 10px;
                width: 10px;
                background-color: #0055ff;
                position: absolute;
                border-radius: 100px;
                border: 1px solid #ffffff;
                user-select: none;
                display: none;
            }
            .resize-handler:hover {background-color: #0000cc;}
            .resize-handler.rotate {cursor: url('https://findicons.com/files/icons/1620/crystal_project/16/rotate_ccw.png'), auto;}

            :root {
                /* id-1 */
                --left-1: 200px;
                --top-1: 480px;
                --width-1: 200px;
                --height-1: 200px;
                --bg-1: #ffff00cc;
                --zi-1: 1;

                /* id-2 */
                --left-2: 500px;
                --top-2: 480px;
                --width-2: 300px;
                --height-2: 200px;
                --bg-2: #0050ffcc;
                --zi-2: 2;
            }
            
            #popup {
                 
             
                background:white;
                 
            }
             
        </style>
    </head>
    <body id="body"> 
    
    
 

        <div class="container" >

        

<div id="boxarea">
        
<div class="box"  id="popup" data-id="popup" style="position:absolute;left: 50px; top: 40px; z-index:99999; width:700px; height:850px; border:10px solid red">
        
        
         
    <div onmousedown="this.parentNode.setAttribute('draggable', false);">Drag me! :)</div>
  
 
</div>

</div>
 
    
        <script type="text/javascript">
         
    function getUniqId() {
      const dateString = Date.now().toString(36);
      const randomness = Math.random().toString(36).substr(2);
      return dateString + randomness;
      
    }
    
    var mouseX, mouseY;
    $(document).mousemove(function(e) {
        mouseX = e.pageX;
        mouseY = e.pageY;
    }).mouseover(); // call the handler immediately

     
     
     
     
     
     
     
     
     
     
    function createBox(name,css) {
        
     
    if(css=="") { css= 'left: '+mouseX+'px; top: '+mouseY+'px; z-index: var(--zi-2); width: var(--width-2); height: var(--height-2); border:10px dashed black'; }
    
    if(name=="pop") { 
        uid='popup';
        var obj =document.getElementById("popup") ;
        obj.style.cssText = 'left: 550px; top: 450px; z-index:99999; width:700px; height:850px; border:10px solid red';
    }else {
        
        if(name!="pop"&& name=="") { var uid= getUniqId();} else { uid=name; }
        
        
        var obj = document.createElement('div');
        obj.class = "box";
        obj.setAttribute('class' , "box"); 
        obj.setAttribute('id' , uid); 
        obj.setAttribute('data-id' , uid); 
        document.getElementById("body").appendChild(obj);
        obj.style.cssText = css;
    }

        $(obj).boxModeling({
            rotate: true,
            resize: true,
            move: true,
        });
    }

// A $( document ).ready() block.
$( document ).ready(function() {
      
    createBox('pop','');
    createBox('','');
    

});
    
     
    </script>
    

    </body>
    <script src="box-modeling.js"></script>

 
  

 
</html>

但我认为我在 JS 方面不够好,因为没有任何效果,所以最后的希望在这里!

谢谢

javascript jquery drag-and-drop draggable drag
1个回答
0
投票

关于初始脚本的一些解释:

如果你看一下

editingStyle
函数,你会发现它首先用这行代码重置所有框
z-index

$(box).css('z-index',
 getComputedStyle(document.body).getPropertyValue('--zi-'+ $(box).data('id'))
);

然后,之后的几行将

z-index: 10000
应用于当前抓取的框。

简而言之,这将始终使抓取的盒子位于所有其他盒子的顶部。


你的代码有什么问题:

所以,代码中的不同之处在于,您在这一行中手动应用了

z-index
99999

$("#popup").css("z-index", "99999");

这会导致其他被抓取的盒子掉到它下面并完全失去

mousemove
事件。

底线:

问题根本不在于性能,而在于哪个盒子在其他盒子之上。

注意:尽量保持你的代码尽可能干净和小,通常简单的代码可以获得更好的性能:)

© www.soinside.com 2019 - 2024. All rights reserved.