Archived
基线:鉴权会话+工作组+工作台三区修复+编排工作区+产品设计文档
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
This commit is contained in:
@@ -2,23 +2,62 @@
|
||||
* 视图区容器 —— **净化渲染,无脚本执行权**(编码规范 §9.2;语义出处 AM 07)。
|
||||
*
|
||||
* 「视图区容器渲染活动推送的 HTML:沙箱 iframe(srcdoc + sandbox)或净化后注入,
|
||||
* 二选一由 `ui-kit` 的 `ViewContainer` 统一实现,**feature 不得自行 dangerouslySetInnerHTML**。」
|
||||
* 二选一由 `ui-kit` 的 `ViewContainer` 统一实现,**feature 不得自行 dangerouslySetInnerHTML`。」
|
||||
*
|
||||
* 这里选沙箱 iframe:结构上就没有脚本执行权,不依赖净化算法的完备性。
|
||||
*
|
||||
* **高度随内容长**:HTML 报告既是独立文件,也是交互视图的组成部分 ——
|
||||
* 它得像页面里的一段正文那样整篇铺开、跟着外层一起滚,而不是缩在一个定高小窗里自己滚。
|
||||
* 定高会把长报告拦腰截断,人得在两层滚动条之间来回找。
|
||||
*/
|
||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||
|
||||
export type ViewContainerProps = {
|
||||
readonly html: string;
|
||||
readonly title?: string;
|
||||
};
|
||||
|
||||
/** 量不到高度时的兜底,避免塌成 0 高 */
|
||||
const FALLBACK_HEIGHT = 420;
|
||||
|
||||
export function ViewContainer({ html, title = '活动视图' }: ViewContainerProps) {
|
||||
const ref = useRef<HTMLIFrameElement>(null);
|
||||
const [height, setHeight] = useState(FALLBACK_HEIGHT);
|
||||
|
||||
const measure = useCallback(() => {
|
||||
const doc = ref.current?.contentDocument;
|
||||
if (doc?.documentElement == null) return;
|
||||
// 取 body 与 documentElement 的较大者:两者谁撑开高度随文档结构而异
|
||||
const next = Math.max(doc.documentElement.scrollHeight, doc.body?.scrollHeight ?? 0);
|
||||
if (next > 0) setHeight(next);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const frame = ref.current;
|
||||
const doc = frame?.contentDocument;
|
||||
if (doc?.body == null) return undefined;
|
||||
// 图片late-load、字体回流都会改高度 —— 盯着 body 尺寸变化重量一次
|
||||
const observer = new ResizeObserver(measure);
|
||||
observer.observe(doc.body);
|
||||
return () => observer.disconnect();
|
||||
}, [measure, html]);
|
||||
|
||||
return (
|
||||
<iframe
|
||||
ref={ref}
|
||||
className="jc-view-frame"
|
||||
title={title}
|
||||
// sandbox 不含 allow-scripts —— 无脚本执行权
|
||||
sandbox=""
|
||||
/*
|
||||
* `allow-same-origin` **只为让外层量到内容高度**(否则 iframe 是不透明源,
|
||||
* contentDocument 读不到,高度无从得知)。
|
||||
* 关键在于**始终不给 `allow-scripts`** —— 里面一行脚本也跑不了,
|
||||
* 「无脚本执行权」这条不变。两者同时给才是破沙箱,这里永远不会。
|
||||
*/
|
||||
sandbox="allow-same-origin"
|
||||
srcDoc={html}
|
||||
style={{ height }}
|
||||
onLoad={measure}
|
||||
scrolling="no"
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user