checkJS + scroll position

pull/1/head
Evan You 4 years ago
parent ba8de9fba7
commit 444b362dea

@ -0,0 +1,57 @@
import { reactive, provide } from 'vue'
export const RouteSymbol = Symbol()
export function useRouter() {
const route = reactive({
path: location.pathname,
scrollPosition: window.scrollY
})
window.addEventListener(
'click',
/**
* @param {*} e
*/
(e) => {
if (e.target.tagName === 'A') {
const { href, target } = e.target
if (
target !== `_blank` &&
href.startsWith(`${location.protocol}//${location.host}`)
) {
e.preventDefault()
// save scroll position before changing url
saveScrollPosition()
history.pushState(null, '', href)
route.path = location.pathname
route.scrollPosition = 0
}
}
},
{ capture: true }
)
window.addEventListener(
'popstate',
/**
* @param {*} e
*/
(e) => {
route.path = location.pathname
route.scrollPosition = e.state && e.state.scrollPosition || 0
}
)
provide(RouteSymbol, route)
}
function saveScrollPosition() {
history.replaceState(
{
scrollPosition: window.scrollY
},
document.title,
''
)
}

@ -1,46 +1,14 @@
import {
createApp,
ref,
h,
provide,
inject,
watchEffect,
shallowRef
} from '/@modules/vue'
import { createApp, h, inject, watchEffect, shallowRef, nextTick } from 'vue'
import { Layout } from '/@theme/index.js'
const PathSymbol = Symbol()
import { useRouter, RouteSymbol } from './composables/router.js'
const App = {
setup() {
const path = ref(location.pathname)
window.addEventListener(
'click',
(e) => {
if (e.target.tagName === 'A') {
const { href, target } = e.target
if (
target !== `_blank` &&
href.startsWith(`${location.protocol}//${location.host}`)
) {
e.preventDefault()
// TODO save scroll position
history.pushState(null, '', href)
path.value = location.pathname
}
}
},
{ capture: true }
)
window.addEventListener('popstate', (e) => {
// TODO restore scroll position
path.value = location.pathname
})
provide(PathSymbol, path)
if (typeof window !== 'undefined') {
useRouter()
} else {
// TODO inject static route for SSR
}
return () => h(Layout)
}
}
@ -49,24 +17,46 @@ const Default404 = () => '404 Not Found'
const Content = {
setup() {
const path = inject(PathSymbol)
const comp = shallowRef()
watchEffect(() => {
let pagePath = path.value.replace(/\.html$/, '')
if (pagePath.endsWith('/')) {
pagePath += 'index'
}
if (typeof window !== 'undefined') {
/**
* @type {{ path: string, scrollPosition: number }}
*/
const route = inject(RouteSymbol, {
path: '/',
scrollPosition: 0
})
watchEffect(() => {
const pendingPath = route.path
let pagePath = pendingPath.replace(/\.html$/, '')
if (pagePath.endsWith('/')) {
pagePath += 'index'
}
// awlays force re-fetch content in dev
import(`${pagePath}.md?t=${Date.now()}`)
.then((m) => {
comp.value = m.default
})
.catch((err) => {
comp.value = Default404
})
})
// awlays force re-fetch content in dev
import(`${pagePath}.md?t=${Date.now()}`)
.then(async (m) => {
if (route.path === pendingPath) {
comp.value = m.default
await nextTick()
window.scrollTo({
left: 0,
top: route.scrollPosition,
behavior: 'auto'
})
}
})
.catch((err) => {
if (route.path === pendingPath) {
comp.value = Default404
}
})
})
} else {
// TODO SSR
}
return () => (comp.value ? h(comp.value) : null)
}

5
lib/shim.d.ts vendored

@ -0,0 +1,5 @@
declare module "*.vue" {
import { ComponentOptions } from 'vue'
const comp: ComponentOptions
export default comp
}

@ -7,6 +7,11 @@
"bin": {
"vitepress": "bin/vitepress.js"
},
"files": [
"bin",
"lib",
"dist"
],
"scripts": {
"dev": "tsc -w -p ."
},

@ -3,19 +3,24 @@
"baseUrl": ".",
"outDir": "./dist",
"module": "commonjs",
"lib": ["ESNext"],
"lib": ["ESNext", "DOM"],
"sourceMap": false,
"target": "esnext",
"moduleResolution": "node",
"esModuleInterop": true,
"declaration": true,
"allowJs": false,
"allowJs": true,
"checkJs": true,
"allowSyntheticDefaultImports": true,
"noUnusedLocals": true,
"strictNullChecks": true,
"noImplicitAny": true,
"removeComments": false,
"preserveSymlinks": true
"preserveSymlinks": true,
"paths": {
"/@app/*": ["lib/app/*"],
"/@theme/*": ["lib/theme-default/*"]
}
},
"include": ["src"]
"include": ["src", "lib"]
}

Loading…
Cancel
Save