質問をすることでしか得られない、回答やアドバイスがある。

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

ただいまの
回答率

89.63%

クリックイベントであれば出来るのにスクロールイベントにした途端、いい加減な挙動になる

解決済

回答 2

投稿

  • 評価
  • クリップ 0
  • VIEW 103

annaPanda

score 28

スクロールしていって見え始めたら0から高速でカウントアップして、htmlのテキストに入っている数字になったら止まるビューが作りたいです。

手始めにクリックしたらカウントアップが始まり600になったら止まるようにはできました。

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <link rel="stylesheet" href="css/reset.css">
  <link rel="stylesheet" href="css/stylesheet.css">
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
  <script src="main.js"></script>
</head>
<body>
  <div class="upNumber">600</div>
</body>
</html>
body{
  height: 2000px;
  padding: 150px;
}
.upNumber{
  margin-top: 1500px;
  font-size: 100px;
}
$(function () {
  let finalNumber = $(".upNumber").html();
  $(".upNumber").html(0);
  let totalTime = 5000;
  let oneUpTime = totalTime / finalNumber
  $(".upNumber").click(
    function () {
      let number = 0;
      let upNumber = setInterval(function(){
        $(".upNumber").html(number);
        number++
        if (number > finalNumber) {
          clearInterval(upNumber);
        }
      } , oneUpTime);
    }
  )
});


動画のリンクを載せます。  

https://gyazo.com/6ff45be154295725b2b24c5aad47db12

これは思った挙動です。

しかし、これをクリックイベントでなく、スクロールイベントにした途端600をちょっと超えたいい加減な動きになります。

$(function () {
  // スクロールに関する基本設定
  let scrollMinus = 140; 
  let scrollPoint; 
  let upNumberHeight = $(".upNumber").offset().top;
  // カウントアップに関する基本設定
  let finalNumber = $(".upNumber").html();
  $(".upNumber").html(0);
  let totalTime = 5000;
  let oneUpTime = totalTime / finalNumber
  let number = 0;

  $(window).scroll(function () {
    let scrollTop = $(this).scrollTop();
    let scrollBtm = scrollTop + $(this).height();
    scrollPoint = scrollBtm - scrollMinus;
    if (scrollPoint > upNumberHeight && number < finalNumber) {
      let upNumber = setInterval(function () {
        $(".upNumber").html(number);
        number++
        if (number > finalNumber) {
          clearInterval(upNumber);
        }
      }, oneUpTime);
    }
  })
});


動画のリンクを載せます。   
 
https://gyazo.com/0527abca76b830882ecc71c1f3cf1297

試しにsetIntervalの処理をゆっくりにしてみると、

let upNumber = setInterval(function () {
  $(".upNumber").html(number);
  number++
  if (number > finalNumber) {
    clearInterval(upNumber);
  }
}, 1000);


よくわからないつっかかりを抱えます。

動画のリンクを載せます。

https://gyazo.com/233a106d896541bf133de07d9ac8dc41

この原因・対策がわかる方いらっしゃいますでしょうか?

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

+2

$(window).scrollの中に書いたコードは、スクロールが行われるたびに毎回実行されます。

setInterval自体が複数登録されてしまって、意図しない動作になっているように思われます。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/02/14 18:10

    ご回答ありがとうございました。
    今回は具体的な代替案をだしてくださった方をベストアンサーにさせていただきました。

    キャンセル

checkベストアンサー

0

    upNumber;
    if (scrollPoint > upNumberHeight && number < finalNumber) {
      let upNumber = setInterval(function () {
        if (number > finalNumber) {
          clearInterval(upNumber);
          return;
        }
        $(".upNumber").html(number);
        number++;
      }, oneUpTime);

スクロールのたびにsetInterval()が呼ばれているのが原因です。
なので、finalNumberを超えていたら、カウンタに触る前に関数を脱出するように書き替えました。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/02/14 17:10

    回答ありがとうございます。
    今、書いてくださったコードを
    ```
    if (scrollPoint > upNumberHeight && number < finalNumber) {
    let upNumber = setInterval(function () {
    $(".upNumber").html(number);
    number++
    if (number > finalNumber) {
    clearInterval(upNumber);
    }
    }, oneUpTime);
    ```
    と置き換えたところ、
    upNumberは定義されてないと言われたので、
    試しに消してみたら、なぜか思った挙動になりました。
    そうすると、clearIntervalの入ったif文とnumberをテキストに入れる文とnumberに1足す文を入れ替えているだけに見え、スクロールのたびにsetIntervalなのは変わらないような気がするのですが、意図されたことと違いますか?

    キャンセル

  • 2020/02/14 17:19

    あ、余分な1行がありましたね、失礼しました。

    > スクロールのたびにsetIntervalなのは変わらないような気がする

    正にその通りです。もちろん、条件文を setInterval に前置してそれ自体を動作させない方法もアリかと思います。
    このようなバグ取り質問の場合、他の部分への影響がわからないので、なるべく元のコードに手を加えない回答をすることにしています。なので、お気に召さなければどんどん変更していただいて構いませんよ。

    キャンセル

  • 2020/02/14 18:07

    なるほどありがとうございました。

    キャンセル

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

  • ただいまの回答率 89.63%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる