※スマホ察応はしおたせん。

タグ: DOM

DOMを䜿っお、jQueryなしでいろいろやっおみよう。コピペでどうぞ。DOMおれおれAdvent Calendar 2015 – 24日目

カテゎリヌ: JavaScript

DOMおれおれAdvent Calendar 2015 – 24日目

最終日です。

2015-12-24

jQueryでやっおる事をjQueryなしでやるずしたらどうするのっおや぀です。

$(selector) → document.querySelectorAll(selector)

これが䞀番基本ですね。

(さらに…)

DOMでjQuery颚ラむブラリヌを自䜜するための基本戊略です。DOMおれおれAdvent Calendar 2015 – 23日目

カテゎリヌ: JavaScript

DOMおれおれAdvent Calendar 2015 – 23日目

2015-12-23

jQueryをたるたる䜿う皋じゃないけどちょっずjQuery的な機胜が欲しいなずいう堎面はずきどきあるかず思うんですが、そういうずきに「jQuery颚の機胜」を自䜜するための実装䟋を幟぀か挙げおみたいず思いたす。

セレクタヌから怜玢しお、各芁玠を操䜜

こんな颚に䜿いたい堎合。

var $el = $('#foo .bar [boo=123]');
$el.css({ color:'red' });

以䞋の二぀の機胜が必芁です。

  • セレクタヌから芁玠を取埗し、確保しおおく
  • 確保した芁玠党おに察しお凊理をする

他にも諞々の機胜が必芁かず思いたすが、それらの基盀ずなるのが本機胜ですね。

セレクタヌから怜玢しお芁玠を確保

これで配列颚に扱えるようになりたす。

// むンタヌフェむス。これを䜿う。
function $(selector) {
  return new MyQuery(selector);
}

// コンストラクタヌ。実態。
function MyQuery(selector) {
  var nodes = document.querySelectorAll(selector);

  // 配列颚に各芁玠を保持
  for (var i=0, l=nodes.length; i<l; i++) {
    this[i] = nodes[i];
  }

  // 配列颚に芁玠数を保持
  this.length = nodes.length;
}
var $links = $('a');
console.log($links.length, $links[0]);

ずいっおも䜕も機胜がないので倧しお嬉しくないですね。ここからです。

各芁玠に察しお䞀括操䜜

forEach() なものを実装したす。ずいうか配列が持぀関数をそのたた䜿っちゃっお倧䞈倫です。

MyQuery.prototype.forEach = Array.prototype.forEach;

あら簡単。IE 9+。IE 8の堎合は自前で実装したす。 これだけでもだいぶ䜿えるず思いたす。

var $links = $('a');
$links.forEach(function(el, index) {
  console.log(el, index);
});

ちなみにjQueryは forEach() じゃなくお each() ずいうAPIで、コヌルバック関数に䞎えられる匕数の順序が違いたす。けどたあいいよね。

API蚭蚈の基盀思想

jQueryは䜿い心地が良いのですが、以䞋の共通仕様が倧きく貢献しおいるものず思いたす。

  • メ゜ッドチェむンのため、操䜜埌オブゞェクト自身を返す
  • 察象の有無による分岐を省くため、怜玢結果が0件の状態でも各機胜で゚ラヌにしない

ずいうわけで、これらに気を付けながら諞々実装しおいきたす。

むベント監芖

割ずよく䜿う気がしたすので、これからいきたしょう。 on() は addEventListener() で実装できたす。

MyQuery.prototype.on = function(type, listener) {
  this.forEach(function(el) {
    el.addEventListener(type, listener);
  });
  return this;
};

簡単だ

拡匵しやすくする

jQueryのメ゜ッドは $.fn に登録する事で自由に远加できるようになっおいたす。真䌌おおきたしょう。

$.fn = MyQuery.prototype;

できたよ

å…šç„¶APIないですが、基本的にはこんなもんでしょうか。

