·

JS高级使用3.0——JS中获取页面的高度、距离顶部的距离

发布时间:2024-08-28 00:15:22阅读量:204
专业文章
转载请注明来源

创作场景

   记录闭包的博客中有一个节流函数的实际用法和这个知识点相关,创作过程中发现这个知识点涉及到的还有很多,在此记录一下相关的所有知识点并进行比较。

阅读前提

   此博客适用于所有人群,不仅有基础的用法,同时也对多种实现方式进行比较,本文将围绕一个例子进行讲解,并对涉及到的所有知识点进行穿插,最后进行总结。

提前了解的知识点

1. 页面可视化高度(clientHeight)

   页面可视化高度指的是你当前页面能看到内容的高度,这个高度是可以动态变化的,比如你打开了F12调试器,那么你的可视化高度就会变化,如果你将浏览器最大化,那么你的可视化高度也会变化,但这并不代表你实际页面的高度,可能你的页面高度会远远超过页面可视化高度。代码实现:

document.body.clientHeight

2. 滚动条高度(scrollHeight)

   滚动条高度就是当你的页面高度超过了页面可视化高度,比如body的高度是900,你的页面高度是800,那么滚动条就会产生,一般来说,滚动条高度是比你的页面高度要大16px,可能不同设备会不一样。代码实现:

document.body.scrollHeight

统计距离页面顶部的距离

参考:https://blog.csdn.net/mouday/article/details/125444003

  // 滚动方向枚举值
  const DIRECTION_ENUM = {
    DOWN: "down",
    UP: "up",
  };

   // 距离顶部或底部的阈值,一般滚动条高度是要比页面高度大的,阈值指的就是大的这一点儿
  const threshold = 20;
  // 记录前一个滚动位置
  let beforeScrollTop = 0;
  function handleScroll() {
    // 距顶部
    var scrollTop =
            document.documentElement.scrollTop || document.body.scrollTop 
            || window.pageYOffset || window.scrollY;
    // 可视区高度
    var clientHeight =
            document.documentElement.clientHeight || document.body.clientHeight;
    // 滚动条总高度
    var scrollHeight =
            document.documentElement.scrollHeight || document.body.scrollHeight;

    // 打印数值,console.table是控制台打印表格的写法,同时也有
    // console.error和console.warn,对应警告和错误
    // 一般使用的就是console.info
    console.table([
      {
        label: "距顶部",
        value: scrollTop,
      },
      {
        label: "可视区高度",
        value: clientHeight,
      },
      {
        label: "滚动条总高度",
        value: scrollHeight,
      },
      {
        label: "距顶部 + 可视区高度",
        value: scrollTop + clientHeight,
      },
    ]);

    // 确定滚动方向
    let direction = DIRECTION_ENUM.DOWN;
    if (beforeScrollTop > scrollTop) {
      direction = DIRECTION_ENUM.UP;
    }

    // 通过滚动方向判断是触底还是触顶
    if (direction == DIRECTION_ENUM.DOWN) {
      // 滚动触底
      if (scrollTop + clientHeight + threshold >= scrollHeight) {
        console.log("滚动触底");
      }
    } else {
      // 滚动到顶部
      if (scrollTop <= threshold) {
        console.log("滚动到顶部");
      }
    }

    beforeScrollTop = scrollTop;
  }
  window.addEventListener('scroll', handleScroll)

window、document、documentElement的区别

window是当前页面的顶级对象,其中包含了很多属性和方法,是一个BOM对象,可进行浏览器的交互。
document是window对象的子元素,它可以理解为一个DOM对象,其中有很多方法和属性,主要是在页面元素中进行交互。

documentElement是document的子元素,注意,这是一个只读对象,也就是说它只能读取元素的属性,不能对元素进行操作。一般他就是你本页面的HTML元素。

这里一定要注意一下,如果你的页面是在一个iframe中,那你获取的一定是你iframe中的所有元素,并不是你最大页面的对象。一般在实际开发中都有头部导航栏,而子页面中也会嵌套子页面,那么获取最外部的HTML元素可以用parent对象,一层一层循环,因为最外部的iframe肯定是有一个ID的,这是我在开发中遇到的一个小问题,分享一下。

