javascript基础二十九:JavaScript如何判断一个元素是否在可视区域中?

news2024/11/25 12:46:49

在这里插入图片描述
一、用途

可视区域即我们浏览网页的设备肉眼可见的区域,如下图

在这里插入图片描述
在日常开发中,我们经常需要判断目标元素是否在视窗之内或者和视窗的距离小于一个值(例如 100 px),从而实现一些常用的功能,例如:

  • 图片的懒加载
  • 列表的无限滚动
  • 计算广告元素的曝光情况
  • 可点击链接的预加载

二、实现方式

判断一个元素是否在可视区域,我们常用的有三种办法:

  • offsetTop、scrollTop
  • getBoundingClientRect
  • Intersection Observer

offsetTop、scrollTop
offsetTop,元素的上外边框至包含元素的上内边框之间的像素距离,其他offset属性如下图所示:
在这里插入图片描述
下面再来了解下clientWidth、clientHeight:

  • clientWidth:元素内容区宽度加上左右内边距宽度,即clientWidth = content + padding
  • clientHeight:元素内容区高度加上上下内边距高度,即clientHeight = content + padding

这里可以看到client元素都不包括外边距

最后,关于scroll系列的属性如下:

  • scrollWidth 和 scrollHeight 主要用于确定元素内容的实际大小
  • scrollLeft 和 scrollTop 属性既可以确定元素当前滚动的状态,也可以设置元素的滚动位置
  • 垂直滚动 scrollTop > 0
  • 水平滚动 scrollLeft > 0
  • 将元素的 scrollLeft 和 scrollTop 设置为 0,可以重置元素的滚动位置

注意
上述属性都是只读的,每次访问都要重新开始

下面再看看如何实现判断:

el.offsetTop - document.documentElement.scrollTop <= viewPortHeight

代码实现:


function isInViewPortOfOne (el) {
    // viewPortHeight 兼容所有浏览器写法
    const viewPortHeight = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight 
    const offsetTop = el.offsetTop
    const scrollTop = document.documentElement.scrollTop
    const top = offsetTop - scrollTop
    return top <= viewPortHeight
}

getBoundingClientRect

返回值是一个 DOMRect对象,拥有left, top, right, bottom, x, y, width, 和 height属性

const target = document.querySelector('.target');
const clientRect = target.getBoundingClientRect();
console.log(clientRect);

// {
//   bottom: 556.21875,
//   height: 393.59375,
//   left: 333,
//   right: 1017,
//   top: 162.625,
//   width: 684
// }

属性对应的关系图如下所示:
在这里插入图片描述
当页面发生滚动的时候,top与left属性值都会随之改变

如果一个元素在视窗之内的话,那么它一定满足下面四个条件:

  • top 大于等于 0
  • left 大于等于 0
  • bottom 小于等于视窗高度
  • right 小于等于视窗宽度
function isInViewPort(element) {
  const viewWidth = window.innerWidth || document.documentElement.clientWidth;
  const viewHeight = window.innerHeight || document.documentElement.clientHeight;
  const {
    top,
    right,
    bottom,
    left,
  } = element.getBoundingClientRect();

  return (
    top >= 0 &&
    left >= 0 &&
    right <= viewWidth &&
    bottom <= viewHeight
  );
}

Intersection Observer

Intersection Observer 即重叠观察者,从这个命名就可以看出它用于判断两个元素是否重叠,因为不用进行事件的监听,性能方面相比

getBoundingClientRect会好很多

使用步骤主要分为两步:创建观察者和传入被观察者

创建观察者

const options = {
  // 表示重叠面积占被观察者的比例,从 0 - 1 取值,
  // 1 表示完全被包含
  threshold: 1.0, 
  root:document.querySelector('#scrollArea') // 必须是目标元素的父级元素
};

const callback = (entries, observer) => { ....}

const observer = new IntersectionObserver(callback, options);

