当我尝试解释这个时,请耐心等待,因为它有些复杂,我对JQuery完全不熟悉并试图了解它。
我和我的团队正在为一个SharePoint项目开发WebParts。 WebPart包含一个用户控件(SearchControl),它有一个链接打开一个包含另一个用户控件(SelectorControl)的对话框(使用jquery ui)。
SelectorControl包含:
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服务检索的数据创建对话框之前填充下拉列表,该服务随后绑定到第一个模板。
“更改”事件绑定到下拉列表,使用live来填充表(第二个模板),方法是调用WCF服务并传递下拉列表中当前选定的项目。
在下拉列表中触发更改事件时,将调用LoadObject:
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和pager的代码必须放在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用于将两个(或更多)对象合并为一个对象,但是从John的响应和我在文档中读到的内容,它听起来像是你应该使用的扩展创建一个jquery对象的副本。
任何人都可以向我解释究竟发生了什么,并推荐上述解决方案吗?
我的一些想法是:
我希望在采用其中任何一种方法之前,先了解代码目前正在做什么。
答案 0 :(得分:0)
这绝不是一个优雅的答案,但实际上,这是IE8的脚本引擎及其前身的失败。如果您的项目有支持这些浏览器的要求,那么代码将会更加难以理解,jQuery将没有多大帮助。你会注意到你在代码中首次使用.clone()
实际上在IE9,Firefox,Chrome和Safari中运行得很好。请允许我解释一下这个特殊的困难。
您的要求是复制DOM对象。 $.extend()
在这个实例中是不合适的,因为它只是克隆一个包装DOM目标集的jQuery对象,而不是实际的DOM目标。这意味着包装器的新副本仍然具有相同的DOM元素,并且不会附加目标副本,而是移动目标。因此,您最初使用.clone()
的假设是正确的。代码无法按预期运行的原因超出了您的控制范围。
IE9使用其前任的Node.cloneNode()
方法纠正了明显的缺陷,其中innerHTML
对象的Node
成员在script
元素的情况下不会被保留。这是jQuery的.clone()
调用使用的方法。在IE8及更早版本的任何脚本块上执行一系列经典JavaScript都会显示出来:
alert(document.getElementById("listTemplate").cloneNode(true).innerHTML);
此警报将包含所有其他主要浏览器中的内容。在IE8及以下版本中并非如此。 “true
”参数执行深层复制只是为了证明一个观点,但事实上这并不是必要的,因为script
元素在其Nodes
集合中没有childNodes
。
解决方法是丑陋的,我不完全确定它会按预期运行,因为我没有你的系统进行测试。您必须明确修改占位符元素的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);
我假设listTemplate
和templatePlaceholder
是jQuery对象,所以如果我弄错了,我道歉。但是,这里的基本思想是将整个脚本块构建为HTML字符串,并用您构建的字符串替换占位符中的HTML。
我不能保证IE会正确解释脚本块并使其可用于您的jQuery模板,但检查我选择的受害者占位符的innerHTML
确实表明,至少它已被替换正确使用生成的脚本块。
我很想知道这是否有效。