【问题标题】:jQuery - Best Practice for creating complex HTML FragmentsjQuery - 创建复杂 HTML 片段的最佳实践
【发布时间】:2011-01-14 02:46:34
【问题描述】:

是否有在 jQuery 中创建有些复杂的 HTML 元素的一般最佳实践?我尝试了几种不同的方法。

首先我尝试使用 createElement 并将其中的很多与 AppendTo 等链接在一起:

var badge = $(document.createElement("div")).attr("class", "wrapper1").appendTo("body");
$(document.createElement("div")).attr("class", "wrapper2").appendTo(".wrapper1");
$(document.createElement("table")).attr("class", "badgeBody").appendTo(".wrapper2");
$(document.createElement("tr")).attr("class", "row1").appendTo(".badgeBody");
$(document.createElement("td")).appendTo(".row1");
$(document.createElement("span")).attr("class", "badgeUnlocked").text("UNLOCKED! ").appendTo("td");
$(document.createElement("td")).attr("class", "badgeTitleText").appendTo(".row1");
$(document.createElement("span")).attr("class", "badgeTitle").text(name).appendTo(".badgeTitleText");
$(document.createElement("tr")).attr("class", "row2").appendTo(".badgeBody");
$(document.createElement("td")).appendTo(".row2");
$(document.createElement("img")).attr("src", imgUrl).appendTo(".row2 td");
$(document.createElement("td")).attr("class", "badgeText").appendTo(".row2");
$(document.createElement("span")).attr("class", "badgeDescription").text(description).appendTo(".badgeText");

这可能很粗略,因为 appendTo 想要添加到每个匹配的元素,所以所有内容都需要自己的名称,否则最终会在整个地方重复添加。

然后我尝试创建一个数组并将其连接在一起:

var badgeFragment = [
'<div><div id="'+ closeId+'" class="closeTab">X</div>',
'<div id="'+ badgeId+'" class="wrapper1">',
'<div class="wrapper2">',
'<div class="badgeBody">',
'<div class="badgeImage">',
'<img src="'+ imgUrl +'">',
'</div>',
'<div class="badgeContents">',
'<div class="badgeUnlocked">ACHIEVEMENT UNLOCKED: </div>',
'<div class="badgeTitle">'+ name +'</div>',
'<div id="'+ textId+'" class="badgeDescription">'+ description +'</div>',
'</div>',
'<div style="clear:both"></div>',
'</div></div></div></div></div>',
]

badgeFragment = $(badgeFragment.join(''));

这似乎工作得很好,虽然在 IE 中当我放一个 alert($(badgeFragment).text()) 时它通常会返回空。 (这是调试更大问题的一部分)。我显然对 jQuery 有点陌生(甚至是 Javascript),所以为了确保这不是问题,我尝试了第三种方法 - 巨大的字符串连接:

var badgeFragment =
'<div><div id="'+ closeId+'" class="closeTab">X</div>' +
'<div id="'+ badgeId+'" class="wrapper1">' +
'<div class="wrapper2">' +
'<div class="badgeBody">' +
'<div class="badgeImage">' +
'<img src="C:/Users/Ryan/Documents/icons/crystal_project/64x64/apps/chat.png">' +
'</div>' +
'<div class="badgeContents">' +
'<div class="badgeUnlocked">ACHIEVEMENT UNLOCKED: </div>' +
'<div class="badgeTitle">test</div>' +
'<div id="'+ textId+'" class="badgeDescription">test</div>' +
'</div>' +
'<div style="clear:both"></div>' +
'</div></div></div></div></div>';

这些方法中的一种通常被认为比其他方法更好吗?我对各种分析器并不是很擅长,所以我不确定如何自己验证这一点。还有一个问题是所有这些方法是否都兼容跨浏览器。

【问题讨论】:

  • 您在 IE 中的警报显示为空,因为“.text()”没有获取 DOM 子树的所有内容。试试 $(badgeFragment).html()

标签: jquery html


【解决方案1】:

从 HTML5 开始就有 &lt;template&gt; 标签。