// 第一个参数是当前的iframe对象,第二个是parent对象
// 调用时parentNode不用传入
function getFrameTop(frame, parentNode) {
	if (frame.attr('id') !== "iframeContent") {
		if (parentNode) {
			frame = parentNode.parent.$("iframe")
		} else {
			frame = parent.$("iframe")
		}
		getFrameTop(frame, parent)
	} else {
		topIframe = frame
		return frame
	}
}

解读获取距离页面顶部距离的四种方式

    // 距顶部
    var scrollTop =
            document.documentElement.scrollTop || document.body.scrollTop 
            || window.pageYOffset || window.scrollY;

  这四种拆分下来就是在两个对象上进行操作的,一个是window,一个是document,而之所以这么写完全是为了兼容性,尤其是pageYOffset方法,这是一个过时方法,但是在某些IE就只能识别这个,如果你的产品不需要兼容,那其中一个就够用了。

   解读一下原理:

   我的div高度是900,页面可视化高度是818,而距离顶部的距离(scrollTop)是98,这其实就是滚动条的高度减去可视区高度算出来的,而这个高度指的是你的div最顶部距离和你可视化页面的顶部距离,如果是计算底部的距离,那加上页面可视化距离即可。

如何使用代码滚动页面(四种方式)

1. scroll()方法

滚动窗口至文档中的特定位置。
window.scroll(x, y) x和y就是你需要滚动的绝对位置坐标
window.scroll(options) options是一个对象,包含x、y坐标,同时也有滚动的方式
window.scroll({
  top: 100,
  left: 100,
  behavior: "smooth",
});

   上面这是一种标准用法,当然一般我们不这么写,直接用第一种方式滚动即可。

2. scrollBy()方法

在窗口中按指定的偏移量滚动文档(比如你只是想在这个基础上向下滚动100px)
scrollBy(x-coord, y-coord)
scrollBy(options)
x-coord 是你想滚动的水平像素值。
y-coord 是你想滚动的垂直像素值。
options
   包含以下参数的字典
top
   指定沿 Y 轴滚动窗口或元素的像素数。
left
   指定沿 X 轴滚动窗口或元素的像素数。
behavior
   指定滚动是否应该平滑(smooth)、瞬时运动到该位置(instant)、或者让浏览器选择(auto,默认)。
window.scrollBy({
  top: 100,
  left: 100,
  behavior: "smooth",
});

   这个方法和scroll区别在于,这里的x和y指的是偏移量,而不是绝对位置

3. scrollTo()

   这个和scroll方法是一样的,个人比较喜欢这种方式,因为可读性比较高,不容易出错,使用标准写法可以随意在x和y上进行随意滚动,因为对象上参数可选。

// 设置滚动行为改为平滑的滚动
window.scrollTo({
    top: 1000,
    behavior: "smooth"
});

4. document.documentElement.scrollTop = 0(非标准写法)

   上面说过documentElement是一个只读属性,官方上也是这么说的,但是经过实验发现这种方式也可以用来操作页面的滚动,但不建议这么使用,也不知道会存在什么bug。

使用节流函数优化

关于节流函数是什么,这个博客中有说明

