2012-03-16 8 views
0

jQueryなどのフレームワークがはるかにアドバイスされ、適用可能であることを「実際の練習」で理解しています。これは本当にフレームワークの使い方、純粋なjavascriptの仕組みとベストプラクティスに関するものではありません)。DOMノードにデータ(オブジェクト、カスタム属性)を格納する方法をコーディングする方法

とにかく、私は単純なJavaScriptコードを書いています。私は、セット{on、off}から一度に1つの状態を持つ一連のボタン群を作成し、各状態は、その状態に入るときに起動される対応する関数にマップしたいと考えました。マスターセット内の各ボタングループには、一度にオン状態のボタンが1つだけ含まれています。概念はラジオボタンの考え方に似ています。 なぜラジオボタンを使用しないのですか?意味的には、いくつかのコントロール要素用のボタンがいくつかあると思われますが、いずれの方法でも可能ですが、質問は実際にはそうではありません。

この問題を解決するために、具体的なbutton要素に多くのカスタム属性を追加しました。これは、私のJavascriptでidです。私はいくつかの調査をしていましたが、これはquestionとこれがquestionで、DOMノード(オブジェクト)のカスタム属性の使用に関するものです。彼らはそのような練習に反対しているようだが、ブラウザの実装に応じてメモリリークを引き起こす可能性があるということさえある。

しかし、ボタンごとにたくさんの属性を記録する必要があります。このスクリプトを展開すると、さらに追加する必要があります。だから、DOMノードにそれらを格納するのに最も良い方法はありますが、すべてを追跡して使用することができますこのなどの機能には?

DOMノードbutton要素にwell-name spacingオブジェクトの参照を最小限格納することなく、これを行う方法を私には容易にはわかりませんでした。

このことから、question jQueryにはこれを行う方法がいくつかありますが、これは純粋なjavascriptでどのように行われているのか知りたいのです。

<!DOCTYPE html> 
<html> 
<head> 
    <title>Button Test Script</title> 

<script language="javascript" type="text/javascript"> 

window.button_groups = {}; 

function isset(type) { 
    return !(type==='undefined'); 
} 

function debug(txt) { 
    if(!isset(typeof console)) { 
     alert(txt); 
    } else { 
     console.log(txt); 
    } 
} 

function img(src) { 
    var t = new Image(); 
    t.src = src; 
    return t;  
} 

function turnGroupOff(group) { 
    if(isset(typeof window.button_groups[group])) {    
     for(var i = 0; i < window.button_groups[group].length; i++) {   
      if(window.button_groups[group][i].toggle == 1) 
       window.button_groups[group][i].click(); 
     }    
    } 
} 
/** 
* buttonId = id attribute of <button> 
* offImg = src of img for off state of button 
* onImg = src of img for on state of button 
* on = function to be fired when button enters on state 
* off = function to be fired when button enters off state 
*/ 
function newButton(buttonId, offImg, onImg, group, on, off) { 

    var b = document.getElementById(buttonId); 
    b.offImg = img(offImg); 
    b.onImg = img(onImg); 
    b.on = on; 
    b.off = off; 
    b.img = document.createElement('img'); 
    b.appendChild(b.img); 
    b.img.src = b.offImg.src; 
    b.group = group; 

    b.toggle = 0; 

    b.onclick = function() { 
     switch(this.toggle) { 
     case 0:            
      turnGroupOff(this.group); 
      this.on(); 
      this.toggle = 1; 
      this.img.src = this.onImg.src; 
      break; 
     case 1: 
      this.off(); 
      this.toggle = 0; 
      this.img.src = this.offImg.src; 
      break; 
     }  
    } 

    if(!isset(typeof window.button_groups[group])) 
     window.button_groups[group] = []; 
    window.button_groups[group].push(b);      

} 


function init() { 

    var on = function() { debug(this.id + " turned on") }; 

    newButton('button1', 'images/apply-off.jpg', 'images/apply-on.jpg', 'group1', 
     on, 
     function() { debug(this.id + " turned off"); } 
     ); 
    newButton('button2', 'images/unapply-off.jpg', 'images/unapply-on.jpg', 'group1', 
     on, 
     function() { debug(this.id + " turned off (diff then usual turn off)"); } 
     ); 

    newButton('button3', 'images/apply-off.jpg', 'images/apply-on.jpg', 'group2', 
     on, 
     function() { debug(this.id + " turned off (diff then usual turn off2)"); } 
     ); 
    newButton('button4', 'images/unapply-off.jpg', 'images/unapply-on.jpg', 'group2', 
     on, 
     function() { debug(this.id + " turned off (diff then usual turn off3)"); } 
     ); 

} 

