最近在建設內部監控平台站點(React + antd),文檔方面選擇的是目前主流的靜態內容站點生成器 VuePress
,進一步考慮希望提供給用戶一站式的訪問體驗打算將文檔內容直接內嵌至站點系統中,短平快地通過 iframe
接入後遇到了兩個問題,特此記錄。
文檔無法完全顯示#
具體現象是點擊導航欄的文檔中心 Tab 後內容展示不全,只能展示上部一截,下面是大段的空白,很明顯是 iframe
默認的高度不夠。
通過修改父層元素為 100vh + 100% 可簡單實現高度自適應:
// pages/docs/*.tsx
import React, { useState, useEffect } from 'react';
const docs_url =
process.env.NODE_ENV === 'production'
? 'http://xxx.com/monitor'
: 'http://localhost:8088/monitor';
const frameRef = React.createRef<any>();
const DocsView = () => {
const [src, setSrc] = useState(
docs_url + window.location.href.split('/docs')[1],
);
useEffect(() => {
const pageMain = document.getElementsByClassName('page-main')[0];
pageMain.setAttribute('style', 'height: 100vh');
const antRow = pageMain.getElementsByClassName(
'ant-row ant-row-center ant-row-middle',
)[0];
antRow.setAttribute('style', 'height: 100%');
return () => {
pageMain.removeAttribute('style');
antRow.removeAttribute('style');
};
}, []);
return (
<iframe
ref={frameRef}
src={src}
style={{
width: '100%',
height: '100%',
border: 0,
}}
></iframe>
);
};
文檔訪問狀態留存#
當用戶訪問文檔其中某個部分後需要更新對應的鏈接錨點,這樣不管是刷新頁面或是分享鏈接出去都可以直接訪問。
實現關鍵在於解決站點系統與 VuePress
之間的通信問題,即站點系統需要知道 VuePress
內部訪問了具體文檔的地址同時更新至鏈接路由地址上。
最終選用的方案如下:VuePress
中監聽點擊事件通過 postMessage
通知站點跳轉 href 來修改外部路由(history.replaceState
)實現路由以及 iframe src 動態改變:
// .vuepress/config.js
module.exports = {
// https://vuepress.vuejs.org/zh/config/#head 注入到頁面 HTML 中的標籤
head: [
['script', { src: '/postMessage.js' }],
],
//...
}
// .vuepress/public/postMessage.js
var topUrl = document.referrer;
document.addEventListener(
'click',
function(e) {
var target = e.target;
if (target.tagName !== 'A' && target.parentNode.tagName === 'A') {
target = target.parentNode;
}
var href = target.getAttribute('href');
if (href && href.indexOf('/') === 0) {
top.postMessage(
{
type: 'monitor_docs_msg',
link: href,
},
topUrl,
);
}
},
false,
);
最後在內嵌 iframe 組件中還需要監聽 message
事件:
// ...
useEffect(() => {
const handleSetSrc = (e: any) => {
if (e.data.type?.includes('monitor_docs')) {
const links = e.data.link?.split('/monitor');
// 變更地址,系統路由直接外鏈寫死
window.history.replaceState(null, '', `/docs${links[1] || links[0]}`);
}
};
window.addEventListener('message', (e) => handleSetSrc(e));
//...
return () => {
// ...
window.removeEventListener('message', (e) => handleSetSrc(e));
};
}, []);
//...