feat(iframe): 添加父窗口与iframe间的页面跳转API
暴露OCDIframeAPI接口,包含getFirstVisiblePageNo和gotoPage方法 移除demo.html中重复实现的页面跳转逻辑,改用新API
This commit is contained in:
parent
27c85de1c4
commit
1335932afa
63
demo.html
63
demo.html
|
|
@ -148,7 +148,14 @@
|
||||||
actions.className = 'bookmark-actions'
|
actions.className = 'bookmark-actions'
|
||||||
const jumpBtn = document.createElement('button')
|
const jumpBtn = document.createElement('button')
|
||||||
jumpBtn.textContent = '跳转'
|
jumpBtn.textContent = '跳转'
|
||||||
jumpBtn.onclick = () => navigateToPage(item.page)
|
jumpBtn.onclick = () => {
|
||||||
|
const api = editorFrame.contentWindow && editorFrame.contentWindow.OCDIframeAPI
|
||||||
|
if (api && typeof api.gotoPage === 'function') {
|
||||||
|
api.gotoPage(item.page)
|
||||||
|
} else {
|
||||||
|
alert('子页面未提供跳转 API')
|
||||||
|
}
|
||||||
|
}
|
||||||
const editBtn = document.createElement('button')
|
const editBtn = document.createElement('button')
|
||||||
editBtn.textContent = '编辑'
|
editBtn.textContent = '编辑'
|
||||||
editBtn.onclick = () => {
|
editBtn.onclick = () => {
|
||||||
|
|
@ -185,52 +192,20 @@
|
||||||
|
|
||||||
addBookmarkBtn.onclick = () => {
|
addBookmarkBtn.onclick = () => {
|
||||||
const name = getNextBookmarkName()
|
const name = getNextBookmarkName()
|
||||||
const page = getFirstVisiblePageNo()
|
let page = 1
|
||||||
|
try {
|
||||||
|
const api = editorFrame.contentWindow && editorFrame.contentWindow.OCDIframeAPI
|
||||||
|
if (api && typeof api.getFirstVisiblePageNo === 'function') {
|
||||||
|
page = api.getFirstVisiblePageNo()
|
||||||
|
} else {
|
||||||
|
console.warn('[demo] 子页面未暴露 getFirstVisiblePageNo,默认使用第1页')
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('[demo] 获取当前可见页失败,默认第1页', e)
|
||||||
|
}
|
||||||
addBookmark(name, page)
|
addBookmark(name, page)
|
||||||
}
|
}
|
||||||
|
|
||||||
function getFirstVisiblePageNo() {
|
|
||||||
const doc = editorFrame.contentDocument || editorFrame.contentWindow?.document
|
|
||||||
if (!doc) return 1
|
|
||||||
const iframeRect = editorFrame.getBoundingClientRect()
|
|
||||||
const canvases = Array.from(doc.querySelectorAll('canvas[data-index]'))
|
|
||||||
if (!canvases.length) return 1
|
|
||||||
const visible = canvases
|
|
||||||
.map(c => {
|
|
||||||
const rect = c.getBoundingClientRect()
|
|
||||||
const overlapY = Math.min(rect.bottom, iframeRect.bottom) - Math.max(rect.top, iframeRect.top)
|
|
||||||
return { c, rect, overlapY }
|
|
||||||
})
|
|
||||||
.filter(x => x.overlapY > 0)
|
|
||||||
.sort((a, b) => a.rect.top - b.rect.top)
|
|
||||||
|
|
||||||
let chosen = visible.length ? visible[0].c : null
|
|
||||||
if (!chosen) {
|
|
||||||
chosen = canvases.sort((a, b) => a.getBoundingClientRect().top - b.getBoundingClientRect().top)[0]
|
|
||||||
}
|
|
||||||
const idxStr = chosen?.getAttribute('data-index') || '0'
|
|
||||||
const idx = parseInt(idxStr, 10)
|
|
||||||
return Number.isFinite(idx) ? idx + 1 : 1
|
|
||||||
}
|
|
||||||
|
|
||||||
function navigateToPage(page) {
|
|
||||||
const doc = editorFrame.contentDocument || editorFrame.contentWindow?.document
|
|
||||||
if (!doc) return
|
|
||||||
const target0 = doc.querySelector(`canvas[data-index="${page - 1}"]`)
|
|
||||||
const target1 = doc.querySelector(`canvas[data-index="${page}"]`)
|
|
||||||
const canvas = target0 || target1
|
|
||||||
if (!canvas) {
|
|
||||||
alert(`未找到第${page}页`)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
canvas.scrollIntoView({ behavior: 'smooth', block: 'center' })
|
|
||||||
const evt = new MouseEvent('mousedown', { bubbles: true })
|
|
||||||
canvas.dispatchEvent(evt)
|
|
||||||
} catch (e) {
|
|
||||||
console.warn('跳转页失败', e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
editorFrame.addEventListener('load', () => {
|
editorFrame.addEventListener('load', () => {
|
||||||
renderBookmarks()
|
renderBookmarks()
|
||||||
|
|
|
||||||
844
public/test.ocd
844
public/test.ocd
File diff suppressed because one or more lines are too long
63
src/main.ts
63
src/main.ts
|
|
@ -456,6 +456,69 @@ window.onload = function () {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 在 iframe 场景下对父窗口暴露:当前页获取与页码跳转
|
||||||
|
// 说明:返回值与入参均为 1 基页码(第 1 页记为 1)
|
||||||
|
winAny.OCDIframeAPI = {
|
||||||
|
getFirstVisiblePageNo: (): number => {
|
||||||
|
try {
|
||||||
|
const container = instance.command.getContainer()
|
||||||
|
const canvases = Array.from(
|
||||||
|
container.querySelectorAll('canvas[data-index]')
|
||||||
|
) as HTMLCanvasElement[]
|
||||||
|
if (!canvases.length) return 1
|
||||||
|
const viewHeight = Math.max(
|
||||||
|
document.documentElement.clientHeight,
|
||||||
|
window.innerHeight || 0
|
||||||
|
)
|
||||||
|
const visible = canvases
|
||||||
|
.map(c => {
|
||||||
|
const rect = c.getBoundingClientRect()
|
||||||
|
const overlapY = Math.min(rect.bottom, viewHeight) - Math.max(rect.top, 0)
|
||||||
|
return { c, rect, overlapY }
|
||||||
|
})
|
||||||
|
.filter(x => x.overlapY > 0)
|
||||||
|
.sort((a, b) => a.rect.top - b.rect.top)
|
||||||
|
let chosen: HTMLCanvasElement | null = visible.length ? visible[0].c : null
|
||||||
|
if (!chosen) {
|
||||||
|
chosen = canvases.sort(
|
||||||
|
(a, b) => a.getBoundingClientRect().top - b.getBoundingClientRect().top
|
||||||
|
)[0] || null
|
||||||
|
}
|
||||||
|
const idx = Number((chosen?.dataset.index ?? '0'))
|
||||||
|
return Number.isFinite(idx) ? idx + 1 : 1
|
||||||
|
} catch {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
gotoPage: (pageNo: number): boolean => {
|
||||||
|
try {
|
||||||
|
if (!Number.isFinite(pageNo) || pageNo <= 0) return false
|
||||||
|
const index = Math.max(0, Math.floor(pageNo - 1))
|
||||||
|
const container = instance.command.getContainer()
|
||||||
|
const target = container.querySelector(
|
||||||
|
`canvas[data-index="${index}"]`
|
||||||
|
) as HTMLCanvasElement | null
|
||||||
|
if (!target) return false
|
||||||
|
// 滚动到该页(居中)
|
||||||
|
target.scrollIntoView({ behavior: 'smooth', block: 'center', inline: 'nearest' })
|
||||||
|
// 触发一次居中位置的 mousedown,让编辑器内部更新 pageNo
|
||||||
|
const rect = target.getBoundingClientRect()
|
||||||
|
const clientX = rect.left + rect.width / 2
|
||||||
|
const clientY = rect.top + rect.height / 2
|
||||||
|
const evt = new MouseEvent('mousedown', {
|
||||||
|
bubbles: true,
|
||||||
|
cancelable: true,
|
||||||
|
clientX,
|
||||||
|
clientY
|
||||||
|
})
|
||||||
|
target.dispatchEvent(evt)
|
||||||
|
return true
|
||||||
|
} catch {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const undoDom = document.querySelector<HTMLDivElement>('.menu-item__undo')!
|
const undoDom = document.querySelector<HTMLDivElement>('.menu-item__undo')!
|
||||||
undoDom.title = `撤销(${isApple ? '⌘' : 'Ctrl'}+Z)`
|
undoDom.title = `撤销(${isApple ? '⌘' : 'Ctrl'}+Z)`
|
||||||
undoDom.onclick = function () {
|
undoDom.onclick = function () {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user