·

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

发布时间:2024-08-28 00:15:22阅读量:219
转载请注明来源

创作场景

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

阅读前提

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

提前了解的知识点

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 人喜欢

评论区

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

弦圈热门内容

GTM023 W.H.Greub线性代数经典教材:Linear Algebra

这本教材是我高中时期入门线性代数的主要教材,我的很多基础知识都来源于这本书,如今看回这本书可以说满满的回忆。这本书可以说,是我读过的内容最为全面且完备的线性代数教材了。而且它的语言风格非常的代数化,没有什么直观可言,以抽象为主,表述简练、知识密度高。总之,真的太对我的胃口了,我当时是挺喜欢看这本书。这本教材跟其他线性代数教材一样,先从最基本的向量空间开始讲起,但不同的是,它这里还应用了群论的知识。紧接着这本书以代数抽象的形式讲矩阵和行列式,尤其是行列式,书中的描述直达其代数本质,这是我当时印象挺深刻的。接着书本还继续往外拓展,讲到与向量空间相关的一些概念,如泛函分析中的内积空间,同调代数中的代数和同调。总之,这本书对初学者有一点小门槛,适合喜欢挑战难度、喜欢看高水平读物的初学者看。PS:作者不再提供附件下载。

QQ频道AI视频泛滥?未来互联网上会充斥着AI生成的垃圾视频吗?

QQ这段时间感觉AI视频比以前多了,而且更主要是现在QQ还给AI视频推流了,可以说举措完全跟其他平台不同。以往QQ上的AI视频,基本上都是没流量的,现在给流量扶持,势必会导致AI视频进一步泛滥。其他平台像知乎、公众号、推特,发AI生成的内容,其实是会直接限流的。昨天我在知乎上发一篇AI生成的小说,创作声明了AI写的,结果直接零流量,阅读量1应该就是我自己吧。而在推特上发东西,如果用Gemini修改你自己写的语句,发上去也会被限流。小红书我没试过,之前看那种AI美女的笔记也挺泛滥的,不过后来我举报过以后就基本没看到了,也不知道是不是算法问题,还是小红书算法更新了。总之,小红书也是不鼓励AI生成的。说实话就没几个平台真的会鼓励AI生成的内容,只有极少数幸运儿会得到流量,毕竟说实话绝大多数AI内容都惨不忍睹,我其中最讨厌的就是那种AI美女图片,现在还多了视频,真的恶心,关键是居然还有人会看?尤其是QQ视频,之前还不给AI内容推流,现在直接开始推流了,更加惨不忍睹,关键是还不少人评论互动。如果是我,肯定直接不点,流量都懒得给它。AI视频如果仅仅只是整活那种,那还勉强能接受,但是我更喜欢那种混剪 ...

我开发的宇宙级APP竟然成为了其他世界的系统

陈木是弦圈一名默默无闻的全栈程序员,他每天身兼多职,任劳任怨地工作,既负责网站前端的开发与维护,又得兼顾后端的开发与维护。前段时间,陈木又接到了新的任务,要求他负责弦圈APP相关的开发工作 计划开发弦圈的桌面端版和APP版。于是,陈木在挑选了众多技术与框架后,选择了使用Universal React Native Pro Max进行APP的开发,这是一个近期在全世界都很火的框架。Universal React Native是基于传统的React Native通过最新的universal技术[1]进一步迭代升级,从而能达到用React Native语言开发任何东西原生的一个技术框架,而Pro Max则是它的超级升级版,你甚至能用它编程纳米机器人和可控核聚变引擎。开发的日子时间总是过得飞快,眨眼间就过了几万年,陈木头发都秃了,才终于从工作中缓过来。这时陈木也收到放假的通知 弦圈APP先开发到这里......,他松了口气,终于可以放松一下,并开始着手考虑自己一直以来的设想——开发一个宇宙级APP。所谓的宇宙级APP数亿年以来,一直都是各大星域争相竞争的研究对象,指的是通过开发宇宙级API接口 ...

如何激怒一位数学爱好者?

知乎提问:如何激怒一位数学爱好者?我的回答:我初三乃至高中想要自学高等数学的时候,像“学数学有什么用?”、“纯数学有什么实际应用吗?”、“你一个做数学的连这么简单的计算都不会?”这些话及其变式,确实有可能让我非常不爽。到了高三乃至本科这个阶段,像“名词党”、“你知道什么相关的例子吗?”、“你需要知道更多具体的数学”、“你问的问题太trivial”、“你看这个内容需要要看这么久?”、“你不是做数学的”等等这些话及其变式,都会让我觉得非常不爽。当然这是之前会感到不爽,直到我开始独立做研究、写论文,真正开始做数学后,才发现这些话要么都是单纯的p话、要么是正确的废话,总是如今是完全不在意。说这些话的人,本身水平如何也要画个大大的问号,有些人连学术产出都没有就喜欢到处指点江山、误人子弟。这时到了做数学阶段,记忆中曾经让我不爽的话,包括“你的论文好像notes啊”,然后就是投稿时审稿人的冷淡回应,如“你的论文不适合本期刊”、“你的论文in general non sense”。直到后来我的论文也得到某些人认可后,我也明白在纯数学什么东西是对的、什么理论是重要的有时候是一件非常主观的事情。最近能让我 ...

世界婴儿危机,我们要被婴儿淹没了吗?(故事线)

