vue-editify 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,712 @@
1
+ <template>
2
+ <Transition :name="animation ? 'editify-layer-' + animation : 'editify-layer'" @enter="handleEnter" @after-enter="handleAfterEnter" @after-leave="handleAfterLeave">
3
+ <div v-if="modelValue" class="editify-layer" :data-editify-placement="realPlacement || null" :style="{ zIndex: zIndex }">
4
+ <Triangle v-if="showTriangle" :color="border && borderColor ? borderColor : background" :background="background" :placement="triPlacement" ref="triangle" />
5
+ <div ref="wrap" class="editify-layer-wrap" :class="{ border: border }" :style="wrapStyle">
6
+ <slot></slot>
7
+ </div>
8
+ </div>
9
+ </Transition>
10
+ </template>
11
+ <script>
12
+ import { getCurrentInstance } from 'vue'
13
+ import Dap from 'dap-util'
14
+ import Triangle from './Triangle'
15
+ export default {
16
+ name: 'Layer',
17
+ emits: ['update:modelValue', 'show', 'shown', 'hidden'],
18
+ props: {
19
+ //是否显示
20
+ modelValue: {
21
+ type: Boolean,
22
+ default: false
23
+ },
24
+ //关联元素
25
+ node: {
26
+ type: [String, Node],
27
+ default: null
28
+ },
29
+ //是否显示边框
30
+ border: {
31
+ type: Boolean,
32
+ default: false
33
+ },
34
+ //边框颜色
35
+ borderColor: {
36
+ type: String,
37
+ default: null
38
+ },
39
+ //背景色
40
+ background: {
41
+ type: String,
42
+ default: null
43
+ },
44
+ //字体颜色
45
+ color: {
46
+ type: String,
47
+ default: null
48
+ },
49
+ //位置
50
+ placement: {
51
+ type: String,
52
+ default: 'bottom',
53
+ validator(value) {
54
+ return ['top', 'bottom', 'top-start', 'top-end', 'bottom-start', 'bottom-end'].includes(value)
55
+ }
56
+ },
57
+ //是否显示三角形
58
+ showTriangle: {
59
+ type: Boolean,
60
+ default: false
61
+ },
62
+ //层级
63
+ zIndex: {
64
+ type: Number,
65
+ default: 10
66
+ },
67
+ //动画
68
+ animation: {
69
+ type: String,
70
+ default: null,
71
+ validator(value) {
72
+ return ['translate', 'fade', null].includes(value)
73
+ }
74
+ },
75
+ //是否根据range对象来定位,此时不需要传入node
76
+ useRange: {
77
+ type: Boolean,
78
+ default: false
79
+ }
80
+ },
81
+ setup() {
82
+ const uid = getCurrentInstance().uid
83
+ return {
84
+ uid
85
+ }
86
+ },
87
+ data() {
88
+ return {
89
+ realPlacement: null,
90
+ //三角图标大小
91
+ triangleSize: 6
92
+ }
93
+ },
94
+ components: {
95
+ Triangle
96
+ },
97
+ computed: {
98
+ //三角形位置
99
+ triPlacement() {
100
+ if (this.realPlacement == 'bottom-start' || this.realPlacement == 'bottom' || this.realPlacement == 'bottom-end') {
101
+ return 'top'
102
+ }
103
+ if (this.realPlacement == 'top-start' || this.realPlacement == 'top' || this.realPlacement == 'top-end') {
104
+ return 'bottom'
105
+ }
106
+ if (this.realPlacement == 'left-start' || this.realPlacement == 'left' || this.realPlacement == 'left-end') {
107
+ return 'right'
108
+ }
109
+ if (this.realPlacement == 'right-start' || this.realPlacement == 'right' || this.realPlacement == 'right-end') {
110
+ return 'left'
111
+ }
112
+ return 'top'
113
+ },
114
+ wrapStyle() {
115
+ return {
116
+ borderColor: this.border ? this.borderColor || '' : '',
117
+ background: this.background || '',
118
+ color: this.color || ''
119
+ }
120
+ }
121
+ },
122
+ mounted() {
123
+ if (this.modelValue) {
124
+ this.setPosition()
125
+ }
126
+ Dap.event.on(window, `click.editify_layer_${this.uid}`, this.handleClick)
127
+ Dap.event.on(window, `resize.editify_layer_${this.uid}`, this.handleResize)
128
+ },
129
+ methods: {
130
+ //显示时
131
+ handleEnter(el) {
132
+ this.setPosition()
133
+ this.$emit('show', el)
134
+ },
135
+ //完全显示后
136
+ handleAfterEnter(el) {
137
+ this.$emit('shown', el)
138
+ },
139
+ //完全隐藏后
140
+ handleAfterLeave(el) {
141
+ this.$emit('hidden', el)
142
+ },
143
+ //窗口尺寸改动
144
+ handleResize() {
145
+ if (this.modelValue) {
146
+ this.$emit('update:modelValue', false)
147
+ }
148
+ },
149
+ //点击定位父元素外的元素关闭浮层
150
+ handleClick(e) {
151
+ if (!Dap.element.isElement(this.$el)) {
152
+ return
153
+ }
154
+ if (Dap.element.isContains(this.$el.offsetParent, e.target)) {
155
+ return
156
+ }
157
+ if (this.modelValue) {
158
+ this.$emit('update:modelValue', false)
159
+ }
160
+ },
161
+ //根据range设置三角形位置
162
+ setTrianglePositionByRange() {
163
+ const selection = window.getSelection()
164
+ if (selection.rangeCount) {
165
+ const range = selection.getRangeAt(0)
166
+ const rects = range.getClientRects()
167
+ if (rects.length) {
168
+ //range的第一个位置
169
+ const firstRect = rects[0]
170
+ //range的最后一个位置
171
+ const lastRect = rects[rects.length - 1]
172
+ if (this.realPlacement == 'top') {
173
+ this.$refs.triangle.$el.style.left = this.$refs.wrap.offsetWidth / 2 - this.$refs.triangle.$el.offsetWidth / 2 + 'px'
174
+ this.$refs.triangle.$el.style.right = 'auto'
175
+ this.$refs.triangle.$el.style.top = this.$refs.wrap.offsetHeight - 1 + 'px'
176
+ this.$refs.triangle.$el.style.bottom = 'auto'
177
+ } else if (this.realPlacement == 'top-start') {
178
+ this.$refs.triangle.$el.style.left = (this.$refs.wrap.offsetWidth > firstRect.width ? firstRect.width : this.$refs.wrap.offsetWidth) / 2 - this.$refs.triangle.$el.offsetWidth / 2 + 'px'
179
+ this.$refs.triangle.$el.style.right = 'auto'
180
+ this.$refs.triangle.$el.style.top = this.$refs.wrap.offsetHeight - 1 + 'px'
181
+ this.$refs.triangle.$el.style.bottom = 'auto'
182
+ } else if (this.realPlacement == 'top-end') {
183
+ this.$refs.triangle.$el.style.left = 'auto'
184
+ this.$refs.triangle.$el.style.right = (this.$refs.wrap.offsetWidth > firstRect.width ? firstRect.width : this.$refs.wrap.offsetWidth) / 2 - this.$refs.triangle.$el.offsetWidth / 2 + 'px'
185
+ this.$refs.triangle.$el.style.top = this.$refs.wrap.offsetHeight - 1 + 'px'
186
+ this.$refs.triangle.$el.style.bottom = 'auto'
187
+ } else if (this.realPlacement == 'bottom') {
188
+ this.$refs.triangle.$el.style.left = this.$refs.wrap.offsetWidth / 2 - this.$refs.triangle.$el.offsetWidth / 2 + 'px'
189
+ this.$refs.triangle.$el.style.right = 'auto'
190
+ this.$refs.triangle.$el.style.top = 'auto'
191
+ this.$refs.triangle.$el.style.bottom = this.$refs.wrap.offsetHeight - 1 + 'px'
192
+ } else if (this.realPlacement == 'bottom-start') {
193
+ this.$refs.triangle.$el.style.left = (this.$refs.wrap.offsetWidth > lastRect.width ? lastRect.width : this.$refs.wrap.offsetWidth) / 2 - this.$refs.triangle.$el.offsetWidth / 2 + 'px'
194
+ this.$refs.triangle.$el.style.right = 'auto'
195
+ this.$refs.triangle.$el.style.top = 'auto'
196
+ this.$refs.triangle.$el.style.bottom = this.$refs.wrap.offsetHeight - 1 + 'px'
197
+ } else if (this.realPlacement == 'bottom-end') {
198
+ this.$refs.triangle.$el.style.left = 'auto'
199
+ this.$refs.triangle.$el.style.right = (this.$refs.wrap.offsetWidth > lastRect.width ? lastRect.width : this.$refs.wrap.offsetWidth) / 2 - this.$refs.triangle.$el.offsetWidth / 2 + 'px'
200
+ this.$refs.triangle.$el.style.top = 'auto'
201
+ this.$refs.triangle.$el.style.bottom = this.$refs.wrap.offsetHeight - 1 + 'px'
202
+ } else {
203
+ this.$refs.triangle.$el.style.left = this.$refs.wrap.offsetWidth / 2 - this.$refs.triangle.$el.offsetWidth / 2 + 'px'
204
+ this.$refs.triangle.$el.style.right = 'auto'
205
+ this.$refs.triangle.$el.style.top = -this.$refs.triangle.$el.offsetHeight + 1 + 'px'
206
+ this.$refs.triangle.$el.style.bottom = 'auto'
207
+ }
208
+ }
209
+ }
210
+ },
211
+ //根据node设置三角形位置
212
+ setTrianglePositionByNode() {
213
+ const node = this.getNode()
214
+ if (!Dap.element.isElement(node)) {
215
+ return
216
+ }
217
+ if (this.realPlacement == 'top') {
218
+ this.$refs.triangle.$el.style.left = this.$refs.wrap.offsetWidth / 2 - this.$refs.triangle.$el.offsetWidth / 2 + 'px'
219
+ this.$refs.triangle.$el.style.right = 'auto'
220
+ this.$refs.triangle.$el.style.top = this.$refs.wrap.offsetHeight - 1 + 'px'
221
+ this.$refs.triangle.$el.style.bottom = 'auto'
222
+ } else if (this.realPlacement == 'top-start') {
223
+ this.$refs.triangle.$el.style.left = (this.$refs.wrap.offsetWidth > node.offsetWidth ? node.offsetWidth : this.$refs.wrap.offsetWidth) / 2 - this.$refs.triangle.$el.offsetWidth / 2 + 'px'
224
+ this.$refs.triangle.$el.style.right = 'auto'
225
+ this.$refs.triangle.$el.style.top = this.$refs.wrap.offsetHeight - 1 + 'px'
226
+ this.$refs.triangle.$el.style.bottom = 'auto'
227
+ } else if (this.realPlacement == 'top-end') {
228
+ this.$refs.triangle.$el.style.left = 'auto'
229
+ this.$refs.triangle.$el.style.right = (this.$refs.wrap.offsetWidth > node.offsetWidth ? node.offsetWidth : this.$refs.wrap.offsetWidth) / 2 - this.$refs.triangle.$el.offsetWidth / 2 + 'px'
230
+ this.$refs.triangle.$el.style.top = this.$refs.wrap.offsetHeight - 1 + 'px'
231
+ this.$refs.triangle.$el.style.bottom = 'auto'
232
+ } else if (this.realPlacement == 'bottom') {
233
+ this.$refs.triangle.$el.style.left = this.$refs.wrap.offsetWidth / 2 - this.$refs.triangle.$el.offsetWidth / 2 + 'px'
234
+ this.$refs.triangle.$el.style.right = 'auto'
235
+ this.$refs.triangle.$el.style.top = 'auto'
236
+ this.$refs.triangle.$el.style.bottom = this.$refs.wrap.offsetHeight - 1 + 'px'
237
+ } else if (this.realPlacement == 'bottom-start') {
238
+ this.$refs.triangle.$el.style.left = (this.$refs.wrap.offsetWidth > node.offsetWidth ? node.offsetWidth : this.$refs.wrap.offsetWidth) / 2 - this.$refs.triangle.$el.offsetWidth / 2 + 'px'
239
+ this.$refs.triangle.$el.style.right = 'auto'
240
+ this.$refs.triangle.$el.style.top = 'auto'
241
+ this.$refs.triangle.$el.style.bottom = this.$refs.wrap.offsetHeight - 1 + 'px'
242
+ } else if (this.realPlacement == 'bottom-end') {
243
+ this.$refs.triangle.$el.style.left = 'auto'
244
+ this.$refs.triangle.$el.style.right = (this.$refs.wrap.offsetWidth > node.offsetWidth ? node.offsetWidth : this.$refs.wrap.offsetWidth) / 2 - this.$refs.triangle.$el.offsetWidth / 2 + 'px'
245
+ this.$refs.triangle.$el.style.top = 'auto'
246
+ this.$refs.triangle.$el.style.bottom = this.$refs.wrap.offsetHeight - 1 + 'px'
247
+ } else {
248
+ this.$refs.triangle.$el.style.left = this.$refs.wrap.offsetWidth / 2 - this.$refs.triangle.$el.offsetWidth / 2 + 'px'
249
+ this.$refs.triangle.$el.style.right = 'auto'
250
+ this.$refs.triangle.$el.style.top = -this.$refs.triangle.$el.offsetHeight + 1 + 'px'
251
+ this.$refs.triangle.$el.style.bottom = 'auto'
252
+ }
253
+ },
254
+ //根据range设置位置
255
+ setPositionByRange() {
256
+ //重置
257
+ this.realPlacement = null
258
+ const selection = window.getSelection()
259
+ if (selection.rangeCount) {
260
+ const range = selection.getRangeAt(0)
261
+ const rects = range.getClientRects()
262
+ if (rects.length) {
263
+ //range的第一个位置
264
+ const firstRect = rects[0]
265
+ //range的最后一个位置
266
+ const lastRect = rects[rects.length - 1]
267
+ //定位父元素的位置
268
+ const parentRect = Dap.element.getElementBounding(this.$el.offsetParent)
269
+ //可视窗口高度
270
+ const documentHeight = document.documentElement.clientHeight || window.innerHeight
271
+ //可视窗口宽度
272
+ const documentWidth = document.documentElement.clientWidth || window.innerWidth
273
+ if (this.placement == 'top' || this.placement == 'top-start' || this.placement == 'top-end') {
274
+ if (firstRect.top >= 0 && firstRect.top >= parentRect.top && firstRect.top >= this.$el.offsetHeight) {
275
+ this.realPlacement = this.placement
276
+ } else if (documentHeight - firstRect.bottom >= 0 && documentHeight - firstRect.bottom >= parentRect.bottom && documentHeight - firstRect.bottom >= this.$el.offsetHeight) {
277
+ this.realPlacement = this.placement == 'top' ? 'bottom' : this.placement == 'top-start' ? 'bottom-start' : 'bottom-end'
278
+ }
279
+ } else if (this.placement == 'bottom' || this.placement == 'bottom-start' || this.placement == 'bottom-end') {
280
+ if (documentHeight - lastRect.bottom >= 0 && documentHeight - lastRect.bottom >= parentRect.bottom && documentHeight - lastRect.bottom >= this.$el.offsetHeight) {
281
+ this.realPlacement = this.placement
282
+ } else if (lastRect.top >= 0 && lastRect.top >= parentRect.top && lastRect.top >= this.$el.offsetHeight) {
283
+ this.realPlacement = this.placement == 'bottom' ? 'top' : this.placement == 'bottom-start' ? 'top-start' : 'top-end'
284
+ }
285
+ }
286
+
287
+ //判断左右是否足够空间显示
288
+ if (this.realPlacement == 'top') {
289
+ if (documentWidth - firstRect.right + firstRect.width / 2 < this.$el.offsetWidth / 2) {
290
+ this.realPlacement = 'top-end'
291
+ } else if (firstRect.left + firstRect.width / 2 < this.$el.offsetWidth / 2) {
292
+ this.realPlacement = 'top-start'
293
+ }
294
+ } else if (this.realPlacement == 'bottom') {
295
+ if (documentWidth - lastRect.right + lastRect.width / 2 < this.$el.offsetWidth / 2) {
296
+ this.realPlacement = 'bottom-end'
297
+ } else if (lastRect.left + lastRect.width / 2 < this.$el.offsetWidth / 2) {
298
+ this.realPlacement = 'bottom-start'
299
+ }
300
+ } else if (this.realPlacement == 'top-start') {
301
+ if (documentWidth - firstRect.right + firstRect.width < this.$el.offsetWidth) {
302
+ if (documentWidth - firstRect.right + firstRect.width / 2 >= this.$el.offsetWidth / 2) {
303
+ this.realPlacement = 'top'
304
+ } else {
305
+ this.realPlacement = 'top-end'
306
+ }
307
+ }
308
+ } else if (this.realPlacement == 'bottom-start') {
309
+ if (documentWidth - lastRect.right + lastRect.width < this.$el.offsetWidth) {
310
+ if (documentWidth - lastRect.right + lastRect.width / 2 >= this.$el.offsetWidth / 2) {
311
+ this.realPlacement = 'bottom'
312
+ } else {
313
+ this.realPlacement = 'bottom-end'
314
+ }
315
+ }
316
+ } else if (this.realPlacement == 'top-end') {
317
+ if (firstRect.left + firstRect.width < this.$el.offsetWidth) {
318
+ if (firstRect.left + firstRect.width / 2 >= this.$el.offsetWidth / 2) {
319
+ this.realPlacement = 'top'
320
+ } else {
321
+ this.realPlacement = 'top-start'
322
+ }
323
+ }
324
+ } else if (this.realPlacement == 'bottom-end') {
325
+ if (lastRect.left + lastRect.width < this.$el.offsetWidth) {
326
+ if (lastRect.left + lastRect.width / 2 >= this.$el.offsetWidth / 2) {
327
+ this.realPlacement = 'bottom'
328
+ } else {
329
+ this.realPlacement = 'bottom-start'
330
+ }
331
+ }
332
+ }
333
+ this.$nextTick(() => {
334
+ //设置位置对应的样式
335
+ if (this.realPlacement == 'top') {
336
+ this.$el.style.left = firstRect.left - parentRect.left + firstRect.width / 2 - this.$el.offsetWidth / 2 + 'px'
337
+ this.$el.style.right = 'auto'
338
+ this.$el.style.top = firstRect.top - parentRect.top - this.$el.offsetHeight + 'px'
339
+ this.$el.style.bottom = 'auto'
340
+ } else if (this.realPlacement == 'top-start') {
341
+ this.$el.style.left = firstRect.left - parentRect.left + 'px'
342
+ this.$el.style.right = 'auto'
343
+ this.$el.style.top = firstRect.top - parentRect.top - this.$el.offsetHeight + 'px'
344
+ this.$el.style.bottom = 'auto'
345
+ } else if (this.realPlacement == 'top-end') {
346
+ this.$el.style.left = 'auto'
347
+ this.$el.style.right = documentWidth - firstRect.right - parentRect.right + 'px'
348
+ this.$el.style.top = firstRect.top - parentRect.top - this.$el.offsetHeight + 'px'
349
+ this.$el.style.bottom = 'auto'
350
+ } else if (this.realPlacement == 'bottom') {
351
+ this.$el.style.left = lastRect.left - parentRect.left + lastRect.width / 2 - this.$el.offsetWidth / 2 + 'px'
352
+ this.$el.style.right = 'auto'
353
+ this.$el.style.top = 'auto'
354
+ this.$el.style.bottom = documentHeight - lastRect.bottom - parentRect.bottom - this.$el.offsetHeight + 'px'
355
+ } else if (this.realPlacement == 'bottom-start') {
356
+ this.$el.style.left = lastRect.left - parentRect.left + 'px'
357
+ this.$el.style.right = 'auto'
358
+ this.$el.style.top = 'auto'
359
+ this.$el.style.bottom = documentHeight - lastRect.bottom - parentRect.bottom - this.$el.offsetHeight + 'px'
360
+ } else if (this.realPlacement == 'bottom-end') {
361
+ this.$el.style.left = 'auto'
362
+ this.$el.style.right = documentWidth - lastRect.right - parentRect.right + 'px'
363
+ this.$el.style.top = 'auto'
364
+ this.$el.style.bottom = documentHeight - lastRect.bottom - parentRect.bottom - this.$el.offsetHeight + 'px'
365
+ } else {
366
+ this.$el.style.top = 'auto'
367
+ this.$el.style.bottom = (parentRect.bottom < 0 ? -parentRect.bottom : 0) + 'px'
368
+ if (this.placement == 'top') {
369
+ //top-end
370
+ if (documentWidth - firstRect.right + firstRect.width / 2 < this.$el.offsetWidth / 2) {
371
+ this.$el.style.left = 'auto'
372
+ this.$el.style.right = documentWidth - firstRect.right - parentRect.right + 'px'
373
+ }
374
+ //top-start
375
+ else if (firstRect.left + firstRect.width / 2 < this.$el.offsetWidth / 2) {
376
+ this.$el.style.left = firstRect.left - parentRect.left + 'px'
377
+ this.$el.style.right = 'auto'
378
+ }
379
+ //top
380
+ else {
381
+ this.$el.style.left = firstRect.left - parentRect.left + firstRect.width / 2 - this.$el.offsetWidth / 2 + 'px'
382
+ this.$el.style.right = 'auto'
383
+ }
384
+ } else if (this.placement == 'bottom') {
385
+ //bottom-end
386
+ if (documentWidth - lastRect.right + lastRect.width / 2 < this.$el.offsetWidth / 2) {
387
+ this.$el.style.left = 'auto'
388
+ this.$el.style.right = documentWidth - lastRect.right - parentRect.right + 'px'
389
+ }
390
+ //bottom-start
391
+ else if (lastRect.left + lastRect.width / 2 < this.$el.offsetWidth / 2) {
392
+ this.$el.style.left = lastRect.left - parentRect.left + 'px'
393
+ this.$el.style.right = 'auto'
394
+ }
395
+ //bottom
396
+ else {
397
+ this.$el.style.left = lastRect.left - parentRect.left + lastRect.width / 2 - this.$el.offsetWidth / 2 + 'px'
398
+ this.$el.style.right = 'auto'
399
+ }
400
+ } else if (this.placement == 'top-start') {
401
+ if (documentWidth - firstRect.right + firstRect.width < this.$el.offsetWidth) {
402
+ //top
403
+ if (documentWidth - firstRect.right + firstRect.width / 2 >= this.$el.offsetWidth / 2) {
404
+ this.$el.style.left = firstRect.left - parentRect.left + firstRect.width / 2 - this.$el.offsetWidth / 2 + 'px'
405
+ this.$el.style.right = 'auto'
406
+ }
407
+ //top-end
408
+ else {
409
+ this.$el.style.left = 'auto'
410
+ this.$el.style.right = documentWidth - firstRect.right - parentRect.right + 'px'
411
+ }
412
+ }
413
+ //top-start
414
+ else {
415
+ this.$el.style.left = firstRect.left - parentRect.left + 'px'
416
+ this.$el.style.right = 'auto'
417
+ }
418
+ } else if (this.placement == 'bottom-start') {
419
+ if (documentWidth - lastRect.right + lastRect.width < this.$el.offsetWidth) {
420
+ //bottom
421
+ if (documentWidth - lastRect.right + lastRect.width / 2 >= this.$el.offsetWidth / 2) {
422
+ this.$el.style.left = lastRect.left - parentRect.left + lastRect.width / 2 - this.$el.offsetWidth / 2 + 'px'
423
+ this.$el.style.right = 'auto'
424
+ }
425
+ //bottom-end
426
+ else {
427
+ this.$el.style.left = 'auto'
428
+ this.$el.style.right = documentWidth - lastRect.right - parentRect.right + 'px'
429
+ }
430
+ }
431
+ //bottom-start
432
+ else {
433
+ this.$el.style.left = lastRect.left - parentRect.left + 'px'
434
+ this.$el.style.right = 'auto'
435
+ }
436
+ } else if (this.placement == 'top-end') {
437
+ if (firstRect.left + firstRect.width < this.$el.offsetWidth) {
438
+ //top
439
+ if (firstRect.left + firstRect.width / 2 >= this.$el.offsetWidth / 2) {
440
+ this.$el.style.left = firstRect.left - parentRect.left + firstRect.width / 2 - this.$el.offsetWidth / 2 + 'px'
441
+ this.$el.style.right = 'auto'
442
+ }
443
+ //top-start
444
+ else {
445
+ this.$el.style.left = firstRect.left - parentRect.left + 'px'
446
+ this.$el.style.right = 'auto'
447
+ }
448
+ }
449
+ //top-end
450
+ else {
451
+ this.$el.style.left = 'auto'
452
+ this.$el.style.right = documentWidth - firstRect.right - parentRect.right + 'px'
453
+ }
454
+ } else if (this.placement == 'bottom-end') {
455
+ if (lastRect.left + lastRect.width < this.$el.offsetWidth) {
456
+ //bottom
457
+ if (lastRect.left + lastRect.width / 2 >= this.$el.offsetWidth / 2) {
458
+ this.$el.style.left = lastRect.left - parentRect.left + lastRect.width / 2 - this.$el.offsetWidth / 2 + 'px'
459
+ this.$el.style.right = 'auto'
460
+ }
461
+ //bottom-start
462
+ else {
463
+ this.$el.style.left = lastRect.left - parentRect.left + 'px'
464
+ this.$el.style.right = 'auto'
465
+ }
466
+ }
467
+ //bottom-end
468
+ else {
469
+ this.$el.style.left = 'auto'
470
+ this.$el.style.right = documentWidth - lastRect.right - parentRect.right + 'px'
471
+ }
472
+ }
473
+ }
474
+ //三角形位置
475
+ if (this.showTriangle) {
476
+ this.setTrianglePositionByRange()
477
+ }
478
+ })
479
+ }
480
+ }
481
+ },
482
+ //根据node设置位置
483
+ setPositionByNode() {
484
+ const node = this.getNode()
485
+ if (!Dap.element.isElement(node)) {
486
+ return
487
+ }
488
+ //重置
489
+ this.realPlacement = null
490
+ //关联元素位置
491
+ const nodeRect = Dap.element.getElementBounding(node)
492
+ //定位父元素位置
493
+ const parentRect = Dap.element.getElementBounding(this.$el.offsetParent)
494
+ //设置真实的位置
495
+ if (this.placement == 'top' || this.placement == 'top-start' || this.placement == 'top-end') {
496
+ if (nodeRect.top >= 0 && nodeRect.top >= parentRect.top && nodeRect.top >= this.$el.offsetHeight) {
497
+ this.realPlacement = this.placement
498
+ } else if (nodeRect.bottom >= 0 && nodeRect.bottom >= parentRect.bottom && nodeRect.bottom >= this.$el.offsetHeight) {
499
+ this.realPlacement = this.placement == 'top' ? 'bottom' : this.placement == 'top-start' ? 'bottom-start' : 'bottom-end'
500
+ }
501
+ } else if (this.placement == 'bottom' || this.placement == 'bottom-start' || this.placement == 'bottom-end') {
502
+ if (nodeRect.bottom >= 0 && nodeRect.bottom >= parentRect.bottom && nodeRect.bottom >= this.$el.offsetHeight) {
503
+ this.realPlacement = this.placement
504
+ } else if (nodeRect.top >= 0 && nodeRect.top >= parentRect.top && nodeRect.top >= this.$el.offsetHeight) {
505
+ this.realPlacement = this.placement == 'bottom' ? 'top' : this.placement == 'bottom-start' ? 'top-start' : 'top-end'
506
+ }
507
+ }
508
+ //判断左右是否足够空间显示
509
+ if (this.realPlacement == 'top') {
510
+ if (nodeRect.right + node.offsetWidth / 2 < this.$el.offsetWidth / 2) {
511
+ this.realPlacement = 'top-end'
512
+ } else if (nodeRect.left + node.offsetWidth / 2 < this.$el.offsetWidth / 2) {
513
+ this.realPlacement = 'top-start'
514
+ }
515
+ } else if (this.realPlacement == 'top-start') {
516
+ if (nodeRect.right + node.offsetWidth < this.$el.offsetWidth) {
517
+ if (nodeRect.right + node.offsetWidth / 2 >= this.$el.offsetWidth / 2) {
518
+ this.realPlacement = 'top'
519
+ } else {
520
+ this.realPlacement = 'top-end'
521
+ }
522
+ }
523
+ } else if (this.realPlacement == 'top-end') {
524
+ if (nodeRect.left + node.offsetWidth < this.$el.offsetWidth) {
525
+ if (nodeRect.left + node.offsetWidth / 2 >= this.$el.offsetWidth / 2) {
526
+ this.realPlacement = 'top'
527
+ } else {
528
+ this.realPlacement = 'top-start'
529
+ }
530
+ }
531
+ } else if (this.realPlacement == 'bottom') {
532
+ if (nodeRect.right + node.offsetWidth / 2 < this.$el.offsetWidth / 2) {
533
+ this.realPlacement = 'bottom-end'
534
+ } else if (nodeRect.left + node.offsetWidth / 2 < this.$el.offsetWidth / 2) {
535
+ this.realPlacement = 'bottom-start'
536
+ }
537
+ } else if (this.realPlacement == 'bottom-start') {
538
+ if (nodeRect.right + node.offsetWidth < this.$el.offsetWidth) {
539
+ if (nodeRect.right + node.offsetWidth / 2 >= this.$el.offsetWidth / 2) {
540
+ this.realPlacement = 'bottom'
541
+ } else {
542
+ this.realPlacement = 'bottom-end'
543
+ }
544
+ }
545
+ } else if (this.realPlacement == 'bottom-end') {
546
+ if (nodeRect.left + node.offsetWidth < this.$el.offsetWidth) {
547
+ if (nodeRect.left + node.offsetWidth / 2 >= this.$el.offsetWidth / 2) {
548
+ this.realPlacement = 'bottom'
549
+ } else {
550
+ this.realPlacement = 'bottom-start'
551
+ }
552
+ }
553
+ }
554
+
555
+ this.$nextTick(() => {
556
+ //设置位置对应的样式
557
+ if (this.realPlacement == 'top') {
558
+ this.$el.style.left = nodeRect.left - parentRect.left + node.offsetWidth / 2 - this.$el.offsetWidth / 2 + 'px'
559
+ this.$el.style.right = 'auto'
560
+ this.$el.style.top = nodeRect.top - parentRect.top - this.$el.offsetHeight + 'px'
561
+ this.$el.style.bottom = 'auto'
562
+ } else if (this.realPlacement == 'top-start') {
563
+ this.$el.style.left = nodeRect.left - parentRect.left + 'px'
564
+ this.$el.style.right = 'auto'
565
+ this.$el.style.top = nodeRect.top - parentRect.top - this.$el.offsetHeight + 'px'
566
+ this.$el.style.bottom = 'auto'
567
+ } else if (this.realPlacement == 'top-end') {
568
+ this.$el.style.left = 'auto'
569
+ this.$el.style.right = nodeRect.right - parentRect.right + 'px'
570
+ this.$el.style.top = nodeRect.top - parentRect.top - this.$el.offsetHeight + 'px'
571
+ this.$el.style.bottom = 'auto'
572
+ } else if (this.realPlacement == 'bottom') {
573
+ this.$el.style.left = nodeRect.left - parentRect.left + node.offsetWidth / 2 - this.$el.offsetWidth / 2 + 'px'
574
+ this.$el.style.right = 'auto'
575
+ this.$el.style.top = 'auto'
576
+ this.$el.style.bottom = nodeRect.bottom - parentRect.bottom - this.$el.offsetHeight + 'px'
577
+ } else if (this.realPlacement == 'bottom-start') {
578
+ this.$el.style.left = nodeRect.left - parentRect.left + 'px'
579
+ this.$el.style.right = 'auto'
580
+ this.$el.style.top = 'auto'
581
+ this.$el.style.bottom = nodeRect.bottom - parentRect.bottom - this.$el.offsetHeight + 'px'
582
+ } else if (this.realPlacement == 'bottom-end') {
583
+ this.$el.style.left = 'auto'
584
+ this.$el.style.right = nodeRect.right - parentRect.right + 'px'
585
+ this.$el.style.top = 'auto'
586
+ this.$el.style.bottom = nodeRect.bottom - parentRect.bottom - this.$el.offsetHeight + 'px'
587
+ } else {
588
+ this.$el.style.top = 'auto'
589
+ this.$el.style.bottom = (parentRect.bottom < 0 ? -parentRect.bottom : 0) + 'px'
590
+ if (this.placement == 'top' || this.placement == 'bottom') {
591
+ if (nodeRect.right + node.offsetWidth / 2 < this.$el.offsetWidth / 2) {
592
+ this.$el.style.left = 'auto'
593
+ this.$el.style.right = nodeRect.right - parentRect.right + 'px'
594
+ } else if (nodeRect.left + node.offsetWidth / 2 < this.$el.offsetWidth / 2) {
595
+ this.$el.style.left = nodeRect.left - parentRect.left + 'px'
596
+ this.$el.style.right = 'auto'
597
+ } else {
598
+ this.$el.style.left = nodeRect.left - parentRect.left + node.offsetWidth / 2 - this.$el.offsetWidth / 2 + 'px'
599
+ this.$el.style.right = 'auto'
600
+ }
601
+ } else if (this.placement == 'top-start' || this.placement == 'bottom-start') {
602
+ if (nodeRect.right + node.offsetWidth < this.$el.offsetWidth) {
603
+ if (nodeRect.right + node.offsetWidth / 2 >= this.$el.offsetWidth / 2) {
604
+ this.$el.style.left = nodeRect.left - parentRect.left + node.offsetWidth / 2 - this.$el.offsetWidth / 2 + 'px'
605
+ this.$el.style.right = 'auto'
606
+ } else {
607
+ this.$el.style.left = 'auto'
608
+ this.$el.style.right = nodeRect.right - parentRect.right + 'px'
609
+ }
610
+ } else {
611
+ this.$el.style.left = nodeRect.left - parentRect.left + 'px'
612
+ this.$el.style.right = 'auto'
613
+ }
614
+ } else if (this.placement == 'top-end' || this.placement == 'bottom-end') {
615
+ if (nodeRect.left + node.offsetWidth < this.$el.offsetWidth) {
616
+ if (nodeRect.left + node.offsetWidth / 2 >= this.$el.offsetWidth / 2) {
617
+ this.$el.style.left = nodeRect.left - parentRect.left + node.offsetWidth / 2 - this.$el.offsetWidth / 2 + 'px'
618
+ this.$el.style.right = 'auto'
619
+ } else {
620
+ this.$el.style.left = nodeRect.left - parentRect.left + 'px'
621
+ this.$el.style.right = 'auto'
622
+ }
623
+ } else {
624
+ this.$el.style.left = 'auto'
625
+ this.$el.style.right = nodeRect.right - parentRect.right + 'px'
626
+ }
627
+ }
628
+ }
629
+ //三角形位置
630
+ if (this.showTriangle) {
631
+ this.setTrianglePositionByNode()
632
+ }
633
+ })
634
+ },
635
+ //设置位置
636
+ setPosition() {
637
+ //如果根据range来定位
638
+ if (this.useRange) {
639
+ this.setPositionByRange()
640
+ }
641
+ //根据传入的node来定位
642
+ else {
643
+ this.setPositionByNode()
644
+ }
645
+ },
646
+ //获取目标元素
647
+ getNode() {
648
+ if (!this.node) {
649
+ return null
650
+ }
651
+ if (Dap.element.isElement(this.node)) {
652
+ return this.node
653
+ }
654
+ return document.body.querySelector(this.node)
655
+ }
656
+ },
657
+ beforeUnmount() {
658
+ Dap.event.off(window, `click.editify_layer_${this.uid} resize.editify_layer_${this.uid}`)
659
+ }
660
+ }
661
+ </script>
662
+ <style lang="less" scoped>
663
+ .editify-layer-fade-enter-from,
664
+ .editify-layer-fade-leave-to {
665
+ opacity: 0;
666
+ }
667
+ .editify-layer-fade-enter-active,
668
+ .editify-layer-fade-leave-active {
669
+ transition: opacity 200ms linear;
670
+ }
671
+
672
+ .editify-layer-translate-enter-from,
673
+ .editify-layer-translate-leave-to {
674
+ opacity: 0;
675
+ transform: translateY(20px);
676
+ }
677
+
678
+ .editify-layer-translate-enter-active,
679
+ .editify-layer-translate-leave-active {
680
+ transition: opacity 200ms ease-in-out, transform 200ms ease-in-out;
681
+ }
682
+
683
+ .editify-layer {
684
+ display: block;
685
+ position: absolute;
686
+ padding: 0 0 10px 0;
687
+ font-size: @font-size;
688
+ color: @font-color;
689
+
690
+ &[data-editify-placement='bottom'],
691
+ &[data-editify-placement='bottom-start'],
692
+ &[data-editify-placement='bottom-end'] {
693
+ padding: 10px 0 0 0;
694
+ }
695
+
696
+ :deep(.editify-triangle) {
697
+ position: absolute;
698
+ z-index: 1;
699
+ }
700
+
701
+ .editify-layer-wrap {
702
+ display: block;
703
+ background-color: @background;
704
+ box-shadow: 0px 2px 10px rgba(0, 0, 0, 0.1);
705
+ border-radius: 4px;
706
+
707
+ &.border {
708
+ border: 1px solid @border-color;
709
+ }
710
+ }
711
+ }
712
+ </style>