通过new IntersectionObserver创建了观察者 observer,传入的参数 callback 在重叠比例超过 threshold 时会被执行`

关于callback回调函数常用属性如下:

// 上段代码中被省略的 callback
const callback = function(entries, observer) { 
    entries.forEach(entry => {
        entry.time;               // 触发的时间
        entry.rootBounds;         // 根元素的位置矩形,这种情况下为视窗位置
        entry.boundingClientRect; // 被观察者的位置举行
        entry.intersectionRect;   // 重叠区域的位置矩形
        entry.intersectionRatio;  // 重叠区域占被观察者面积的比例(被观察者不是矩形时也按照矩形计算)
        entry.target;             // 被观察者
    });
};

传入被观察者

通过 observer.observe(target) 这一行代码即可简单的注册被观察者

const target = document.querySelector('.target');
observer.observe(target);

三、案例分析

实现:创建了一个十万个节点的长列表,当节点滚入到视窗中时,背景就会从红色变为黄色

Html结构如下:

<div class="container"></div>

css样式如下:


.container {
    display: flex;
    flex-wrap: wrap;
}
.target {
    margin: 5px;
    width: 20px;
    height: 20px;
    background: red;
}

往container插入1000个元素

const $container = $(".container");

// 插入 100000 个 <div class="target"></div>
function createTargets() {
  const htmlString = new Array(100000)
    .fill('<div class="target"></div>')
    .join("");
  $container.html(htmlString);
}

这里,首先使用getBoundingClientRect方法进行判断元素是否在可视区域

function isInViewPort(element) {
    const viewWidth = window.innerWidth || document.documentElement.clientWidth;
    const viewHeight =
          window.innerHeight || document.documentElement.clientHeight;
    const { top, right, bottom, left } = element.getBoundingClientRect();

    return top >= 0 && left >= 0 && right <= viewWidth && bottom <= viewHeight;
}

然后开始监听scroll事件,判断页面上哪些元素在可视区域中,如果在可视区域中则将背景颜色设置为yellow

$(window).on("scroll", () => {
    console.log("scroll !");
    $targets.each((index, element) => {
        if (isInViewPort(element)) {
            $(element).css("background-color", "yellow");
        }
    });
});

通过上述方式,可以看到可视区域颜色会变成黄色了,但是可以明显看到有卡顿的现象,原因在于我们绑定了scroll事件,scroll事件伴随了大量的计算,会造成资源方面的浪费

下面通过Intersection Observer的形式同样实现相同的功能

首先创建一个观察者

const observer = new IntersectionObserver(getYellow, { threshold: 1.0 });

getYellow回调函数实现对背景颜色改变,如下:

function getYellow(entries, observer) {
    entries.forEach(entry => {
        $(entry.target).css("background-color", "yellow");
    });
}

最后传入观察者,即.target元素

$targets.each((index, element) => {
    observer.observe(element);
});

可以看到功能同样完成,并且页面不会出现卡顿的情况

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/616466.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

路径规划算法:基于和声优化的路径规划算法- 附代码

路径规划算法&#xff1a;基于和声优化的路径规划算法- 附代码 文章目录 路径规划算法&#xff1a;基于和声优化的路径规划算法- 附代码1.算法原理1.1 环境设定1.2 约束条件1.3 适应度函数 2.算法结果3.MATLAB代码4.参考文献 摘要&#xff1a;本文主要介绍利用智能优化算法和声…

chatgpt赋能python:Python如何倒序循环

Python如何倒序循环 在Python编程中&#xff0c;倒序循环是一种常见的操作。有时候我们需要倒序遍历一个序列&#xff0c;以便获取最后一个元素或在某些情况下需要运算。Python提供了多种方法来实现倒序循环。在本文中&#xff0c;我们将介绍Python中可用的不同循环遍历方法&a…

源代码加密技术分析

在源代码开发企业&#xff0c;如何保护好自己开发的产品&#xff0c;维护好自主知识产权&#xff0c;是企业开发过程中必要了解的&#xff0c;对于经常做开发的来讲对源代码加密也多种方法&#xff0c;对于传统的C或C之类的语言来说&#xff0c;要在Web上保护源代码是很容易的&…

快手流批一体数据湖构建实践

导读 本次将介绍快手为什么建设数据湖&#xff0c;在数据湖建设过程中遇到的问题和取得的成果&#xff0c;并对未来发展进行展望。 主要内容包括以下四大部分&#xff1a; 1. 数据湖架构 2. 基于 Hudi 构建快手数据湖 3. 快手的实践案例 4. 快手的发展规划 01 数据湖架构…

AB压测工具的介绍及安装

前言 今天我要和大家聊聊AB压测工具&#xff0c;如果你对网站性能测试感兴趣或有需要&#xff0c;那么这篇文章一定会帮到你。 我曾经也因为缺少良好的压力测试工具而苦恼&#xff0c;直到我发现了AB压测工具。它可以帮助我们测试网站在高并发情况下的性能表现&#xff0c;让…

4. 共享模型之管程(4.1 共享带来的问题)

4.1 共享带来的问题 1、Java 的体现2、问题分析3、临界区4、竞态条件 1、Java 的体现 两个线程对初始值为 0 的静态变量一个做自增&#xff0c;一个做自减&#xff0c;各做 5000 次&#xff0c;结果是 0 吗&#xff1f; public class TestCounterUnsafe {static int counter …

Arrays源码

介绍 java.util中的工具类&#xff0c;提供数组相关的常用操作&#xff0c;排序、比较、填充、二分查找等功能 该类还包含一个静态内部类ArrayList&#xff0c;其中add、remove、clear方法都是没有实现的。 常量&变量 /*** The minimum array length below which a para…

测试人总结怎么写?一篇文章详细总结全了!

目录 前言&#xff1a; 总结内容应包括哪些 不可缺少的模板-前期准备 总结过去-用数据来说话 纵向数据 横向数据 展望未来-做好规划 总结亮点 从其他人学到的点 总结弊病 结尾&#xff1a; 前言&#xff1a; 在这一年里&#xff0c;我作为一名测试人员&#xff0c;不断努力…

Tree 树形控件一级菜单没有复选框,子菜单有复选框,如何实现?

<el-dialogtitle"技术职称选择":visible.sync"isShow"width"30%"top"50px":before-close"closeInputSelectedDepDialog"><div class"tree-content"><el-treeclass"filter-tree my-left-tree&…

AMD HD7850 4G显卡刷Bios验真伪(二)

结果就是&#xff1a;开机黑屏&#xff0c;使用HD7850的bios无法识别它… 秉着寻根问底的原则&#xff0c;继续冲浪找线索~ 是的 你猜对了&#xff0c;不出意外的话 就出了意外… 初步断定&#xff0c;这货是7850的阉割版Radeon HD 7850 768SP 1. 首先&#xff0c;尝试在泡泡…

Spring高手之路3——揭秘Spring依赖注入和SpEL表达式

本篇会给大家举出各种Spring属性依赖注入的例子&#xff0c;方便大家理解。 文章目录 1. setter属性注入1.1 使用XML进行setter方法注入1.2 使用Bean注解进行setter方法注入1.3 setter方法注入完整代码示例 2. 构造器注入2.1 使用XML进行构造器注入2.2 使用Bean注解进行构造器属…

面试经历:我为什么选择的测试的?

目录 前言&#xff1a; 判定缺陷间的重复及依赖关系需要开发能力 使用自动化测试工具需要开发能力 黑盒测试偏爱开发能力 说明 白盒测试需要开发能力 安全测试需要开发能力 开发测试工具 前言&#xff1a; 不知不觉已经从事软件测试六年了&#xff0c;从毕业到进入外包公司外…

Android系统的Ashmem匿名共享内存系统分析(5)- 实现共享的原理

声明 其实对于Android系统的Ashmem匿名共享内存系统早就有分析的想法&#xff0c;记得2019年6、7月份Mr.Deng离职期间约定一起对其进行研究的&#xff0c;但因为我个人问题没能实施这个计划&#xff0c;留下些许遗憾…文中参考了很多书籍及博客内容&#xff0c;可能涉及的比较…

SSM 框架

ssm框架是spring MVC &#xff0c;spring和mybatis框架的整合&#xff0c;是标准的MVC模式&#xff0c;将整个系统划分为表现层&#xff0c;controller层&#xff0c;service层&#xff0c;DAO层四层。ssm框架是目前比较主流的Java EE企业级框架&#xff0c;适用于搭建各种大型…

张小飞的Java之路——第四十六章——网络编程基础

写在前面&#xff1a; 视频是什么东西&#xff0c;有看文档精彩吗&#xff1f; 视频是什么东西&#xff0c;有看文档速度快吗&#xff1f; 视频是什么东西&#xff0c;有看文档效率高吗&#xff1f; 诸小亮&#xff1a;关于网络你了解多少&#xff1f; 张小飞&#xff1a…

五月份跳槽了,历经阿里测开岗4轮面试,不出意外,还是被刷了....

大多数情况下&#xff0c;测试员的个人技能成长速度&#xff0c;远远大于公司规模或业务的成长速度。所以&#xff0c;跳槽成为了这个行业里最常见的一个词汇。 前几天&#xff0c;我看到有朋友留言说&#xff0c;他在面试阿里的测试开发工程师的时候&#xff0c;灵魂拷问三小…

Java开发工程师是做什么的?高考结束最重要的专业选择!

各位同学大家好&#xff0c;我是小源&#xff0c;明天就是高考了&#xff0c;对于正常的一个考生来说&#xff0c;专本线的同学已经开始陆陆续续准备看专业。今天&#xff0c;好程序员分享一个专业&#xff0c;他的名字叫做Java开发工程师&#xff0c;不知道同学有没有听说过这…

【Linux学习】多线程——信号量 | 基于环形队列的生产者消费者模型 | 自旋锁 | 读写锁

&#x1f431;作者&#xff1a;一只大喵咪1201 &#x1f431;专栏&#xff1a;《Linux学习》 &#x1f525;格言&#xff1a;你只管努力&#xff0c;剩下的交给时间&#xff01; 目录 一、 信号量1.1 概念1.2 信号量的基本操作1.3 信号量的基本使用接口 二、基于环形队列的生产…

第8章:SpringMVC的文件上传和下载

一、文件上传和下载 1.文件下载 使用ResponseEntity用于控制器方法的返回值类型&#xff0c;该控制器方法的返回值就是响应到浏览器的响应报文。使用ResponseEntity实现下载文件的功能。 ①创建file.html ② 在FileController.java类里面 文件不管是上传还是下载&#xff0…

思科无线AC旁挂并由第三方网关下发业务上网VLAN的案例

在企业网络环境中&#xff0c;思科无线AC&#xff08;Access Controller&#xff09;常用于无线网络的管理和控制。通常情况下&#xff0c;AC会负责分配无线设备的IP地址和VLAN标识&#xff0c;但在某些特定场景下&#xff0c;我们可能需要通过第三方网关来下发业务上网所需的V…