【问题标题】:append script containing html for jquery template为 jquery 模板附加包含 html 的脚本
【发布时间】:2011-11-05 01:45:52
【问题描述】:

请多多包涵,因为它有点复杂,而且我对 JQuery 完全陌生,并试图理解它。

我和我的团队正在为一个 SharePoint 项目开发 WebPart。 WebPart 包含一个用户控件 (SearchControl),该控件具有用于打开包含另一个用户控件 (SelectorControl) 的对话框(使用 jquery ui)的链接。

SelectorControl 包含:

  • 使用 JQuery 模板填充的下拉列表 (objTemplates)
  • 使用另一个 JQuery 模板填充的表;和
  • 只读文本输入,用于显示表中当前选定的项目

SelectorControl 代码:

        <div class="objSelector">
        <script id="objSelectorTemplate" type="text/x-jquery-tmpl">
        <div class="table">
            <div class="row">
               <div class="labelInputGroup">
                    <label for="objTemplates">Obj Template</label>
                    <select id="objTemplates">
                        {{each ObjectTemplates}}
                            <option value="${ObjectTemplateId}">${Name}</option>
                        {{/each}}
                    </select>
                </div>
            </div>
            <div><br></div>
            <div class="row">
                <div>
                    <table class="tableGrid">
                        <thead>
                            <tr>
                                <th>Object Name</th>
                            </tr>
                        </thead>
                        <tbody id="listPlaceholder">
                        </tbody>
                    </table>
                    <div id="pagerPlaceholder"></div>
                </div>        
            </div>     
            <div id="templatePlaceholder">
            </div>
            <div><br></div>
            <div class="row">
                <input type="hidden" id="localSelectedObjectId" class="hidden" />
                <label for="localSelectedObject">Selected Object</label>
                <input type="text" class="dealName" id="localSelectedObject" readonly="readonly" placeholder="No object selected"/>
            </div>
        </div>
        </script>    
        <script id="listTemplate" type="text/x-jquery-tmpl">
            <tr>
                <td><a class="objectItem" id="${Id}" href="#">${Name}</a></td>
            </tr>
       </script>    
       <div id="pagerControl">
          <uc1:PagerControl ID="PagerControl1" runat="server" />
       </div> 
    </div>

在使用从 WCF 服务检索的数据创建对话框之前填充下拉列表,然后绑定到第一个模板。

通过调用 WCF 服务并通过下拉列表中当前选定的项目,使用 live 填充表(第二个模板)将“更改”事件绑定到下拉列表。

当下拉列表触发change事件时,调用LoadObjects:

            function LoadObjects(event) {

            var dialogDom = event.data.DialogDom;
            var searchObj = GetSearchFilters(); // removed irrelevant code here

            var listTemplate = searchDom.find('#listTemplate');
                    var templatePlaceholder = dialogDom.find('#templatePlaceholder');
                    templatePlaceholder.empty();
                    templatePlaceholder.append(listTemplate);

                    var pagerControl = searchDom.find('#pagerControl');
                    var pagerPlaceholder = dialogDom.find('#pagerPlaceholder');
                    pagerPlaceholder.append(pagerControl);

                    var list = GenerateList(
                        dialogDom,
                        $('<div></div>'),
                        searchObj,
                        Connection('MyUiService', 'GetObjects'));
        }

GenerateList() 方法使用各种方法创建一个 JQuery 对象,包括从 WCF 服务获取对象数据并将其绑定到模板 (listTemplate) 的方法

PagerControl 代码还包含一个模板,该模板与 listTemplate 同时填充。

listTemplate 和分页器的代码必须放在 objectSelectorTemplate 脚本之外,然后再复制进去,以防止在解析页面以填充下拉列表时将其删除。

第一次打开对话框并从下拉列表中选择一个项目时,上述所有操作都可以正常工作。可以毫无问题地更改表中数据内的页面,但是一旦下拉列表中的选定项目发生更改,就不再加载表数据。如果我单步执行代码,我可以看到 append()(在 LoadObjects 方法中)在将 listTemplate 脚本插入 listPlaceholder 时将其删除,这意味着当对话框再次加载表数据时,该脚本不再那里。为了解决这个问题,我尝试添加一个克隆:

    templatePlaceholder.append(listTemplate.clone());

