🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Safari

SafariはAppleのウェブブラウザであり、Mac OS XとiOSのデフォルトのブラウザです。

iOS

iOSとは、Apple製のスマートフォンであるiPhoneやタブレット端末のiPadに搭載しているオペレーションシステム(OS)です。その他にもiPod touch・Apple TVにも搭載されています。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

HTML

HTMLとは、ウェブ上の文書を記述・作成するためのマークアップ言語のことです。文章の中に記述することで、文書の論理構造などを設定することができます。ハイパーリンクを設定できるハイパーテキストであり、画像・リスト・表などのデータファイルをリンクする情報に結びつけて情報を整理します。現在あるネットワーク上のほとんどのウェブページはHTMLで作成されています。

Q&A

解決済

2回答

3341閲覧

iOSのSafariで上向きの無限スクロールを実装したい

Ibuki90

総合スコア8

Safari

SafariはAppleのウェブブラウザであり、Mac OS XとiOSのデフォルトのブラウザです。

iOS

iOSとは、Apple製のスマートフォンであるiPhoneやタブレット端末のiPadに搭載しているオペレーションシステム(OS)です。その他にもiPod touch・Apple TVにも搭載されています。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

HTML

HTMLとは、ウェブ上の文書を記述・作成するためのマークアップ言語のことです。文章の中に記述することで、文書の論理構造などを設定することができます。ハイパーリンクを設定できるハイパーテキストであり、画像・リスト・表などのデータファイルをリンクする情報に結びつけて情報を整理します。現在あるネットワーク上のほとんどのウェブページはHTMLで作成されています。

0グッド

0クリップ

投稿2019/12/16 04:45

編集2019/12/17 03:52

前提・実現したいこと

iOSのSafariで上向きの無限スクロールを行おうとしているんですがうまくいかず、困っています。
上向きにスクロールした際に、その先頭部分に要素を追加しようと考えています。
ただ、iOSでは追加した際にスクロール位置が更新できず、上部に要素を追加した際にスクロールが動いてしまい、自然なスクロールになりません。
PCのChromeやSafariでは意図通りに動くのですが、実機のSafariではうまく動きません。以下のCodePenをiosで開いてもらえれば確認できると思います。

iOSのSafariでスクロール中に、先頭部分に要素を追加した際にスクロール位置を保持するにはどうすればいいでしょうか。

該当のソースコード

CodePenで再現したものは以下のとおりです。
https://codepen.io/ibuki90/pen/XWJjvdO

スクロールして上から200pxを超えると、その上部に要素を追加します。
その際、要素追加前に位置を記録し、追加後に追加された高さ分スクロールした位置にスクロールを移動させています。
ただ、iosでは慣性スクロールの影響か、慣性スクロールが止まるまでスクロール位置が移動してくれません。

ライブラリでも実装でも何でも良いので、解決策があれば教えていただけないでしょうか。よろしくお願いします。

指摘がありましたので、CodePen内のコードを以下にも記載します。

html

1<div class="posts"></div>

js

1function postEl(text) { 2 return `<div>${text}</div>`; 3} 4 5function setupInitialPosts() { 6 [...Array(100).keys()].forEach(i => { 7 const text = `post${i}` 8 $('.posts').append(postEl(text)); 9 }); 10 $(document).scrollTop(1000); 11} 12 13$(() => { 14 setupInitialPosts(); 15 16 let prependedCount = 0; 17 $(document).scroll(() => { 18 if($(document).scrollTop() < 200) { 19 const beforeUpdatingScrollTop = $(document).scrollTop(); 20 [...Array(10).keys()].forEach(i => { 21 const text = `prependPost${prependedCount * 10 + i}`; 22 $('.posts').prepend(postEl(text)); 23 }); 24 prependedCount++; 25 26 const elements = $('.posts div'); 27 const movedScroll = elements[10].offsetTop - elements[0].offsetTop; 28 $(document).scrollTop(beforeUpdatingScrollTop + movedScroll); 29 }; 30 }); 31});

追記です。

