div拖拽缩放jquery插件编写——带8个控制点

项目中需要对div进行拖拽缩放,需要有控制面板8个控制点的那种,原以为这么常见的效果应该能搜索到很多相关插件,然而可以完成拖拽的实繁,却找不到我想要的,还是自己动手丰衣足食吧
效果预览(只支持pc端)

思路

一、舞台拖拽项定义

拖拽以及缩放需要有一个范围,姑且管这个叫舞台(stage)。另外,在舞台范围内,如何以一种简单的方式定义拖拽项?可以通过给div增加一个拖拽class(例如:resize-item),拖拽项应该是absolute布局,舞台是relative/absolute布局

所以拖拽类需要有如下两个参数

    /**
     * 默认参数
     */
    var defaultOpts = {
        stage: document, //舞台,默认为stage
        itemClass: 'resize-item', //可缩放的类名
    };

    /**
     * 定义类
     */
    var ZResize = function(options) {
        this.options = $.extend({}, defaultOpts, options);
        this.init();
    }

二、生成控制面板

 
控制面板
  1. 面板:为了尽可能少的影响到拖拽项,就不直接在拖拽项上生成控制点,而是为拖拽项增加一个半透明层作为控制面板,控制面板尺寸位置和拖拽项一致,将控制面板插入拖拽项(由于都是absolute布局,不影响原内容),可以更好的控制位置和一一对应
    var width = $(this).width();
    var height = $(this).height();
    var resizePanel = $('<div class"resize-panel"></div>');
    resizePanel.css({
         width,
        height: height,
        top: 0,
        left: 0,
        position: 'absolute',
        'background-color': 'rgba(0,0,0,0.5)',
        cursor: 'move',
        display: 'none'
    });
    self.appendHandler(resizePanel, $(this));
  1. 控制点:为控制面板增加东、南、西、北、东北、西北、西南、东南控制点,为每个控制点设置对应的cursor
    'cursor': 'n-resize' //北
    'cursor': 's-resize' //南
    'cursor': 'e-resize' //东
    'cursor': 'w-resize' //西
    'cursor': 'ne-resize' //东北
    'cursor': 'nw-resize' //西北
    'cursor': 'se-resize' //东南
    'cursor': 'sw-resize' //西南

三、缩放

  1. 每个控制点影响的属性不一样
    北(上):
        高度(height) 
        位置y(拖拽上边,应该保持下边固定,所以高度变化之后位置也要变化)
    南(下):
        高度(height)
    东(右):
        宽度(width)
    西(左):
        宽度(width)
        位置x(拖拽左边,应该保持右边固定,所以宽度变化之后位置也要变化)

    东北、西北、东南、西南  以上两两结合
  1. 监听控制点mousedown,分别定义一个标志,并且记录下原始位置,如:
    //西
    var wmove = false;
    el.on('mousedown','.w', function(e) {
        ox = e.pageX;//原始x位置
        ow = el.width();
        oleft = parseInt(org.css('left').replace('px', ''));
        wmove = true;
    });
  1. 监听控制面板的mousedown,同样定义一个标志,用于拖动(drag)
  2. 监听舞台(stage)的mousemove(注意这里不是监听控制点的mousemove,因为控制点实在是太小,无法灵敏的拖动),判断各个控制点以及控制面板mousedown的标志分别对宽高和位置进行处理。处理的逻辑为:touchmove过程中的e.pageX/e.pageY - ox/oy(原始) = 偏移量,对于第一点中提到的每个控制点影响的属性,根据偏移量进行变化
 
监听
  1. 监听舞台(stage)的mouseup事件(这里同样不能是控制点的mouseup),把所有的mousedown标志重置为false

pc端的mouse事件不同于手机端的touch事件,touchstart->touchmove->touchend触发有顺序性,mouse事件没有顺序性,未触发mousedown也能触发mousemove,所以需要设置标志来判断

四、控制面板的出现隐藏

