简体   繁体   English

当用户将元素滚动到视口中时触发函数– Vanilla JavaScript

[英]Trigger a function when the user scrolls the element into the viewport – Vanilla JavaScript

I have written a function which animates a bar chart. 我写了一个动画条形图的函数。 Currently this action is being triggered on page load, but I only want it triggered when I get to the element – otherwise the user wont see the animation. 当前,此操作是在页面加载时触发的,但是我只希望在到达该元素时触发它–否则用户将看不到动画。 I would like to achieve this through vanilla JavaScript, is it possible? 我想通过香草JavaScript实现这一目标,这可能吗?

Here is my mark up: 这是我的标记:

<div class="section">
  section
</div>
<div class="section">
  section
</div>
<div class="section">
  section
</div>
<div class="section">
  section
  <ul class="skills__list">
    <li class="skills__list-item">
      <div class="bar">
        <span>HTML</span>
        <div class="bar__inner" data-percent="90%"></div>
      </div>
    </li>
    <li class="skills__list-item">
      <div class="bar">
        <span>css</span>
        <div class="bar__inner" data-percent="80%"></div>
      </div>
    </li>
    <li class="skills__list-item">
      <div class="bar">
        <span>Javascript</span>
        <div class="bar__inner" data-percent="60%"></div>
      </div>
    </li>
    <li class="skills__list-item">
      <div class="bar">
        <span>UI design</span>
        <div class="bar__inner" data-percent="70%"></div>
      </div>
    </li>
    <li class="skills__list-item">
      <div class="bar">
        <span>sketch</span>
        <div class="bar__inner" data-percent="50%"></div>
      </div>
    </li>
    <li class="skills__list-item">
      <div class="bar">
        <span>Photoshop</span>
        <div class="bar__inner" data-percent="80%"></div>
      </div>
    </li>
    <li class="skills__list-item">
      <div class="bar">
        <span>Illustrator</span>
        <div class="bar__inner" data-percent="90%"></div>
      </div>
    </li>
  </ul>
</div>

And here is the Scss: 这是Scss:

*{
  padding: 0;
  margin: 0;
  box-sizing: border-box;
}

.section {
  padding: 20px;
  font-size: 30px;
  font-family: sans-serif;
  text-transform: uppercase;
  height: 400px;
  &:nth-child(1){
    background-color: #ddd;
  }
  &:nth-child(2){
    background-color: #aaa;
  }
  &:nth-child(3){
    background-color: #bbb;
  }
  &:nth-child(4){
    background-color: #000;
  }
}

.skills__list-item {
  & + .skills__list-item {
    margin-top: 20px;
  }
}

// bar chart styles
.bar {
  position: relative;
  width: 100%;
  height: 28px;
  overflow: hidden;
  background-color: blue;

  span {
    position: absolute;
    z-index: 9;
    display: flex;
    align-items: center;
    height: 100%;
    padding: 10px;
    color: #fff;
    background-color: red;
  }

  &__inner {
    display: flex;
    justify-content: flex-end;
    width: 0;
    height: 100%;
    background-color: green;
    transform-origin: 0 100%;
    transition: width 0.6s linear;

    &::after {
      content: attr(data-percent);
      align-self: center;
      padding-right: 20px;
      color: #fff;
    }
  }
}

And here is the JavaScript: 这是JavaScript:

const bars = document.querySelectorAll('.bar__inner');


Array.from(bars).forEach((bar, index) => {
  setTimeout(() => {
    const eachBar = bar;
    eachBar.style.width = bar.dataset.percent;
  }, index * 400);
});

Here's a working example Codepen . 这是一个工作示例Codepen

You can follow a very helpful tip of the website Gomakethings.com . 您可以关注Gomakethings.com网站上非常有用的提示

It shows that you could use the getBoundingClientRect() method to achieve your goal: 它表明您可以使用getBoundingClientRect()方法实现您的目标:

// Get the an HTML element
var element = document.querySelector('<a selector>');

// Get its bounding client rectangle
var bounding = element.getBoundingClientRect();

Use it to build a function which checks if the element is in the viewport client by retrieving the bounding box (okay, the code could be improved, it's just a demo): 使用它来构建一个函数,该函数通过检索边界框来检查元素是否在视口客户端中(好的,可以改进代码,这只是一个演示):

function isInViewPort(element) {
    // Get the bounding client rectangle position in the viewport
    var bounding = element.getBoundingClientRect();

    // Checking part. Here the code checks if it's *fully* visible
    // Edit this part if you just want a partial visibility
    if (
        bounding.top >= 0 &&
        bounding.left >= 0 &&
        bounding.right <= (window.innerWidth || document.documentElement.clientWidth) &&
        bounding.bottom <= (window.innerHeight || document.documentElement.clientHeight)
    ) {
        console.log('In the viewport! :)');
        return true;
    } else {
        console.log('Not in the viewport. :(');
        return false;
    }
}

Finally, add an event listener on scroll event which call the above function: 最后,在scroll事件上添加事件侦听器 ,以调用上述函数:

window.addEventListener('scroll', function (event) {
    if (isInViewport(theElementToWatch)) {
      // update the element display
    }
}, false);

According to the browser compatibility displayed by the MDN page , getBoundingClientRect() is fully supported by Chrome and Firefox (>= 3.5). 根据MDN页面显示的浏览器兼容性,Chrome和Firefox(> = 3.5)完全支持getBoundingClientRect() )。 The provided solution here is fully supported by the most used browsers (it's unknown for some mobile versions). 最常用的浏览器完全支持此处提供的解决方案(某些移动版本不知道)。

According to the one provided by Can I use... website, mobile browsers (Chrome, Firefox, etc.) fully support the method, at least from a given version. 根据我可以使用...网站提供的信息,至少从给定版本开始,移动浏览器(Chrome,Firefox等)完全支持该方法。

Finally, you could keep in mind a still-experimental solution that aims to replace the use of the method getBoundingClientRect() , the Intersection Observer API (see Tom M's answer). 最后,您可以记住一个仍在实验中的解决方案,该解决方案旨在替代使用getBoundingClientRect() Observer API getBoundingClientRect()方法(请参见Tom M的答案)。 The MDN related page explains why: 与MDN相关的页面说明了原因:

Implementing intersection detection in the past involved event handlers and loops calling methods like Element.getBoundingClientRect() to build up the needed information for every element affected. 过去实现交叉检测涉及事件处理程序,并循环调用Element.getBoundingClientRect()类的方法来为每个受影响的元素建立所需的信息。 Since all this code runs on the main thread, even one of these can cause performance problems. 由于所有这些代码都在主线程上运行,因此即使其中一个也会导致性能问题。 When a site is loaded with these tests, things can get downright ugly. 当网站加载了这些测试时,事情可能会变得很丑陋。

You can use the IntersectionObserver API for this. 您可以为此使用IntersectionObserver API。

const observer = new IntersectionObserver((entries) => { 
    entries.forEach((entry) => {
        console.log(entry.target);
        // your callback here
    })
}); 

observer.observe(document.querySelector('.skills__list-item'));

Mind the Browser support though, it's not supported in IE, Safari and Opera Mini for instance. 请注意浏览器支持 ,例如IE,Safari和Opera Mini不支持它。

在此处输入图片说明

If you want to support IE7+ you can use the polyfill provided by the W3C though. 如果要支持IE7 +,则可以使用W3C提供的polyfill

Resources 资源

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM