接上篇,上篇写了大致的思路,其实还有很多问题,由于没写测试,在运行时出现了很多问题,比如绘制相关代码,会一直添加元素到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 width: this.$rangeEl.width(), 76 height: $rect.css(‘top‘) 77 }); 78 79 $left.css({ 80 top: $rect.css(‘top‘), 81 left: $top.css(‘left‘), 82 width: $rect.css(‘left‘), 83 height: $rect.height() 84 }); 85 86 $right.css({ 87 top: $rect.css(‘top‘), 88 left: $left.width() + $rect.width(), 89 width: 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 width: $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 width: 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>
直接保存js代码到frame_selection.js文件,和index.html放在同一目录下,双击浏览器打开即可运行。运行效果如下
原文:http://www.cnblogs.com/Johnzhang/p/7191487.html