这成功地阻止了 listTemplate 脚本被删除,但是,克隆的副本包含脚本标签但不包含其内容,因此仍然没有加载表数据。我搜索了SO,发现John Resig对this question的回复:

所以我把上面的代码改成:

    var listTemplateCopy = jQuery.extend({}, listTemplate);
    templatePlaceholder.append(listTemplateCopy);

这成功地将脚本标签及其内容复制到 listTemplateCopy,但 append() 会删除 listTemplate 以及 listTemplateCopy。起初我认为这是因为 extend 旨在将两个(或更多)对象合并为一个对象,但从约翰的回应和我在文档中读到的内容来看,听起来 extend 是你应该用来创建一个 jquery 对象的副本。

谁能向我解释到底发生了什么并推荐解决上述问题的方法?

我的一些想法是:

  • 将脚本标签移动到仅围绕模板代码。然后我可以将第二个模板代码放在适当的位置,而无需附加它。绑定将通过绑定到下拉列表模板然后绑定到表格来完成
  • 使用不同的方式填充下拉列表而不是模板来简化页面并消除附加脚本的“必要性”,因为整个批次不会有脚本标记

在采用这两种方法之前,我想了解代码当前正在做什么。

【问题讨论】:

    标签: jquery web-parts jquery-templates


    【解决方案1】:

    这绝不是一个优雅的答案,但本质上,这是 IE8 脚本引擎及其前身的失败。如果您的项目要求支持这些浏览器,那么代码看起来会有点难看,而 jQuery 不会有太大帮助。您会注意到您第一次在代码中使用.clone() 实际上在 IE9、Firefox、Chrome 和 Safari 中运行良好。请允许我解释一下具体的困难。

    您的要求是复制一个 DOM 对象。 $.extend() 在这种情况下是不合适的,因为它只会克隆一个包装 DOM 目标集的 jQuery 对象,而不是实际的 DOM 目标。这意味着包装器的新副本仍然具有相同的目标 DOM 元素,而不是附加目标的副本,而是移动目标。因此,您最初使用.clone() 的假设是正确的。代码未能按预期运行的原因超出了您的控制范围。

    IE9 使用其前身的Node.cloneNode() 方法纠正了一个明显的缺陷,其中Node 对象的innerHTML 成员在script 元素的情况下不保留。这是 jQuery 的 .clone() 调用使用的方法。在 IE8 及更早版本中的任何脚本块上执行一行经典 JavaScript 将显示同样多的信息:

    alert(document.getElementById("listTemplate").cloneNode(true).innerHTML);
    

    此警报将在所有其他主要浏览器中包含内容。在 IE8 及以下版本中并非如此。 "true" 参数执行一个深拷贝只是为了证明一个观点,但实际上这不是必需的,因为script 元素在其childNodes 集合中没有Nodes

    解决方法很难看,我不完全确定它会按预期运行,因为我没有您的系统可供测试。您必须显式修改占位符元素的 innerHTML 属性。您可能会考虑的一件事是包含一个defer 属性,该属性倾向于使脚本块在动态插入 IE 时表现得更好(请参阅MSDN - innerHTML Property at,“当使用 innerHTML 插入脚本时,您必须在脚本元素中包含 DEFER 属性”)。它会让你的 JavaScript 看起来像下面这样:

    var listTemplate = searchDom.find('#listTemplate');
    var myHtml = '<script defer="defer" type="text/x-jquery-tmpl">';
    myHtml += listTemplate.html();
    myHtml += "</script" + ">";
    
    var templatePlaceholder = dialogDom.find('#templatePlaceholder');
    templatePlaceholder.html(myHtml);
    

    我假设listTemplatetemplatePlaceholder 是jQuery 对象,所以如果我弄错了,我深表歉意。但是,这里的基本思想实际上是将整个脚本块构建为 HTML 字符串,并将占位符内的 HTML 替换为您已构建的字符串。

    我不能保证 IE 会正确解释脚本块并使其可用于您的 jQuery 模板,但检查我选择的受害者占位符的 innerHTML 确实表明,至少,它被正确替换为生成的脚本块。

    我很想知道这是否有效。

    【讨论】:

    • 谢谢 :) 我曾怀疑在使用 extend 制作的副本中引用了相同的 DOM 元素,但不确定。您的建议适用于将 id 添加到脚本的细微调整(否则下次加载表数据时无法找到它)。
    猜你喜欢
    • 2013-08-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多