在jQuery中构建html元素的最清晰方法


73

我已经看到了许多在jQuery中创建元素的样式(和几种不同的方法)。我对构建它们的最清晰方法以及任何特定方法是否出于某种原因客观上优于另一种方法感到好奇。下面是一些我所看到的样式和方法的示例

var title = "Title";
var content = "Lorem ipsum";

// escaping endlines for a multi-line string
// (aligning the slashes is marginally prettier but can add a lot of whitespace)
var $element1 = $("\
    <div><h1>" + title + "</h1>\
        <div class='content'>  \
        " + content + "        \
        </div>                 \
    </div>                     \
");

// all in one
// obviously deficient
var $element2 = $("<div><h1>" + title + "</h1><div class='content'>" + content + "</div></div>");

// broken on concatenation
var $element3 = $("<div><h1>" +
                title + 
                "</h1><div class='content'>" +
                content +
                "</div></div>");

// constructed piecewise
// (I've seen this with nested function calls instead of temp variables)
var $element4 = $("<div></div>");
var $title = $("<h1></h1>").html(title);
var $content = $("<div class='content'></div>").html(content);
$element4.append($title, $content);

$("body").append($element1, $element2, $element3, $element4);

请随时演示您可能使用的任何其他方法/样式。


1
在前三个示例中,为什么要使用jquery?在jquery选择器中编写完整的html只会降低性能。var element2 = "<div><h1>"+title+"</h1>...</div>";
朱利安·拉丰

我也正在使用jQuery处理这些元素,因此,如果我没有使用jQuery创建它们,则无论如何都必须使用jQuery选择器。
bkconrad

Answers:


73

模板很棒,如果您可以在项目中访问它们,我建议您使用它们。如果您使用下划线Lodash它内置的。然而,在一些情况下,你无论是重构或测试需要建立HTML代码中的。我发现以下格式是最清楚的读法,这是必需的。

注意:HTML规范允许标记中的属性使用单引号或双引号,因此不必理会所有疯狂的转义。

this.$fixture = $([
  "<div>",
  "  <div class='js-alert-box'></div>",
  "  <form id='my-form-to-validate'>",
  "    <input id='login-username' name='login-username'>",
  "  </form>",
  "</div>"
].join("\n"));

9
哇!绝对完美。答案是易于理解且易于维护的,花费了将近整整两年的时间。
bkconrad 2014年

3
我喜欢这个。你会想到什么的.join("\n")来代替.join("")
Jeffery Thomas

2
请注意,在打字稿中,您可以使用模板字符串basarat.gitbooks.io/typescript/docs/template-strings.html
罗尼

47

环顾了一会后,我终于找到了自己的风格。首先,我会说我使用Mustache进行模板制作,并且效果很好。但是,有时候,您只需要一次构建一个元素,而无需重用它,或者有其他动机不引入另一个库。在这种情况下,我习惯使用:

$("body")
.append(
    $("<div>")
    .append(
        $("<div>")
        .append(
            $("<h1>").text(title)
        )
    )
    .append(
        $("<div>").text(content)
    )
);​

这工作,因为append()返回到你的对象的引用追加,所以链式append()s安装到同一个对象。有了适当的缩进,标记的结构就显而易见了,这样就很容易修改。显然,这比使用模板要慢(整个过程必须一步一步地构建),但是,如果仅将其用于初始化或类似操作,则这是一个很大的折衷。

可以通过多种方式格式化这样的构造,但是我选择了一种方法来弄清楚发生了什么。我使用的规则是每行上最多应有一个圆括号和/或一个圆括号。同样,这些附加树的叶子不需要传递给jQuery构造函数,但是我在这里这样做是为了视觉重复。


4
到目前为止,最干净的jQuery jQuery方法要比用引号引起来,如可接受的答案所示。接受的答案感觉像是在PHP echo/
shudder中

6
$("<h1>" + title + "</h1>")可能是$("<h1>").text(title)
鲍勃·斯坦

4
.append()与构造一个字符串(例如在var中)并将其附加一个字符串相比,所有这些调用是否会对性能产生不利影响.append()
Scribblemacher

记住也.append()可以接受数组可能会很有用。例如,在尝试构建列表时,这可能会派上用场。然后可以使用匿名函数自调用函数生成的列表<li>s。[类似.append( (function () { ... return li; })() )]
Fabien Snauwaert

@adamj-相反,我更喜欢接受的版本,因为它实际上类似于嵌套标记,因此更易于阅读。
马丁·詹姆斯

32

当涉及到DOM构建时,我尝试避免使用字符串连接,因为它们可能会导致细微的错误和未正确编码的输出。

我喜欢这一个:

$('<div/>', {
    html: $('<h1/>', {
        html: title
    }).after(
        $('<div/>', {
            'text': content,
            'class': 'content'
        })
    )
}).appendTo('body');

产生:

    ...
    <div><h1>some title</h1><div class="content">some content</div></div>
</body>

并确保适当的HTML编码和带有匹配的开始和结束标签的DOM树构建。


1
我打算为此添加一个示例,但是我从来没有看过它能很好地完成。这种方法虽然很清楚。
bkconrad 2012年

23

我的建议:不要尝试使用jQuery构建html元素,这不是它的责任。

使用Java模板系统,例如MustacheHandlebarJs

行数非常有限,您可以直接从Javascript对象创建html元素。并不复杂,只有两个功能和一个模板。

<div class="entry">
  <h1>{{title}}</h1>
  <div class="body">
    {{body}}
  </div>
</div>

var context  = {title: "My New Post", body: "This is my first post!"}
var template = Handlebars.compile($("#template-skeleton"));
var html     = template(context);

编辑:
没有html的另一个示例,纯Javascript(来自ICanHaz):

var skeleton = '<div><h1>{{title}}</h1><div class="content">{{content}}</div></div>';
var data = { title: "Some title", content: "Some content" };
var html = Mustache.to_html(skeleton, data);

它比一系列串联更易于维护。


我没有太多研究模板系统。我非常喜欢这种语法。但是,当前我正在MVC框架中工作,我的javascript与我的实际视图模板很好地分开了。这意味着我的js模板无论如何都必须构造为字符串(在它们各自的.js文件中),否则将达到html模板中定义的js模板,从而破坏了demeter的定律。+1,因为这在任何其他情况下都是一个很好的解决方案。
bkconrad 2012年

似乎不兼容。看看我的第二个例子。
朱利安·拉丰

在实际尝试之后,事实证明这是一个非常好的解决方案。语法很明显,并且因为这些模板很小,所以当直接嵌入.js文件时,它们看起来不错。另外,如果我的模板发疯了,我仍然可以使用转义的换行符。
bkconrad 2012年

13

2015年答案:对于较旧的浏览器,请使用multiline

var str = multiline(function(){/*
<!doctype html>
<html>
    <body>
        <h1>❤ unicorns</h1>
    </body>
</html>
*/});

对于ES6,请使用JavaScript模板字符串

var str = `
<!doctype html>
<html>
    <body>
        <h1>❤ unicorns</h1>
    </body>
</html>`

这比.append在各处使用s简单得多。
克里斯·阿克里奇

7

这是根据巴尔的回答改编而成的。我发现它更具可读性,无需创建和加入数组,也无需在每一行都加引号:

http://jsfiddle.net/emza5Ljb/

var html =

    '                                                           \
      <div>                                                     \
        <div class="js-alert-box"></div>                        \
        <form id="my-form-to-validate">                         \
          <input id="login-username" name="login-username">     \
        </form>                                                 \
      </div>                                                    \
    '

// using jQuery:
//
var dom = $( html )

// or if you need performance, don't use jQuery
// for the parsing.
// http://jsperf.com/create-dom-innerhtml-vs-jquery
//
var div       = document.createElement( 'div' )
div.innerHTML = html
var dom = $( div )

仅供参考,当性能不成问题并且元素包含大量动态数据时,有时我会像这样编写代码(请注意,闭包编译器会发出有关未引用类属性的警告,但在现代浏览器中,此方法可以正常工作):

$(
      '<a></a>'

    , {
           text     : this.fileName
         , href     : this.fileUrl
         , target   : '_blank'
         , class    : 'file-link'
         , appendTo : this.container
      }
)


2

这是一个使用$(htmlString)并模仿HTML代码的标准布局的示例:

function getPage(title, contents) {
  return (
    $("<div>", {id: "container", class: "box"}).append(
      $("<div>", {class: "title"}).append(
        $("<h1>").text(title)
      ),
      $("<div>").html(contents)
    )
  );
}

2

我发现功能方法非常方便。例如

// reusable generics TABLE constructor helpers
var TD = function(content) { return $('<td>', { html: content }) }
var TH = function(content) { return $('<th>', { html: content }) }
var TR = function(cell, cells) {  // note the kind of cell is a 2^order parameter
    return $('<tr>', { html: $.map(cells, cell) })
}

// application example
THEAD = $('<thead>', {html:
    TR(TH, [1,2,3,4])})
TBODY = $('<tbody>', {html: [
    TR(TD, ['a','b','c','d']),
    TR(TD, ['a','b','c','d']),
]})

现在打电话

$('#table').append($('<table>', {html: [THEAD, TBODY]}))

产量

<table><thead><tr><th>1</th><th>2</th><th>3</th><th>4</th></tr></thead><tbody><tr><td>a</td><td>b</td><td>c</td><td>d</td></tr><tr><td>a</td><td>b</td><td>c</td><td>d</td></tr></tbody></table>

编辑

我已经改进了方法,现在可以作为html_uty.js使用


1
html就像在中一样使用属性{ html: content },但它的行为似乎有所不同。有趣的功能记录在哪里?
鲍勃·斯坦

1
也许之后,As of jQuery 1.8, any jQuery instance method (a method of jQuery.fn) can be used as a property...但是我隐约记得我是在尝试构建类似于微型反应的脚本时,通过反复试验而不是从文档中发现的。顺便说一句,现在我已经改进了构造(特别是无法直接处理attr样式,我将在答案中添加指向github的链接)
CapelliC

1
我真的很喜欢这种没有模板语言的脚本。它仍然在弯曲我的大脑(就像$ .map总是那样,更不用说将数组传递给$ .html了),但我会继续寻找。
鲍勃·斯坦

0

最简单的方法-

var optionsForLength = 
'<option value="Kilometre">Kilometre</option>'+
'<option value="Metre">Metre</option>'+
'<option value="Centimetre">Centimetre</option>'+
'<option value="Milimetre">Milimetre</option>'+
'<option value="Micrometre">Micrometre</option>'+
'<option value="Nanometre">Nanometre</option>'+
'<option value="Mile">Mile</option>'+
'<option value="Yard">Yard</option>'+
'<option value="Foot">Foot</option>'+
'<option value="Inch">Inch</option>'+
'<option value="Nautical mile">Nautical mile</option>';
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.