将内容动态写入 iframe。

huangapple go评论68阅读模式
英文:

Dynamically write contents to 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,未发现错误。

英文:

I use this to preview an e-mail

When I dynamically write HTML to an iframe somehow the &lt;body&gt; tag is omitted? The body tag holds the font-family etc. but now the whole tag is gone and the HTML document is not shown correctly

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

contents of data.html

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

After the HTML is written to the iframe, the source of the iframe looks like this (the body tag is gone!)

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

I have tried to validate the HTML via https://validator.w3.org/ and no errors

答案1

得分: 8

"原因是jQuery的.html(value)方法不是用于设置带有顶层<html>标记的内容的。我们可以在jQuery源代码中看到这一点。在调用iframe_content.html(data.html);时,jQuery库内部将进行以下调用:html()调用access()access()通过回调调用append()append()调用domManip()domManip()调用buildFragment()buildFragment()执行以下代码,其中elem是你传递的data.html,而fragment是一个documentFragment

tmp = tmp || fragment.appendChild( context.createElement( "div" ) );
// 反序列化标准表示
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;

现在它将工作。"

英文:

The reason is that jQuery's .html(value) method is not intended to be used for setting content with a (top-level) &lt;html&gt; tag. We can see this in the jQuery source code. When calling iframe_content.html(data.html);, the following calls are made inside the jQuery library:

html() calls access(), which calls (via callback) append(), which calls domManip(), which calls buildFragment(), which executes the following code, where elem is the data.html you passed as argument, and fragment is a documentFragment:

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

So tmp is a &lt;div&gt; element (as appendChild returns the argument). tag is set to "html", and wrap to [0, &quot;&quot;, &quot;&quot;], and jQuery.htmlPrefilter(elem) just returns elem. So in short, this is executed:

tmp.innerHTML = elem;

The problem is HTML does not allow a &lt;div&gt; element to have an &lt;html&gt; or &lt;head&gt; or &lt;body&gt; element as child, so the DOM (not jQuery) will not create those DOM elements as intended.

This is not the end of the jQuery processing, but already at this point we can see that information has been lost.

Work around

As jQuery's .html(value) method cannot do the job, bypass jQuery and set innerHTML directly. Replace this:

iframe_content.html(data.html);

with this:

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

And now it will work.

答案2

得分: 0

你尝试过使用Shadow DOM吗?

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

示例用法:

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

Have you tried using a Shadow DOM?

All styles are encapsulated just like an iframe, but you also get the added benefits of naturally expanding content (compared to the fixed height of an iframe) and faster render times.

Example usage:

const shadow = someParentElement.attachShadow({
  mode: &#39;closed&#39;
});
shadow.innerHTML = `&lt;whatever&gt;`;

huangapple
  • 本文由 发表于 2023年4月6日 23:57:38
  • 转载请务必保留本文链接:https://go.coder-hub.com/75951501.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定