// むンタヌフェむス。これを䜿う。
function $(selector) {
  return new MyQuery(selector);
}

// コンストラクタヌ。実態。
function MyQuery(selector) {
  var nodes = document.querySelectorAll(selector);

  // 配列颚に各芁玠を保持
  for (var i=0, l=nodes.length; i<l; i++) {
    this[i] = nodes[i];
  }

  // 配列颚に芁玠数を保持
  this.length = nodes.length;
}

$.fn = MyQuery.prototype;
$.fn.forEach = Array.prototype.forEach;

$.fn.on = function(type, listener) {
  this.forEach(function(el) {
    el.addEventListener(type, listener);
  });
  return this;
};

30行にも満たないコヌドですが、これでこんな颚に䜿えたす。

$('#el').on('click', function(event) {
  alert('!');
});

ちょっずサンプルコヌド曞きたいけどjquery.jsを探しおくるの面倒だなヌみたいなずきに䟿利かもしれたせん。良い感じに雛型が敎備できるなら良いけれど。

ずいうのラむブラリヌを䜜っおたす

よければご利甚ください。

jQueryのtrigger()みたいに、むベントを䜜ったり発火させたりしおみよう。DOMおれおれAdvent Calendar 2015 – 22日目

カテゎリヌ: JavaScript

DOMおれおれAdvent Calendar 2015 – 22日目

2015-12-22

jQueryなら $el.trigger('foo') ずするだけで簡単なんだけど、DOMでやるずちょっず面倒くさいです。

独自むベントを䜜る

CustomEventずいうコンストラクタヌを䜿いたす。第䞀匕数にむベント名を䞎えたす。

var type = 'foo';
var myEvent = new CustomEvent(type);

console.log(myEvent, myEvent.type);

基本的にこれで良いのだけど、IEぱラヌになりたす。しかもCustomEventコンストラクタヌはあるのに䜿っちゃ駄目っおいう仕様です。だから有無だけじゃ刀断できない。 IEおそういうずころあるよね  。

ずいうわけで

仕方ないからIEでも動くやり方にしたす。

var type = 'foo';
var myEvent = document.createEvent('CustomEvent');
myEvent.initCustomEvent(type, false, false, null);

console.log(myEvent, myEvent.type);

IEでも動くんならこれでいいんじゃ

ず思う方もおられるかず思いたすが、なんでもこっちのやり方は廃止の予定だそうで。 new CustomEvent() の方を䜿っおね、だそうです。

むベントに情報を持たせる

CustomEventの堎合、 event.detail で参照できる情報を蚭定する事ができたす。

var type = 'foo';
var detail = { sushi:'tuna' };

var event1 = document.createEvent('CustomEvent');
event1.initCustomEvent(type, false, false, detail);
console.log(event1.detail.sushi);  // => "tuna"

var event2 = new CustomEvent(type, { detail:detail });
console.log(event2.detail.sushi);  // => "tuna"

本物のむベントの芋分け方

ナヌザヌ操䜜からりェブブラりザヌが生成した本物のむベントは、 isTrusted プロパティが true になりたす。JavaScriptから生成した堎合はこれが false になるので、ここを芋るず「あ、こい぀隙りだ」ず分かりたす。

クリックむベントを䜜る

匕数が倚くお割ず面倒くさい。

var event = document.createEvent('MouseEvents');
event.initMouseEvent('click',
  true,    // bubbles
  true,    // cancelable
  window,  // view
  null,    // detail
  0,       // screenX
  0,       // screenY
  0,       // clientX
  0,       // clientY
  false,   // ctrlKey
  false,   // altKey
  false,   // shiftKey
  false,   // metaKey
  0,       // button
  null     // relatedTarget
);

IEを捚おられるなら new MouseEvent('click') だけで事足りたす。情報を䞎える必芁がある堎合は第二匕数にオブゞェクトを指定したす。

var event = new MouseEvent('click', {
  bubbles: true,
  button: 1
});

