mirror of
https://github.com/KevinMidboe/vue-js-modal.git
synced 2025-10-29 18:00:20 +00:00
This commit is contained in:
123
src/Modal.vue
123
src/Modal.vue
@@ -33,6 +33,23 @@
|
||||
import { inRange } from './util'
|
||||
import parseNumber from './parser'
|
||||
|
||||
/**
|
||||
* MutationObserver feature detection:
|
||||
* Detects if MutationObserver is available, return false if not.
|
||||
* No polyfill is provided here, so height 'auto' recalculation will simply stay at its initial height (won't crash).
|
||||
* (Provide polyfill to support IE < 11)
|
||||
*/
|
||||
const MutationObserver = (function () {
|
||||
const prefixes = ['', 'WebKit', 'Moz', 'O', 'Ms']
|
||||
for (let i = 0; i < prefixes.length; i++) {
|
||||
if (prefixes[i] + 'MutationObserver' in window) {
|
||||
console.log('got MutationObserver:', prefixes[i] + 'MutationObserver')
|
||||
return window[prefixes[i] + 'MutationObserver']
|
||||
}
|
||||
}
|
||||
return false
|
||||
}())
|
||||
|
||||
export default {
|
||||
name: 'VueJsModal',
|
||||
props: {
|
||||
@@ -155,16 +172,25 @@
|
||||
width: 0,
|
||||
widthType: 'px',
|
||||
height: 0,
|
||||
heightType: 'px'
|
||||
heightType: 'px',
|
||||
renderedHeight: 0
|
||||
},
|
||||
|
||||
window: {
|
||||
width: 0,
|
||||
height: 0
|
||||
}
|
||||
},
|
||||
|
||||
mutationObserver: null
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
/**
|
||||
* Sets the visibility of overlay and modal.
|
||||
* Events 'opened' and 'closed' is called here
|
||||
* inside `setTimeout` and `$nextTick`, after the DOM changes.
|
||||
* This fixes `$refs.modal` `undefined` bug (fixes #15)
|
||||
*/
|
||||
visible (value) {
|
||||
if (value) {
|
||||
this.visibility.overlay = true
|
||||
@@ -173,6 +199,7 @@
|
||||
this.visibility.modal = true
|
||||
this.$nextTick(() => {
|
||||
this.addDraggableListeners()
|
||||
this.callAfterEvent(true)
|
||||
})
|
||||
}, this.delay)
|
||||
} else {
|
||||
@@ -182,6 +209,7 @@
|
||||
this.visibility.overlay = false
|
||||
this.$nextTick(() => {
|
||||
this.removeDraggableListeners()
|
||||
this.callAfterEvent(false)
|
||||
})
|
||||
}, this.delay)
|
||||
}
|
||||
@@ -211,6 +239,16 @@
|
||||
console.warn(`Modal "${this.name}" has scrollable flag set to true ` +
|
||||
`but height is not "auto" (${this.height})`)
|
||||
}
|
||||
|
||||
// init MutationObserver
|
||||
// Only observe when using height: 'auto'
|
||||
// The callback will be called when modal DOM changes,
|
||||
// this is for updating the `top` attribute for height 'auto' modals.
|
||||
if (this.isAutoHeight && MutationObserver) {
|
||||
this.mutationObserver = new MutationObserver(mutations => {
|
||||
this.updateRenderedHeight()
|
||||
})
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Removes "resize" window listener
|
||||
@@ -236,16 +274,12 @@
|
||||
const maxLeft = window.width - trueModalWidth
|
||||
const maxTop = window.height - trueModalHeight
|
||||
|
||||
const minTop = this.scrollable
|
||||
? Number.NEGATIVE_INFINITY
|
||||
: 0
|
||||
|
||||
const left = shift.left + pivotX * maxLeft
|
||||
const top = shift.top + pivotY * maxTop
|
||||
|
||||
return {
|
||||
left: inRange(0, maxLeft, left),
|
||||
top: inRange(minTop, maxTop, top)
|
||||
top: inRange(0, maxTop, top)
|
||||
}
|
||||
},
|
||||
/**
|
||||
@@ -267,7 +301,7 @@
|
||||
* Returns pixel height (if set with %) and makes sure that modal size
|
||||
* fits the window.
|
||||
*
|
||||
* Returns 0 if height set as "auto"
|
||||
* Returns modal.renderedHeight if height set as "auto"
|
||||
*/
|
||||
trueModalHeight () {
|
||||
const { window, modal, isAutoHeight, adaptive } = this
|
||||
@@ -277,7 +311,8 @@
|
||||
: modal.height
|
||||
|
||||
if (isAutoHeight) {
|
||||
return 0
|
||||
// use renderedHeight when height 'auto'
|
||||
return this.modal.renderedHeight
|
||||
}
|
||||
|
||||
return adaptive
|
||||
@@ -366,6 +401,8 @@
|
||||
},
|
||||
/**
|
||||
* Event handler which is triggered on $modal.show and $modal.hight
|
||||
* BeforeEvents: ('before-close' and 'before-open') are `$emit`ed here,
|
||||
* but AfterEvents ('opened' and 'closed') are moved to `watch.visible`.
|
||||
*/
|
||||
toggle (state, params) {
|
||||
const { reset, scrollable, visible } = this
|
||||
@@ -374,10 +411,6 @@
|
||||
? 'before-close'
|
||||
: 'before-open'
|
||||
|
||||
const afterEventName = visible
|
||||
? 'closed'
|
||||
: 'opened'
|
||||
|
||||
if (beforeEventName === 'before-open') {
|
||||
if (reset) {
|
||||
this.setInitialSize()
|
||||
@@ -388,9 +421,7 @@
|
||||
if (scrollable) {
|
||||
document.body.classList.add('v--modal-block-scroll')
|
||||
}
|
||||
}
|
||||
|
||||
if (beforeEventName === 'before-close') {
|
||||
} else {
|
||||
if (scrollable) {
|
||||
document.body.classList.remove('v--modal-block-scroll')
|
||||
}
|
||||
@@ -406,10 +437,8 @@
|
||||
this.$emit(beforeEventName, beforeEvent)
|
||||
|
||||
if (!stopEventExecution) {
|
||||
const afterEvent = this.genEventObject({ state, params })
|
||||
|
||||
this.visible = state
|
||||
this.$emit(afterEventName, afterEvent)
|
||||
// after events are called in `watch.visible`
|
||||
}
|
||||
},
|
||||
|
||||
@@ -501,6 +530,61 @@
|
||||
|
||||
removeDraggableListeners () {
|
||||
// console.log('removing draggable handlers')
|
||||
},
|
||||
|
||||
/**
|
||||
* 'opened' and 'closed' events are `$emit`ed here.
|
||||
* This is called in watch.visible.
|
||||
* Because modal DOM updates are async,
|
||||
* wrapping afterEvents in `$nextTick` fixes `$refs.modal` undefined bug.
|
||||
* (fixes #15)
|
||||
*/
|
||||
callAfterEvent (state) {
|
||||
if (state) {
|
||||
this.observe()
|
||||
} else {
|
||||
this.disconnectObserver()
|
||||
}
|
||||
const afterEventName = state
|
||||
? 'opened'
|
||||
: 'closed'
|
||||
const afterEvent = this.genEventObject({ state })
|
||||
|
||||
this.$emit(afterEventName, afterEvent)
|
||||
|
||||
// recalculate the true modal height
|
||||
if (state && this.isAutoHeight) {
|
||||
this.updateRenderedHeight()
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Update $data.modal.renderedHeight using getBoundingClientRect.
|
||||
* This method is called when:
|
||||
* 1. modal opened
|
||||
* 2. MutationObserver's observe callback
|
||||
*/
|
||||
updateRenderedHeight () {
|
||||
this.modal.renderedHeight = this.$refs.modal.getBoundingClientRect().height
|
||||
},
|
||||
|
||||
/**
|
||||
* Start observing modal's DOM, if childList or subtree changes,
|
||||
* the callback (registered in created) will be called.
|
||||
*/
|
||||
observe () {
|
||||
if (this.mutationObserver) {
|
||||
this.mutationObserver.observe(this.$refs.modal, { childList: true, subtree: true })
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Disconnects MutationObserver
|
||||
*/
|
||||
disconnectObserver () {
|
||||
if (this.mutationObserver) {
|
||||
this.mutationObserver.disconnect()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -537,6 +621,7 @@
|
||||
|
||||
.v--modal-overlay.scrollable .v--modal-box {
|
||||
margin-bottom: 10px;
|
||||
transition: top 0.2s ease;
|
||||
}
|
||||
|
||||
.v--modal {
|
||||
|
||||
Reference in New Issue
Block a user