window.onload = init; 
</script> 

</head> 

<body> 


<button id="button1" type="button"></button> 
<button id="button2" type="button"></button> 
<br/> 
<button id="button3" type="button"></button> 
<button id="button4" type="button"></button> 

</body> 
</html> 

UPDATE

jQueryの事は私の目的のためにビットやり過ぎだった:

は、ここに私が働いている完全なサンプルコードです。私は任意の要素を拡張する必要はありません。私はそれがどのようにjQuery(キャッシュインデックス整数を格納している任意の名前のついた任意の属性を持つ)に固有であるかを知っています。

私は、どのホスト要素を拡張する必要があるのか​​、またその方法を知っています。また、HTML側のそれぞれにid属性を設定することもできます。

jQueryの設定に影響を受けて、DOMキーのid属性をキャッシュキーとして使用する以外は、グローバルキャッシュ変数も作成することにしました。それは一意の識別子(定義による)でなければならないので、idを動的に変更する予定はなく、これは簡単な作業でなければなりません。私のJavascriptオブジェクトはDOMオブジェクトから完全に分離されていますが、dataへの多くの呼び出しでコードがかなり醜く見えにくくなります。私は本当に唯一の「特別な」属性を格納する必要が閉鎖の電源を使用して、それがボタンのグループであることがわかっ

<!DOCTYPE html> 
<html> 
<head> 
    <title>Button Test Script</title> 
<script language="javascript" type="text/javascript"> 

window.button_groups = {}; 

function isset(type) { // For browsers that throw errors for !object syntax 
    return !(type==='undefined'); 
} 

var c = { // For browsers without console support 
    log: function(o) { 
     if(isset(typeof console)) { 
      console.log(o); 
     } else { 
      alert(o); 
     } 
    }, 
    dir: function(o) { 
     if(isset(typeof console)) { 
      console.dir(o); 
     } 
    } 
}; 

function img(src) { // To avoid repeats of setting new Image src 
    var t = new Image(); 
    t.src = src; 
    return t;  
} 

var cache = {}; 
function data(elemId, key, data) { // retrieve/set data tied to element id 

    if(isset(typeof data)) {// setting data   
     if(!isset(typeof cache[elemId])) 
      cache[elemId] = {}; 
     cache[elemId][key] = data; 

    } else { // retreiving data 
     return cache[elemId][key];  
    } 

} 

var button_groups = {}; // set of groups of buttons 

function turnGroupOff(group) { // turn off all buttons within a group 
    if(isset(typeof window.button_groups[group])) {    
     for(var i = 0; i < window.button_groups[group].length; i++) {   
      if(data(window.button_groups[group][i].id, 'toggle') == 1) 
       window.button_groups[group][i].click(); 
     }    
    } 
} 


/** 
* buttonId = id attribute of <button> 
* offImg = src of img for off state of button 
* onImg = src of img for on state of button 
* on = function to be fired when button enters on state 
* off = function to be fired when button enters off state 
*/ 
function newButton(buttonId, offImg, onImg, group, on, off) { 

    var b = document.getElementById(buttonId); 
    data(b.id, 'offImg', img(offImg)); 
    data(b.id, 'onImg', img(onImg)); 
    data(b.id, 'on', on); 
    data(b.id, 'off', off); 
    var btnImg = document.createElement('img'); 
    btnImg.src = data(b.id, 'offImg').src; 
    data(b.id, 'img', btnImg ); 
    b.appendChild(btnImg); 
    data(b.id, 'group', group); 
    data(b.id, 'toggle', 0); 

    var click = function() { 
     switch(data(this.id,'toggle')) { 
     case 0:            
      turnGroupOff(data(this.id,'group')); 
      (data(this.id,'on'))(); 
      data(this.id,'toggle',1); 
      data(this.id,'img').src = data(this.id,'onImg').src; 
      break; 
     case 1: 
      (data(this.id,'off'))(); 
      data(this.id,'toggle',0); 
      data(this.id,'img').src = data(this.id,'offImg').src; 
      break; 
     } 

    } 

    b.onclick = click; 

    if(!isset(typeof window.button_groups[group])) 
     window.button_groups[group] = []; 
    window.button_groups[group].push(b);      
} 