控制面板初始化的时候,应该是隐藏的,只有点击对应的拖拽项的时候才出现,并且点击舞台空白部分,需要隐藏控制面板(组织事件冒泡)

    /**
     +  点击item显示拖拽面板
     */
    bindTrigger: function(el) {
        var self = this;
        el.on('click', function(e) {
            //组织事件冒泡,不然会被舞台触发,舞台触发会把控制面板隐藏掉
            e.stopPropagation();
            self.triggerResize(el);
        });
    },
    /**
     +  点击舞台空闲区域 隐藏缩放面板
     */
    bindHidePanel: function(el) {
        var stage = this.options.stage;
        var itemClass = this.options.itemClass;
        $(stage).bind('click', function() {
            $('.' + itemClass).children('div').css({
                display: 'none'
            });
        })
    }
备注:
相应的HTML内容:
<!doctype html>
<html>

<head>
    <meta charset="utf-8">
    <title>jQuery拖拽放大缩小插件idrag</title>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <style type="text/css">
    .item1 {
         405px;
        height: 291px;
        cursor: move;
        position: absolute;
        top: 30px;
        left: 30px;
        background-color: #FFF;
        border: 1px solid #CCCCCC;
        -webkit-box-shadow: 10px 10px 25px #ccc;
        -moz-box-shadow: 10px 10px 25px #ccc;
        box-shadow: 10px 10px 25px #ccc;
    }
    
    .item2 {
         200px;
        height: 100px;
        cursor: move;
        position: absolute;
        top: 400px;
        left: 100px;
        background-color: #FFF;
        border: 1px solid #CCCCCC;
        -webkit-box-shadow: 10px 10px 25px #ccc;
        -moz-box-shadow: 10px 10px 25px #ccc;
        box-shadow: 10px 10px 25px #ccc;
        line-height: 100px;
        text-align: center;
    }
    
    body {
        background-color: #F3F3F3;
    }
    </style>
</head>

<body>
    <div class="resize-item item1">
        <img src="images/dog.png" width="100%" height="100%">
    </div>

    <div class="resize-item item2">
        你是我的小小狗
    </div>
    <script src="js/jquery.min.js"></script>
    <script type="text/javascript" src='js/jquery.ZResize.js'></script>
    <script type="text/javascript">
        new ZResize();
    </script>
</body>

</html>

  相应的js插件jquery.ZResize.js为:

