ExtJS Template append 导致子元素丢失的排查与源码分析

作者:像素猫时间:2026-10-23 11:11:49浏览:432

本文通过一个ExtJS Template append操作导致子元素在overwrite后消失的案例,深入分析了底层源码。发现问题根源在于insertAdjacentHTML方法对表格标签的特殊处理以及innerHTML直接赋值机制,导致动态生成的节点被插入到文本节点之后而非作为子元素,最终在覆盖时被清除。

在2008年的最后一天,在此祝愿大家元旦快乐。


郑重声明:此问题根本不是问题,现在看来就是本人知识匮乏,庸人自扰,望广大朋友勿喷。


细心发现问题,耐心解决问题,信心面对问题。


作者:白某人


问题复现与期望结果

长话短说:"服务员,上代码..."


测试代码:


 </head> <body> <div id="div1">this is div1</div> </body> 

[Ctrl+A 全选 注:引入外部Js需再刷新一下页面才能执行]


以下是在IE下的测试。我所期望的结果是(旁白:我已经开始犯错了):


<div id="div88">this is div88</div>


<div id="div2">this is div2</div>


<div id="div3">this is div3</div>


实际结果:


<div id="div88">this is div88</div>


问题:


Div2,div3 丢了?


源码追踪:Template与DomHelper

发现问题怎么办?看代码。


Template.js line:197 (Extjs ver 2.2)


append : function(el, values, returnElement){


return this.doInsert('beforeEnd', el, values, returnElement);


}

在看 line201:


doInsert : function(where, el, values, returnEl){


el = Ext.getDom(el);


var newNode = Ext.DomHelper.insertHtml(where, el, this.applyTemplate(values));


return returnEl ? Ext.get(newNode, true) : newNode;


}

在在看:DomHelper.js line:267


insertHtml : function(where, el, html){


where = where.toLowerCase();


if(el.insertAdjacentHTML){


if(tableRe.test(el.tagName)){


var rs;


if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){


return rs;


}
}

switch(where){


case "beforebegin":


el.insertAdjacentHTML('BeforeBegin', html);


return el.previousSibling;


case "afterbegin":


el.insertAdjacentHTML('AfterBegin', html);


return el.firstChild;


case "beforeend":


el.insertAdjacentHTML('BeforeEnd', html);


return el.lastChild;


case "afterend":


el.insertAdjacentHTML('AfterEnd', html);


return el.nextSibling;


}

throw 'Illegal insertion point -> "' + where + '"';


}

//////后面省略


}

深入分析:insertAdjacentHTML的行为

原来还是用的insertAdjacentHTML方法,为什么会有问题呢?


输出中间代码:


var tpl = new Ext.Template('<div id="div{id}">this is div{id}</div>');


tpl.append('div1',{id:'2'});


tpl.insertAfter('div2',{id:'3'});


$("result-area").innerText = Ext.getDom("div1").innerHTML;


//.........

结果如下:


this is div1


<DIV id=div2>this is div2</DIV>


<DIV id=div3>this is div3</DIV>


?????? 为什么会这样? “this is div1”两边的<div>标签呢?


在测试:


var tpl = new Ext.Template('<div id="div{id}">this is div{id}</div>');


tpl.append('div1',{id:'2'});


tpl.insertAfter('div2',{id:'3'});


$("result-area").innerText = Ext.getDom("div1").outerHTML;


//.........

结果如下:


<DIV id=div1>


this is div1


<DIV id=div2>this is div2</DIV>


<DIV id=div3>this is div3</DIV>


</DIV>


根本原因:innerHTML赋值与节点位置

(旁白:本来到这就已经能发现问题所在了,但执迷不悟,继续犯错)


原来它把div2,div3插到div1的value/text 后边了.所以运行tpl.overwrite('div1',{id:'88'});后div2,div3没了.


在此附上tpl.overwrite源码(innerHTML直接赋值):


overwrite : function(el, values, returnElement){


el = Ext.getDom(el);


el.innerHTML = this.applyTemplate(values);


return returnElement ? Ext.get(el.firstChild, true) : el.firstChild;


}

问题知道了,可怎么办呢,改Ext源码?


1

2下一页阅读全文

作者最新文章