fix(submit): let the editor iframe grow with the body instead of scrolling internally
正文超过 iframe 高度时会在编辑器内部出现第二根滚动条,正文应该随页面一起变长。 登录态实测确认了滚动来源与两个副作用: 1. 经典投稿表单完全没做高度同步(iframe 固定 504px,正文 1824px → 内滚动)。 在共用基础插件里补上 syncHeight():测量正文高度并同步 iframe, 下限取编辑器声明高度;图片加载后重新同步。工作台自带 syncEditorHeight() 负责块浮层定位,用 __jioStudioOwnsEditorHeight 让插件跳过,避免双写。 2. 直接量 scrollHeight 会把 body 的 min-height 撑满算进内容高度,形成 「撑高 → 再撑高」的反馈循环(实测涨到 22616px)。测量时临时把 min-height 归零、同帧恢复。 3. body 的 min-height 基准从 100% 改成 100vh:iframe 随正文变高, 百分比会跟着循环;同时把 WordPress content CSS 的 body 外边距改内边距, 外边距不计入高度,会让 html 比 iframe 高一截、长正文时又冒出内滚动。 登录态实测(studio 与经典两条路径): - iframe 2152px / 1874px,与正文一致,innerHasScrollbar=false; - 空正文占位符正常、点击空白落光标正常; - 只有页面级滚动。 测试:新增 iframe 随正文增长、测量忽略 min-height 两个回归用例;903 全通过。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
305896796c
commit
4f9347b6aa
7 files changed
+164
-38
No files matched your search
@@ -9,8 +9,17 @@
|
||||
*/
|
||||
|
||||
export const EDITOR_CONTENT_STYLE = `
|
||||
/*
|
||||
* 正文撑满编辑区:内容很短时点击正文下方的空白区域也应落光标。
|
||||
* iframe 高度由 syncEditorHeight() 跟随内容。
|
||||
*
|
||||
* 高度基准取 iframe 视口(100vh 而不是 100%):iframe 会随正文同步变高,
|
||||
* 用百分比会形成「撑高 → 再撑高」的循环。100vh 只保证空正文铺满一屏。
|
||||
*/
|
||||
body {
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
min-height: 100vh;
|
||||
margin: 0;
|
||||
color: #2b2b2b;
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Noto Sans SC", "PingFang SC", "Microsoft YaHei", sans-serif;
|
||||
@@ -36,22 +45,6 @@ body[data-jio-empty="1"]::before {
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
/*
|
||||
* body 撑满编辑区:内容很短时点击正文下方的空白区域也应落光标。
|
||||
* iframe 高度由 syncEditorHeight() 跟随内容,这里保证 body 至少铺满。
|
||||
*
|
||||
* min-height:100% 依赖父级有确定高度,所以 html 必须 height:100%
|
||||
* (只写 min-height 的话 html 的高度仍由内容决定,百分比会退化成 auto)。
|
||||
*/
|
||||
html {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
box-sizing: border-box;
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6 { margin: 1.5em 0 0.65em; line-height: 1.4; }
|
||||
img, iframe { max-width: 100%; }
|
||||
img { height: auto; }
|
||||
|
||||
@@ -89,8 +89,10 @@ export function removeAdjacentBlock(editor: any, event: any): void {
|
||||
* 页面整体滚动由外层工作台负责。
|
||||
*
|
||||
* 下限取编辑器初始化时声明的高度(studio 为 520),这样正文很短时 iframe
|
||||
* 也保持一个完整写作区,空白处由 content CSS 的 body min-height 撑满,
|
||||
* 点击正文下方仍能落光标。
|
||||
* 也保持一个完整写作区,空白处由 content CSS 的 body min-height 撑满。
|
||||
*
|
||||
* 测量时必须先摘掉 body 的 min-height:它按 iframe 视口撑满,直接量
|
||||
* scrollHeight 会得到「撑高 → 再撑高」的反馈循环。
|
||||
*/
|
||||
export function syncEditorHeight(editor: any): void {
|
||||
if (!editor || editor.removed) {
|
||||
@@ -98,17 +100,22 @@ export function syncEditorHeight(editor: any): void {
|
||||
}
|
||||
const doc = editor.getDoc();
|
||||
const iframe = editor.getContentAreaContainer()?.querySelector('iframe') as HTMLIFrameElement | null;
|
||||
if (!doc || !iframe) {
|
||||
if (!doc || !doc.body || !iframe) {
|
||||
return;
|
||||
}
|
||||
const body = doc.body;
|
||||
const prevMinHeight = body.style.minHeight;
|
||||
body.style.minHeight = '0';
|
||||
const contentHeight = Math.max(body.scrollHeight, body.offsetHeight);
|
||||
body.style.minHeight = prevMinHeight;
|
||||
|
||||
const floor = Math.max(320, Number(editor.getParam?.('height', 0)) || 0);
|
||||
const height = Math.max(
|
||||
floor,
|
||||
doc.documentElement.scrollHeight,
|
||||
doc.body ? doc.body.scrollHeight : 0
|
||||
);
|
||||
iframe.style.height = `${height}px`;
|
||||
const height = Math.max(floor, contentHeight);
|
||||
if (iframe.style.height !== `${height}px`) {
|
||||
iframe.style.height = `${height}px`;
|
||||
}
|
||||
iframe.style.overflow = 'hidden';
|
||||
iframe.setAttribute('scrolling', 'no');
|
||||
}
|
||||
|
||||
/** 块选中状态写在块自身的 class 上,跨 iframe 重排也能保留。 */
|
||||
|
||||
@@ -380,6 +380,8 @@ function Studio(): JSX.Element {
|
||||
external_plugins: bootstrap.creator?.editorBasicsPlugin
|
||||
? { jio_editor_basics: bootstrap.creator.editorBasicsPlugin }
|
||||
: undefined,
|
||||
// 高度由 editor-runtime 的 syncEditorHeight() 接管(还要配合块浮层定位),
|
||||
// 基础插件据此跳过自己的高度同步。
|
||||
wpautop: true,
|
||||
body_class: 'jio-creator__tinymce',
|
||||
content_css: bootstrap.creator?.contentCss || '',
|
||||
@@ -388,6 +390,8 @@ function Studio(): JSX.Element {
|
||||
height: 520,
|
||||
placeholder: String(bootstrap.limits?.contentPlaceholder || ''),
|
||||
setup: (editor: any) => {
|
||||
// 告诉共用基础插件:高度由 syncEditorHeight() 负责。
|
||||
(window as any).__jioStudioOwnsEditorHeight = true;
|
||||
editorRef.current = editor;
|
||||
editor.on('init', () => {
|
||||
editorReadyRef.current = true;
|
||||
@@ -430,6 +434,7 @@ function Studio(): JSX.Element {
|
||||
wpEditor.remove?.(EDITOR_ID);
|
||||
editorReadyRef.current = false;
|
||||
editorRef.current = null;
|
||||
delete (window as any).__jioStudioOwnsEditorHeight;
|
||||
};
|
||||
}, [updateContent, updateBlockValue, updateFormatValue]);
|
||||
|
||||
|
||||
Reference in new issue
Block a user