feat: 单独保存预览窗口滚动条位置

This commit is contained in:
purocean
2021-08-05 17:24:45 +08:00
parent 0c8cd392dd
commit 499407461b
9 changed files with 127 additions and 72 deletions
+2 -38
View File
@@ -5,19 +5,14 @@
</template>
<script lang="ts">
import { debounce } from 'lodash-es'
import { defineComponent, nextTick, onBeforeMount, onMounted, ref, toRefs, watch } from 'vue'
import { useStore } from 'vuex'
import { useBus } from '@fe/support/bus'
import Storage from '@fe/utils/storage'
import { isEncrypted, saveDoc, toUri } from '@fe/context/document'
import { setScrollToTop, whenEditorReady } from '@fe/context/editor'
import { getActionHandler } from '@fe/context/action'
import { Doc } from '@fe/support/types'
import { whenEditorReady } from '@fe/context/editor'
import type { Doc } from '@fe/support/types'
import MonacoEditor from './MonacoEditor.vue'
const FILE_POSITION_KEY = 'filePosition'
export default defineComponent({
name: 'editor',
components: { MonacoEditor },
@@ -32,29 +27,12 @@ export default defineComponent({
const getEditor = () => refEditor.value
function saveFileOpenPosition (top: number) {
if (currentFile.value) {
const map = Storage.get(FILE_POSITION_KEY, {})
map[`${currentFile.value.repo}|${currentFile.value.path}`] = top
Storage.set(FILE_POSITION_KEY, map)
}
}
const saveFileOpenPositionDebounce = debounce((line: number) => {
saveFileOpenPosition(line)
}, 1000)
function setCurrentValue ({ uri, value }: { uri: string; value: any}) {
if (toUri(currentFile.value) === uri) {
store.commit('setCurrentContent', value)
}
}
function syncScrollView (line: number, top: number) {
getActionHandler('view.reveal-line')(line)
saveFileOpenPositionDebounce(top)
}
function clearTimer () {
if (timer) {
window.clearTimeout(timer)
@@ -108,14 +86,6 @@ export default defineComponent({
}
getEditor().setModel(toUri(current), current?.content ?? '\n')
if (current && current.status) {
// 切换文件时候保留定位
nextTick(() => {
const top = Storage.get(FILE_POSITION_KEY, {})[`${current.repo}|${current.path}`] || 1
setScrollToTop(top)
})
}
}
function resize () {
@@ -142,12 +112,6 @@ export default defineComponent({
changeFile(currentFile.value)
}
editor.onDidScrollChange(() => {
const line = Math.max(1, editor.getVisibleRanges()[0].startLineNumber - 2)
const top = editor.getScrollTop()
syncScrollView(line, top)
})
editor.addCommand(monaco.KeyMod.CtrlCmd | monaco.KeyCode.KEY_S, () => {
saveFile()
})
+9 -2
View File
@@ -147,14 +147,19 @@ export default defineComponent({
function handleScroll (e: any) {
scrollTop.value = e.target.scrollTop
triggerHook('ON_VIEW_SCROLL', e)
}
function syncScroll (line: number) {
revealLineInCenter(line)
}
function scrollTopTo (top: number) {
refViewWrapper.value!.scrollTo(0, top)
}
function scrollToTop () {
refViewWrapper.value!.scrollTo(0, 0)
scrollTopTo(0)
syncScroll(1)
}
@@ -168,7 +173,7 @@ export default defineComponent({
function revealLine (line: number) {
if (line <= 1) {
refViewWrapper.value!.scrollTo(0, 0)
scrollTopTo(0)
return
}
@@ -213,6 +218,7 @@ export default defineComponent({
triggerHook('ON_VIEW_MOUNTED', { getViewDom })
registerAction({ name: 'view.refresh', handler: render })
registerAction({ name: 'view.reveal-line', handler: revealLine })
registerAction({ name: 'view.scroll-top-to', handler: scrollTopTo })
window.addEventListener('keydown', keydownHandler, true)
bus.on('global.resize', resizeHandler)
resizeHandler()
@@ -221,6 +227,7 @@ export default defineComponent({
onBeforeUnmount(() => {
removeAction('view.refresh')
removeAction('view.reveal-line')
removeAction('view.scroll-top-to')
window.removeEventListener('keydown', keydownHandler)
bus.off('global.resize', resizeHandler)
})
+2 -2
View File
@@ -33,7 +33,7 @@ import markdownMermaid from '@fe/plugins/markdown-mermaid'
import markdownApplet from '@fe/plugins/markdown-applet'
import markdownEcharts from '@fe/plugins/markdown-echarts'
import markdownLuckysheet from '@fe/plugins/markdown-luckysheet'
import viewSyncScroll from '@fe/plugins/view-sync-scroll'
import syncScroll from '@fe/plugins/sync-scroll'
export default [
documentHistoryStack,
@@ -71,5 +71,5 @@ export default [
markdownApplet,
markdownEcharts,
markdownLuckysheet,
viewSyncScroll,
syncScroll,
]
+1
View File
@@ -33,6 +33,7 @@ const ctx = {
statusBar,
layout,
editor,
view,
theme,
storage,
embed
+16 -1
View File
@@ -1,10 +1,25 @@
import { getActionHandler } from './action'
export type HookType = 'ON_VIEW_ELEMENT_CLICK'
| 'ON_VIEW_ELEMENT_DBCLICK'
| 'ON_VIEW_KEY_DOWN'
| 'ON_VIEW_SCROLL'
| 'ON_VIEW_RENDER'
| 'ON_VIEW_RENDERED'
| 'ON_VIEW_MOUNTED'
| 'ON_VIEW_FILE_CHANGE'
| 'ON_VIEW_BEFORE_CONVERT'
export type ActionName = 'view.refresh' | 'view.reveal-line'
export type ActionName = 'view.refresh' | 'view.reveal-line' | 'view.scroll-top-to'
export function refresh () {
getActionHandler('view.refresh')()
}
export function revealLine (line: number) {
getActionHandler('view.reveal-line')(line)
}
export function scrollTopTo (top: number) {
getActionHandler('view.scroll-top-to')(top)
}
+8 -8
View File
@@ -2,6 +2,7 @@ import StateCore from 'markdown-it/lib/rules_core/state_core'
import Token from 'markdown-it/lib/token'
import { Plugin, Ctx } from '@fe/context/plugin'
import store from '@fe/support/store'
import { sleep } from '@fe/utils'
import { isElectron, nodeRequire } from '@fe/utils/env'
import { basename, dirname, join } from '@fe/utils/path'
import { switchDoc } from '@fe/context/document'
@@ -43,12 +44,11 @@ const handleLink = (link: HTMLAnchorElement) => {
name: basename(path),
repo: fileRepo,
type: 'file'
})
// 跳转锚点
const hash = tmp.slice(1).join('#')
if (hash) {
setTimeout(() => {
}).then(async () => {
const hash = tmp.slice(1).join('#')
// 跳转锚点
if (hash) {
await sleep(50)
const el = document.getElementById(hash) ||
document.getElementById(encodeURIComponent(hash))
@@ -59,8 +59,8 @@ const handleLink = (link: HTMLAnchorElement) => {
}
el.scrollIntoView()
}
}, 50)
}
}
})
return true
} else if (href && href.startsWith('#')) { // 处理 TOC 跳转
+83
View File
@@ -0,0 +1,83 @@
import { debounce } from 'lodash-es'
import type { Plugin, Ctx } from '@fe/context/plugin'
import type { Doc } from '@fe/support/types'
import { sleep } from '@fe/utils'
export default {
name: 'sync-scroll',
register: (ctx: Ctx) => {
type ScrollTop = { editor?: number, view?: number }
const STORAGE_KEY = 'plugin.scroll-position'
let enableSyncScroll = true
function saveScrollPosition (scrollTop: ScrollTop) {
const key = ctx.doc.toUri(ctx.store.state.currentFile)
const data: Record<string, ScrollTop> = ctx.storage.get(STORAGE_KEY, {})
data[key] = { ...data[key], ...scrollTop }
ctx.storage.set(STORAGE_KEY, data)
}
// 切换文件后恢复滚动位置
let xTimer: any
ctx.bus.on('doc.switched', async (file?: Doc) => {
if (file) {
await sleep(0)
const key = ctx.doc.toUri(ctx.store.state.currentFile)
const data: Record<string, ScrollTop> = ctx.storage.get(STORAGE_KEY, {})
const position = data[key] || { editor: 0, view: 0 }
await ctx.editor.whenEditorReady()
clearTimeout(xTimer)
enableSyncScroll = false
ctx.editor.setScrollToTop(position.editor || 1)
if (typeof position.view === 'number') {
await sleep(0)
ctx.view.scrollTopTo(position.view)
}
xTimer = setTimeout(() => {
enableSyncScroll = true
}, 500)
}
})
ctx.editor.whenEditorReady().then(({ editor }) => {
const savePosition = debounce(saveScrollPosition, 500)
editor.onDidScrollChange(() => {
const line = Math.max(1, editor.getVisibleRanges()[0].startLineNumber - 2)
const top = editor.getScrollTop()
if (enableSyncScroll) {
ctx.view.revealLine(line)
}
savePosition({ editor: top })
})
})
const savePosition = debounce(saveScrollPosition, 500)
ctx.registerHook('ON_VIEW_SCROLL', (e: WheelEvent) => {
if (ctx.store.state.currentFile?.status) {
const { scrollTop } = e.target as HTMLElement
savePosition({ view: scrollTop })
}
})
ctx.registerHook('ON_VIEW_ELEMENT_CLICK', async (e: MouseEvent) => {
const target = e.target as HTMLElement
if (
ctx.store.state.showEditor &&
!ctx.store.state.presentation &&
target.classList.contains('source-line') &&
window.getSelection()!.toString().length < 1
) {
ctx.editor.revealLineInCenter(parseInt(target.dataset.sourceLine || '0'))
}
return false
})
}
} as Plugin
-21
View File
@@ -1,21 +0,0 @@
import { Plugin, Ctx } from '@fe/context/plugin'
export default {
name: 'view-sync-scroll',
register: (ctx: Ctx) => {
ctx.registerHook('ON_VIEW_ELEMENT_CLICK', async (e: MouseEvent) => {
const target = e.target as HTMLElement
if (
ctx.store.state.showEditor &&
!ctx.store.state.presentation &&
target.classList.contains('source-line') &&
window.getSelection()!.toString().length < 1
) {
ctx.editor.revealLineInCenter(parseInt(target.dataset.sourceLine || '0'))
}
return false
})
}
} as Plugin
+6
View File
@@ -42,3 +42,9 @@ export const getLogger = (subject: string) => {
error: logger('error')
}
}
export function sleep (ms: number) {
return new Promise(resolve => {
setTimeout(resolve, ms)
})
}