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

时间:2021-05-12 23:49:35

I'm building a web application (using prototype) that requires the addition of large chunks of HTML into the DOM. Most of these are rows that contain elements with all manner of attributes.

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

Currently I keep a blank row of HTML in a variable and

目前,我在变量和中保留了一行空白的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 );
}

Now that works all well and dandy, but is it the best practice?

现在一切都很好,很棒,但这是最佳实践吗?

I have to update the code in the blankRow when I update code on the page, so the new elements being inserted are the same. It gets sucky when I have like 40 lines of HTML to go in a blankRow and then I have to escape it too.

当我更新页面上的代码时,我必须更新空白行中的代码,因此插入的新元素是相同的。当我有大约40行HTML代码要放到空白行中,然后我也要转义。

Is there an easier way? I was thinking of urlencoding and then decoding it before insertion but that would still mean a blankRow and lots of escaping.

有更简单的方法吗?我在考虑urlencoding,然后在插入之前解码,但这仍然意味着一个空白行和很多转义。

What would be mean would be a eof function a la PHP et al.

它的意思是eof函数a PHP等。

$blankRow = <<<EOF
text
text
EOF;

That would mean no escaping but it would still need a blankRow.

这将意味着无法逃避,但它仍需要一个空白。

What do you do in this situation?

在这种情况下你会怎么做?

SOLVED

Ended up using a DOMBuilder in prototype. No other libraries were needed:

最终在prototype中使用了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);

See my solution here or here.

看这里或这里的解。

3 个解决方案

#1


19  

is it the best practice?

这是最好的做法吗?

No. In fact you've got HTML-injection problems leading to bugs, and in the worst case where the injected strings may contain user-submitted content, XSS security holes.

不。实际上,您已经遇到了html注入问题,导致了bug,在最坏的情况下,注入的字符串可能包含用户提交的内容,即XSS安全漏洞。

When you put plain text content and attribute values into an HTML string, you must HTML-encode them. In PHP, you have to call htmlspecialchars() on strings going into HTML to do it. In JavaScript, you don't get a built-in HTML-escaping function, so you have to make your own, eg. by using s.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/"/g, '&quot;') on the string going into the HTML.

当将纯文本内容和属性值放入HTML字符串时,必须对它们进行HTML编码。在PHP中,必须对进入HTML的字符串调用htmlspecialchars()。在JavaScript中,您不会得到一个内置的html转义函数,所以您必须自己创建一个。通过使用。替换(/ & / g ',')。替换(/ < / g,“& lt;”)。在进入HTML的字符串中替换(/"/g, "; ")。

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

onclick = " someFunc(\ ' {字符串} \ ');“

That's a whole new level of escaping mess. In a JavaScript string literal inside an event handler attribute, you would have to JS-encode the string (\-escaping ' and \ plus a few Unicode characters for completeness) and then HTML-encode the results. Otherwise the string can break out of its string-literal delimiter and inject arbitrary JS code. Avoid inline event handler attributes in all cases, but especially in templating.

这是一种全新的逃离困境。在事件处理程序属性内的JavaScript字符串文字中,您将不得不对字符串进行js编码(\-转义'和\再加上一些Unicode字符来完成),然后对结果进行html编码。否则,字符串可以跳出字符串-文字分隔符并注入任意的JS代码。避免在所有情况下使用内联事件处理程序属性,尤其是在模板中。

Creating page content with HTML strings sucks. You are very likely to make escaping errors and compromise the security of your application. Use DOM-like methods instead and you don't have to worry about this. You seem to be using jQuery, so try the jQuery 1.4 element creation shortcuts:

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

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

or, keep your blank row actually inside the document as HTML, but then hide it (display: none) or detach it from the document at start time (removeChild or jQuery detach). Then when you want a new row, clone the blank row and make the changes you need:

或者,将空白行作为HTML保存在文档中,然后隐藏它(显示: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);
});

If you must create content from string templates, ensure your templating function HTML-escapes every replacement by default, and attach events by selecting nodes inside the parsed content to call click(function() { ... }) on. Or use event delegation (eg. jQuery live()) to handle events without having to bind to new nodes when added.

