鼠标框选 下篇

接上篇,上篇写了大致的思路,其实还有很多问题,由于没写测试,在运行时出现了很多问题,比如绘制相关代码,会一直添加元素到dom,这主要因为我在考虑元素绘制和插入dom没有分开处理,本次主要增加了计算和绘制的代码逻辑,逻辑中有些代码还是需要优化的,比如dom访问次数过多,绘制过程做节流处理等,有需要各位自行优化即可,为了操作方便,直接封装成了jQuery插件。

完整代码如下,解释可直接看注释部分:

  1 ; (function ($) {
  2 
  3     $.fn.frameSelection = function (options) {
  4         var defaultOpts = {
  5             callback: function () { },
  6             mask: false,
  7             done: function (result) { console.log(result) }
  8         };
  9         var options = $.extend({}, defaultOpts, options);
 10         new FrameSelection($(this), options);
 11     }
 12     /**
 13      * 坐标点
 14      * @param {*} x 
 15      * @param {*} y 
 16      */
 17     function Point(x, y) {
 18         this.x = x;
 19         this.y = y;
 20     }
 21     /**
 22      * 框选构造函数
 23      * @param {*} $rangeEl 容器元素
 24      * @param {*} options 选择项
 25      */
 26     function FrameSelection($rangeEl, options) {
 27         this.$rangeEl = $rangeEl;
 28         this.options = options;
 29 
 30         this.init();
 31     }
 32     /**
 33      * 框选初始化
 34      */
 35     FrameSelection.prototype.init = function () {
 36         this.unbind();
 37         this.bind();
 38     }
 39     /**
 40      * 解除事件绑定
 41      */
 42     FrameSelection.prototype.unbind = function () {
 43 
 44         this.$rangeEl.off('mousedown');
 45         this.$rangeEl.off('mousemove');
 46         this.$rangeEl.off('mouseup');
 47     }
 48     /**
 49      * 绘制接口
 50      */
 51     FrameSelection.prototype.render = function (p1, p2) {
 52         this.options.mask && this.renderMask(p1, p2);
 53         this.renderRect(p1, p2);
 54     }
 55     /**
 56      * 清理元素
 57      */
 58     FrameSelection.prototype.clear = function () {
 59         this.$rangeEl.find('.rect,.mask').remove();
 60     }
 61 
 62     /**
 63      * 创建遮罩层
 64      */
 65     FrameSelection.prototype.renderMask = function (p1, p2) {
 66         var $rect = this.$rangeEl.find('div.rect');
 67         var $top = this.$rangeEl.find('div.mask:eq(0)'),
 68             $left = this.$rangeEl.find('div.mask:eq(1)'),
 69             $right = this.$rangeEl.find('div.mask:eq(2)'),
 70             $bottom = this.$rangeEl.find('div.mask:eq(3)');
 71 
 72         $top.css({
 73             top: this.$rangeEl.css('top'),
 74             left: this.$rangeEl.css('left'),
 75              this.$rangeEl.width(),
 76             height: $rect.css('top')
 77         });
 78 
 79         $left.css({
 80             top: $rect.css('top'),
 81             left: $top.css('left'),
 82              $rect.css('left'),
 83             height: $rect.height()
 84         });
 85 
 86         $right.css({
 87             top: $rect.css('top'),
 88             left: $left.width() + $rect.width(),
 89              this.$rangeEl.width() - ($left.width() + $rect.width()),
 90             height: $left.height()
 91         });
 92 
 93         $bottom.css({
 94             top: $top.height() + $left.height(),
 95             left: this.$rangeEl.css('left'),
 96              $top.width(),
 97             height: this.$rangeEl.height() - ($top.height() + $left.height())
 98         });
 99 
100     }
101     /**
102      * 创建矩形选框
103      */
104     FrameSelection.prototype.renderRect = function (p1, p2) {
105         var $rect = this.$rangeEl.find('div.rect');
106 
107         $rect.css({
108             top: Math.min(p1.y, p2.y),
109             left: Math.min(p1.x, p2.x),
110              Math.abs(p1.x - p2.x),
111             height: Math.abs(p1.y - p2.y)
112         })
113 
114     }
115     /**
116      * 创建元素
117      */
118     FrameSelection.prototype.create = function (eleDes, n, callback) {
119         var desArr = eleDes.split('.');
120         var eleName = desArr[0], className = desArr[1] || '', eles = '';
121 
122         for (var i = 0; i < n; i++) {
123             eles += `<${eleName} class="${className}"></${eleName}>`;
124         }
125 
126         callback && typeof callback === "function" && callback($(eles));
127 
128     }
129     FrameSelection.prototype.createElToDom = function () {
130         //默认不绘制mask
131         var fn = ($eles) => {
132             $eles.appendTo(this.$rangeEl);
133         }
134         this.options.mask && this.create('div.mask', 4, fn);
135         this.create('div.rect', 1, fn);
136 
137         typeof this.options.callback === 'function' && this.options.callback();
138     }
139     /**
140      * 注册事件绑定
141      */
142     FrameSelection.prototype.bind = function () {
143         var self = this;
144         this.$rangeEl.bind('mousedown', function (event) {
145             var start = new Point(event.pageX, event.pageY);
146             //清理
147             self.clear();
148             self.createElToDom();
149 
150             self.$rangeEl.bind('mousemove', function (e) {
151                 var end = new Point(e.pageX, e.pageY);
152                 //绘制
153                 self.render(start, end);
154 
155             })
156         });
157 
158         this.$rangeEl.bind('mouseup', function (e) {
159             self.$rangeEl.off('mousemove');
160         })
161     }
162 })(window.jQuery);

直接在html中测试打开即可,css代码未独立处理,直接写入了html文件中,具体代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>frame_selection</title>
    <script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.js"></script>
    <script src="./frame_selection.js"></script>
    <script>
        $(document).ready(function(){
            $('.container').frameSelection({
                mask:true,
                callback:function(){
                    console.log('rendering!!!');
                },
                done:function(result){
                    console.log('rendering done',result);
                }
            }) ;
        })
    </script>
    <style>
        .container{
            width:600px;
            height: 400px;
            left:0;
            top:0;
        }
        .mask,
        .rect {
            position: absolute;
        }

        .mask {
            background-color: #000;
            opacity: 0.2;
        }

        .rect {
            background-color: #fff;
            opacity: 0.1;
            border:1px dashed #000;
        }
    </style>
</head>

<body>
    <div class="container">

    </div>
</body>

</html>
View Code

直接保存js代码到frame_selection.js文件,和index.html放在同一目录下,双击浏览器打开即可运行。运行效果如下

原文地址:https://www.cnblogs.com/Johnzhang/p/7191487.html