by-onlineeditor/demo.html
hanshiyang 1335932afa feat(iframe): 添加父窗口与iframe间的页面跳转API
暴露OCDIframeAPI接口,包含getFirstVisiblePageNo和gotoPage方法
移除demo.html中重复实现的页面跳转逻辑,改用新API
2025-12-02 11:26:54 +08:00

216 lines
8.8 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Canvas Editor Iframe Demo</title>
<style>
body { font-family: system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial; margin: 0; padding: 16px; }
.panel { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; margin-bottom: 12px; }
.panel input[type="text"] { width: 420px; padding: 6px 8px; font-size: 12px; }
.panel button { padding: 6px 12px; font-size: 12px; cursor: pointer; }
.layout { display: flex; gap: 12px; align-items: flex-start; }
.sidebar { width: 280px; border: 1px solid #e2e6ed; border-radius: 8px; padding: 12px; background: #fafafa; }
.sidebar h4 { margin: 0 0 8px; font-weight: 600; font-size: 14px; }
.bookmark-form { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 10px; }
.bookmark-form input { flex: 1; min-width: 0; padding: 6px 8px; font-size: 12px; }
.bookmark-form input[type="number"] { width: 80px; }
.bookmark-form button { padding: 6px 12px; font-size: 12px; cursor: pointer; }
.bookmark-list { list-style: none; padding: 0; margin: 0; }
.bookmark-item { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 8px; border-bottom: 1px solid #eee; }
.bookmark-item span { font-size: 12px; color: #111827; }
.bookmark-actions { display: flex; gap: 6px; }
.bookmark-actions button { padding: 4px 8px; font-size: 12px; cursor: pointer; }
.editorWrap { flex: 1; }
iframe { width: 100%; height: 80vh; border: 1px solid #e2e6ed; }
small { color: #6b7280; }
</style>
</head>
<body>
<h3>父页面通过地址拼接加载子页面filePath + mode=edit</h3>
<div class="panel">
<input id="urlInput" type="text" placeholder="输入同源文件URL" />
<label style="display:flex;align-items:center;gap:6px;">
<input id="editModeToggle" type="checkbox" />
<span>编辑模式(勾选则拼接 mode=edit不勾选为只读</span>
</label>
<button id="loadBtn">设置 iframe 地址</button>
<small>示例vocd.html?filePath=URL&mode=edit 或 vocd.html?filePath=URL</small>
</div>
<div class="layout">
<aside class="sidebar">
<h4>书签</h4>
<div class="bookmark-form">
<button id="addBookmarkBtn">添加书签</button>
<small>自动命名为书签N+1页码取当前可见页</small>
</div>
<ul id="bookmarkList" class="bookmark-list"></ul>
</aside>
<div class="editorWrap">
<iframe id="editorFrame" src="./vocd.html" referrerpolicy="no-referrer"></iframe>
</div>
</div>
<script>
const editorFrame = document.getElementById('editorFrame')
const loadBtn = document.getElementById('loadBtn')
const urlInput = document.getElementById('urlInput')
const editModeToggle = document.getElementById('editModeToggle')
const addBookmarkBtn = document.getElementById('addBookmarkBtn')
const bookmarkList = document.getElementById('bookmarkList')
function buildSrc(filePath, isEdit) {
const base = './vocd.html'
return `${base}?filePath=${encodeURIComponent(filePath)}` + (isEdit ? '&mode=edit' : '')
}
// 页面加载后,自动将 iframe 指向 vocd.html 并使用同源 /test.ocd
document.addEventListener('DOMContentLoaded', () => {
const defaultUrl = '/test.ocd' // 来自 public同源可直接访问
urlInput.value = defaultUrl
const base = './vocd.html'
// 默认不勾选:只读模式(不拼接 mode
editModeToggle.checked = false
const src = buildSrc(defaultUrl, editModeToggle.checked)
editorFrame.src = src
console.log('[demo] 自动设置 iframe src:', src)
renderBookmarks()
})
// 切换编辑模式时,刷新 iframe 地址,保留当前 filePath
editModeToggle.addEventListener('change', () => {
const typedUrl = urlInput.value.trim()
const currentAbs = editorFrame.src || './vocd.html'
const currentUrl = new URL(currentAbs, window.location.href)
const currentFilePath = currentUrl.searchParams.get('filePath') || (typedUrl || '/test.ocd')
const src = buildSrc(currentFilePath, editModeToggle.checked)
editorFrame.src = src
console.log('[demo] 编辑模式切换,刷新 iframe src:', src)
renderBookmarks()
})
loadBtn.onclick = () => {
const typedUrl = urlInput.value.trim()
const base = './vocd.html'
const targetUrl = typedUrl || '/test.ocd'
const src = buildSrc(targetUrl, editModeToggle.checked)
editorFrame.src = src
console.log('[demo] 设置 iframe src:', src)
renderBookmarks()
}
function getCurrentFilePath() {
const currentAbs = editorFrame.src || './vocd.html'
const currentUrl = new URL(currentAbs, window.location.href)
return currentUrl.searchParams.get('filePath') || '/test.ocd'
}
function getBookmarkKey() {
const fp = getCurrentFilePath()
return `bookmarks:${fp}`
}
function readBookmarks() {
try {
const raw = localStorage.getItem(getBookmarkKey())
return raw ? JSON.parse(raw) : []
} catch {
return []
}
}
function writeBookmarks(list) {
localStorage.setItem(getBookmarkKey(), JSON.stringify(list))
}
function getNextBookmarkName() {
const list = readBookmarks()
let maxN = 0
list.forEach(b => {
const m = /^书签(\d+)$/.exec(String(b.name || ''))
if (m) {
const n = parseInt(m[1], 10)
if (Number.isFinite(n)) maxN = Math.max(maxN, n)
}
})
return `书签${maxN + 1}`
}
function renderBookmarks() {
const list = readBookmarks()
bookmarkList.innerHTML = ''
list.forEach(item => {
const li = document.createElement('li')
li.className = 'bookmark-item'
const label = document.createElement('span')
label.textContent = `${item.name}(第${item.page}页)`
const actions = document.createElement('div')
actions.className = 'bookmark-actions'
const jumpBtn = document.createElement('button')
jumpBtn.textContent = '跳转'
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')
editBtn.textContent = '编辑'
editBtn.onclick = () => {
const newName = window.prompt('书签名称', item.name) || item.name
const newPageStr = window.prompt('页码(正整数)', String(item.page)) || String(item.page)
const newPage = Math.max(1, parseInt(newPageStr, 10) || item.page)
const list2 = readBookmarks().map(b => (b.id === item.id ? { ...b, name: newName, page: newPage } : b))
writeBookmarks(list2)
renderBookmarks()
}
const delBtn = document.createElement('button')
delBtn.textContent = '删除'
delBtn.onclick = () => {
const list2 = readBookmarks().filter(b => b.id !== item.id)
writeBookmarks(list2)
renderBookmarks()
}
actions.appendChild(jumpBtn)
actions.appendChild(editBtn)
actions.appendChild(delBtn)
li.appendChild(label)
li.appendChild(actions)
bookmarkList.appendChild(li)
})
}
function addBookmark(name, page) {
const list = readBookmarks()
const id = Date.now().toString(36) + Math.random().toString(36).slice(2)
const item = { id, name, page }
writeBookmarks([...list, item])
renderBookmarks()
}
addBookmarkBtn.onclick = () => {
const name = getNextBookmarkName()
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)
}
editorFrame.addEventListener('load', () => {
renderBookmarks()
})
</script>
</body>
</html>