11
12

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Knockout.jsで'touchend'のカスタムバインディング

Last updated at Posted at 2014-10-24

スマフォ用サイトでclickイベントを使用すると、モサっとした感じになります。
この現象については、clickイベントには待ち時間が存在するからで、スマフォサイトの場合はtouchイベントを使う事で解決する事になると思います。

しかしながら、今のところKnockout.jsにはtouchstarttouchendといったバインディングは存在しません。
touchendイベントを指定したい場合等は、eventバインディングを使用します。

event-binding.html
<div data-bind="with: app">
  <button type="button" data-bind="event: {touchend: foo}">TOUCH!!</button>
</div>

<script>
var ViewModel = (function(){
  function ViewModel(){}

  ViewModel.prototype.foo = function(){
    alert('タッチされました。');
  };
})();

ko.applyBindings({
  app: new ViewModel()
});
</script>

これでtouchendイベントを紐付ける事が出来ました。
めでたし・めでたし

###・・・ではありません

touchendは画面をタッチしてスクロールした時も、指を離した瞬間に発生してしまいます。
これを防ぐために、touchstarttouchendの組み合わせで制御したりしますが、上記の様にeventバインディングで対応するとなると、これはもう大変な作業になってしまいます。

そこで、カスタムバインディングを使用する方法を考えてみます。

touchend-binding.html
<div data-bind="with: app">
  <button type="button" data-bind="touchend: foo">TOUCH!!</button>
</div>

<script>
var ViewModel = (function(){
  function ViewModel(){}

  ViewModel.prototype.foo = function(){
    alert('タッチされました。');
  };
})();

ko.applyBindings({
  app: new ViewModel()
});

// touchendのカスタムバインディング
ko.bindingHandlers['touchend'] = {
  'init': function(element, valueAccessor, allBindings, viewModel, bindingContext){
    var $el = $(element);
    var srcYOffset = null;

    // タッチスタート時に、元々のY座標を取得
    $el.on("touchstart", function(){
      srcYOffset = window.pageYOffset;
    });

    // タッチエンド
    $el.on("touchend", function(){
      var destYOffset = window.pageYOffset;

      if (srcYOffset === destYOffset) {
        var handlerFunction = valueAccessor();

        viewModel = bindingContext['$data'];

        handlerReturnValue = handlerFunction.apply(viewModel, arguments);
      }
    });
  }
};
</script>

touchend用のカスタムバインディングの中で、スクロールが発生している場合を判断する様に制御を入れました。
これでdata-bind="touchend: foo"といった様な記述だけで、スクロール制御がされたtouchendイベントが使用できます。

###追記(答えなし)
上記のコードでちょっと気になっているのが、$elに直接イベントをバインディングしているところです。
これだと、イベントの登録数が増える事が想定されるので、改善案を考えたいところです。

11
12
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
12

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?