将内容动态写入 iframe



我用它来预览电子邮件

当我动态地将 HTML 写入 iframe 时,不知何故省略了<body>标记?body 标签包含font-family等,但现在整个标签都消失了,HTML 文档无法正确显示

const iframe_content = $('#'+iframe_id).contents().find('html');
iframe_content.html(data.html);

data.html的内容

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="color-scheme" content="light dark">
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>@media (prefers-color-scheme: dark){
.body_inner{background:#000 !important}
.content{border:0}
.content_inner{background:#000 !important;color:#fff !important}
}</style>
</head>
<body style="margin:0;padding:0;font-family:arial,helvetica,garuda">
<div>first element</div>
</body>
</html>

将 HTML 写入 iframe 后,iframe 的源代码如下所示(body 标记不见了!

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="color-scheme" content="light dark">
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>@media (prefers-color-scheme: dark){
.body_inner{background:#000 !important}
.content{border:0}
.content_inner{background:#000 !important;color:#fff !important}
}</style>
</head>
<div>first element</div>
</html>

我尝试通过 https://validator.w3.org/验证 HTML,没有错误

原因是 jQuery 的.html(value)方法不用于设置带有(顶级)<html>标签的内容。我们可以在jQuery源代码中看到这一点。当调用iframe_content.html(data.html);时,在jQuery库内进行以下调用:

html()调用access(),它调用(通过回调)append(),它调用domManip(),它调用buildFragment(),执行以下代码,其中elem是作为参数传递的data.htmlfragment是 documentFragment:

tmp = tmp || fragment.appendChild( context.createElement( "div" ) );
// Deserialize a standard representation
tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase();
wrap = wrapMap[ tag ] || wrapMap._default;
tmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ];

所以tmp是一个<div>元素(因为appendChild返回参数)。tag设置为 "html",wrap设置为[0, "", ""]jQuery.htmlPrefilter(elem)只返回elem。简而言之,这是执行的:

tmp.innerHTML = elem;

问题是HTML不允许<div>元素具有<html><head><body>元素作为子元素,因此DOM(不是jQuery)不会按预期创建这些DOM元素。

这不是jQuery处理的结束,但是在这一点上我们已经可以看到信息已经丢失。

解决方法

由于 jQuery 的.html(value)方法无法完成这项工作,请绕过 jQuery 并直接设置innerHTML。替换此内容:

iframe_content.html(data.html);

有了这个:

iframe_content.get(0).innerHTML = data.html;

现在它将起作用。

你试过使用 Shadow DOM 吗?

所有样式都像 iframe 一样封装,但您还可以获得自然扩展内容(与 iframe 的固定高度相比)和更快的渲染时间的额外好处。

用法示例:

const shadow = someParentElement.attachShadow({
mode: 'closed'
});
shadow.innerHTML = `<whatever>`;

相关内容

  • 没有找到相关文章

最新更新