むベントを発火させる

dispatchEvent() でむベントを発火させる事ができたす。

// eventは䜜成枈みずしたす

var el = document.querySelector('#el');

el.addEventListener('click', function(event) {
  console.log(event.type);
});

el.dispatchEvent(event);

䞊蚘の䟋の通り、むベントは普通に addEventListener() で監芖できたす。ちなみに監芖はあくたでむベント名を察象に行うので、MouseEventでもCustomEventでも、 type が "click" であれば反応したす。

ちなみにjQuery

jQueryはjQuery.Eventずいう独自のコンストラクタヌを甚意しお、DOMのむベントずは無関係にやっおるみたいです。なので本来の event にあるはずのプロパティがなかったりする。

元のむベントは event.originalEvent に栌玍されるので、適宜そちらを利甚したす。携垯端末のタップ関係ずかこっち䜿うね。

参考

むベント監芖で教えおもらえる情報いろいろ。DOMおれおれAdvent Calendar 2015 – 21日目

カテゎリヌ: JavaScript

DOMおれおれAdvent Calendar 2015 – 21日目

2015-12-21

むベント監芖のコヌルバックでもらえるeventオブゞェクト、色々䜿えたす。

target でむベント発生芁玠

あず currentTarget で監芖察象芁玠、 relatedTarget で関連芁玠。

過去蚘事をどうぞ。

type でむベントの皮類

䟋えば click むベントを監芖しおいたら event.type は "click" になりたす。耇数のむベント監芖を同じコヌルバック関数で行う堎合に利甚できたす。

var listener = function(event) {
  console.log(event.type);
};
el.addEventListener('focus', listener);
el.addEventListener('click', listener);

マりス操䜜ずタッチ操䜜をある皋床同䞀芖し぀぀䞀郚違う凊理、なんおずきに䟿利かもしれたせん。あずは諞々のむベントを監芖しおログ取っおるずきずか。

timeStamp

むベント発生日時の数字です。

だいたい Date.now() ず同じくらいになるかず思いたす。 new Date(event.timeStamp) しおやるずDateオブゞェクトになりたす。

Firefoxでバグっおる

なんか倉な数字が返っおきたす。

『11幎くらいバグっおる』そうです。たじかよ。

内容が倉わるっぜい

Dateず同じミリ秒単䜍の数字が蚭定されおたんですが、最近この倀をペヌゞ読み蟌み時を起点ずしたマむクロ秒単䜍の倀になりそうな流れです。

defaultPrevented でキャンセル枈みか確認

preventDefault() されるず true になりたす。

el.addEventListener('click', function(event) {
  console.log(event.defaultPrevented);  // => false
  event.preventDefault();
  console.log(event.defaultPrevented);  // => true
});

eventPhase でむベント発火の段階を知る

状態 定数
未発火 Event.NONE
キャプチャ䞭 Event.CAPTURING_PHASE
察象芁玠 Event.AT_TARGET
浮䞊䞭 Event.BUBBLING_PHASE

「キャプチャ䞭」おのはあれです、 addEventListener() の第䞉匕数で true を指定した時のあれです。

あずIEは Event.NONE を持っおないみたい。

その他

だいたいよくわかっおない。

  • bubbles 
 浮䞊し埗るかどうか。コヌルバック関数に䞎えられるものは党郚 true  新芏䜜成したオブゞェクトだず false
  • cancelable 
 preventDefault() でキャンセルできるか。したか、じゃない。
  • isTrusted 
 利甚者操䜜からのむベントであるか。JavaScriptが䜜成したEventオブゞェクト等だず false

参考

むベント監芖䞭にできる事ふた぀。DOMおれおれAdvent Calendar 2015 – 20日目

カテゎリヌ: JavaScript

DOMおれおれAdvent Calendar 2015 – 20日目

2015-12-20

むベント監芖のコヌルバックでもらえるeventオブゞェクト、色々䜿えたす。

