|
44 | 44 | </span>
|
45 | 45 | </div>
|
46 | 46 | <div class="mx-datepicker-popup"
|
47 |
| - :style="position" |
| 47 | + :style="innerPopupStyle" |
48 | 48 | v-show="popupVisible"
|
49 | 49 | ref="calendar">
|
50 | 50 | <slot name="header">
|
|
106 | 106 | <script>
|
107 | 107 | import fecha from 'fecha'
|
108 | 108 | import clickoutside from '@/directives/clickoutside'
|
109 |
| -import { isValidDate, isValidRange, isDateObejct, isPlainObject, formatDate, parseDate } from '@/utils/index' |
| 109 | +import { isValidDate, isValidRange, isDateObejct, isPlainObject, formatDate, parseDate, throttle } from '@/utils/index' |
110 | 110 | import CalendarPanel from './calendar.vue'
|
111 | 111 | import locale from '@/mixins/locale'
|
112 | 112 | import Languages from '@/locale/languages'
|
@@ -183,6 +183,13 @@ export default {
|
183 | 183 | inputClass: {
|
184 | 184 | type: [String, Array],
|
185 | 185 | default: 'mx-input'
|
| 186 | + }, |
| 187 | + appendToBody: { |
| 188 | + type: Boolean, |
| 189 | + default: false |
| 190 | + }, |
| 191 | + popupStyle: { |
| 192 | + type: Object |
186 | 193 | }
|
187 | 194 | },
|
188 | 195 | data () {
|
@@ -290,8 +297,31 @@ export default {
|
290 | 297 | return this.format
|
291 | 298 | }
|
292 | 299 | return this.format.replace(/[Hh]+.*[msSaAZ]|\[.*?\]/g, '').trim() || 'YYYY-MM-DD'
|
| 300 | + }, |
| 301 | + innerPopupStyle () { |
| 302 | + return { ...this.position, ...this.popupStyle } |
293 | 303 | }
|
294 | 304 | },
|
| 305 | + mounted () { |
| 306 | + if (this.appendToBody) { |
| 307 | + this.popupElm = this.$refs.calendar |
| 308 | + document.body.appendChild(this.popupElm) |
| 309 | + } |
| 310 | + this._displayPopup = throttle(() => { |
| 311 | + if (this.popupVisible) { |
| 312 | + this.displayPopup() |
| 313 | + } |
| 314 | + }, 200) |
| 315 | + window.addEventListener('resize', this._displayPopup) |
| 316 | + window.addEventListener('scroll', this._displayPopup) |
| 317 | + }, |
| 318 | + beforeDestroy () { |
| 319 | + if (this.popupElm && this.popupElm.parentNode === document.body) { |
| 320 | + document.body.removeChild(this.popupElm) |
| 321 | + } |
| 322 | + window.removeEventListener('resize', this._displayPopup) |
| 323 | + window.removeEventListener('scroll', this._displayPopup) |
| 324 | + }, |
295 | 325 | methods: {
|
296 | 326 | initCalendar () {
|
297 | 327 | this.handleValueChange(this.value)
|
@@ -384,31 +414,53 @@ export default {
|
384 | 414 | closePopup () {
|
385 | 415 | this.popupVisible = false
|
386 | 416 | },
|
| 417 | + getPopupSize (element) { |
| 418 | + const originalDisplay = element.style.display |
| 419 | + const originalVisibility = element.style.visibility |
| 420 | + element.style.display = 'block' |
| 421 | + element.style.visibility = 'hidden' |
| 422 | + const styles = window.getComputedStyle(element) |
| 423 | + const width = element.offsetWidth + parseInt(styles.marginLeft) + parseInt(styles.marginRight) |
| 424 | + const height = element.offsetHeight + parseInt(styles.marginTop) + parseInt(styles.marginBottom) |
| 425 | + const result = { width, height } |
| 426 | + element.style.display = originalDisplay |
| 427 | + element.style.visibility = originalVisibility |
| 428 | + return result |
| 429 | + }, |
387 | 430 | displayPopup () {
|
388 | 431 | const dw = document.documentElement.clientWidth
|
389 | 432 | const dh = document.documentElement.clientHeight
|
390 | 433 | const InputRect = this.$el.getBoundingClientRect()
|
391 |
| - const PopupRect = this.$refs.calendar.getBoundingClientRect() |
392 |
| - this.position = {} |
| 434 | + const PopupRect = this._popupRect || (this._popupRect = this.getPopupSize(this.$refs.calendar)) |
| 435 | + const position = {} |
| 436 | + let offsetRelativeToInputX = 0 |
| 437 | + let offsetRelativeToInputY = 0 |
| 438 | + if (this.appendToBody) { |
| 439 | + offsetRelativeToInputX = window.pageXOffset + InputRect.left |
| 440 | + offsetRelativeToInputY = window.pageYOffset + InputRect.top |
| 441 | + } |
393 | 442 | if (
|
394 | 443 | dw - InputRect.left < PopupRect.width &&
|
395 | 444 | InputRect.right < PopupRect.width
|
396 | 445 | ) {
|
397 |
| - this.position.left = 1 - InputRect.left + 'px' |
| 446 | + position.left = offsetRelativeToInputX - InputRect.left + 1 + 'px' |
398 | 447 | } else if (InputRect.left + InputRect.width / 2 <= dw / 2) {
|
399 |
| - this.position.left = 0 |
| 448 | + position.left = offsetRelativeToInputX + 'px' |
400 | 449 | } else {
|
401 |
| - this.position.right = 0 |
| 450 | + position.left = offsetRelativeToInputX + InputRect.width - PopupRect.width + 'px' |
402 | 451 | }
|
403 | 452 | if (
|
404 |
| - InputRect.top <= PopupRect.height + 1 && |
405 |
| - dh - InputRect.bottom <= PopupRect.height + 1 |
| 453 | + InputRect.top <= PopupRect.height && |
| 454 | + dh - InputRect.bottom <= PopupRect.height |
406 | 455 | ) {
|
407 |
| - this.position.top = dh - InputRect.top - PopupRect.height - 1 + 'px' |
| 456 | + position.top = offsetRelativeToInputY + dh - InputRect.top - PopupRect.height + 'px' |
408 | 457 | } else if (InputRect.top + InputRect.height / 2 <= dh / 2) {
|
409 |
| - this.position.top = '100%' |
| 458 | + position.top = offsetRelativeToInputY + InputRect.height + 'px' |
410 | 459 | } else {
|
411 |
| - this.position.bottom = '100%' |
| 460 | + position.top = offsetRelativeToInputY - PopupRect.height + 'px' |
| 461 | + } |
| 462 | + if (position.top !== this.position.top || position.left !== this.position.left) { |
| 463 | + this.position = position |
412 | 464 | }
|
413 | 465 | },
|
414 | 466 | handleInput (event) {
|
|
0 commit comments