当用户将元素滚动到视口中时触发一个函数 – Vanilla JavaScript [英] Trigger a function when the user scrolls the element into the viewport – Vanilla JavaScript

查看:23
本文介绍了当用户将元素滚动到视口中时触发一个函数 – Vanilla JavaScript的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我编写了一个动画条形图的函数.目前这个动作是在页面加载时触发的,但我只希望它在我到达元素时触发——否则用户将看不到动画.我想通过 vanilla JavaScript 实现这一点,这可能吗?

这是我的标记:

部分

<div class="section">部分

<div class="section">部分

<div class="section">部分<ul class="skills__list"><li class="skills__list-item"><div class="bar"><span>HTML</span><div class="bar__inner" data-percent="90%"></div>

<li class="skills__list-item"><div class="bar"><span>css</span><div class="bar__inner" data-percent="80%"></div>

<li class="skills__list-item"><div class="bar"><span>Javascript</span><div class="bar__inner" data-percent="60%"></div>

<li class="skills__list-item"><div class="bar"><span>UI 设计</span><div class="bar__inner" data-percent="70%"></div>

<li class="skills__list-item"><div class="bar"><span>草图</span><div class="bar__inner" data-percent="50%"></div>

<li class="skills__list-item"><div class="bar"><span>Photoshop</span><div class="bar__inner" data-percent="80%"></div>

<li class="skills__list-item"><div class="bar"><span>插画家</span><div class="bar__inner" data-percent="90%"></div>

这是 Scss:

<代码>*{填充:0;边距:0;box-sizing: 边框框;}.部分 {填充:20px;字体大小:30px;字体系列:无衬线;文本转换:大写;高度:400px;&:nth-child(1){背景色:#ddd;}&:nth-child(2){背景色:#aaa;}&:nth-child(3){背景色:#bbb;}&:nth-child(4){背景色:#000;}}.skills__list-item {&+ .skills__list-item {边距顶部:20px;}}//条形图样式.酒吧 {位置:相对;宽度:100%;高度:28px;溢出:隐藏;背景颜色:蓝色;跨度 {位置:绝对;z-索引:9;显示:弹性;对齐项目:居中;高度:100%;填充:10px;颜色:#fff;背景颜色:红色;}&__内{显示:弹性;justify-content: flex-end;宽度:0;高度:100%;背景颜色:绿色;变换原点:0 100%;过渡:宽度0.6s线性;&::after {内容:属性(数据百分比);对齐自我:居中;padding-right: 20px;颜色:#fff;}}}

这里是 JavaScript:

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

这是一个工作示例 Codepen.

解决方案

您可以关注 Gomakethings.com 的 the-viewport-with-vanilla-javascript/" rel="noreferrer">非常有用的提示.

它表明您可以使用 getBoundingClientRect() 方法来实现您的目标:

//获取一个 HTML 元素var element = document.querySelector('');//获取它的边界客户端矩形var bounding = element.getBoundingClientRect();

使用它来构建一个函数,通过检索边界框来检查元素是否在视口客户端中(好吧,代码可以改进,这只是一个演示):

function isInViewPort(element) {//获取边界客户端矩形在视口中的位置var bounding = element.getBoundingClientRect();//检查部分.这里的代码检查它是否*完全*可见//如果您只想要部分可见性,请编辑此部分如果 (bounding.top >= 0 &&bounding.left >= 0 &&bounding.right <= (window.innerWidth || document.documentElement.clientWidth) &&bounding.bottom <= (window.innerHeight || document.documentElement.clientHeight)){console.log('在视口中!:)');返回真;} 别的 {console.log('不在视口中.:(');返回假;}}

最后,在调用上述函数的scroll事件上添加一个事件监听器:

window.addEventListener('scroll', function (event) {如果(isInViewport(theElementToWatch)){//更新元素显示}}, 错误的);

根据浏览器兼容性 显示在 MDN 页面, getBoundingClientRect() 完全支持 Chrome 和 Firefox (>= 3.5).最常用的浏览器完全支持此处提供的解决方案(某些移动版本未知).

根据我可以使用...网站、移动浏览器(Chrome、Firefox 等)完全支持该方法,至少在给定版本中如此.

最后,您可以记住一个仍处于实验阶段的解决方案,该解决方案旨在取代 getBoundingClientRect() 方法的使用,Intersection Observer API(见 Tom M 的回答).MDN 相关页面 解释了原因:

<块引用>

过去实现交叉检测涉及事件处理程序和循环调用诸如 Element.getBoundingClientRect() 之类的方法来为每个受影响的元素构建所需的信息.由于所有这些代码都在主线程上运行,即使其中之一也会导致性能问题.当网站加载了这些测试时,事情会变得非常丑陋.

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?

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:

*{
  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:

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.

解决方案

You can follow a very helpful tip of the website Gomakethings.com.

It shows that you could use the getBoundingClientRect() method to achieve your goal:

// 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:

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). 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.

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). The MDN related page explains why:

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. 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.

这篇关于当用户将元素滚动到视口中时触发一个函数 – Vanilla JavaScript的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
前端开发最新文章
热门教程
热门工具
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