爆款云主机2核4G限时秒杀,88元/年起!
查看详情

活动

天翼云最新优惠活动,涵盖免费试用,产品折扣等,助您降本增效!
热门活动
  • 618智算钜惠季 爆款云主机2核4G限时秒杀,88元/年起!
  • 免费体验DeepSeek,上天翼云息壤 NEW 新老用户均可免费体验2500万Tokens,限时两周
  • 云上钜惠 HOT 爆款云主机全场特惠,更有万元锦鲤券等你来领!
  • 算力套餐 HOT 让算力触手可及
  • 天翼云脑AOne NEW 连接、保护、办公,All-in-One!
  • 中小企业应用上云专场 产品组合下单即享折上9折起,助力企业快速上云
  • 息壤高校钜惠活动 NEW 天翼云息壤杯高校AI大赛,数款产品享受线上订购超值特惠
  • 天翼云电脑专场 HOT 移动办公新选择,爆款4核8G畅享1年3.5折起,快来抢购!
  • 天翼云奖励推广计划 加入成为云推官,推荐新用户注册下单得现金奖励
免费活动
  • 免费试用中心 HOT 多款云产品免费试用,快来开启云上之旅
  • 天翼云用户体验官 NEW 您的洞察,重塑科技边界

智算服务

打造统一的产品能力,实现算网调度、训练推理、技术架构、资源管理一体化智算服务
智算云(DeepSeek专区)
科研助手
  • 算力商城
  • 应用商城
  • 开发机
  • 并行计算
算力互联调度平台
  • 应用市场
  • 算力市场
  • 算力调度推荐
一站式智算服务平台
  • 模型广场
  • 体验中心
  • 服务接入
智算一体机
  • 智算一体机
大模型
  • DeepSeek-R1-昇腾版(671B)
  • DeepSeek-R1-英伟达版(671B)
  • DeepSeek-V3-昇腾版(671B)
  • DeepSeek-R1-Distill-Llama-70B
  • DeepSeek-R1-Distill-Qwen-32B
  • Qwen2-72B-Instruct
  • StableDiffusion-V2.1
  • TeleChat-12B

应用商城

天翼云精选行业优秀合作伙伴及千余款商品,提供一站式云上应用服务
进入甄选商城进入云市场创新解决方案
办公协同
  • WPS云文档
  • 安全邮箱
  • EMM手机管家
  • 智能商业平台
财务管理
  • 工资条
  • 税务风控云
企业应用
  • 翼信息化运维服务
  • 翼视频云归档解决方案
工业能源
  • 智慧工厂_生产流程管理解决方案
  • 智慧工地
建站工具
  • SSL证书
  • 新域名服务
网络工具
  • 翼云加速
灾备迁移
  • 云管家2.0
  • 翼备份
资源管理
  • 全栈混合云敏捷版(软件)
  • 全栈混合云敏捷版(一体机)
行业应用
  • 翼电子教室
  • 翼智慧显示一体化解决方案

合作伙伴

天翼云携手合作伙伴,共创云上生态,合作共赢
天翼云生态合作中心
  • 天翼云生态合作中心
天翼云渠道合作伙伴
  • 天翼云代理渠道合作伙伴
天翼云服务合作伙伴
  • 天翼云集成商交付能力认证
天翼云应用合作伙伴
  • 天翼云云市场合作伙伴
  • 天翼云甄选商城合作伙伴
天翼云技术合作伙伴
  • 天翼云OpenAPI中心
  • 天翼云EasyCoding平台
天翼云培训认证
  • 天翼云学堂
  • 天翼云市场商学院
天翼云合作计划
  • 云汇计划
天翼云东升计划
  • 适配中心
  • 东升计划
  • 适配互认证

开发者

开发者相关功能入口汇聚
技术社区
  • 专栏文章
  • 互动问答
  • 技术视频
资源与工具
  • OpenAPI中心
开放能力
  • EasyCoding敏捷开发平台
培训与认证
  • 天翼云学堂
  • 天翼云认证
魔乐社区
  • 魔乐社区

支持与服务

为您提供全方位支持与服务,全流程技术保障,助您轻松上云,安全无忧
文档与工具
  • 文档中心
  • 新手上云
  • 自助服务
  • OpenAPI中心
定价
  • 价格计算器
  • 定价策略
基础服务
  • 售前咨询
  • 在线支持
  • 在线支持
  • 工单服务
  • 建议与反馈
  • 用户体验官
  • 服务保障
  • 客户公告
  • 会员中心
增值服务
  • 红心服务
  • 首保服务
  • 客户支持计划
  • 专家技术服务
  • 备案管家

