接上篇,上篇写了大致的思路,其实还有很多问题,由于没写测试,在运行时出现了很多问题,比如绘制相关代码,会一直添加元素到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放在同一目录下,双击浏览器打开即可运行。运行效果如下