iOS13から慣性スクロールがデフォルトで有効になっていて、無効にできなくなっているようです。無効にできれば早いんですが。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

自己解決

自己解決しました。

iOSデフォルトのスクロール機能を無効にして、自前で実装したらなんとかなりそうです。(=慣性スクロールがなくなる)
お騒がせしました。

以下typescriptですがサンプルです。

typescript

1 this.scrollEl.addEventListener( 2 'touchmove', 3 e => { 4 e.preventDefault(); 5 const currentScreenY = (e as any).touches[0].screenY; 6 if(this.previousScreenY) { 7 this.scrollEl.scrollTop = this.scrollEl.scrollTop + this.previousScreenY - currentScreenY; 8 } 9 10 this.previousScreenY = currentScreenY; 11 }, 12 true, 13 ); 14 this.scrollEl.addEventListener( 15 'touchend', 16 e => { 17 e.preventDefault(); 18 this.previousScreenY = undefined; 19 }, 20 true, 21 );

codepenでもやろうとしましたがtouchmoveが取れないのかうまく動きませんでした。実例がなくてすみません。

投稿2019/12/17 05:55

Ibuki90

総合スコア8

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

miyabi_takatsuk

2019/12/17 05:59

なるほど。 モーダルウィンドウとかのdivとかのスクロールを実装する時は、 よくその技法使ったりしますが、 上にスクロールの場合でもその技法が必要だったわけですね。 解決されて何よりです。
guest

0

大量にイベントが発火を防ぐなら、下記でいけるかと・・・。

javascript

1let scTimer = null; 2 3function postEl(text) { 4 return `<div>${text}</div>`; 5} 6 7function setupInitialPosts() { 8 [...Array(100).keys()].forEach(i => { 9 const text = `post${i}` 10 $('.posts').append(postEl(text)); 11 }); 12 $(document).scrollTop(1000); 13} 14 15$(() => { 16 setupInitialPosts(); 17 18 let prependedCount = 0; 19 $(document).scroll(() => { 20 21 if (scTimer) { 22 clearTimeout(scTimer); 23 } 24 25 scTimer = setTimeout(() => { 26 if($(document).scrollTop() < 200) { 27 const beforeUpdatingScrollTop = $(document).scrollTop(); 28 [...Array(10).keys()].forEach(i => { 29 const text = `prependPost${prependedCount * 10 + i}`; 30 $('.posts').prepend(postEl(text)); 31 }); 32 prependedCount++; 33 34 const elements = $('.posts div'); 35 const movedScroll = elements[10].offsetTop - elements[0].offsetTop; 36 $(document).scrollTop(beforeUpdatingScrollTop + movedScroll); 37 } 38 }, 10); 39 40 }); 41});

setTimeoutを使い、スクロールイベントの発生頻度を制御したものです。
ただし、スマホ実機では確認していませんので、そこはご了承ください。
それと、イベント発火頻度を制御したところで、問題解決になるかはわかりません。

それと、コードは、ソースコードサービスのURLを張るなら、貼った上で、
質問本文にも、ソースコードを記載するようにしましょう。

投稿2019/12/16 08:09

miyabi_takatsuk

総合スコア9555

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Ibuki90

2019/12/16 08:15

ご回答ありがとうございます。コードを記載しました。 イベントの大量発火を防ぎたいのではなく、スクロールの位置を調整したいのです。 イベントの大量発火を防ぎたいのであればlodashのthrottleを使ったほうがシンプルになるように思います。
miyabi_takatsuk

2019/12/16 08:18 編集

うむむ、了解です。 発火頻度に関して、逆にそのような方法があるのを知れてよかったです。 ありがとうございます。 ちょっと、私の方でも、もう少し検証したりしてみますね。
Ibuki90

2019/12/16 08:20

ありがとうございます。 iOS実機特有の問題だと思っていますので、実機で見てもらわないとイメージが沸かないかもしれません。 iOSシミュレータでは再現しますが、safariやchromeのDeveloperToolでは再現しません。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問