자바스크립트 code_javascript 스킬의 한 조각으로 인한 생각

PHP中文网
풀어 주다: 2016-05-16 18:56:44
원래의
993명이 탐색했습니다.

这是一个关于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下的测试.我所期望的结果是(旁白:我已经开始犯错了): 

this is div88
 
this is div2
 
this is div3
 
实际结果: 
this is div88
 
问题: 
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('
this is div{id}
'); 
tpl.append('div1',{id:'2'}); 
tpl.insertAfter('div2',{id:'3'}); 
$("result-area").innerText = Ext.getDom("div1").innerHTML; 
//......... 
结果如下: 
this is div1 
this is div2
 
this is div3
 
?????? 为什么会这样? “this is div1”两边的
标签呢? 
在测试: 
var tpl = new Ext.Template('
this is div{id}
'); 
tpl.append('div1',{id:'2'}); 
tpl.insertAfter('div2',{id:'3'}); 
$("result-area").innerText = Ext.getDom("div1").outerHTML; 
//......... 
结果如下: 
 
this is div1 
this is div2
 
this is div3
 
 
(旁白:本来到这就已经能发现问题所在了,但执迷不悟,继续犯错) 
原来它把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('
this is div{id}
'); 
//tpl.append('div1',{id:'2'}); 
//tpl.insertAfter('div2',{id:'3'}); 
Insertion.After($('div1'),tpl.applyTemplate({id:'2'})); 
Insertion.After($('div1'),tpl.applyTemplate({id:'3'})); 
结果: 
this is div88
 
this is div2
 
this is div3

문제 해결................................................
반영: 왜 ?
코드를 보세요 (내레이션: 문제가 점점 깊어집니다)
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) }) ;
},
하단: function(element, content) {
return Element.insert(element, {bottom:content})
},
이후: function(element) , content ) {
return Element.insert(element, {after:content})
}
}
다음을 살펴보세요: line:1616
insert: function(element, inserts ) {
요소 = $(요소)
................................. ..........
for(삽입의 var 위치) {
content = inserts[position];
position = position.toLowerCase()
insert = Element._insertionTranslations [위치]
..........................
요소 반환
}
다음 참조: 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)
},
.......... ...
}
차이점 보기:
Ext:
El.insertAdjacentHTML
프로토타입:
El.parentNode.insertBefore
Protoype는 El.parentNode.insertBefore를 사용합니다. 호환성 문제를 고려해보세요. Mozilla는 El.insertAdjacentHTML을 지원하지 않아서 Ext를 사용하기 어렵다고 생각하지 않으셨나요? (해설: 아이디어가 완전히 엉망이 되어 점점 손실의 나락으로 향하고 있습니다.)
코드 검토 : DomHelper.js 라인: 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 '잘못된 삽입 지점 -> '''
}
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; ;
}
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 insert point -> "' where '"'
}
두 번째 부분(두 번째 스위치 블록)을 보면 Ext도 고려되는 것을 알 수 있는데, IE라면 , 코드는 두 번째 부분으로 이동할 수 없습니다.
이제 케이스 분기와 이전 메서드 이름 간의 대응 관계를 나열합니다.
insertFirst:' afterBegin'
insertBefore:' beforeBegin'
insertAfter:' afterEnd '
append:' beforeEnd'
위 코드를 비교해 보면 문제는 추가, insertAfter를 혼동한 것 같습니다. 추가는 현재 노드 바로 뒤에 노드를 추가하는 것을 의미하고 insertAfter는 삽입을 의미하는 것으로 생각했습니다. 사실 이것을 이해하면, add와 insertAfter는 동일한 기능을 가지고 있습니다. 그러면 Ext의 저자는 What is this method?라는 두 가지를 썼습니다. 아아, 제가 멍청해서 분석하지 않고 무작위로 사용했습니다.
발췌: Ext.Template의 add 및 insertAfter 메소드에 대한 설명
제공된 값을 템플릿에 적용하고 새 노드를 el에 추가합니다
제공된 값을 템플릿에 적용하고 el
뒤에 새 노드를 삽입합니다. 팁: 그렇지 않은 경우 이해가 안 되시면 넣어주세요. 첫 번째 문장의 "to"를 "in"으로 이해하시면 더 명확하지 않을까요? 또한, 페이지 요소에 대한 작업을 할 경우에는 위의 삽입과 추가 기능이 있는 Element를 사용해주세요. .
너무 많은 노력이 잘못된 방향으로 사용되어 최종 결과는 0입니다!
아아,
세상에 아무것도 없고, 평범한 사람들이 방해할 뿐입니다.

관련 라벨:
원천:php.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