ホームページ  >  記事  >  ウェブフロントエンド  >  JavaScript コードの一部によって引き起こされる思考_JavaScript スキル

JavaScript コードの一部によって引き起こされる思考_JavaScript スキル

PHP中文网
PHP中文网オリジナル
2016-05-16 18:56:44963ブラウズ

这是一个关于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
問題は解決しました....................................
考察: なぜ?
コードを見てください (ナレーション: 問題はますます深くなります)
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});
After: 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.insertBefore(node, element.firstChild);
},
bottom: function(element, ノード) {
element.appendChild(node); 🎜>},
after: function(element, node) {
element.parentNode.insertBefore(node, element.nextSibling);
},
.... ...
};
違いを参照してください:
拡張:
El.insertAdjacentHTML
プロトタイプ:
El.parentNode.insertBefore
プロトタイプは 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" :
return el.firstChild; >case "beforeend":
el.insertAdjacentHTML('BeforeEnd', html);
return el .lastChild;
case "afterend":
el.insertAdjacentHTML('AfterEnd', html);
return el.nextSibling;
throw '不正な挿入ポイント ->' where '"';
var range = el.ownerDocument.createRange(); >var frag;
switch(where){
case "beforebegin":
frag = range.createContextualFragment(html); (frag, el);
return el.previousSibling;
case "afterbegin":
if(el.firstChild){
range.setStartBefore(el.firstChild); .createContextualFragment(html);
el.insertBefore(frag, el.firstChild);
el.firstChild;
el.innerHTML = html; ;
}
ケース "beforeend":
if(el.lastChild){
range.setStartAfter(el.lastChild);
frag = range.createContextualFragment(html); el.appendChild(frag);
return el.lastChild;
el .innerHTML = html;
return el.lastChild;
range.setStartAfter(el);
frag = range.createContextualFragment(html);
el.parentNode.insertBefore(frag, el.nextSibling);
throw 'Illegal insert point -> where '"';
}
2 番目の部分 (2 番目の switch ブロック) から、Ext も考慮されていることがわかりますが、IE の場合は
ここで、case ブランチと前のメソッド名との対応をリストします。
insertFirst:' afterBegin'
insertBefore:' beforeBegin'
insertAfter:' afterEnd '
append:' beforeEnd'
上記のコードを比較すると、append、insertAfter を混同していることが問題のようです。append は現在のノードの直後にノードを追加することを意味し、insertAfter はノードを挿入することを意味すると思いました。実際、これが理解されていれば、append と insertAfter は同じ機能を持っています。Ext の作成者は、このメソッドは何のためにあるのかを 2 つ書きました。ああ、私は愚かで、それを分析せずにランダムに使用しました。
抜粋: Ext.Template の append メソッドと insertAfter メソッドの説明
指定された値をテンプレートに適用し、新しいノードを el
に追加します。 指定された値をテンプレートに適用し、新しいノードを el
の後に挿入します。 ヒント:わかりません、入れてください 最初の文の「to」を「in」と理解したほうがわかりやすいでしょうか? また、ページ要素を操作する場合は、上記の挿入および追加機能を持つ Element を使用してください。
多くの努力は間違った方向に使われ、最終的な結果はゼロです。
ああ、
世の中には何もなく、凡庸な人間が自分自身を邪魔するだけです。 🎜>

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。