了解天翼云

天翼云秉承央企使命,致力于成为数字经济主力军,投身科技强国伟大事业,为用户提供安全、普惠云服务
品牌介绍
  • 关于天翼云
  • 智算云
  • 天翼云4.0
  • 新闻资讯
  • 天翼云APP
基础设施
  • 全球基础设施
  • 信任中心
最佳实践
  • 精选案例
  • 超级探访
  • 云杂志
  • 分析师和白皮书
  • 天翼云·创新直播间
市场活动
  • 2025智能云生态大会
  • 2024智算云生态大会
  • 2023云生态大会
  • 2022云生态大会
  • 天翼云中国行
天翼云
  • 活动
  • 智算服务
  • 产品
  • 解决方案
  • 应用商城
  • 合作伙伴
  • 开发者
  • 支持与服务
  • 了解天翼云
      • 文档
      • 控制中心
      • 备案
      • 管理中心

      动态监听DOM元素的高度

      首页 知识中心 软件开发 文章详情页

      动态监听DOM元素的高度

      2025-03-26 10:18:58 阅读次数:22

      DOM,展示,按钮,监听,高度

      1、背景

      考虑这样一种情况,产品同学希望达到以下功能:

      在我们的网页中有一个固定区域,这个区域会用于渲染从后端拉取的含有图片等资源的富文本字符串。

      他需要在内容不超过一个最大高度的时候完全显示所有内容,超过最大内容后仅展示最大高度范围内的内容,超出部分隐藏,并通过一个按钮 “展示更多” 来给用户展示更多的选择。

      动态监听DOM元素的高度

      在这看似简单的需求当中,其实涉及到了一个难点,那就是怎样动态的监听到内容区域的高度变化?

      因为在这里面会含有图片资源,他们在渲染的时候会发起网络请求,等待图片加载完成后触发浏览器重排,该区域的高度被撑开。

      因此,内容区域的高度是动态变化,且变化的时间点是未知的,那么怎样知道我们的内容区高度发生了变化呢?

      为此我做了以下几种尝试:

      1. MutationObserver

      2. IntersectionObserver

      3. ResizeObserver

      4. 监听所有资源的 onload 事件

      5. iframe(推荐)

      • MutationObserver
        MutationObserver 接口提供了监视对 DOM 树所做更改的能力。它被设计为旧的 Mutation Events 功能的替代品,该功能是 DOM3 Events 规范的一部分。

      • observe(target, options)
        这个方法会根据传入的 options 配置,观察 DOM 树中的单个 Node 或者所有的子孙节点的变化。

        他一共有七个属性,这里就不一一介绍了,可以通过 MutationObserverInit 来获取相应的介绍.

        那么我们要怎么使用这个 API 来监听目标区域的高度变化呢?

        首先我们要创建对该区域的 dom 根结点引用:

      	const Details = () => {
      	    // useRef创建引用
      	    const contentRef = useRef();
      	    const [height, setHeight] = useState(-1);
      	    const [observer, setObserver] = useState<MutationObserver>(null!);
      	
      	    useEffect(() => {
      	          const observer = new MutationObserver((mutationList) => {
      	            if (height !== contentRef.current?.clientHeight) {
      	                console.log('高度变化了!');
      	                setHeight(contentRef.current.clientHeight);
      	            }
      	          });
      	          setObserver(observer);
      	    }, []);
      	
      	    useEffect(() => {
      	          if (!observer || !contentRef.current) return
      	          observer.observe(contentRef, {
      	            childList: true, // 子节点的变动(新增、删除或者更改)
      	            attributes: true, // 属性的变动
      	            characterData: true, // 节点内容或节点文本的变动
      	            subtree: true// 是否将观察器应用于该节点的所有后代节点
      	          });
      	    }, [contentRef.current, observer]);
      	
      	    // 绑定ref
      	    return<div className="content" dangerouslySetInnerHTML={{ __html: details }} style={{ maxHeight }} ref={contentRef} />
      	}
      

      经过上面的一番操作之后,发现根本达不到效果,因为我们的 css 属性根本没有发生变化(我们是通过 maxHeight 来约束容器的高度的), 但是资源加载完毕之后,浏览器重排根本没有产生 css 属性的变化,它的高度是自动计算的

      因此这个方案无济于事!但是它确实可以监听到认为修改容器的高度产生的变化,比如:contentRef.current.style.height = ‘1000px’,这个 api 是可以监听到这一操作的,但是并不符合我们的场景

      此外,它的浏览器兼容性也还行:

      动态监听DOM元素的高度

      • IntersectionObserver
        经过激情编码,最后发现 MutationObserver 根本达不到我们想要的效果之后,其实我的心态已经产生了一些变化,不过不要紧!

        我们可以换一种思路,既然我们无法通过监听容器的高度变化来展示相应的 “展开更多” 操作,那么我们可不可以将这个 “展开更多” 固定到一个位置上,然后超出部分隐藏,

        当我们的内容自动撑开,达到指定高度后,我们这个 “展开更多” 的操作的按钮就显示出来了,听上去不错,能达到要求!废话不多说,开撸!

        因为这里只涉及到相应的 css 样式的书写,就不做展示了。

        经过处理之后,确实在容器高度小于指定高度的时候,“展示更多” 按钮不会展示,超过最大值之后,会将该按钮展示出来,

        但是也遇到了一个问题,操作按钮是有高度的,如果我们的内容高度介于最大高度 - 按钮高度 到 容器的最大高度之间, 按钮会产生显示一部分,同时又隐藏一部分的效果,这可不是我们想要的!

        显然这种效果是不符合要求的,我们的 “展示更多” 按钮,只有两种状态,要么全部展示,要么不展示,没有这种部分展示的效果

        因此我查阅了相关资料,了解到了 IntersectionObserver 这个 API,它可以监听一个元素是否进入用户视野,它的相关使用方法可以参考这篇文章:IntersectionObserver API 使用教程

        它使用起来和 MutationObserver 几乎一样,只是名字不一样而已

        它监听的值里面有一个比较重要的属性:intersectionRatio

        动态监听DOM元素的高度

        借助这个 API,我的设计思路是这样的:

        当用户滚动网页的时候(或者不滚动,此时目标区域已经出现在屏幕中),可以得到 intersectionRatio 的值,通过判断这个值是否等于 1 来决定要不要展示 “展示更多” 按钮

        但经过我的编码实现后,发现滚动事件发生的时候,intersectionRatio 的变化是不可靠的,有时候完全可见了,但是它并不等于 1。经过多轮实验,结果依然如此。但是它确实可以用来判断一个元素是否进入用户视野

        由于使用上结果的不可靠,我放弃这个方案(可能是我使用方式上出了问题)

        它的各浏览器兼容性如下:

      动态监听DOM元素的高度

      • ResizeObserver
        顾名思义,这个 API 就是专门监听 DOM 尺寸变化的,只不过它还处于试验阶段,各浏览器的兼容性很差,所以基本不考虑

        具体使用方法可以参考这篇文章:检测 DOM 尺寸变化 JS API ResizeObserver 简介

        它现阶段各浏览器的兼容性情况:

      动态监听DOM元素的高度

      • 监听所有资源的 onload 事件
        既然上述方法都不行,那么我绞尽脑汁,又想出了另外一种方法:监听所有带有 src 属性的 DOM 元素的 onload 事件,通过他的回调来判断当前容器的高度情况

        这种实现方式,在思路上是完全符合目的的,具体做法参考如下:

      const [height, setHeight] = useState(-1);
      	const [showMore, setShowMore] = useState(false);
      	// contentRef 的定义见 MutationObserver 一节
      	useEffect(() => {
      	  const sources = contentRef.current.querySelectorAll("[src]");
      	  sources.onload = () => {
      	    const height = contentRef?.current?.clientHeight ?? 0;
      	    const show = height >= parseInt(MAX_HEIGHT, 10);
      	
      	    setHeight(height);
      	    setShowMore(show);
      	  };
      	}, []);
      

      通过这种方式可以实现对富文本中的图片进行加载后,对容器高度进行相应的判断。

      但是这种方式,存在不确定性,即无法判断是否找齐了所有高度由内容撑开的资源。

      • Iframe
        这是终极方案,也是在此背景中所采用的方案。

        既然 window 可以监听到 resize 事件,那么我们就可以利用 iframe 来达到同样的效果,具体做法就是在容器里面嵌套一个隐藏的高度为 100% 的 iframe,通过监听他的 resize 事件,来判断当前容器的高度。

        话不多说,具体实现方式如下:

      const Detail: FC<{}> = () => {
      	  const ref = useRef<HTMLDivElement>(null);
      	  const ifr = useRef<HTMLIFrameElement>(null);
      	  const [height, setHeight] = useState(-1);
      	  const [showMore, setShowMore] = useState(false);
      	  const [maxHeight, setMaxHeight] = useState(MAX_HEIGHT);
      	  const introduceInfo = useAppSelect(
      	    (state) => state.courseInfo?.data?.introduce_info ?? {}
      	  );
      	  const details = introduceInfo.details ?? "";
      	  const isFolded = maxHeight === MAX_HEIGHT;
      	  const onresize = useCallback(() => {
      	    const height = ref?.current?.clientHeight ?? 0;
      	    const show = height >= parseInt(MAX_HEIGHT, 10);
      	
      	    setHeight(height);
      	    setShowMore(show);
      	    if (ifr.current && show) {
      	      ifr.current.remove();
      	    }
      	  }, []);
      	
      	  useEffect(() => {
      	    if (!ref.current || !ifr.current?.contentWindow) return;
      	    ifr.current.contentWindow.onresize = onresize;
      	    onresize();
      	  }, [details]);
      	
      	  if (!details) returnnull;
      	
      	  return (
      	    <section className="section detail-content">
      	      <div className="content-wrapper">
      	        <div
      	          className="content"
      	          dangerouslySetInnerHTML={{ __html: details }}
      	          style={{ maxHeight }}
      	          ref={ref}
      	        />
      	        {/* 这个iframe是用来动态监听content高度的变化的 */}
      	        <iframe title={IFRAME_ID} id={IFRAME_ID} ref={ifr} />
      	      </div>
      	      {isFolded && showMore && (
      	        <>
      	          <div
      	            className="show-more"
      	            onClick={() => {
      	              setMaxHeight(isFolded ? "none" : MAX_HEIGHT);
      	            }}
      	          >
      	            查看全部
      	            <IconArrowDown className="icon" />
      	          </div>
      	          <div className="mask" />
      	        </>
      	      )}
      	    </section>
      	  );
      	};
      
      这种方式实际上就是对 ResizeObserver 的一种 hack,经过多次实践,符合功能要求。
      

      总结:
      解决问题要尽可能的考虑多种情况,对比多种方案,采取最为可靠的一种方案。

      注: 监听 DOM 元素的高度变化,可以采用内嵌 iframe 的方式来解决。

      版权声明:本文内容来自第三方投稿或授权转载,原文地址:https://blog.csdn.net/qq_34574204/article/details/125706202,作者:大莲芒,版权归原作者所有。本网站转在其作品的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如因作品内容、版权等问题需要同本网站联系,请发邮件至ctyunbbs@chinatelecom.cn沟通。

      上一篇:数组的API中可以return的有哪些

      下一篇:手写代码实现call/apply/bind

      相关文章

      2025-05-19 09:04:30

      TNS-01189: 监听程序无法验证用户

      TNS-01189: 监听程序无法验证用户

      2025-05-19 09:04:30
      用户 , 监听 , 验证
      2025-05-09 09:30:19

      将有序数组转换为二叉搜索树

       nums ,其中元素已经按 升序 排列,请你将其转换为一棵 高度平衡 二叉搜索树。

      2025-05-09 09:30:19
      二叉 , 二叉树 , 数组 , 示例 , 高度
      2025-05-09 08:50:35

      Element学习(布局组件、案例操作)(4)

      Element学习(布局组件、案例操作)(4)

      2025-05-09 08:50:35
      展示 , 布局 , 效果 , 查询 , 组件 , 表单 , 表示
      2025-04-18 07:11:02

      DOM和树结构之间怎么相互转换

      DOM和树结构之间怎么相互转换

      2025-04-18 07:11:02
      DOM , 对象 , 转换
      2025-04-11 07:16:05

      spring-boot-admin-starter-server监控springboot项目

      spring-boot-admin-starter-server监控springboot项目

      2025-04-11 07:16:05
      参考 , 场景 , 实现 , 展示 , 监控 , 项目
      2025-04-11 07:03:35

      文心一言 VS 讯飞星火 VS chatgpt (160)-- 算法导论12.4 2题

      二叉搜索树(Binary Search Tree,BST)是一种特殊的二叉树,它对于每个节点都满足:左子树上所有节点的值均小于它的根节点的值,右子树上所有节点的值均大于它的根节点的值。

      2025-04-11 07:03:35
      二叉 , 结点 , 节点 , 高度
      2025-04-09 09:16:56

      Python的PyQt框架的使用-资源文件夹的使用

      P

      2025-04-09 09:16:56
      图片 , 对话框 , 按钮 , 文件 , 资源
      2025-04-09 09:12:41

      Vue学习笔记:$refs与ref

      前面两篇学习的是使用props实现数据父传子,以及使用$emit实现父组件响应响应子组件。

      2025-04-09 09:12:41
      ref , 按钮 , 组件 , 绑定 , 节点
      2025-03-31 08:57:48

      Vue 自定义一个可以高度自由化的模态框组件

      Vue 自定义一个可以高度自由化的模态框组件

      2025-03-31 08:57:48
      url , 按钮
      2025-03-31 08:57:16

      单选按钮控制页面部分的显示的流程

      单选按钮控制页面部分的显示的流程

      2025-03-31 08:57:16
      按钮 , 触发 , 页面
      查看更多
      推荐标签

      作者介绍

      天翼云小翼
      天翼云用户

      文章

      33561

      阅读量

      5252159

      查看更多

      最新文章

      TNS-01189: 监听程序无法验证用户

      2025-05-19 09:04:30

      将服务器传入的字段转成html渲染出来

      2025-03-31 08:57:16

      理解VUE-nextTick实现原理

      2025-03-28 07:42:42

      JavaScript之事件

      2025-03-27 10:12:02

      Shell提升配置管理的效率与质量:基于Shell脚本修改变更值

      2025-03-21 06:56:46

      Java-Spring中的事件监听

      2025-03-04 09:11:34

      查看更多

      热门文章

      Windows监听进程是否退出C++

      2023-03-13 10:02:19

      React-传统写法

      2024-07-01 01:32:44

      Spring Boot HttpSessionListener 监听使用

      2024-09-25 10:14:09

      html+css实战135-按钮

      2023-05-23 08:22:30

      使用layui弹框实现添加时,当添加成功之后如何进行关闭当前窗口刷新父页面的数据

      2024-04-24 07:18:34

      JavaScript实现点击按钮显示当前时间

      2024-06-06 08:03:43

      查看更多

      热门标签

      java Java python 编程开发 代码 开发语言 算法 线程 Python html 数组 C++ 元素 javascript c++
      查看更多

      相关产品

      弹性云主机

      随时自助获取、弹性伸缩的云服务器资源

      天翼云电脑(公众版)

      便捷、安全、高效的云电脑服务

      对象存储

      高品质、低成本的云上存储服务

      云硬盘

      为云上计算资源提供持久性块存储

      查看更多

      随机文章

      【[C++BFS】1765. 地图中的最高点

      css3实现鼠标悬停特效代码

      前端 -- 单选框内容影响复选框的隐藏与显示 附代码

      Spring Boot HttpSessionListener 监听使用

      详细分析Vue中的$refs用法

      ios开发之--键盘的监听

      • 7*24小时售后
      • 无忧退款
      • 免费备案
      • 专家服务
      售前咨询热线
      400-810-9889转1
      关注天翼云
      • 旗舰店
      • 天翼云APP
      • 天翼云微信公众号
      服务与支持
      • 备案中心
      • 售前咨询
      • 智能客服
      • 自助服务
      • 工单管理
      • 客户公告
      • 涉诈举报
      账户管理
      • 管理中心
      • 订单管理
      • 余额管理
      • 发票管理
      • 充值汇款
      • 续费管理
      快速入口
      • 天翼云旗舰店
      • 文档中心
      • 最新活动
      • 免费试用
      • 信任中心
      • 天翼云学堂
      云网生态
      • 甄选商城
      • 渠道合作
      • 云市场合作
      了解天翼云
      • 关于天翼云
      • 天翼云APP
      • 服务案例
      • 新闻资讯
      • 联系我们
      热门产品
      • 云电脑
      • 弹性云主机
      • 云电脑政企版
      • 天翼云手机
      • 云数据库
      • 对象存储
      • 云硬盘
      • Web应用防火墙
      • 服务器安全卫士
      • CDN加速
      热门推荐
      • 云服务备份
      • 边缘安全加速平台
      • 全站加速
      • 安全加速
      • 云服务器
      • 云主机
      • 智能边缘云
      • 应用编排服务
      • 微服务引擎
      • 共享流量包
      更多推荐
      • web应用防火墙
      • 密钥管理
      • 等保咨询
      • 安全专区
      • 应用运维管理
      • 云日志服务
      • 文档数据库服务
      • 云搜索服务
      • 数据湖探索
      • 数据仓库服务
      友情链接
      • 中国电信集团
      • 189邮箱
      • 天翼企业云盘
      • 天翼云盘
      ©2025 天翼云科技有限公司版权所有 增值电信业务经营许可证A2.B1.B2-20090001
      公司地址:北京市东城区青龙胡同甲1号、3号2幢2层205-32室
      • 用户协议
      • 隐私政策
      • 个人信息保护
      • 法律声明
      备案 京公网安备11010802043424号 京ICP备 2021034386号