7cc@はてなブログ

JavaScriptとかとか

element.addEvent の順で書く その2

addEventListenerとattachEventを両立するよくある話。
前回書いたのがいまいちに思えるので

理想

  • なるべくaddEventListenerと同じ順で書きたい(けどaddEventListenerってそもそも長い!)
  • 複数の要素相手にforループもいちいち面倒なので省略したい
  • 複数のイベントも楽につけたい

ということで書いてみたが…パターンがいろいろ考えられるのでどれがよいのやら。一番単純なパターンはこうなりました。考えられるパターンは下記に。

コード

// IE8+
QQ.doc = document
QQ.sup = QQ.doc.addEventListener
QQ.add = QQ.sup ? 'addEventListener' : 'attachEvent'
QQ.pre = QQ.sup ? '' : 'on'

function QQ(sel) {
  this.eles = typeof sel === "string" ? // string
    QQ.doc.querySelectorAll(sel) : sel === null ? // getElementById(no-such-element)
      [] : sel.nodeName || sel === window ? // array, NodeList, HTMLCollection
        [sel] : sel  // single:element, window, document
}

QQ.prototype.addEvent = function(type, listener, useCapture) {
  for(var i=0; i<this.eles.length; i++){
    this.eles[i][QQ.add](QQ.pre + type, listener, useCapture || false)
  }
  var _this = this
  return function(t, l, u){
    return _this.addEvent(t, l ,u)
  }
}

function qq(sel){
  return new QQ(sel)
}

usage

qq("div").addEvent("click", fn, false)
qq(window).addEvent("click", fn, false)
qq([window, document]).addEvent("click", fn, false)
qq(document.getElementById("test")).addEvent("mouseover", mouseFn, false)("mousemove", mouseFn, false)("mouseout", mouseFn, false)

考えられるパターン

  1. ノーマル。これだとtype,listenerは一つだけしか渡せない
    [elements].addEvent(type, fn, false)
  2. jQueryみたいな?
    [elements].addEvent([types], fn, false)
  3. 2の逆パターン
    [elements].addEvent(type, [fns], false)
  4. type,fnをオブジェクトで渡す
    [elements].addEvent({type:fn, type:fn, ....}, false)
  5. 今回の。
    [elements].addEvent(type, fn, false)(type, fn, false)(....

4を用いれば2,3は両立できる。しかしusecaptureを個別に設定できない。
個別に設定できる5は配列を何度もループすることになるので効率が良くはない...と思ったら大して変わらなかった。

書きやすさなら4, usecaptureも設定したなら5でしょうか。
ほとんどfalseにしますけどね。