4

私がやろうとしていることをよりよく反映するようにタイトルを更新しました。

つまり、dom要素ごとに異なるコンストラクターがあり、それらすべてが共通のプロトタイプを共有しているわけではないようです。これらのプロトタイプを変更して、すべてのDOM要素に関数プロパティを追加する方法を探していますが、それらを見つける方法がわかりません。

たとえば、次のようなことができます。

function enhanceDom (tagNames, methods) {
  var i=-1, tagName;
  while (tagName=tagNames[++i]) {
    var tag=document.createElement(tagName);
    if (!(tag && tag.constructor)) continue;
    for (var methodName in methods) {
      tag.constructor.prototype[methodName]=methods[methodName];
    }
  }
}

var thingsToEnhance = ['a','abbr','acronym','address'/* on and on... */];

enhance(thingsToEnhance, {
  doStuff : function(){
    /* ... */
  },
  doOtherStuff : function(){
    /* ... */
  } 
  /* ... */
});

もちろん、すべてのhtml要素をリストせずにこれを実行したいと思います。誰かがより良い方法を考えることができますか?

(元の質問は次のとおりです)

目標-getElementsByClassName任意のブラウザの任意のDOMノードで動作するようにします。

それは以前に(ある種の)行われたことがありますが、これが私のショットです。

私が持っている質問は、動的に作成された要素でこれを機能させる良い方法はありますか?HTML DOM要素は、追加できる共通の予測可能なプロトタイプを共有していないgetElementsByClassNameようです...または、何かが足りないのでしょうか。

これが私がこれまでに得たものです(編集-ディスカッションごとに更新されます)。

(function(){

  var fn = 'getElementsByClassName'; 
  // var fn = 'gEBCN'; // test

  if (typeof document[fn] != 'undefined') return;

  // This is the part I want to get rid of...
  // Can I add getByClass to a single prototype
  // somewhere below Object and be done with it?

  document[fn]=getByClass;
  withDescendants(document, function (node) {
    node[fn]=getByClass;
  });

  function withDescendants (node, callback, userdata) {
    var nodes = node.getElementsByTagName('*'), i=-1;
    while (node=nodes[++i]) {
      callback(node, userdata);
    }
    return userdata;
  }

  function getByClass (className) {
    return withDescendants(this, getMatches, {
      query:new RegExp('(^|\\s+)' + className + '($|\\s+)'), 
      found:[]
    }).found;
  }

  function getMatches (node, data) {
    if (node.className && node.className.match(data.query)) {
      data.found.push(node);
    }
  }

}());

スクリプトがロードされる前にロードされたコンテンツではうまく機能しますが、動的に作成された新しい要素はgetElementsByClassNameメソッドを取得しません。何か提案はありますか(setInterval以外にお願いします)?

4

2 に答える 2

5

私はあなたが望むものは、次のようなElementインターフェースのプロトタイプを作成することによって達成できると思います

Element.prototype.getElementsByClassName = function() {
    /* do some magic stuff */
};

しかし、これをしないでください。すべての主要なブラウザで確実に機能するわけではありません。

質問の例で行っていることもお勧めできません。実際には、ホストオブジェクトを拡張しています。繰り返しますが、これを行わないでください。

プロトタイプが遭遇した落とし穴に正確に陥ります。

Kangaxの記事を単にコピーしたくないので、DOMを拡張することの何が問題になっているのかを読んでください。

そもそもなぜこれが欲しいのですか?あなたの目標は何ですか?

于 2010-09-06T23:10:03.257 に答える
0

これはうまくいくようですが、醜いです。IEで動作するのだろうか?

(function(){

  enhanceDom('a abbr acronym address applet area b base basefont bdo big blockquote body br button caption center cite code col colgroup dd del dfn dir div dl dt em fieldset font form frame frameset h1 h2 h3 h4 h5 h6 head hr html i iframe img input ins isindex kbd label legend li link map menu meta noframes noscript object ol optgroup option p param pre q s samp script select small span strike strong style sub sup table tbody td textarea tfoot th thead title tr tt u ul var'
  ,{
    getElementsByClassName : getByClass
    /* , ... */
  });

  function enhanceDom (tagNames, methods) {
    var i=-1, tagName;
    if (tagNames==''+tagNames) {
      tagNames=tagNames.split(' ');
    }
    for (var methodName in methods) {
      setIfMissing(document, methodName, methods[methodName]);
      while (tagName=tagNames[++i]) {
        var tag=document.createElement(tagName);
        if (tag || !tag.constructor) continue;
        var proto=tag.constructor.prototype;
        setIfMissing(proto, methodName, methods[methodName]);
      }
    }
  }

  function setIfMissing (obj, prop, val) {
    if (typeof obj[prop] == 'undefined') {
      obj[prop]=val;
    }
  }

  function withDescendants (node, callback, userdata) {
    var nodes=node.getElementsByTagName('*'), i=-1;
    while (node=nodes[++i]) {
      callback(node, userdata);
    }
    return userdata;
  }

  function getByClass (className) {
    return withDescendants(this, getMatches, {
      query:new RegExp('(^|\\s+)' + className + '($|\\s+)'), 
      found:[]
    }).found;
  }

  function getMatches (node, data) {
    if (node.className && node.className.match(data.query)) {
      data.found.push(node);
    }
  }

}());
于 2010-09-07T00:15:03.960 に答える