(function($) {

    /**
     * 默认参数
     */
    var defaultOpts = {
        stage: document, //舞台
        itemClass: 'resize-item', //可缩放的类名
    };

    /**
     * 定义类
     */
    var ZResize = function(options) {
        this.options = $.extend({}, defaultOpts, options);
        this.init();
    }

    ZResize.prototype = {
        init: function() {
            this.initResizeBox();
        },
        /**
         *  初始化拖拽item
         */
        initResizeBox: function() {
            var self = this;
            $('.' + self.options.itemClass).each(function() {
                //创建面板
                var width = $(this).width();
                var height = $(this).height();
                var resizePanel = $('<div class"resize-panel"></div>');
                resizePanel.css({
                     width,
                    height: height,
                    top: 0,
                    left: 0,
                    position: 'absolute',
                    'background-color': 'rgba(0,0,0,0.5)',
                    cursor: 'move',
                    display: 'none'
                });
                self.appendHandler(resizePanel, $(this));
                /**
                 * 创建控制点
                 */
                var n = $('<div class="n"></div>');//北
                var s = $('<div class="s"></div>');//南
                var w = $('<div class="w"></div>');//西
                var e = $('<div class="e"></div>');//东
                var ne = $('<div class="ne"></div>');//东北
                var nw = $('<div class="nw"></div>');//西北
                var se = $('<div class="se"></div>');//东南
                var sw = $('<div class="sw"></div>');//西南

                //添加公共样式
                self.addHandlerCss([n, s, w, e, ne, nw, se, sw]);
                //添加各自样式
                n.css({
                    'top': '-4px',
                    'margin-left': '-4px',
                    'left': '50%',
                    'cursor': 'n-resize'
                });
                s.css({
                    'bottom': '-4px',
                    'margin-left': '-4px',
                    'left': '50%',
                    'cursor': 's-resize'
                });
                e.css({
                    'top': '50%',
                    'margin-top': '-4px',
                    'right': '-4px',
                    'cursor': 'e-resize'
                });
                w.css({
                    'top': '50%',
                    'margin-top': '-4px',
                    'left': '-4px',
                    'cursor': 'w-resize'
                });
                ne.css({
                    'top': '-4px',
                    'right': '-4px',
                    'cursor': 'ne-resize'
                });
                nw.css({
                    top: '-4px',
                    'left': '-4px',
                    'cursor': 'nw-resize'
                });
                se.css({
                    'bottom': '-4px',
                    'right': '-4px',
                    'cursor': 'se-resize'
                });
                sw.css({
                    'bottom': '-4px',
                    'left': '-4px',
                    'cursor': 'sw-resize'
                });

                // 添加项目
                self.appendHandler([n, s, w, e, ne, nw, se, sw], resizePanel);
                
                //绑定拖拽缩放事件
                self.bindResizeEvent(resizePanel, $(this));

                //绑定触发事件
                self.bindTrigger($(this));
            });
            self.bindHidePanel();
        },
        //控制点公共样式
        addHandlerCss: function(els) {
            for(var i = 0; i < els.length; i++) {
                el = els[i];
                el.css({
                    position: 'absolute',
                     '8px',
                    height: '8px',
                    background: '#ff6600',
                    margin: '0',
                    'border-radius': '2px',
                    border: '1px solid #dd5500',
                });
            }
        },
        /**
         *  插入容器
         */
        appendHandler: function(handlers, target) {
            for(var i = 0; i < handlers.length; i++) {
                el = handlers[i];
                target.append(el);
            }
        },
        /**
         *  显示拖拽面板
         */
        triggerResize: function(el) {
            var self = this;
            el.siblings('.' + self.options.itemClass).children('div').css({
                display: 'none'
            });
            el.children('div').css({
                display: 'block'
            });
        },
        /**
         * 拖拽事件控制 包含8个缩放点  和一个拖拽位置
         */
        bindResizeEvent: function(el) {

            var self = this;
            var ox = 0; //原始事件x位置
            var oy = 0; //原始事件y位置
            var ow = 0; //原始宽度
            var oh = 0; //原始高度

            var oleft = 0; //原始元素位置
            var otop = 0;
            var org = el.parent('div');

            //东
            var emove = false;
            el.on('mousedown','.e', function(e) {
                ox = e.pageX;//原始x位置
                ow = el.width();
                emove = true;
            });

            //南
            var smove = false;
            el.on('mousedown','.s', function(e) {
                oy = e.pageY;//原始x位置
                oh = el.height();
                smove = true;
            });

            //西
            var wmove = false;
            el.on('mousedown','.w', function(e) {
                ox = e.pageX;//原始x位置
                ow = el.width();
                wmove = true;
                oleft = parseInt(org.css('left').replace('px', ''));
            });

            //北
            var nmove = false;
            el.on('mousedown','.n', function(e) {
                oy = e.pageY;//原始x位置
                oh = el.height();
                nmove = true;
                otop = parseInt(org.css('top').replace('px', ''));
            });

            //东北
            var nemove = false;
            el.on('mousedown','.ne', function(e) {
                ox = e.pageX;//原始x位置
                oy = e.pageY;
                ow = el.width();
                oh = el.height();
                nemove = true;
                otop = parseInt(org.css('top').replace('px', ''));
            });

            //西北
            var nwmove = false;
            el.on('mousedown','.nw', function(e) {
                ox = e.pageX;//原始x位置
                oy = e.pageY;
                ow = el.width();
                oh = el.height();
                otop = parseInt(org.css('top').replace('px', ''));
                oleft = parseInt(org.css('left').replace('px', ''));
                nwmove = true;
            });

            //东南
            var semove = false;
            el.on('mousedown','.se', function(e) {
                ox = e.pageX;//原始x位置
                oy = e.pageY;
                ow = el.width();
                oh = el.height();
                semove = true;
            });

            //西南
            var swmove = false;
            el.on('mousedown','.sw', function(e) {
                ox = e.pageX;//原始x位置
                oy = e.pageY;
                ow = el.width();
                oh = el.height();
                swmove = true;
                oleft = parseInt(org.css('left').replace('px', ''));
            });

            //拖拽
            var drag = false;
            el.on('mousedown', function(e) {
                ox = e.pageX;//原始x位置
                oy = e.pageY;
                otop = parseInt(org.css('top').replace('px', ''));
                oleft = parseInt(org.css('left').replace('px', ''));
                drag = true;
            });

            $(self.options.stage).on('mousemove', function(e) {
                if(emove) {
                    var x = (e.pageX - ox);
                    el.css({
                         ow + x
                    });
                    org.css({
                         ow + x
                    });
                } else if(smove) {
                    var y = (e.pageY - oy);
                    el.css({
                        height: oh + y
                    });
                    org.css({
                        height: oh + y
                    });
                } else if(wmove) {
                    var x = (e.pageX - ox);
                    el.css({
                         ow - x,
                        // left: oleft + x
                    });
                    org.css({
                         ow - x,
                        left: oleft + x
                    });
                } else if(nmove) {
                    var y = (e.pageY - oy);
                    el.css({
                        height: oh - y,
                        // top: otop + y
                    });
                    org.css({
                        height: oh - y,
                        top: otop + y
                    });
                } else if(nemove) {
                    var x = e.pageX - ox;
                    var y = e.pageY - oy;
                    el.css({
                        height: oh - y,
                        // top: otop + y,
                         ow + x
                    });
                    org.css({
                        height: oh - y,
                        top: otop + y,
                         ow + x
                    });
                } else if(nwmove) {
                    var x = e.pageX - ox;
                    var y = e.pageY - oy;
                    el.css({
                        height: oh - y,
                        // top: otop + y,
                         ow - x,
                        // left: oleft + x
                    });
                    org.css({
                        height: oh - y,
                        top: otop + y,
                         ow - x,
                        left: oleft + x
                    });
                } else if(semove) {
                    var x = e.pageX - ox;
                    var y = e.pageY - oy;
                    el.css({
                         ow + x,
                        height: oh + y
                    });
                    org.css({
                         ow + x,
                        height: oh + y
                    });
                } else if(swmove) {
                    var x = e.pageX - ox;
                    var y = e.pageY - oy;
                    el.css({
                         ow - x,
                        // left: oleft + x,
                        height: oh + y
                    });
                    org.css({
                         ow - x,
                        left: oleft + x,
                        height: oh + y
                    });
                } else if(drag) {
                    var x = e.pageX - ox;
                    var y = e.pageY - oy;
                    org.css({
                        left: oleft + x,
                        top: otop + y
                    });
                }
            }).on('mouseup', function(e) {
               emove = false;
               smove = false;
               wmove = false;
               nmove = false;
               nemove = false;
               nwmove = false;
               swmove = false;
               semove = false;
               drag = false;
            });
        },
        /**
         *  点击item显示拖拽面板
         */
        bindTrigger: function(el) {
            var self = this;
            el.on('click', function(e) {
                e.stopPropagation();
                self.triggerResize(el);
            });
        },
        /**
         *  点击舞台空闲区域 隐藏缩放面板
         */
        bindHidePanel: function(el) {
            var stage = this.options.stage;
            var itemClass = this.options.itemClass;
            $(stage).bind('click', function() {
                $('.' + itemClass).children('div').css({
                    display: 'none'
                });
            })
        }
    }

    window.ZResize = ZResize;

})(jQuery);

  


源码链接:https://github.com/zengwenfu/z-resize
作者:小虫巨蟹
链接:https://www.jianshu.com/p/822afede7489
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
原文地址:https://www.cnblogs.com/sweeeper/p/9035717.html