$(function () {
    // Get template
    var template = $("#template").html();

    // Create a new row from the template
    var $row = $(template);

    // Add data to the row
    $row.find("td[data-template='firstName']").text("Foo");
    $row.find("td[data-template='lastName']").text("Bar");

    // Add the row to the table
    $("#table").append($row);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<template id="template">
  <tr>
    <td data-template="firstName"></td>
    <td data-template="lastName"></td>
  </tr>
</template>

<table id="table">
  <tr>
    <th>Firstname</th>
    <th>Lastname</th>
  </tr>
</table>

【讨论】:

    【解决方案2】:

    如果 JavaScript 代码类似于 HTML 标记结构,则更具可读性和可维护性。你可以使用 $('div', { 'class': 'etc'})...

    这是一种稍微不同的方法,它使用函数 $$ 使每个元素成为可编辑的 jQuery 对象。它应该非常快,因为没有进行 html 解析。

    $$('div', {'id':'container'},
        $$('div', {'id':'my_div'},
            $$('h1',{'class':'my_header'},
                $$('a',{'href':'/test/', 'class':'my_a_class'}, 'teststring'))));
    

    这使得该方法更加灵活,您可以使用链接非常容易地将事件处理程序、数据等添加到嵌套的 jQuery 对象中,例如

    $$('div', {'id':'container'},
        $$('div', {'id':'my_div'},
            $$('h1',{'class':'my_header'},
                $$('a', { 'href': '/test/', 'class': 'my_a_class' }, 'teststring')
            ).click(function() { alert('clicking on the header'); })
        ).data('data for the div')
    ).hide();
    

    与使用官方 jQuery 方法通过单独调用 .append()、.text()、.html() 等或向 jQuery $ 提供连接的 HTML 时相比,代码更具可读性字符串。

    参考函数$$:

    function $$(tagName, attrTextOrElems) {
        // Get the arguments coming after the params argument
        var children = [];
        for (var _i = 0; _i < (arguments.length - 2) ; _i++) {
            children[_i] = arguments[_i + 2];
        }
    
        // Quick way of creating a javascript element without JQuery parsing a string and creating the element
        var elem = document.createElement(tagName);
        var $elem = $(elem);
    
        // Add any text, nested jQuery elements or attributes
        if (attrTextOrElems) {
            if (typeof attrTextOrElems === "string") { // text
                var text = document.createTextNode(attrTextOrElems);
                elem.appendChild(text);
            }
            else if (attrTextOrElems instanceof jQuery) { // JQuery elem
                $elem.append(attrTextOrElems);
            }
            else // Otherwise an object specifying attributes e.g. { 'class': 'someClass' }
            {
                for (var key in attrTextOrElems) {
                    var val = attrTextOrElems[key];
                    if (val) {
                        elem.setAttribute(key, val);
                    }
                }
            }
        }
    
        // Add any further child elements or text    
        if (children) {
            for (var i = 0; i < children.length; i++) {
                var child = children[i];
                if (typeof child === "string") { // text
                    var text = document.createTextNode(child);
                    elem.appendChild(text);
                } else { // JQuery elem
                    $elem.append(child);
                }
            }
        }
        return $elem;
    }
    

    【讨论】:

      【解决方案3】:

      我喜欢模板语言Handlebars.js

      【讨论】:

        【解决方案4】:

        使用 jQuery 1.4,您可以像这样创建 HTML 元素:

        // create an element with an object literal, defining properties
        var e = $("<a />", {
            href: "#",
            "class": "a-class another-class", // you need to quote "class" since it's a reserved keyword
            title: "..."
        });
        
        // add the element to the body
        $("body").append(e);
        

        这里是a link to the documentation

        我不确定这种方法是否比使用 jQuery 的 html() 函数更快。或者比一起跳过 jQuery 并在元素上使用 innerHTML 属性更快。但就可读性而言; jQuery 方法是我的最爱。在大多数情况下,使用innerHTML 的性能提升是微不足道的。

        【讨论】:

        • 您在 jQuery ($) 的第一个参数后遗漏了一个逗号。
        • @roosteronacid 取决于 jQuery docs The name "class" must be quoted in the object since it is a JavaScript reserved word
        • @Peter 是的。适用于所有保留字。更新了我的答案。
        • 如何用这种方式声明嵌套元素?
        • +1 旨在提高可读性。这总是明智的,因为 CPU 速度会随着时间的推移而提高,而对代码的理解会降低。
        【解决方案5】:

        我正在做的方式如下所示。我不确定你是否应该创建这么多 div,但它对我来说效果很好。

        var div1 = $('<div class="colwrap_fof"></div>');        //THE COMPLEX DIV ITSELF
        var div2 = $('<div class="homeimg"></div>');                
        var div21 = $('<div id="backImageDiv'+fof_index+'" class="backDiv"></div>');
        var div22 = $('<div id="frontImageDiv'+fof_index+'"  class="frontDiv"></div>');
        div2.append(div21);
        div2.append(div22);
        div1.append(div2);
        $("#df_background").append(div1);     // ADDING the complex div to the right place      
        

        干杯,

        【讨论】:

        • 嗨@mar​​celosalloum,根据我的经验,当有人说我需要你现在将 添加到你的代码中时,这绝对是痛苦的。是的,它确实有效,但我不能评论性能,但维护起来很痛苦..
        • 如果您的目标只是创建一个模板然后用一些数据填充它,我个人喜欢为我的模板元素创建一个 display:none; 容器,使用 getElementById 将它们获取到 javascript 变量中() 或 jQuery,克隆它,然后自己处理填充数据 (.textContent=val/.text(val), .setAttribute(attr,val)/.attr(attr,val)) 因为自己做比自己做更容易担心一些劣质的模板库是否会正确地完成它的工作并且性能要好得多,因为我确切地知道我想用模板做什么。
        【解决方案6】:

        John Resig(jQuery 的创建者)早在 2008 年就建议使用这种模板方法。它实际上有一些非常酷的功能:

        <script type="text/html" id="item_tmpl">
        
          <div id="<%=id%>" class="<%=(i % 2 == 1 ? " even" : "")%>">
            <div class="grid_1 alpha right">
              <img class="righted" src="<%=profile_image_url%>"/>
            </div>
            <div class="grid_6 omega contents">
              <p><b><a href="/<%=from_user%>"><%=from_user%></a>:</b> <%=text%></p>
            </div>
          </div>
        
        </script>
        

        然后使用...检索它

        var results = document.getElementById("results");
        results.innerHTML = tmpl("item_tmpl", dataObject);
        

        详情请看这里:
        http://ejohn.org/blog/javascript-micro-templating/

        【讨论】:

        • ICanHaz 看起来很棒,@MarkAmery,但在我最终发现它或 Mustache 模板不能很好地处理某些字符(例如反斜杠 \ )之前,它只是浪费了我几个小时的时间。我不能承受这种浪费时间!
        • @ErikE 哎哟。我很惊讶一个像 icanhaz 一样活跃的图书馆会以任何重大的方式被破坏。你有没有机会在 jsfiddle 中提供一个最小的演示案例?我可能会玩一下,看看我能不能修复这个错误。
        【解决方案7】:

        我倾向于查看 jquery 的模板引擎之一,例如 jQote

        【讨论】:

        • +1。或 jsRender 或下划线 - 有很多选择,而且它们更好,尤其是因为 Javscript 不支持多行字符串和 sprintf 类型的参数替换功能
        【解决方案8】:

        你不必调用 document.createElement:

        $('#existingContainer').append(
          $('<div/>')
            .attr("id", "newDiv1")
            .addClass("newDiv purple bloated")
            .append("<span/>")
              .text("hello world")
        );
        

        在 jQuery 中有各种有用的工具来扩展/修改 DOM。以各种“包装”方法为例。

        另一种可能性:对于非常大的新内容,您最好让服务器准备这些内容(使用服务器端模板系统,无论您使用什么)并使用 $.load() 或其他一些 ajax 获取这些内容接近。

        【讨论】:

          【解决方案9】:

          我个人认为,代码的可读性和可编辑性比性​​能更重要。无论您发现哪一个更易于查看和更改而不破坏它,都应该是您选择的那个。

          【讨论】:

            猜你喜欢
            • 2012-05-26
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2020-04-03
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多