节流函数(闭包中的使用)
  function throttle(func, wait){
    let previous = 0;
    return function() {
      var now = Date.now()
      var context = this
      // ES5写法:var args = []; args.push.apply(null, arguments)
      var args = [...arguments]	// ES6数组解构知识点:复制数组
      // 如果当前时间减去上一次执行时间大于我们执行函数的时间间隔再执行
      if(now - previous > wait){
        func.apply(context, args);
        // 闭包,记录本次执行时间戳
        // 这么写就是不用将上次执行的时间作为参数传给函数了
        // 就算多次调用闭包不会消失,上一次执行时间不会消失,这就是闭包的常用方式
        previous = now;
      }
    }
  }
  // 滚动方向枚举值
  const DIRECTION_ENUM = {
    DOWN: "down",
    UP: "up",
  };

  // 距离顶部或底部的阈值,一般滚动条高度是要比页面高度大的,阈值指的就是大的这一点儿
  const threshold = 20;
  // 记录前一个滚动位置
  let beforeScrollTop = 0;
  function handleScroll() {
    // 距顶部
    var scrollTop =
            document.documentElement.scrollTop || document.body.scrollTop || window.pageYOffset || window.scrollY;
    // 可视区高度
    var clientHeight =
            document.documentElement.clientHeight || document.body.clientHeight;
    // 滚动条总高度
    var scrollHeight =
            document.documentElement.scrollHeight || document.body.scrollHeight;
    // 打印数值
    console.table([
      {
        label: "距顶部",
        value: scrollTop,
      },
      {
        label: "可视区高度",
        value: clientHeight,
      },
      {
        label: "滚动条总高度",
        value: scrollHeight,
      },
      {
        label: "距顶部 + 可视区高度",
        value: scrollTop + clientHeight,
      },
    ]);

    // 确定滚动方向
    let direction = DIRECTION_ENUM.DOWN;
    if (beforeScrollTop > scrollTop) {
      direction = DIRECTION_ENUM.UP;
    }

    // 通过滚动方向判断是触底还是触顶
    if (direction == DIRECTION_ENUM.DOWN) {
      // 滚动触底
      if (scrollTop + clientHeight + threshold >= scrollHeight) {
        console.log("滚动触底");
      }
    } else {
      // 滚动到顶部
      if (scrollTop <= threshold) {
        console.log("滚动到顶部");
      }
    }

    beforeScrollTop = scrollTop;
  }
  // window.addEventListener('scroll', handleScroll)
  window.addEventListener('scroll', throttle(handleScroll, 200))

这里只是一个例子,请注意,如果想要绝对精度,也就是当滚动条快速滑动的时候也要监听到,那就将延迟设置为0-50内。

总结

获取距离顶部的距离

  • document.documentElement.scrollTop
  • document.body.scrollTop
  • window.pageYOffset
  • window.scrollY

可视区高度

  • document.documentElement.clientHeight
  • document.body.clientHeight

滚动条总高度

  • document.documentElement.scrollHeight
  • document.body.scrollHeight

滚动页面

  • scroll()
  • scrollTo()
  • scrollBy()
  • document.documentElement.scrollY = 100


原文链接:https://blog.csdn.net/weixin_48588897/article/details/138413621

0 人喜欢

评论区

暂无评论,来发布第一条评论吧!

弦圈热门内容

为什么可能没有体积的量子所组成的物质却有体积?

当你测量和观察周围的宇宙时,有一件事是可以肯定的:你看到、触摸到并以其他方式与之互动的物理对象都占据了一定的空间体积。无论是固体、液体、气体还是物质的任何其他形态,它都需要消耗能量来减少任何有形物质所占的体积。然而,看似矛盾的是,作为物质的基本成分,标准模型的粒子却根本没有可测量的体积;它们只是点粒子。那么,由无体积实体组成的物质如何占据空间,创造出我们所观察到的世界和宇宙呢?让我们从我们熟悉的事物开始,一步步分解,直到我们深入到支撑我们存在的量子规则。最后,我们可以从那里开始逐步向上。上图显示了对应于电磁波谱各个部分的尺寸、波长和温度/能量尺度。你必须使用更高的能量和更短的波长来探测最小的尺度。紫外线足以使原子电离,但随着宇宙的膨胀,光会系统地转移到更低的温度和更长的波长。如果你想了解体积,那么你必须了解我们测量物体大小的方式。确定宏观实体大小的方式通常是将其与已知大小的参考标准进行比较,例如尺子或其他测量棒。或者测量弹簧(或类似弹簧的物体)因该物体而位移的力、测量光穿过物体跨度所需的传播时间,甚至通过用特定波长的粒子或光子撞击物体的实验反馈来进行确定。正如光具有由其能量定义的量子力 ...

波尔兹曼大脑:宇宙中漂浮着至少7万5千亿亿亿个意识体

