JavaScript、スマホで、bodyのみスクロール無効

謎のプリン語る。
プログラミングの役立つ情報とか、どうでもいい雑談とか書いてます。
一人書く人増えました。

JavaScript、スマホで、bodyのみスクロール無効

2016年11月11日

みやびプリン 500 316

500 320

JavaScript、スマホで、bodyのみスクロール無効 - サムネイル

※この記事は4年以上前の記事です。
現在は状況が異なる可能性がありますのでご注意ください。

どうも、禁ゲーの禁断症状で死にそうなみやびです。
もうね、会社行かなくなる勢いだからねマジ。

さて、表記の件やっていこう。

これね、全部スクロール無効にすんなら簡単なんだよ。
例えば、下記HTMLの、div#testTargetをスワイプした時はスクロールさせない、とか。

●HTML

<body>
<div id="testTarget" style="overflow-y: auto; height: 200px;">
  <p>
    あかさたな
    はまやらわ
    <span style="display: block; margin-top: 800%;">わをーーーん</span>
  </p>
</div>
</body>

●JavaScript(jQuery)

$('#testTarget').on('touchmove.noScroll', function(e) {
  e.preventDefault();
});

ターゲットDOMに対して、このようにイベントを追加すればいい。
ただし、これやるとどうなるかってと、
div自体のスクロールも不能になる。
例えば、サイドバーを表示する時、
サイドバーの高さが高い時なんかは、コンテンツの下のほうが見えなくなる。

そしたらねぇ、自分でスクロールを作るしかない。
※jQuery使ってます。

$('#testTarget').on('touchmove.noScroll', function(e) {
  e.preventDefault();
});//div上では全部スクロールできないようにする。

//共通変数を定義
var scrollYStart = 0,
  scrollYMove = 0,
  swipeTime = new Date();

var scrollAction = function(setDom, d, spd){
  setDom.stop().animate({scrollTop: d}, spd, 'easeOutQuint');
};


$(function(){
$('#testTarget').bind({
  touchstart: function(e) {
    //タッチ始め
    $(this).stop();//アニメーションストップ
    scrollYStart = event.changedTouches[0].pageY;//タッチ始めの座標
    scrollYMove = scrollYStart;
  swipeTime = new Date();//タッチ始めの時間
  },
  touchmove: function(e) {
    //スワイプ中
    var posY = event.changedTouches[0].pageY,//スワイプ中の座標
      scrollNow = $(this).scrollTop();//現在のスクロール
    
    var lastSc = scrollNow + scrollYMove - posY;
   
    scrollAction($(this), lastSc, 0.5);//スクロールを実行
    scrollYMove = posY;//スワイプ中座標を格納
  },
  touchend: function(e) {
    //タッチが終わった時
    var lastY = scrollYStart - scrollYMove;//どれだけスワイプしたか
    var nowT = new Date();//タッチ終了時間
    var difTime = nowT.getTime() - swipeTime.getTime();//スワイプ経過時間
    
    if (difTime < 601) {
      //601ミリ秒以内のスワイプなら実行
      var scP = (lastY < 0 ? lastY * -1: lastY) / difTime * 100;//追加スクロール量計算

      var lastScroll = $(this).scrollTop() + (lastY < 0 ? -1 * scP : scP);//スクロール位置

      scrollAction($(this), lastScroll, 700);
    }
  }
});
});

見ればわかると思うけど、
touchstart、touchmove、touchendの三点セットを使って、
スクロールを再現してるわけだ。
スタートでスワイプ開始時間をとり、タッチ終了時との時間比較で、
短ければ、スワイプとみなし、アニメーションで追加スクロールをする。

これを使えば、
サイドバーを表示している間は、bodyはスクロールさせないで、
その中身をスクロール、なんてできる。

設定数値を変えれば、スクロールの感じを変えることができる。
iPhoneでやればそれっぽくって設定したつもり。

やり方は全然違うが、下記エントリーが非常に参考になった。
タッチイベントを用いたスワイプ&フリックの実装サンプル

これやるのに、えらく苦労したんだよ。
最初は、背景要素とコンテンツ要素を分け、背景要素にだけ、スクロール禁止をし、
対象要素だけ、デフォルトのスクロールをそのまま残すようにした。
だが、それだと、対象要素をスクロールしている間に、bodyが動いてしまう時があった(特にiPhone)
しかし、これなら、そんなんもクリアできる。
問題はデバイスのスペックだけど、
現代のデバイスならだいたいいけると思う。

さて、帰るかね・・・。

ラグナロクオンライン - メイン

トラックバック(0)

トラックバックURL:

コメントする

ページトップへ戻る