function init() { 

    var on = function() { c.log(this.id + " turned on") }; 

    newButton('button1', 'images/apply-off.jpg', 'images/apply-on.jpg', 'group1', 
     on, 
     function() { c.log(this.id + " turned off"); } 
     ); 
    newButton('button2', 'images/unapply-off.jpg', 'images/unapply-on.jpg', 'group1', 
     on, 
     function() { c.log(this.id + " turned off (diff then usual turn off)"); } 
     ); 

    newButton('button3', 'images/apply-off.jpg', 'images/apply-on.jpg', 'group2', 
     on, 
     function() { c.log(this.id + " turned off (diff then usual turn off2)"); } 
     ); 
    newButton('button4', 'images/unapply-off.jpg', 'images/unapply-on.jpg', 'group2', 
     on, 
     function() { c.log(this.id + " turned off (diff then usual turn off3)"); } 
     ); 

} 


window.onload = init; 


</script>  
</head> 

<body> 


<button id="button1" type="button"></button> 
<button id="button2" type="button"></button> 
<br/> 
<button id="button3" type="button"></button> 
<button id="button4" type="button"></button> 


</body> 
</html> 

UPDATE 2

:私は、以下の変更を提示します所属していた。

私は閉鎖を通じて、私がしたものを他のものの多くを保存する必要性を排除するには、次のnewButton機能を変更:

function newButton(buttonId, offImg, onImg, group, on, off) { 

    var b = document.getElementById(buttonId); 
    offImg = img(offImg); 
    onImg = img(onImg); 
    var btnImg = document.createElement('img'); 
    btnImg.src = offImg.src; 
    b.appendChild(btnImg); 
    data(b.id, 'group', group); 
    var toggle = 0; 

    var click = function(event) { 
     switch(toggle) { 
     case 0:            
      turnGroupOff(data(this.id,'group')); 
      if(on(event)) { 
       toggle = 1; 
       btnImg.src = onImg.src; 
      } 
      break; 
     case 1: 
      if(off(event)) { 
       toggle = 0; 
       btnImg.src = offImg.src; 
      } 
      break; 
     } 

    } 

    b.onclick = click; 

    if(!isset(typeof window.button_groups[group])) 
     window.button_groups[group] = []; 
    window.button_groups[group].push(b);  

    b = null; 
} 
+0

jQueryはJavaScriptで_written_です。 [how they do it](https://github.com/jquery/jquery/blob/master/src/data.js)、特に 'data()'関数を見てください。 – voithos

答えて

1

ラップされたオブジェクトを使用してハッシュテーブル内の関連するデータを識別するオブジェクト(ホストオブジェクトには問題がある)を拡張するか、jQueryのようにオブジェクトをラップします。本質的には、DOMノードをハッシュし、関連付けられたデータのハッシュテーブルで参照を行います。もちろん、ホストオブジェクトを拡張する必要がありますが、任意のプロパティセットではなく、ブラウザ間で追加するのがかなり安全であることを知っている単一のプロパティだけを追加します。関連するデータを持つ要素を調べると、element.jQuery171023696433915756643のようなものが表示されます。この要素には、その要素の内部ストレージインデックスが含まれています。関心のある方、特にdata()関数の場合は、jQueryソースを読むことをお勧めします。

+0

私はこの質問を "進化した"と思って、[jQueryデータ関数のしくみ](http://stackoverflow.com/questions/5948099/jquery-data-how-to-work-question)に進化させました。したがって、実際にはこれを回避する方法はなく、最低限、単一の属性(例:ハッシュ名)をDOMノードに設定する必要があります。また、jQueryコードのコメントから、IE6-7だけがGCに問題があるように見えますか? – user17753

+0

私は今、それを取得すると思いますが、各DOMオブジェクトのデータが結び付けられているのは、データのキー/値を指すグローバル配列に数値インデックスを含む同じ任意のランダムプロパティ名で拡張されています。したがって、少なくとも少しはホストオブジェクトを拡張しない方法はありません。 – user17753

+0

はい。 IE6/7がGC:Pに問題がないのはいつですか?これについてもっと知りたいのであれば、http://javascript.info/tutorial/memory-leaks- "jQueryのアンチリーク対策とリーク"を読むことをお勧めします。 –

1

私はあなたにいくつかを与える可能性のJavaScriptのデザインパターンにthis記事を見つけましたアイデア。プロトタイプパターンを見て、インスタンス間でメソッドを再利用することができます。

+0

興味深い記事を指摘してくれてありがとう。 'Object.create'がとても新しく、古いブラウザーでの振る舞いを模倣するためにいくつかのシミングが必要になることに失望しています。しかし、実際には、再利用したいjavascriptオブジェクトには、メソッドやデフォルトのプロパティはありません。しかし、これは私が必要があるときに役立つかもしれません。この時点で私のコードが誤解を招く部分があることはわかっています。 – user17753

関連する問題