タイマーで常に変数を監視し、慣性スクロールを疑似的に表現する自作のJSがあります。
iphone safariでは標準スクロール中にアニメーションのレンダリングが止まる問題があり、
それに対処するためにcssのtopプロパティにマイナスの値を入れることで疑似的にスクロールしているように見せています。
jqueryやその他フレームワークには依存せずネイティブで書いています。
そこで「ページトップへ戻る」ボタンのようにページ内スクロールをしたいのですが、
うまい実装方法があれば教えていただきたいです。
トップだけではなく特定のセクションへも移動できる必要があります。
ブラウザ標準スクロールと疑似スクロールを切り替える機能があり、
標準スクロールモードなら普通にjqueryなどで楽にページ内移動できます。
ただ慣性スクロールをしたい場合にどうしたらいいのか客観的に見られなくなってきて悩んでいます。
全コードは長くなるので割愛しますが下記が当問題にかかわる部分です。
以上質問の仕方が難しいですがよろしくお願いいたします。
##画面描画・監視用のメソッド
render : function render() { // アニメーションをレンダリングするメソッド var self = this; var getPos = self.getPos(); render.speed = render.speed || 0; // 初めて呼び出した場合スタイルを設定 if (!body.style.top && Merimiroll.touch_mode === true) { Merimiroll.scroll.y = 0; body.style.cssText = "position: fixed; " + "top:" + 0 + "px;"; // ウィンドウをfixedにしてスクロールバーが消えたのでサイズを再取得 self.updateSize(); } if (!render.setListener) { // 初回呼び出し時にタッチムーブイベントをセット this.addEvent(window, "touchmove", function (e) { self.emulateScroll(e); }); this.addEvent(window, "resize", function (e) { self.updateSize(); }); if (Merimiroll.touch_mode === true) { this.addEvent(window, "wheel", function (e) { self.emulateScroll(e); }); } render.setListener = true; } // ナビゲーションフラグが立っている場合 イベントリスナが登録されたボタンが押されるとisNavigationをtrueにする if (Merimiroll.isNavigation) { ///////////////////////////////////////////// // このセクション内をどうするか知りたい Merimiroll.dy = Math.floor(Merimiroll.scroll.targetY - Merimiroll.scroll.y); // targetY をうまく更新できたらいいような気がする Merimiroll.vy += Merimiroll.dy; Merimiroll.vy *= Merimiroll.friction;// 慣性スクロールのための摩擦 Merimiroll.scroll.y += Merimiroll.vy; Merimiroll.scroll.targetY = Merimiroll.scroll.y; ///////////////////////////////////////////// } else { // このセクションはちゃんと動く Merimiroll.dy = Math.floor(Merimiroll.scroll.targetY - Merimiroll.scroll.y); Merimiroll.vy += Merimiroll.dy; Merimiroll.vy *= Merimiroll.friction;// 慣性スクロールのための摩擦 Merimiroll.scroll.y += Merimiroll.vy; Merimiroll.scroll.targetY = Merimiroll.scroll.y; Merimiroll.isNavigation = false; } // 全体のスクロール位置を更新 body.style.cssText = "position: fixed; " + "top:" + Math.floor(Merimiroll.scroll.y) + "px;"; // スクロールバーの位置 scrollbar.amount_move = window_height * (Merimiroll.scroll.y / container_height); scrollbar.el.style.cssText += "position: fixed; " + "top:" + -scrollbar.amount_move + "px;"; // 一番下までスクロールした時 if (Merimiroll.scroll.y < -distance_max) { body.style.cssText = "position: fixed; " + "top:" + -distance_max + "px;"; Merimiroll.vy = 0;// 速度をなくす // スクロールバー scrollbar.el.style.cssText += "position: fixed; " + "top:" + -distance_max + "px;"; Merimiroll.scroll.y = -distance_max; } // 一番上までスクロールした時 if (Merimiroll.scroll.y > 0) { Merimiroll.scroll.y = 0; body.style.cssText = "position: fixed; " + "top:" + 0 + "px;"; Merimiroll.vy = 0;// 速度をなくす // スクロールバー scrollbar.el.style.cssText += "position: fixed; " + "top:" + 0 + "px;"; } Merimiroll.timerId = function(){ Merimiroll.prototype.render(); }; setTimeout(Merimiroll.timerId, 60);// 更新 }
emulateScroll : function _emulateScroll(e) { e = e || window.event; //for legacy IE e.preventDefault();// デフォルトのスクロール動作をキャンセル e.cancelBubble = true; e.stopPropagation(); var self = this; // ここからイベントの処理 if (!_emulateScroll.setListener) { this.addEvent(window, "touchstart", function() { self.touchStart(); }); _emulateScroll.setListener = true; } if (e.type == "touchmove") { // 割愛 /////////////////////// } else if (e.type == "wheel") { Merimiroll.clock = e.timeStamp - Merimiroll.save; Merimiroll.save = e.timeStamp; if (Merimiroll.clock < Merimiroll.clock_limit) { return false;// 比較結果が指定ミリ秒より少ない場合はキャンセル } // pcでスクロールされた時 if (this.getDelta(e) < 0 && Merimiroll.scroll.y > -distance_max) { // 下にスクロールした場合の処理 Merimiroll.scroll.targetY = (Merimiroll.scroll.y + -Merimiroll.speed); } else if (this.getDelta(e) > 0) { // 上にスクロールした場合の処理 if (Merimiroll.scroll.y >= -distance_max && Merimiroll.scroll.y !== 0) { Merimiroll.scroll.targetY = (Merimiroll.scroll.y + Merimiroll.speed); } } } }
##トップへ戻るボタンへ登録するイベントハンドラ
hrefから#hogeを取得しその要素(移動先)の座標を取得
scrollTo: function _scrollTo (e) { if (Merimiroll.isNavigation == true) { return false;// 移動中はフラグをはずして何度も押せなくする } e = e || window.event; var reg = new RegExp("(#{1})([\\w\\-\\_]*)");// 先頭が#記号かつ、-と_を含んだ文字列を取得 var href = e.target.getAttribute("href"); _scrollTo.link_target = href.replace(reg, "$2");// #記号を削除 var self = this; var nav = e.target; var target_view = document.getElementById(_scrollTo.link_target) ? document.getElementById(_scrollTo.link_target) : null; // スクロール値を取得 var scrollTop = Math.floor(Merimiroll.prototype.getPos().y); var x = target_view.getBoundingClientRect().left; var y = target_view.getBoundingClientRect().top;// スクロール先の座標 var viewY = Math.floor(scrollTop + y);// ドキュメント座標 _scrollTo.distance = Math.floor(scrollTop - viewY); Merimiroll.isNavigation = true; Merimiroll.navigation_distance = _scrollTo.distance; Merimiroll.navigation_distance_now = Merimiroll.navigation_distance; Merimiroll.navigation_view = target_view; Merimiroll.navigation_view_docY = viewY; Merimiroll.navigation_view_x = target_view.getBoundingClientRect().left; Merimiroll.navigation_view_y = target_view.getBoundingClientRect().top;// スクロール先の座標 //////////////////////////////////////////////////// // このセクションでどういう処理をするのが良いか //////////////////////////////////////////////////// }
回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。