使用 Javascript 将大块 HTML 插入元素的最佳实践?

Posted

技术标签:

【中文标题】使用 Javascript 将大块 HTML 插入元素的最佳实践?【英文标题】:Best practice for inserting large chunks of HTML into elements with Javascript? 【发布时间】:2011-02-19 20:33:32 【问题描述】:

我正在构建一个需要在 DOM 中添加大量 html 的 Web 应用程序(使用原型)。其中大部分是包含具有各种属性的元素的行。

目前我在一个变量中保留了一行空白的 HTML

var blankRow = '<tr><td>'
    +'<a href="LINK" onclick="someFunc(\'STRING\');">WORD</a>'
    +'</td></tr>';

function insertRow(o) 
    newRow = blankRow
        .sub('LINK',o.link)
        .sub('STRING',o.string)
        .sub('WORD',o.word);
    $('tbodyElem').insert( newRow );

现在这一切都很好,而且很好,但这是最佳做法吗?

当我更新页面上的代码时,我必须更新blankRow中的代码,因此插入的新元素是相同的。当我有 40 行 HTML 进入一个 blankRow 时,它会变得很糟糕,然后我也必须转义它。

有没有更简单的方法?我正在考虑 urlencoding,然后在插入之前对其进行解码,但这仍然意味着空白行和大量转义。

什么意思是 eof 函数 a la php et al.

$blankRow = <<<EOF
text
text
EOF;

这意味着没有转义,但它仍然需要一个空白行。

遇到这种情况你会怎么做?

已解决

最终在原型中使用了 DOMBuilder。不需要其他库:

$w('a div p span img table thead td th tr tbody tfoot input').each(function(e) 
        window['$' + e] = function() 
            return new Element(e, arguments[0]);
        
);

newPart = $div(id: 'partition-4')
    .insert( $p()
        .insert('<b>Stuff</b>')
    )
    .insert( $p(
        id: 'a-p')
        .insert('<b>More stuff</b>')
    );

$('parentDiv').insert(newPart);

请参阅我的解决方案 here 或 here。

【问题讨论】:

你的点击函数总是字符串吗?如果它是一个实际的函数会更好,但不确定这是否是一个选项,你也在使用 jQuery 吗?从你的语法中我不能 100% 确定,但看起来你是。 不建议将许多节点一个接一个地插入 DOM。你应该一次完成。尝试先将它们插入容器对象,然后再从对象插入 DOM。 不,点击功能只是一个例子,主要是它的数字减少了我需要做的转义量。是的,它是原型,应该采用 jquery 的方式,但现在为时已晚。 嘿 vsync 我会先创建容器对象,比如 container = document.createElement('tbody') 把所有的 tr 扔进去然后做一个 $('actualTable').insert(container.childElements( ))?或 .insert( container.innerHTML ) - [iirc insert 想要一个字符串 arg...] 【参考方案1】:

你用一种很好的方式来做这件事,考虑到其他方式,这很快。

另一种可能是干净的解决方案是在 javascript 中构建您要使用的 DOM 元素,方法是调用几个

document.createElement(tagName);

但在我看来,你的代码会迅速增长,但不会白费。

另一种,我最喜欢的实现 DOM 创建的方法,是将要复制的代码放在 HTML 正文中,给它一个 className 和/或像“模板”这样的 id,这将另外(使用 css)隐藏它,然后根据需要在事件上处理它,方法是取回元素,克隆它,并在附加它所属的位置之前设置你想要的属性

【讨论】:

【参考方案2】:

如果我理解你的话,你的问题是关于初始化大字符串的方式,你将在 PHP(或 Perl 中)这样做?对于我使用的长(多行)字符串:

var blankRow = [
     'a line',
     'another line',
     'still more lines',
     'lines lines lines',
     '... etc'
    ].join('')

您也可以使用反斜杠来继续,但这会有点混乱:

var blankRow = 'a line\
another line\
still more lines\
lines lines lines\
... etc';

根据评论编辑:我也很懒!所以我用它来逃避:

function qs(str)
    str = str || this || '';
    return "'"+str+"'";


function qd(str)
    str = str || this || '';
    return '"'+str+'"';



String.prototype.qs = qs;
String.prototype.qd = qd;

// applied:
var blankRow = [
         'a line',
         'another '+qd('line'),
         'still more lines',
         'lines '+'lines'.qs()+ ' lines',
         '... etc'
        ].join('');