在这个广袤无垠的宇宙中,我们总爱幻想自己独一无二,是万物之灵。但你知道吗?根据某个奇妙的科学理论,你、我,甚至整个地球,可能都只是宇宙中随机“涨落”出来的一个意识体——没错,这就是让人脑洞大开的“玻尔兹曼大脑”假说!熵增定律:宇宙为何越来越“乱”?你的房间如果不打扫,是不是会越来越乱?这就是“熵增定律”在生活中的体现。简单来说,熵就是系统混乱程度的量度,而熵增定律则告诉我们,一个孤立系统的熵总是趋向于增加,直到达到最大化,也就是系统变得最混乱。宇宙,作为一个巨大的孤立系统,按理说也应该遵循这一法则。但奇怪的是,我们观测到的宇宙,似乎是从一个极其有序、熵极低的状态开始的。这,是为什么呢?玻尔兹曼的“脑洞”:宇宙其实是个“随机播放器”?这时,奥地利物理学家路德维希·玻尔兹曼登场了。他提出,熵增定律其实是统计性的,就像抛硬币,虽然正面朝上的概率是50%,但在无限次抛掷中,正面和反面出现的次数会趋于相等。同样,宇宙在大部分时间处于高熵态,但无限的时间尺度上,偶尔也会有“小概率事件”发生,即熵的随机涨落导致低熵态的出现。换句话说,我们现在所看到的这个有序、低熵的宇宙,可能只是一次“宇宙级”的随机 ...

Jürgen Jost黎曼几何与几何分析教材:Riemannian Geometry and Geometric Analysis

这本书是几何分析方面的入门教材,该教材先从最基本的黎曼流形讲起,然后逐步深入到李群和向量丛,接着到联络与曲率,基本上覆盖了几何分析很多重要的基础概念。这本书需要有一定的微分几何基础以及分析、李群等相关领域的基础,初学者谨慎使用。我高中的时候,就是对这本书的内容感兴趣,想要尝试理解,结果看到测地线就不懂了,接着后面看了点李群和向量丛就没再看了。建议先读Loring W Tu的两本微分几何教材Loring W Tu微分几何经典入门教材:An Introduction to Manifolds和Loring W Tu微分几何教材:Differential Geometry Connections, Curvature, and Characteristic Classes,有了一定的基础再专研Jürgen Jost的这本教材。我毕竟不是做微分几何的,所以关于这方面的就不说太多了。PS:作者不再提供附件下载。

Loring W Tu微分几何教材:Differential Geometry Connections, Curvature, and Characteristic Classes

