generated from dellevin/template
1
This commit is contained in:
175
node_modules/vue-router/src/util/scroll.js
generated
vendored
Normal file
175
node_modules/vue-router/src/util/scroll.js
generated
vendored
Normal file
@@ -0,0 +1,175 @@
|
||||
/* @flow */
|
||||
|
||||
import type Router from '../index'
|
||||
import { assert } from './warn'
|
||||
import { getStateKey, setStateKey } from './state-key'
|
||||
import { extend } from './misc'
|
||||
|
||||
const positionStore = Object.create(null)
|
||||
|
||||
export function setupScroll () {
|
||||
// Prevent browser scroll behavior on History popstate
|
||||
if ('scrollRestoration' in window.history) {
|
||||
window.history.scrollRestoration = 'manual'
|
||||
}
|
||||
// Fix for #1585 for Firefox
|
||||
// Fix for #2195 Add optional third attribute to workaround a bug in safari https://bugs.webkit.org/show_bug.cgi?id=182678
|
||||
// Fix for #2774 Support for apps loaded from Windows file shares not mapped to network drives: replaced location.origin with
|
||||
// window.location.protocol + '//' + window.location.host
|
||||
// location.host contains the port and location.hostname doesn't
|
||||
const protocolAndPath = window.location.protocol + '//' + window.location.host
|
||||
const absolutePath = window.location.href.replace(protocolAndPath, '')
|
||||
// preserve existing history state as it could be overriden by the user
|
||||
const stateCopy = extend({}, window.history.state)
|
||||
stateCopy.key = getStateKey()
|
||||
window.history.replaceState(stateCopy, '', absolutePath)
|
||||
window.addEventListener('popstate', handlePopState)
|
||||
return () => {
|
||||
window.removeEventListener('popstate', handlePopState)
|
||||
}
|
||||
}
|
||||
|
||||
export function handleScroll (
|
||||
router: Router,
|
||||
to: Route,
|
||||
from: Route,
|
||||
isPop: boolean
|
||||
) {
|
||||
if (!router.app) {
|
||||
return
|
||||
}
|
||||
|
||||
const behavior = router.options.scrollBehavior
|
||||
if (!behavior) {
|
||||
return
|
||||
}
|
||||
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
assert(typeof behavior === 'function', `scrollBehavior must be a function`)
|
||||
}
|
||||
|
||||
// wait until re-render finishes before scrolling
|
||||
router.app.$nextTick(() => {
|
||||
const position = getScrollPosition()
|
||||
const shouldScroll = behavior.call(
|
||||
router,
|
||||
to,
|
||||
from,
|
||||
isPop ? position : null
|
||||
)
|
||||
|
||||
if (!shouldScroll) {
|
||||
return
|
||||
}
|
||||
|
||||
if (typeof shouldScroll.then === 'function') {
|
||||
shouldScroll
|
||||
.then(shouldScroll => {
|
||||
scrollToPosition((shouldScroll: any), position)
|
||||
})
|
||||
.catch(err => {
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
assert(false, err.toString())
|
||||
}
|
||||
})
|
||||
} else {
|
||||
scrollToPosition(shouldScroll, position)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function saveScrollPosition () {
|
||||
const key = getStateKey()
|
||||
if (key) {
|
||||
positionStore[key] = {
|
||||
x: window.pageXOffset,
|
||||
y: window.pageYOffset
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function handlePopState (e) {
|
||||
saveScrollPosition()
|
||||
if (e.state && e.state.key) {
|
||||
setStateKey(e.state.key)
|
||||
}
|
||||
}
|
||||
|
||||
function getScrollPosition (): ?Object {
|
||||
const key = getStateKey()
|
||||
if (key) {
|
||||
return positionStore[key]
|
||||
}
|
||||
}
|
||||
|
||||
function getElementPosition (el: Element, offset: Object): Object {
|
||||
const docEl: any = document.documentElement
|
||||
const docRect = docEl.getBoundingClientRect()
|
||||
const elRect = el.getBoundingClientRect()
|
||||
return {
|
||||
x: elRect.left - docRect.left - offset.x,
|
||||
y: elRect.top - docRect.top - offset.y
|
||||
}
|
||||
}
|
||||
|
||||
function isValidPosition (obj: Object): boolean {
|
||||
return isNumber(obj.x) || isNumber(obj.y)
|
||||
}
|
||||
|
||||
function normalizePosition (obj: Object): Object {
|
||||
return {
|
||||
x: isNumber(obj.x) ? obj.x : window.pageXOffset,
|
||||
y: isNumber(obj.y) ? obj.y : window.pageYOffset
|
||||
}
|
||||
}
|
||||
|
||||
function normalizeOffset (obj: Object): Object {
|
||||
return {
|
||||
x: isNumber(obj.x) ? obj.x : 0,
|
||||
y: isNumber(obj.y) ? obj.y : 0
|
||||
}
|
||||
}
|
||||
|
||||
function isNumber (v: any): boolean {
|
||||
return typeof v === 'number'
|
||||
}
|
||||
|
||||
const hashStartsWithNumberRE = /^#\d/
|
||||
|
||||
function scrollToPosition (shouldScroll, position) {
|
||||
const isObject = typeof shouldScroll === 'object'
|
||||
if (isObject && typeof shouldScroll.selector === 'string') {
|
||||
// getElementById would still fail if the selector contains a more complicated query like #main[data-attr]
|
||||
// but at the same time, it doesn't make much sense to select an element with an id and an extra selector
|
||||
const el = hashStartsWithNumberRE.test(shouldScroll.selector) // $flow-disable-line
|
||||
? document.getElementById(shouldScroll.selector.slice(1)) // $flow-disable-line
|
||||
: document.querySelector(shouldScroll.selector)
|
||||
|
||||
if (el) {
|
||||
let offset =
|
||||
shouldScroll.offset && typeof shouldScroll.offset === 'object'
|
||||
? shouldScroll.offset
|
||||
: {}
|
||||
offset = normalizeOffset(offset)
|
||||
position = getElementPosition(el, offset)
|
||||
} else if (isValidPosition(shouldScroll)) {
|
||||
position = normalizePosition(shouldScroll)
|
||||
}
|
||||
} else if (isObject && isValidPosition(shouldScroll)) {
|
||||
position = normalizePosition(shouldScroll)
|
||||
}
|
||||
|
||||
if (position) {
|
||||
// $flow-disable-line
|
||||
if ('scrollBehavior' in document.documentElement.style) {
|
||||
window.scrollTo({
|
||||
left: position.x,
|
||||
top: position.y,
|
||||
// $flow-disable-line
|
||||
behavior: shouldScroll.behavior
|
||||
})
|
||||
} else {
|
||||
window.scrollTo(position.x, position.y)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user