我打算补全一下之前写的 世界婴儿危机,我们要被婴儿淹没了吗?的故事线,这个故事的灵感源于一次在微信上跟朋友聊天,我突发奇想下说出来的。当时记得是在讨论泡菜国的一则新闻,水里检测出伟哥的成分超标😅。然后我直接展开想象,原本我很想把故事像小说那样一章一章的全写出来,但奈何我的文笔真的有限,我语文一向不太好,每写一点就像挤牙膏一样特别难受。不过这么有趣的故事就这么荒废在那了,我觉得很是心疼,即便自己文采不行,不能把细节刻画好,还是把故事线理一理吧。第一章 危机开始泡菜国H市,有一条河名为“生命之河”,它原本清澈见底,但如今因为泛滥的伟哥成分,而变得“浑浊”,晚上河面上散发着“诡异”的光芒。这本是一个平常的晚上,但是泡菜国的年轻人像打了鸡血一样,免疫了伟哥的副作用开始以一天七次的频率疯狂造娃。由于每次都一发入魂,泡菜国的新生人口直接开始暴增,出生率轻松超过了人类历史最高记录。很快这也引起了政府的注意,然而政府不仅对此十分冷淡,直接打算坐视不管,他们认为这次婴儿潮危机会很快过去,泡菜国总统还忙着处理他的弹劾案件呢。泡菜国也因为这次史无前例的婴儿潮事件,沦为全世界的笑柄,其他国家的人纷纷落井下石, ...

在下22岁打算毕生献身于攻克黎曼猜想,可以给我一句忠告吗?

知乎提问:在下22岁打算毕生献身于攻克黎曼猜想,可以给我一句忠告吗?我的回答:在我看来数学研究者执着于攻克某个猜想、某个问题,除了名利外,毫无意义。比起关注某个著名的open question,还不如多些关注数学本身,解决问题也罢、构建理论也罢,所有这一切不过是为了数学的发展罢了。即便你对黎曼猜想真的很感兴趣,也没必要毕生都花费在这上面,得在合适的时机干合适的事情。怀尔斯很小的时候就被费马大定理所吸引,但他最后也是在代数几何领域有了突破性进展后,觉得是时候了才选择攻克费马大定理。有句话叫“站在巨人的肩膀上”,个人是渺小的,很多时候你总是夸大了个人的作用。想要攻克黎曼猜想这种级别的问题,需要好多代数学家们的努力。因此,与其执着于这个虚无缥缈的猜想,还不如着眼于当下,先解决当下的数学问题,发展当下的数学理论。只有这个做好了,你才有资格挑战黎曼猜想。

AI写小说:陈默重生(版本一+版本二)

这篇短文出于今年6月份,故事线是自己写的,内容是AI输出的,可以发现质量并不怎么好,AI总是get不到我的点,老是差么点,达不到我的要求和期望。经过几个月的改进,现在的AI应该好些了吧。版本一陈默坐在高三的课堂上,心中却是翻涌着前世的记忆。他曾是鸿蒙神,统领亿万星域,仅差半步就能踏入传说中的灭神境。然而,在突破的关键时刻,他意外陨落,重生回到了这个看似平凡的高三时期。这个世界与他前世的修仙界截然不同,这是一个属于职业者的世界。人们通过转职仪式来觉醒自己的职业天赋,从而决定未来的道路。陈默深知,他即将面临的转职仪式,对他来说不仅是一次重新选择的机会,更可能是他重拾前世力量,再次踏上巅峰的起点。随着校长慷慨激昂的演讲落幕,转职仪式正式开始。同学们怀着紧张与期待的心情,一个个走上转职阵法,去迎接他们命运的转折。然而,对于大多数人来说,转职结果都是普通的职业,虽然让他们有些失望,但也只能接受现实。终于轮到了陈默。他站起身,深吸一口气,稳步走向转职阵法。当他将手放在觉醒石上的那一刻,他感受到了一股前所未有的能量波动。紧接着,天地间突发异象,黑云笼罩了方圆数十万公里,仿佛要将整个世界都吞噬进去。老 ...

Serge Lang经典代数教材:Algebra Revised Third Edition

这是GTM211,Serge Lang写的代数经典教材Algebra。关于Serge Lang的教材,虽然在知乎上褒贬不一,但我自己以前在数学圈中,倒是没听过这些负面评价,倒是听说过有人推荐Serge Lang的这本Algebra,遇到代数方面不懂的可以直接查Algebra。我自己基本没读过Serge Lang的教材,这本Algebra除了,记得当初也是看了一些的。这本书作为入门教材,因为篇幅过长,对于不懂得跳着读书的人来说要耗费很多时间,因此不适合。但是翻看目录就可以发现,这本书应该是迄今为止代数方面最完备的教材之一了,前面我分享的GTM242 Grillet抽象代数经典教材:Abstract Algebra 2nd,也是非常完备的代数教材,跟Serge Lang的这本Algebra结合起来正好,因此我之前查抽象代数方面的知识,就是拿GTM242和GTM211这两本作为参考文献,当然还有Stack Project。然后在知乎上我发现(这也是我为啥讨厌知乎)有人会说某教材不好,原因是肤浅或者说书中有不少小错。我觉得还是少拿这种言论来误人子弟,真的知乎什么人都能随便评价数学😅。在我看来, ...