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

时间:2010-05-15 11:00:10

标签: javascript html ajax dom

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

目前,我在变量和

中保留了一行空白的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,然后在插入之前解码它,但这仍然意味着一个blankRow和大量的转义。

PHP等人的eof函数是什么意思

$blankRow = <<<EOF
text
text
EOF;

这意味着没有逃脱,但它仍然需要一个blankRow。

在这种情况下你做了什么?

解决

在原型中使用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

3 个答案:

答案 0 :(得分:20)

  

这是最佳做法吗?

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

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

  

的onclick = “someFunc(\ '{STRING} \');”

这是逃离混乱的全新程度。在事件处理程序属性中的JavaScript字符串文字中,您必须对字符串进行JS编码(\ - 转义'\以及一些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())来处理事件,而不必在添加时绑定到新节点。

答案 1 :(得分:5)

你用一种好的方式做到这一点,考虑到其他方式,这是非常快的。

一个替代的,假设干净的解决方案是在javascript中构建您要使用的DOM元素,通过调用几个

  

使用document.createElement(的tagName);

但是,在我的思想中,你的代码会迅速增长。

另一个,我最喜欢的创建DOM的方法是在HTML主体内放置要复制的代码,给它一个className和/或一个像“template”这样的id,另外(使用css)隐藏它,然后根据事件的需要处理它,方法是返回元素,克隆它,并在追加它所属的位置之前设置你想要的属性

答案 2 :(得分:1)

如果我理解你的话,你的问题是关于用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('');

懒惰的问题:坚持懒惰是非常困难的