Home  >  Article  >  Web Front-end  >  Thoughts caused by a piece of javascript code_javascript skills

Thoughts caused by a piece of javascript code_javascript skills

PHP中文网
PHP中文网Original
2016-05-16 18:56:44963browse

这是一个关于Ext, Prototype, JavaScript方面的问题,其实下面遇到的问题本不是问题,都是因为错误的理解造成的,本文的宗旨是希望读者朋友避免我犯的同类错误,遇事三思而后行,同时也体会下发现问题,解决问题,反思问题这种精神活动所带来的快乐!

测试代码

<script type="text/javascript"> 
function init(){ 
var tpl = new Ext.Template(&#39;<p id="p{id}">this is p{id}</p>&#39;); 
tpl.append(&#39;p1&#39;,{id:&#39;2&#39;}); 
tpl.insertAfter(&#39;p2&#39;,{id:&#39;3&#39;}); 
tpl.overwrite(&#39;p1&#39;,{id:&#39;88&#39;}); 
} 
Ext.onReady(init); 
</script> 
</head> 
<body> 
<p id="p1">this is p1</p> 
</body>

以下是在IE下的测试.我所期望的结果是(旁白:我已经开始犯错了): 
6dc214457e614d597f9d4d529debc81fthis is div8816b28748ea4df4d9c2150843fecfba68 
295e81a0ea4e7eed4f43b0669aad50c2this is div216b28748ea4df4d9c2150843fecfba68 
83ac4715e7087b135b455d34056492d6this is div316b28748ea4df4d9c2150843fecfba68 
实际结果: 
6dc214457e614d597f9d4d529debc81fthis is div8816b28748ea4df4d9c2150843fecfba68 
问题: 
Div2,div3 丢了? 
发现问题怎么办?看代码. 
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方法,为什么会有问题呢? 
输出中间代码: 
var tpl = new Ext.Template('d84829bf1326c239e3bf8396276f45e2this is div{id}16b28748ea4df4d9c2150843fecfba68'); 
tpl.append('div1',{id:'2'}); 
tpl.insertAfter('div2',{id:'3'}); 
$("result-area").innerText = Ext.getDom("div1").innerHTML; 
//......... 
结果如下: 
this is div1 
3054d5539162fa827ace69aa18d2ebcbthis is div2c997cec9f4b83324a7145373fde865ba 
f9596f12c25af0459e75dee8a46aa161this is div3c997cec9f4b83324a7145373fde865ba 
?????? 为什么会这样? “this is div1”两边的dc6dce4a544fdca2df29d5ac0ea9906b标签呢? 
在测试: 
var tpl = new Ext.Template('d84829bf1326c239e3bf8396276f45e2this is div{id}16b28748ea4df4d9c2150843fecfba68'); 
tpl.append('div1',{id:'2'}); 
tpl.insertAfter('div2',{id:'3'}); 
$("result-area").innerText = Ext.getDom("div1").outerHTML; 
//......... 
结果如下: 
b6301f87509127fbacc7431228a6286c 
this is div1 
3054d5539162fa827ace69aa18d2ebcbthis is div2c997cec9f4b83324a7145373fde865ba 
f9596f12c25af0459e75dee8a46aa161this is div3c997cec9f4b83324a7145373fde865ba 
c997cec9f4b83324a7145373fde865ba 
(旁白:本来到这就已经能发现问题所在了,但执迷不悟,继续犯错) 
原来它把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源码? 

从做项目的角度来看,最好别改,因为你不清楚原作者的想法,容易把问题扩大化. 
改源码不是不行,但那是没有办法的办法,如果能找到其它好的解决方案, 最好别改 
(实际上Ext这块没有问题,只是我在参照API使用时,混淆了一些概念) 
不改源码,只能找到其它好的解决方案了,用prototype.js看看: 
var tpl = new Ext.Template('d84829bf1326c239e3bf8396276f45e2this is div{id}16b28748ea4df4d9c2150843fecfba68'); 
//tpl.append('div1',{id:'2'}); 
//tpl.insertAfter('div2',{id:'3'}); 
Insertion.After($('div1'),tpl.applyTemplate({id:'2'})); 
Insertion.After($('div1'),tpl.applyTemplate({id:'3'})); 
结果: 
6dc214457e614d597f9d4d529debc81fthis is div8816b28748ea4df4d9c2150843fecfba68 
295e81a0ea4e7eed4f43b0669aad50c2this is div216b28748ea4df4d9c2150843fecfba68 
83ac4715e7087b135b455d34056492d6this is div316b28748ea4df4d9c2150843fecfba68
Problem solved......................................
Reflection: Why?
Look at the code (Narration: the problem gets deeper and deeper)
Prototype.js line:4042 (ver 1.6.0.2)
var Insertion = {
Before: function(element, content) {
return Element.insert(element, {before:content});
},
Top: function(element, content) {
return Element.insert(element, {top:content}) ;
},
Bottom: function(element, content) {
return Element.insert(element, {bottom:content});
},
After: function(element, content ) {
return Element.insert(element, {after:content});
}
};
Then look at: line:1616
insert: function(element, insertions) {
element = $(element);
.............................................
for (var position in insertions) {
content = insertions[position];
position = position.toLowerCase();
insert = Element._insertionTranslations[position];
.......... .....................
return element;
}
See next: line:2490
Element._insertionTranslations = {
before: function(element, node) {
element.parentNode.insertBefore(node, element);
},
top: function(element, node) {
element.insertBefore(node, element.firstChild);
},
bottom: function(element, node) {
element.appendChild(node);
},
after: function(element, node) {
element.parentNode.insertBefore(node, element.nextSibling);
},
.............
};
See the difference:
Ext:
El. insertAdjacentHTML
Prototype:
El.parentNode.insertBefore
Protoype uses El.parentNode.insertBefore to consider compatibility issues. Mozilla does not support El. insertAdjacentHTML, so it is difficult to use Ext Didn’t you consider it? (Narration: The idea is completely messed up and gradually heading towards the abyss of loss)
Reviewing the code: DomHelper.js line: 267
insertHtml: function(where, el, html){
. .....
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 '"';
}
var range = el.ownerDocument.createRange();
var frag;
switch(where){
case "beforebegin":
range. setStartBefore(el);
frag = range.createContextualFragment(html);
el.parentNode.insertBefore(frag, el);
return el.previousSibling;
case "afterbegin":
if(el.firstChild){
range.setStartBefore(el.firstChild);
frag = range.createContextualFragment(html);
el.insertBefore(frag, el.firstChild);
return el .firstChild;
}else{
el.innerHTML = html;
return el.firstChild;
}
case "beforeend":
if(el.lastChild){
range.setStartAfter(el.lastChild);
frag = range.createContextualFragment(html);
el.appendChild(frag);
return el.lastChild;
}else{
el .innerHTML = html;
return el.lastChild;
}
case "afterend":
range.setStartAfter(el);
frag = range.createContextualFragment(html);
el.parentNode.insertBefore(frag, el.nextSibling);
return el.nextSibling;
}
throw 'Illegal insertion point -> "' where '"';
}
From the second part (the second switch block), we can see that Ext is also considered, but if it is IE, the code cannot go to the second part.
Now list the correspondence between the case branch and the previous method name:
insertFirst:' afterBegin'
insertBefore:' beforeBegin'
insertAfter:' afterEnd'
append:' beforeEnd'
Comparing the above code, it seems that the problem is that I am confused append, insertAfter. I thought that append means appending a node directly after the current node, and insertAfter means inserting the node after the current node. In fact, if this is understood, append and insertAfter have the same functions. Then the author of Ext wrote two What is this method for?., Alas, I am stupid, I used it randomly without analyzing the code carefully, and it led to this long series of things.
Excerpt: Explanation on the append and insertAfter methods in Ext.Template
Applies the supplied values ​​to the template and appends the new node(s) to el
Applies the supplied values ​​to the template and inserts the new node(s) after el
Tip: For those who don’t understand, please put Wouldn’t it be much clearer if “to” in the first sentence is understood as “in”? In addition, if you operate on page elements, please use Element, which has the insert and append functions above.
So much effort is used in the wrong way In the direction, the final result is zero!
Alas,
There is nothing in the world, and it is only for mediocre people to disturb themselves.

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn