【问题标题】:Run jQuery animation on pageload if inside viewport如果在视口内,则在页面加载时运行 jQuery 动画
【发布时间】:2018-06-27 08:48:44
【问题描述】:

这是another question 的后续内容。我被要求提出一个新问题,而不是在 cmets 中讨论这个问题,以便其他人可以从它的解决方案中受益。

问题:

我有一些progressbar.js 圈子在滚动到视图中时会产生动画。

他们正在按预期制作动画,但我需要在页面加载时完全可见的圆圈立即制作动画,而不是等待滚动。

在页面加载时不完全可见的其他圆圈在滚动到视图后应该像现在一样进行动画处理。

这是我当前的代码:

//Loop through my divs and create animated circle for each one
function makeCircles() {
  var divsValues = {
    'total-score-circle': 0.75,
    'general-score-circle': 0.80,
    'speed-score-circle': 0.85,
    'privacy-score-circle': 0.90,
  };

  for (var i in divsValues) {
    if (divsValues.hasOwnProperty(i)) {
      bgCircles(i, divsValues[i]);
    }
  }
}
makeCircles();

// Check if element is scrolled into view
function isScrolledIntoView(elem) {
  var docViewTop = jQuery(window).scrollTop();
  var docViewBottom = docViewTop + jQuery(window).height();
  var elemTop = jQuery(elem).offset().top;
  var elemBottom = elemTop + jQuery(elem).height();

  return ((elemBottom <= docViewBottom) && (elemTop >= docViewTop));
}

//Circle design and animation
function bgCircles(divid, countvalue) {
  // Design the circle using progressbar.js
  var bar = new ProgressBar.Circle(document.getElementById(divid), {
    color: '#ddd',
    // This has to be the same size as the maximum width to
    // prevent clipping
    strokeWidth: 4,
    trailWidth: 4,
    easing: 'easeInOut',
    duration: 1400,
    text: {
      autoStyleContainer: false
    },
    from: {
      color: '#ddd',
      width: 4
    },
    to: {
      color: '#888',
      width: 4
    },
    // Set default step function for all animate calls
    step: function(state, circle) {
      circle.path.setAttribute('stroke', state.color);
      circle.path.setAttribute('stroke-width', state.width);

      var value = Math.round(circle.value() * 100);
      if (value === 0) {
        circle.setText('');
      } else {
        circle.setText(value + '%');
      }
    }
  });
  bar.text.style.fontFamily = '"Montserrat", sans-serif';
  bar.text.style.fontSize = '1.7rem';
  bar.trail.setAttribute('stroke-linecap', 'round');
  bar.path.setAttribute('stroke-linecap', 'round');

  //Animate the circle when scrolled into view
  $(window).scroll(function () {
    if (isScrolledIntoView(jQuery('#' + divid))) bar.animate(countvalue);
  });
}
#total-score-circle,
#general-score-circle,
#speed-score-circle,
#privacy-score-circle {
  margin: 0.8em auto;
  width: 100px;
  height: 100px;
  position: relative;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/progressbar.js/1.0.1/progressbar.min.js"></script>

<div id="total-score-circle"></div>
<div id="general-score-circle"></div>
<div id="speed-score-circle"></div>
<div id="privacy-score-circle"></div>

我也尝试过这个备用 JS,但没有成功:

它将可见性检查线封装到一个单独的函数中,并在创建圆圈时运行。

但它与原始代码有相同的问题,页面加载时可见的圆圈不会立即运行。

//Loop through my divs and create animated circle for each one
function makeCircles() {
  var divsValues = {
    'total-score-circle': 0.75,
    'general-score-circle': 0.80,
    'speed-score-circle': 0.85,
    'privacy-score-circle': 0.90,
  };

  for (var i in divsValues) {
    if (divsValues.hasOwnProperty(i)) {
      bgCircles(i, divsValues[i]);
    }
  }
}
makeCircles();

// Check if element is scrolled into view
function isScrolledIntoView(elem) {
  var docViewTop = jQuery(window).scrollTop();
  var docViewBottom = docViewTop + jQuery(window).height();
  var elemTop = jQuery(elem).offset().top;
  var elemBottom = elemTop + jQuery(elem).height();

  return ((elemBottom <= docViewBottom) && (elemTop >= docViewTop));
}