如果您必须从字符串模板中创建内容,请确保您的模板函数html -escape默认情况下的所有替换,并通过选择解析后的内容中的节点来调用click(function(){……})。或使用事件委托(如。jQuery live()处理事件,无需在添加时绑定到新节点。

#2


5  

You do it using a good way, and that's pretty fast considering other manners.

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

An alternate, supposely clean solution is to build in javascript the DOM elements you are to use, by calling several

另一种非常干净的解决方案是,通过调用多个DOM元素,在javascript中构建要使用的DOM元素

document.createElement(tagName);

document.createElement(tagName);

But your code will rapidly grow, in my thought, for nothing.

但是,在我看来,你的代码将会迅速成长。

Another one, my favorite way to achieve DOM creation, is to place inside the HTML body the code you want to copy, give it a className and / or an id like "template" which will additionally ( using css ) hide it, and then process it as needed on event by getting the element back, cloning it, and setting property you want before appending where it belongs

实现DOM创建另一个,我最喜欢的方式,是将HTML体内你想复制的代码,给它一个名称和/或一个id像“模板”,此外(使用css)隐藏它,然后根据需要处理事件的元素,克隆它,设置属性之前你想要添加的属于他们的权利

#3


1  

If I understand you well, your question is about initializing large strings the way you'll do that in PHP (or Perl for that matter)? For long (multiline) string I use:

如果我理解得很好,你的问题是用PHP(或Perl)来初始化大字符串?对于长(多行)字符串,我使用:

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

You can also use a backslash for continuation, but that can get kind of messy:

你也可以使用反斜杠作为延续,但这可能会有点混乱:

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

EDIT based on comment: I'm lazy too! So I use this for escaping:

编辑基于评论:我也很懒!我用这个来逃避

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('');

Problem with being lazy: it's pretty hard work to persist ones lazyness

懒惰的问题:坚持懒惰是很难的

#1


19  

is it the best practice?

这是最好的做法吗?

No. In fact you've got HTML-injection problems leading to bugs, and in the worst case where the injected strings may contain user-submitted content, XSS security holes.

不。实际上,您已经遇到了html注入问题,导致了bug,在最坏的情况下,注入的字符串可能包含用户提交的内容,即XSS安全漏洞。

When you put plain text content and attribute values into an HTML string, you must HTML-encode them. In PHP, you have to call htmlspecialchars() on strings going into HTML to do it. In JavaScript, you don't get a built-in HTML-escaping function, so you have to make your own, eg. by using s.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/"/g, '&quot;') on the string going into the HTML.

当将纯文本内容和属性值放入HTML字符串时,必须对它们进行HTML编码。在PHP中,必须对进入HTML的字符串调用htmlspecialchars()。在JavaScript中,您不会得到一个内置的html转义函数,所以您必须自己创建一个。通过使用。替换(/ & / g ',')。替换(/ < / g,“& lt;”)。在进入HTML的字符串中替换(/"/g, "; ")。

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

onclick = " someFunc(\ ' {字符串} \ ');“

That's a whole new level of escaping mess. In a JavaScript string literal inside an event handler attribute, you would have to JS-encode the string (\-escaping ' and \ plus a few Unicode characters for completeness) and then HTML-encode the results. Otherwise the string can break out of its string-literal delimiter and inject arbitrary JS code. Avoid inline event handler attributes in all cases, but especially in templating.

这是一种全新的逃离困境。在事件处理程序属性内的JavaScript字符串文字中,您将不得不对字符串进行js编码(\-转义'和\再加上一些Unicode字符来完成),然后对结果进行html编码。否则,字符串可以跳出字符串-文字分隔符并注入任意的JS代码。避免在所有情况下使用内联事件处理程序属性,尤其是在模板中。

Creating page content with HTML strings sucks. You are very likely to make escaping errors and compromise the security of your application. Use DOM-like methods instead and you don't have to worry about this. You seem to be using jQuery, so try the jQuery 1.4 element creation shortcuts:

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

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

or, keep your blank row actually inside the document as HTML, but then hide it (display: none) or detach it from the document at start time (removeChild or jQuery detach). Then when you want a new row, clone the blank row and make the changes you need:

或者,将空白行作为HTML保存在文档中,然后隐藏它(显示: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);
});

If you must create content from string templates, ensure your templating function HTML-escapes every replacement by default, and attach events by selecting nodes inside the parsed content to call click(function() { ... }) on. Or use event delegation (eg. jQuery live()) to handle events without having to bind to new nodes when added.

如果您必须从字符串模板中创建内容,请确保您的模板函数html -escape默认情况下的所有替换,并通过选择解析后的内容中的节点来调用click(function(){……})。或使用事件委托(如。jQuery live()处理事件,无需在添加时绑定到新节点。

#2


5  

You do it using a good way, and that's pretty fast considering other manners.

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

An alternate, supposely clean solution is to build in javascript the DOM elements you are to use, by calling several

另一种非常干净的解决方案是,通过调用多个DOM元素,在javascript中构建要使用的DOM元素

document.createElement(tagName);

document.createElement(tagName);

But your code will rapidly grow, in my thought, for nothing.

但是,在我看来,你的代码将会迅速成长。

Another one, my favorite way to achieve DOM creation, is to place inside the HTML body the code you want to copy, give it a className and / or an id like "template" which will additionally ( using css ) hide it, and then process it as needed on event by getting the element back, cloning it, and setting property you want before appending where it belongs

实现DOM创建另一个,我最喜欢的方式,是将HTML体内你想复制的代码,给它一个名称和/或一个id像“模板”,此外(使用css)隐藏它,然后根据需要处理事件的元素,克隆它,设置属性之前你想要添加的属于他们的权利

#3


1  

If I understand you well, your question is about initializing large strings the way you'll do that in PHP (or Perl for that matter)? For long (multiline) string I use:

如果我理解得很好,你的问题是用PHP(或Perl)来初始化大字符串?对于长(多行)字符串,我使用:

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

You can also use a backslash for continuation, but that can get kind of messy:

你也可以使用反斜杠作为延续,但这可能会有点混乱:

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

EDIT based on comment: I'm lazy too! So I use this for escaping:

编辑基于评论:我也很懒!我用这个来逃避

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('');

Problem with being lazy: it's pretty hard work to persist ones lazyness

懒惰的问题:坚持懒惰是很难的