【问题标题】:Best practice for inserting large chunks of HTML into elements with Javascript?使用 Javascript 将大块 HTML 插入元素的最佳实践?
【发布时间】: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);

请参阅我的解决方案 herehere

【问题讨论】:

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

标签: javascript html ajax dom


【解决方案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/402668pastebin.com/Du5Ejjjj 非常感谢您提供的信息 bobince!
    • 我强烈避免从字符串设置事件处理程序属性。我不记得 Prototype 是否可以解决通常会阻止此工作的许多 IE 错误,但无论如何这都是非常糟糕的做法;像您稍后在代码中所做的那样调用.observe 通常会好得多。 &lt;a href="javascript:void(0)"&gt; 也是一种不愉快。考虑一个可点击的跨度或一个按钮(如果你想要的话,它的样式看起来不像一个按钮)。有关此问题的讨论,请参见 stackoverflow.com/questions/1291942/…
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-17
    • 1970-01-01
    相关资源
    最近更新 更多