//Circle design and animation
function bgCircles(divid, countvalue) {
  // Design the circle using progressbar.js
  var bar = new ProgressBar.Circle(document.getElementById(divid), {
    color: '#ddd',
    // This has to be the same size as the maximum width to
    // prevent clipping
    strokeWidth: 4,
    trailWidth: 4,
    easing: 'easeInOut',
    duration: 1400,
    text: {
      autoStyleContainer: false
    },
    from: {
      color: '#ddd',
      width: 4
    },
    to: {
      color: '#888',
      width: 4
    },
    // Set default step function for all animate calls
    step: function(state, circle) {
      circle.path.setAttribute('stroke', state.color);
      circle.path.setAttribute('stroke-width', state.width);

      var value = Math.round(circle.value() * 100);
      if (value === 0) {
        circle.setText('');
      } else {
        circle.setText(value + '%');
      }
    }
  });
  bar.text.style.fontFamily = '"Montserrat", sans-serif';
  bar.text.style.fontSize = '1.7rem';
  bar.trail.setAttribute('stroke-linecap', 'round');
  bar.path.setAttribute('stroke-linecap', 'round');

  function visibilityChecker(bar) {
    jQuery(window).scroll(function() {
      if (isScrolledIntoView(jQuery('#' + divid))) bar.animate(countvalue);
    });
  }
  visibilityChecker(bar);

}

【问题讨论】:

  • 请检查我的回答,了解将您的代码提取并分离到自己的函数中以减少代码重复DRY principle.

标签: javascript jquery progress-bar


【解决方案1】:

在滚动事件外调用动画函数

//Loop through my divs and create animated circle for each one
function makeCircles() {
  var divsValues = {
    'total-score-circle': 0.75,
    'general-score-circle': 0.80,
    'speed-score-circle': 0.85,
    'privacy-score-circle': 0.90,
  };

  for (var i in divsValues) {
    if (divsValues.hasOwnProperty(i)) {
      bgCircles(i, divsValues[i]);
    }
  }
}
makeCircles();

// Check if element is scrolled into view
function isScrolledIntoView(elem) {
  var docViewTop = jQuery(window).scrollTop();
  var docViewBottom = docViewTop + jQuery(window).height();
  var elemTop = jQuery(elem).offset().top;
  var elemBottom = elemTop + jQuery(elem).height();

  return ((elemBottom <= docViewBottom) && (elemTop >= docViewTop));
}

//Circle design and animation
function bgCircles(divid, countvalue) {
  // Design the circle using progressbar.js
  var bar = new ProgressBar.Circle(document.getElementById(divid), {
    color: '#ddd',
    // This has to be the same size as the maximum width to
    // prevent clipping
    strokeWidth: 4,
    trailWidth: 4,
    easing: 'easeInOut',
    duration: 1400,
    text: {
      autoStyleContainer: false
    },
    from: {
      color: '#ddd',
      width: 4
    },
    to: {
      color: '#888',
      width: 4
    },
    // Set default step function for all animate calls
    step: function(state, circle) {
      circle.path.setAttribute('stroke', state.color);
      circle.path.setAttribute('stroke-width', state.width);

      var value = Math.round(circle.value() * 100);
      if (value === 0) {
        circle.setText('');
      } else {
        circle.setText(value + '%');
      }
    }
  });
  
  bar.text.style.fontFamily = '"Montserrat", sans-serif';
  bar.text.style.fontSize = '1.7rem';
  bar.trail.setAttribute('stroke-linecap', 'round');
  bar.path.setAttribute('stroke-linecap', 'round');
  if (isScrolledIntoView(jQuery('#' + divid))) bar.animate(countvalue);//add this
  //Animate the circle when scrolled into view
  $(window).scroll(function () {
    if (isScrolledIntoView(jQuery('#' + divid))) bar.animate(countvalue);
  });
}
#total-score-circle,
#general-score-circle,
#speed-score-circle,
#privacy-score-circle {
  margin: 0.8em auto;
  width: 100px;
  height: 100px;
  position: relative;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/progressbar.js/1.0.1/progressbar.min.js"></script>

<div id="total-score-circle"></div>
<div id="general-score-circle"></div>
<div id="speed-score-circle"></div>
<div id="privacy-score-circle"></div>

【讨论】:

    【解决方案2】:

    不错。


    在滚动事件期间检查和更新元素时​​,您将面临检查器/更新程序代码不运行的情况,因为没有发生滚动事件。

    要在将来解决此问题,将您正在使用的代码提取到单独的函数中,在这种情况下:

    // Checks whether an element is visible and updates it accordingly
    function checkVisibility(elem, bar, countvalue) {
        if (isScrolledIntoView(elem)) {
            bar.animate(countvalue);
        } else {
            bar.animate(0);
        }
    }
    

    然后您可以在初始化期间以及滚动事件期间运行代码。 More on the DRY principle.


    还有

    我稍微重构了您的代码并存储了容器元素以尽可能减少调用jQuery(...)

    // Select and store the element
    var elem = jQuery('#' + divid);
    

    这样,您的代码将不会不必要地运行jQuery(...),并且您也可以在初始化圆时使用elem 变量:

    var bar = new ProgressBar.Circle(elem.get(0), {
    

    More on the .get() method.


    工作示例

    //Loop through my divs and create animated circle for each one
    function makeCircles() {
      var divsValues = {
        'total-score-circle': 0.75,
        'general-score-circle': 0.80,
        'speed-score-circle': 0.85,
        'privacy-score-circle': 0.90,
      };
    
      for (var i in divsValues) {
        if (divsValues.hasOwnProperty(i)) {
          bgCircles(i, divsValues[i]);
        }
      }
    }
    makeCircles();
    
    // Check if element is scrolled into view
    function isScrolledIntoView(elem) {
      var docViewTop = jQuery(window).scrollTop();
      var docViewBottom = docViewTop + jQuery(window).height();
      var elemTop = jQuery(elem).offset().top;
      var elemBottom = elemTop + jQuery(elem).height();
    
      return ((elemBottom <= docViewBottom) && (elemTop >= docViewTop));
    }
    
    // Checks whether an element is visible and updates it accordingly
    function checkVisibility(elem, bar, countvalue) {
      if (isScrolledIntoView(elem)) {
        bar.animate(countvalue);
      } else {
        bar.animate(0);
      }
    }
    
    //Circle design and animation
    function bgCircles(divid, countvalue) {
      // Select and store the element
      var elem = jQuery('#' + divid);
      
      // Design the circle using progressbar.js
      var bar = new ProgressBar.Circle(elem.get(0), {
        color: '#ddd',
        // This has to be the same size as the maximum width to
        // prevent clipping
        strokeWidth: 4,
        trailWidth: 4,
        easing: 'easeInOut',
        duration: 1400,
        text: {
          autoStyleContainer: false
        },
        from: {
          color: '#ddd',
          width: 4
        },
        to: {
          color: '#888',
          width: 4
        },
        // Set default step function for all animate calls
        step: function(state, circle) {
          circle.path.setAttribute('stroke', state.color);
          circle.path.setAttribute('stroke-width', state.width);
    
          var value = Math.round(circle.value() * 100);
          if (value === 0) {
            circle.setText('');
          } else {
            circle.setText(value + '%');
          }
        }
      });
      bar.text.style.fontFamily = '"Montserrat", sans-serif';
      bar.text.style.fontSize = '1.7rem';
      bar.trail.setAttribute('stroke-linecap', 'round');
      bar.path.setAttribute('stroke-linecap', 'round');
    
      // Check element visibility and update it, when needed
      checkVisibility(elem, bar, countvalue);
    
      // Animate the circle when scrolled into view
      $(window).scroll(function () {
        checkVisibility(elem, bar, countvalue);
      });
    }
    #total-score-circle,
    #general-score-circle,
    #speed-score-circle,
    #privacy-score-circle {
      margin: 0.8em auto;
      width: 100px;
      height: 100px;
      position: relative;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/progressbar.js/1.0.1/progressbar.min.js"></script>
    
    <div id="total-score-circle"></div>
    <div id="general-score-circle"></div>
    <div id="speed-score-circle"></div>
    <div id="privacy-score-circle"></div>

    【讨论】:

    • 奇怪的是,如果您在页面底部刷新页面,然后在页面重新加载后向上滚动,一切正常。
    • 它适用于我(类别得分元素中的所有圆圈都动画)。如果它们没有为您制作动画,请清空浏览器的缓存。 Check this answer,虽然它是关于 CSS 的,但你也可以在你的情况下应用它。
    • 如果你的圈子过早地动画到他们的百分比,检查你的isScrolledIntoView(elem)函数(使用console.log(...)注销函数中的特定值),它是否给你正确的结果。
    • 我已经清除了缓存并更改了 JS 文件名以用于缓存清除等目的。仍然是同样的问题。奇怪的是,你看不到它发生在你身上。我认为类别圆圈(页面的一半)在页面加载时会产生动画,而它们应该只在滚动时产生动画。我删除了“去动画”效果以使其更明显,一旦圆圈有动画,它们现在将保持这种状态。
    • 我将奖励您答案,因为它是最清晰的答案,并且解决了这里提出的问题,尽管由于某种原因这两个答案在我的实时开发网站上都不起作用。
    猜你喜欢
    • 1970-01-01
    • 2014-06-09
    • 2012-01-18
    • 1970-01-01
    • 1970-01-01
    • 2022-08-11
    • 2017-07-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多