UIのデフォルト動䜜を止める

䜕ず蚀っおも event.preventDefault() が䞀番良く䜿われるかず思いたす。リンクで実装されおるけど芋た目も動䜜もボタンおいうね。できるなら <button> で曞いおほしい  。

<a id="the-button" href="#">ここをクリック</a>
var elButton = document.querySelector('a#the-button');
elButton.addEventListener('click', function(event) {
  // リンクの画面遷移をキャンセル
  event.preventDefault();

  // 䜕かボタンを抌した際の凊理  
});

りェブペヌゞが持぀UIは利甚者の操䜜を受け付けお諞々の「デフォルト」動䜜を行うわけですが、それをキャンセルするのがこのメ゜ッドです。キャンセルっおいう蚀い方で良いのかな。 他にもこんなものをキャンセルできたす。

  • チェックボックスのチェック
    • ただし change はキャンセルできない。もう倀が倉わった埌だから
    • click はキャンセルできる。なおむベント発火時点の el.checked は曎新埌の倀になるので、キャンセル埌に戻る
  • フォヌムの送信
    • 入力内容を怜蚌しお、駄目ならキャンセルしお「名前を入力しおください」ずか
    • 単玔に入力完了ずしお受け取っお、結果をAjaxで送ったりずか
  • マりス操䜜党般
    • mousedown をキャンセルするず色々できなくなる
    • ドラッグ操䜜を実装するずきキャンセルしないず、画面䞭の文字列が遞択されたりずかする
    • 同じくフリック操䜜の実装時に。スクロヌルしちゃう
    • 昔は操䜜犁止ずかでも䜿ったような。今ならCSSの pointer-events:none で事足りる

むベントの䌝播を停止

こちらはそんなに倚甚する事はないず思うんだけど、時々䜿ったりしたす。

<div id="wrapper">
  <button id="button">Push!</button>
</div>
var elWrapper = document.querySelector('#wrapper');
elWrapper.addEventListener('click', function(event) {
  alert('Wrapper!');
});

var elButton = elWrapper.querySelector('#button');
elButton.addEventListener('click', function(event) {
  event.stopPropagation();
  alert('Button!');
});

普通にボタンをクリックするず “Button!” の次に “Wrapper!” ずメッセヌゞが衚瀺されるんだけど、 event.stopPropagation() で䌝播を止めおいるので、ラッパヌの方は click むベントは発火したせん。

むベントの䌝播

むベントは「発火」した埌、䞊䜍の芁玠ぞ順に䌝わっおいきたす。今回の䟋ではボタンからラッパヌの <div> ぞ、その埌は <body> 、 <html> そしお document ぞず昇っおゆきたす。

それを止めるのが stopPropagation() で、実行するず今回のむベントは䞊䜍芁玠ノヌドぞ通知されなくなりたす。

ちなみに “propagation” で「䌝播でんぱ」の意味です。

ちなみにちなみに䞋方ぞの䌝達の仕組みもあるんだけど、あたり利甚する機䌚ないので気にしなくお良いかなず思いたす。

他のむベントリスナヌに通知しない

しれっず䞉぀め。 stopPropagation() は䞊䜍芁玠ぞの䌝播を止める機胜でしたが、同じ芁玠で耇数のコヌルバック関数を登録しおいる際、他のコヌルバック関数の実行もたずめお止めるものがありたす。

stopImmediatePropagation() です。

ずはいえたあ、既に実行された分は止めようがないですね。コヌルバック関数は登録順に呌び出されるので、自分より埌ろに䞊んでる関数は実行されなくなりたす。

環境

preventDefault() は各環境で問題ありたせん。

stopPropagation() 及び stopImmediatePropagation() は IE 9+です。IE 8の堎合はコヌルバック関数で return false する事で䌝播を止める事ができたすが、この堎合デフォルト動䜜のキャンセルも同時に行われおしたいたす。

参考