懒惰的问题:坚持一个人的懒惰是相当困难的工作

【讨论】:

啊,这是一个聪明的方法。我提到 PHP 示例的原因是您不需要在中间转义任何内容;) 【参考方案3】:

这是最佳做法吗?

没有。实际上,您遇到了导致错误的 HTML 注入问题,并且在最坏的情况下,注入的字符串可能包含用户提交的内容,XSS 安全漏洞。

当您将纯文本内容和属性值放入 HTML 字符串时,您必须对它们进行 HTML 编码。在 PHP 中,您必须在进入 HTML 的字符串上调用 htmlspecialchars() 来执行此操作。在 JavaScript 中,您没有内置的 HTML 转义功能,因此您必须自己制作,例如。通过在进入 HTML 的字符串上使用 s.replace(/&amp;/g, '&amp;amp;').replace(/&lt;/g, '&amp;lt;').replace(/"/g, '&amp;quot;')

onclick="someFunc(\'STRING\');"

这是一个全新的逃避混乱的水平。在事件处理程序属性内的 JavaScript 字符串文字中,您必须对字符串进行 JS 编码(\-escaping '\ 加上一些 Unicode 字符以确保完整性)然后对结果进行 HTML 编码。否则,字符串可以突破其字符串文字分隔符并注入任意 JS 代码。在所有情况下都避免使用内联事件处理程序属性,尤其是在模板中。

用 HTML 字符串创建页面内容很糟糕。您很可能会出现转义错误并危及应用程序的安全性。改为使用类似 DOM 的方法,您不必担心这一点。您似乎在使用 jQuery,因此请尝试使用 jQuery 1.4 元素创建快捷方式:

$('<tr>').append(
    $('<td>').append(
        $('<a>', 
            href: o.link,
            text: o.word,
            onclick: function() 
                someFunc(o.string);
            
        )
    )
);

或者,将您的空白行作为 HTML 保留在文档中,然后将其隐藏(display: none)或在开始时将其从文档中分离(removeChild 或 jQuery detach)。然后,当您需要新行时,克隆空白行并进行所需的更改:

var blankRow= $('#blankRow').detach();

    ...

var newRow= blankRow.clone();
var link= newRow.find('td>a');
link.attr('href': o.link);
link.text(o.word);
link.click(function() 
    someFunc(o.string);
);

如果您必须从字符串模板创建内容,请确保您的模板函数默认对每个替换进行 HTML 转义,并通过选择解析内容中的节点来附加事件以调用 click(function() ... )。或者使用事件委托(例如 jQuery live())来处理事件,而无需在添加时绑定到新节点。

【讨论】:

伙计……多么伟大的使命。谢谢你的帮助。真希望我现在使用 jquery 而不是原型 :( @hamstar:哎呀!我应该发现这是一个原型 ID 选择器$ 而不是 jQuery。哦。 Prototype 有一个类似的(IMO:在某些方面更好)创建元素的快捷方式,new Element。见prototypejs.org/2007/5/12/dom-builder 甜蜜!我可能不得不试一试 :) 干杯 最终以这种方式完成,效果非常好!花了一段时间才弄清楚。如果有人想查看代码,请参阅 gist.github.com/402668 或 pastebin.com/Du5Ejjjj 非常感谢您提供的信息 bobince! 我强烈避免从字符串设置事件处理程序属性。我不记得 Prototype 是否可以解决通常会阻止此工作的许多 IE 错误,但无论如何这都是非常糟糕的做法;像您稍后在代码中所做的那样调用.observe 通常会好得多。 &lt;a href="javascript:void(0)"&gt; 也是一种不愉快。考虑一个可点击的跨度或一个按钮(如果你想要的话,它的样式看起来不像一个按钮)。有关此问题的讨论,请参见 ***.com/questions/1291942/…。

以上是关于使用 Javascript 将大块 HTML 插入元素的最佳实践?的主要内容,如果未能解决你的问题,请参考以下文章

Java希尔排序

如何使用 javascript/jquery 将大型 html 块附加到刀片文件?

新手面对网页该如何下手

尝试使用Javascript将HTML元素插入另一个HTML元素

寻找将 html 代码插入 Javascript 的更好方法

如何将 javascript 函数从子 flash swf 文件插入 HTML 文档?