UNPKG

7.08 kBPlain TextView Raw
1<template>
2 <!-- author: Betsey(冰晶)
3 可形变区域组件:
4 inspiredby:https://github.com/PUGE/deformation, thank you with love
5 可设定该区域resize的方向,上下左右及四角
6 目前拉伸仅可以改变宽度和高度
7 todo(可优化):
8 1. 针对绝对定位,调整top和left的值实现绝对的resize,但是注意,此时需要监测绝对定位是什么方向的定位,根据方向进行调整,留到有需求的时候完成;
9-->
10
11 <div class="c-deformableBox" :style="style" ref="content">
12 <!-- 不可见的控制区域 -->
13 <template v-if="resizable">
14 <div
15 class="ctrl ctrl-v ctrl-t"
16 v-if="canResizeDirection('top')"
17 @mousedown.stop.left.prevent="handleResizeStart(['t'])"
18 ></div>
19 <div
20 class="ctrl ctrl-h ctrl-r"
21 v-if="canResizeDirection('right')"
22 @mousedown.stop.left.prevent="handleResizeStart(['r'])"
23 ></div>
24 <div
25 class="ctrl ctrl-v ctrl-b"
26 v-if="canResizeDirection('bottom')"
27 @mousedown.stop.left.prevent="handleResizeStart(['b'])"
28 ></div>
29 <div
30 class="ctrl ctrl-h ctrl-l"
31 v-if="canResizeDirection('left')"
32 @mousedown.stop.left.prevent="handleResizeStart(['l'])"
33 ></div>
34 <div
35 class="ctrl ctrl-c ctrl-t ctrl-r"
36 v-if="canResizeDirection('top') && canResizeDirection('right')"
37 @mousedown.stop.left.prevent="handleResizeStart(['t', 'r'])"
38 ></div>
39 <div
40 class="ctrl ctrl-c ctrl-t ctrl-l"
41 v-if="canResizeDirection('top') && canResizeDirection('left')"
42 @mousedown.stop.left.prevent="handleResizeStart(['t', 'l'])"
43 ></div>
44 <div
45 class="ctrl ctrl-c ctrl-b ctrl-r"
46 v-if="canResizeDirection('bottom') && canResizeDirection('right')"
47 @mousedown.stop.left.prevent="handleResizeStart(['b', 'r'])"
48 ></div>
49 <div
50 class="ctrl ctrl-c ctrl-b ctrl-l"
51 v-if="canResizeDirection('left') && canResizeDirection('right')"
52 @mousedown.stop.left.prevent="handleResizeStart(['b', 'l'])"
53 ></div>
54 </template>
55 <slot></slot>
56 </div>
57</template>
58<script>
59export default {
60 name: 'deformable-box',
61 data() {
62 return {
63 w: undefined,
64 h: undefined,
65 resizeDirections: [],
66 resizing: false
67 };
68 },
69 props: {
70 // 区域是否可以拖动,拖动方向, 默认可以拖动
71 resizable: {
72 // 要求是一个布尔值或者一个指定值的数组
73 validator(val) {
74 if (typeof val === 'boolean') return val;
75 return Array.isArray(val) && // eslint-disable-line
76 val.every(each => ['top', 'left', 'right', 'bottom'].indexOf(each) > -1); // eslint-disable-line
77 },
78 default: true
79 },
80 // 初始宽度
81 initWidth: Number,
82 // 初始高度
83 initHeight: Number,
84 // 高度及宽度限制
85 maxHeight: Number,
86 minHeight: Number,
87 maxWidth: Number,
88 minWidth: Number
89 },
90 mounted() {
91 this.init();
92 },
93 computed: {
94 style() {
95 if (this.w === 0 && this.h === 0) return {};
96 const result = {};
97 // 判断可以改变大小的方向,从而修改宽度或者高度
98 if (this.canResizeDirection('left') || this.canResizeDirection('right')) {
99 result.width = `${this.w}px`;
100 }
101 if (this.canResizeDirection('top') || this.canResizeDirection('bottom')) {
102 result.height = `${this.h}px`;
103 }
104 return result;
105 }
106 },
107 methods: {
108 init() {
109 this.w = this.initWidth || this.$el.clientWidth;
110 this.h = this.initHeight || this.$el.clientHeight;
111 },
112 // 判断该方向可否改变大小
113 canResizeDirection(direction) {
114 if (typeof this.resizable === 'boolean') return this.resizable;
115 return this.resizable.indexOf(direction) > -1;
116 },
117 handleResizeStart(directionArray) {
118 this.resizeDirections = directionArray;
119 this.resizing = true;
120 this.$emit('resize-start');
121 document.documentElement.addEventListener('mousemove', this.handleResize);
122 // 当鼠标抬起的时候解除监听
123 document.documentElement.addEventListener(
124 'mouseup',
125 this.handleResizeEnd,
126 { once: true }
127 );
128 document.getElementById('monitor-iframe').addEventListener('mouseover', this.handleResizeEnd); //eslint-disable-line
129 },
130 getElementLeft(el) {
131 let actualLeft = el.offsetLeft;
132 let parent = el.offsetParent;
133 while (parent !== null) {
134 actualLeft += parent.offsetLeft + parent.clientLeft;
135 parent = parent.offsetParent;
136 }
137 return actualLeft;
138 },
139 getElementTop(el) {
140 let actualTop = el.offsetTop;
141 let parent = el.offsetParent;
142 while (parent !== null) {
143 actualTop += parent.offsetTop + parent.clientTop;
144 parent = parent.offsetParent;
145 }
146 return actualTop;
147 },
148 handleResize(e) {
149 console.log('resizing');
150 if (this.resizeDirections.indexOf('r') > -1) {
151 const widthAfterMove =
152 e.pageX - this.getElementLeft(this.$refs.content);
153 this.w = Math.max(Math.min(widthAfterMove, this.maxWidth || Infinity), this.minWidth || 1); // eslint-disable-line
154 }
155 if (this.resizeDirections.indexOf('l') > -1) {
156 const widthAfterMove =
157 this.getElementLeft(this.$refs.content) + this.w - e.pageX;
158 this.w = Math.max(Math.min(widthAfterMove, this.maxWidth || Infinity), this.minWidth || 1); // eslint-disable-line
159 }
160
161 if (this.resizeDirections.indexOf('b') > -1) {
162 const heightAfterMove =
163 e.pageY - this.getElementTop(this.$refs.content);
164 this.h = Math.max(Math.min(heightAfterMove, this.maxHeight || Infinity), this.minHeight || 1); // eslint-disable-line
165 }
166 if (this.resizeDirections.indexOf('t') > -1) {
167 const heightAfterMove =
168 this.getElementTop(this.$refs.content) + this.h - e.pageY;
169 this.h = Math.max(Math.min(heightAfterMove, this.maxHeight || Infinity), this.minHeight || 1); // eslint-disable-line
170 }
171
172 this.$emit('resizing', {
173 width: this.w,
174 height: this.h
175 });
176 },
177 handleResizeEnd() {
178 this.resizeDirections = [];
179 document.documentElement.removeEventListener(
180 'mousemove',
181 this.handleResize
182 );
183 this.$emit('resize-end');
184 }
185 }
186};
187</script>
188<style lang="scss">
189.c-deformableBox {
190 position: relative;
191 & .ctrl {
192 position: absolute;
193
194 &-h {
195 width: 4px;
196 height: calc(100% + 4px);
197 top: -2px;
198 cursor: ew-resize;
199 }
200 &-v {
201 width: calc(100% + 4px);
202 height: 4px;
203 left: -2px;
204 cursor: ns-resize;
205 }
206
207 &-c {
208 width: 4px;
209 height: 4px;
210 }
211
212 &-t {
213 top: -2px;
214 }
215 &-r {
216 right: -2px;
217 }
218 &-b {
219 bottom: -2px;
220 }
221 &-l {
222 left: -2px;
223 }
224
225 &.ctrl-t.ctrl-l,
226 &.ctrl-b.ctrl-r {
227 cursor: nwse-resize;
228 }
229
230 &.ctrl-t.ctrl-r,
231 &.ctrl-b.ctrl-l {
232 cursor: nesw-resize;
233 }
234 }
235}
236</style>