在上帖Loring W Tu微分几何经典入门教材:An Introduction to Manifolds中,我提到高中时期,我为了看懂Jürgen Jost的几何分析教材Riemannian Geometry and Analysis,转而看Loring W Tu的An Introduction to Manifolds以及Differential Geometry Connections, Curvature, and Characteristic Classes。这本教材可以说是An Introduction to Manifolds的后续,建议先看一下An Introduction to Manifolds有了流形的基础,再看这本Connections, Curvature, and Characteristic Classes。本书开始就直接先从黎曼流形开始讲起,接着就讲曲率、联络这些微分几何进阶的重要基本概念。这也是为什么当初我会选择看这本书,因为这些内容刚好有助于我理解Riemannian Geometry and Analysis这本教材的内容(记得当时看到测地线就看不 ...

素数在整数整环中还是素的吗?

我的提问:一个整环$R$中的元素$p$是素的,如果$p$不是零或者一个单元,并且$p|ab$意味着$p|a$或者$p|b$(等价的$ab\in Rp$意味着$a \in Rp$或者$b\in Rp$)。一个整环$R$的元素$q$是不可约的,当$q$不是零或者一个单元,并且$q = ab$意味着$a$或$b$是一个单元。那么素数在整数整环中是素的吗?然后素数都是不可约的吗?回答1:这两个问题的都是对的。根据基础数论的事实,$\pm 1$是唯一可逆的整数,除$\pm 1$以外的整数可以唯一地表示为不同素数的乘积加上$\pm$,每个素数的幂都是正整数,这两个结果都很容易得到。回答2:素数在整数整环中既是素的,也是不可约的。根据定义,它们就是不可约的。为了证明它们是素的,请回顾一下欧几里得算法,该算法用于找到两个整数的GCD(并同时证明任意两个整数都有一个在等价意义下唯一的GCD,其中并不涉及素数的分解)。根据欧几里德算法可以得出,如果$d=\gcd(a,b)$对两个整数$a,b\in\mathbb Z$,则存在整数$u,v\in\mathbb Z$使得$d=ua+vb$。(贝祖特性。)现在, ...

2024-11-22凌晨:弦圈最近两周更新情况

在上篇弦圈11月10日上下更新计划:小金库、打赏等功能,我提到会更新网站多个功能。原本以为这些功能最多一周就能全部写完,结果当我真正开始写,才发现自己完全低估了这些功能实现的难度,以及所需要耗费的时间。而且由于我的完美主义倾向,导致我比原计划多开发了好几个功能,比如说编辑器插入公式、交易中心、收藏党最喜爱的收藏夹等。因为我想反正都大更新了,那干脆就更新得多一些,把以前埋的坑都填上。再然后支付功能比我想象中的要难得多,这不仅仅指代码难写,还包括支付宝的审核等问题,人事问题上也耗费了不少时间。在这里忍不住吐槽一下支付宝和微信支付,这国内两家巨头技术文档写的是真烂、真水。多少年了,支付宝支付SDK的demo示例还是Java、PHP,Python压根没写,只能自己摸索然后网上找到些零散的资料。微信支付先是需要微信认证强制每年收费300元,然后文档也是写得不清不楚。反正目前网站就暂时只支持支付宝吧,之后再把微信支付补上吧,因为真的被恶心到了。总之如今写了快两个星期了,这些功能终于要完成了,预计明后天就能上线测试。网站也完全没更新,也找不到人帮忙更新,只能先放着了。之后我会发一篇更新日志,更加详细 ...

弦圈11月10日上下更新计划:小金库、打赏等功能

这几天忙于写代码完善网站功能,不太有空更新文章和内容。因为弦圈没有借助任何建站工具和博客框架,是我自己前后端一起从零开始写的,因此开发得会比较慢,请谅解。。。目前计划上线功能首先就包括,前面弦圈更新日志:关于智力值和金币提到的小金库。获取金币的机制是:智力值存入银行(叫时空银行time bank?),然后根据日利率每天产生相应的金币。下图为测试画面其次为了让网站能够更好的运作下去,从而给大家提供更好的服务,我计划引入盈利功能。所谓盈利功能即是用户通过弦圈来获得收益的相关功能,包括打赏功能、接广告功能、接悬赏功能。这些功能主要是为了鼓励大家为社区做贡献,并且让需要得到帮助的人更容易获得帮助(毕竟大佬们忙得很,不会轻易帮助你解决问题)。具体规则暂定如下:想要让弦圈的用户能赚钱,那弦圈必须自己先能赚到钱,目前我计划引入弦圈广告和用户交易中心。至于弦圈广告,我打算采用信息流广告、侧边栏广告、文章内嵌广告,拒绝弹窗之类遮蔽视线的广告,因此不会影响用户体验。最后我还得把之前留的坑——创作中心给填上,就是一个给创作者的方便管理内容、查看数据的模块。测试画面如下:尽情期待😇

Grothendieck经典著作:代数几何原理EGA 1(1971第二版)法语+英译

在前面几贴中,我已经分别分享了Grothendieck的代数几何三部曲EGA、SGA、FGA,链接如下:代数几何教皇Grothendieck经典著作:代数几何原理EGA法语原版全系列(1)代数几何教皇Grothendieck经典著作:代数几何讨论班SGA法语原版全系列代数几何教皇Grothendieck经典著作:代数几何基础FGA法语原版+英文译版但其实EGA 1还有1971年的第二版,Grothendieck在EGA 1第二版中更新了一些内容,因此一些概念定义会与第一版中有出入。原本我也是不太知道EGA竟然还会有第二版,直到后来有次看文献时,发现作者引用了EGA 1(1971)才知道有这一版本。对比EGA 1第一版跟第二版,感觉第二版要比第一版更好读一些,似乎思路行文更清晰,也更好理解。并且值得开心的是,EGA 1第二版有完整英译,现在我全都分享出来。更新:作者不再提供文件下载。