为自己的项目媒体资源添加固定高度
为自己的项目媒体资源添加固定高度
未媒体资源添加固定高度,不仅有利于确定懒加载后的切确位置,还可以做骨架屏、loading动画等等,但是因为历史数据中很多没有加高度的媒体资源,所以一直嫌麻烦没有做。
直到这个季度有一个自上而下(不可抗力)的push。一个需求需要在懒加载的情况下跳转到底部的一个坐标。
一开始我们拟定的方案是中途查询,边查询边修改目标高度,但是这样做无法避免有些很大的图片加载慢的情况,跳转到正确位置后整整1~2秒才加载出来,这时候我们已经跳转到目标地在那里正常浏览了,页面突然被顶下去的效果是我们无法接受的。(尤其是在移动端真机测试上表现得更加明显)。
于是不得已之下必须还是得选择固定高度的方案,翻找了一下网上的建议,最后找到了一个比较快捷的方式如下,只需要设定好每个媒体资源的宽高比例,以及宽度,即可自动设定好高度。
根据padding-bottom
配置比例。
图片和视频资源都需要配置固定高度,以前一直以为视频是有高度的,但是在精确测试后发现视频未加载时候的高度和它加载后的高度不匹配。
把懒加载组件和中途查询函数的代码列如下方
图片固定高度组件
需注意:因为固定高度的span包裹在lazyload里面,所以它仍然会用户下滑到某个距离才显示出内部内容 以及 高度,但是span \ padding-bottom的加载速度极快,比媒体资源快很多,所以可以达到下滑时看到固定高度的效果。
但是要达到我上面的需求:锚点定位跳转,可能还是会有定位不准的情况,因此我采用两种方式相结合,也就是中途查询+固定高度。
import React, { useEffect } from 'react';
import LazyLoad from 'react-lazyload';
import ossImgCompress from '@/utils/ossImgCompress';
import styles from './index.module.less';/*** @param {string} className* @param {Array} ratio [长,宽]图片比例,设置比例后必须设定懒加载组件className或者outerStyle中的宽度。* @param {Object} outerStyle* @returns*/
const LazyLoadImg = ({ children, ...props }) => {let {src,offset = 400,ratio,className,coverClassName,outerStyle = {},style = { width: '100%' },onClick,webp,type = 'img',key,...restProps} = props;src = webp ? ossImgCompress(src, { webp }) : src;const hasRatio = Array.isArray(ratio) && type !== 'cover';return (<LazyLoad offset={offset} className={[styles.lazyimg, className].join(' ')} style={outerStyle}>{hasRatio && <span className={styles.ratioSpan} style={{ paddingBottom: `${(ratio[1] / ratio[0]) * 100}%` }} />}{type === 'img' && <img {...restProps} src={src} style={style} onClick={onClick} alt='' />}{type === 'cover' && (<div{...restProps}className={coverClassName ?? styles.cover}style={{ backgroundImage: `url(${src})`, ...style }}onClick={onClick}>{children}</div>)}</LazyLoad>);
};
export default LazyLoadImg;
// css.cover {width: 100%;height: 100%;background-size: cover;background-position: center;background-repeat: no-repeat;
}.lazyimg {position: relative;font-size: 0;line-height: 0;overflow: hidden;.ratioSpan {position: unset !important;display: inline-block;box-sizing: border-box;width: initial;height: initial;background: none;opacity: 0;border: 0px !important;margin: 0px !important;& + img {border-radius: inherit;position: absolute;inset: 0px;box-sizing: border-box;padding: 0px;border: none;margin: auto;display: block;width: 0px;height: 0px;min-width: 100%;max-width: 100%;min-height: 100%;max-height: 100%;}}
}
视频固定高度组件
视频的懒加载函数既是将data-src的内容放到src里,这个函数在其他文章《如何优化一个很多视频的网页》中给出了。
video的固定高度放在了lazyload组件上,所以高度会一直存在,基本不存在图片固定高度组件中 滑动一定距离才加载出内部元素 & 高度的情况。
import React from 'react';
import LazyLoad from 'react-lazyload';
import styles from './index.module.less';/*** 存在两种懒加载方案、可以自动设置高度的video组件* @param {Object} style video元素的style* @param {Object} outerStyle video元素父级组件的style* @param src 采用LazyLoad 懒加载组件加载* @param poster 采用LazyLoad 懒加载组件加载* @param data_src 不采用懒加载组件(否则获取不到video元素),配合VideoLazyLoad使用* @param data_poster 不采用懒加载组件,配合VideoLazyLoad使用* @param offset* @param {Array} ratio 视频宽高比例,设置后需要设定父级className的宽度* @param className* @param autoPlay* @param onClick* @param {object} videoProps* @returns*/
const LazyLoadVideo = ({ children, ...props }) => {let {src,poster,data_src,data_poster,offset = 400,ratio,className,autoPlay = true,onClick,videoProps,outerStyle = {},style = { width: '100%' },key,} = props;return data_src ? (<div key={key} className={[styles.lazyVideo1, className].join(' ')} style={outerStyle}><spanclassName={styles.ratioSpan}style={{ paddingBottom: Array.isArray(ratio) && `${(ratio[1] / ratio[0]) * 100}%` }}/><videodata-src={data_src}data-poster={data_poster || poster}poster={poster}src={src}style={style}disablePictureInPictureautoPlay={autoPlay}loopmutedplaysInlinecontrols={false}onClick={onClick}{...videoProps}/></div>) : (<LazyLoadkey={key}offset={offset}className={[styles.lazyVideo, className].join(' ')}style={{ ...outerStyle, paddingBottom: Array.isArray(ratio) ? `${(ratio[1] / ratio[0]) * 100}%` : 'auto' }}><videosrc={src}style={style}poster={poster}disablePictureInPictureautoPlay={autoPlay}loopmutedplaysInlinecontrols={false}onClick={onClick}{...videoProps}/></LazyLoad>);
};
export default LazyLoadVideo;
// css
.lazyVideo {position: relative;width: 100%;height: 0;overflow: hidden;display: inline-block;box-sizing: border-box;background: none;border: 0px;margin: 0px;font-size: 0;line-height: 0;video {object-fit: fill;position: absolute;inset: 0px;box-sizing: border-box;padding: 0px;border: none;margin: 0 auto;display: block;width: 100%;height: 100%;font-size: 0;line-height: 0;border-radius: inherit;}
}.lazyVideo1 {position: relative;font-size: 0;line-height: 0;.ratioSpan {width: 100%;inset: 0px;height: 0;overflow: hidden;display: inline-block;box-sizing: border-box;background: none;border: 0px;margin: 0px;font-size: 0;line-height: 0;}video {object-fit: fill;position: absolute;inset: 0px;box-sizing: border-box;padding: 0px;border: none;margin: 0 auto;display: block;width: 100%;height: 100%;border-radius: inherit;}
}
中途查询修改目标高度的函数
其实JQUERY似乎是有一个$().animation()函数已经直接实现了这个功能,但是因为我的项目没有用到,所以就只能自己实现一下了。
const targetRef = useRef(null);
const menuHeader = useRef(null);
const timer = useRef(null);
const max_call = 10;
let max_call_count = 0;
const [res, setRes] = useState([]);<button onClick={handleScrollToTarget}>跳转</button>const scrollToElement = async (lastScrollTop, lastWindowScrollY, lastElementTop) => {// 安卓手机端兼容性const windowScrollY = document.documentElement.scrollTop || document.body.scrollTop;const nowElementTop = targetRef.current.offsetTop;clearTimeout(timer.current);timer.current = null;const margin = isMobile ? (menuHeader.current ? menuHeader.current.clientHeight : 80) : 50;const target = nowElementTop - margin;const step1 = nowElementTop / 3;const step2 = nowElementTop * 0.75;let scrollTop = 0; // 记录本次指定的高度,避免反复赋值造成卡顿// 分阶段赋予高度,避免过快跳转导致中间有高度变化查询不到if (windowScrollY < step1 - 300) {scrollTop = step1;}if (windowScrollY >= step1 - 300 && windowScrollY < step2 - 300) {scrollTop = step2;}if (windowScrollY >= step2 - 300) {scrollTop = target;}if (isReachBottom(10)) {max_call_count = 0;return window.scrollTo(0, targetRef.current.offsetTop);}if (targetRef.current.getBoundingClientRect().top.toFixed(0) > margin) {// 判断当前高度 避免反复赋值造成卡顿if (windowScrollY >= lastScrollTop - 300 || nowElementTop.toFixed(0) !== lastElementTop.toFixed(0)) {window.scrollTo({top: scrollTop,left: 0,behavior: 'instant',});}// 每100ms更新一次if (max_call_count < max_call) {if (lastWindowScrollY === windowScrollY) max_call_count += 1;timer.current = setTimeout(() => {scrollToElement(scrollTop, windowScrollY, nowElementTop);}, 90);}}};// 避免懒加载一直加载导致屏幕滚动失败,将路程分为4段,每隔一段查询一次目标高度,直到滚动到目标位置const handleScrollToTarget = async () => {try {// 查询目标let firstScrollTop = 0;if (!targetRef.current) {const t = await querySelector('#target').then((ele) => {targetRef.current = ele;return ele;});if (!t) return;firstScrollTop = t.offsetTop;} else {firstScrollTop = targetRef.current.offsetTop;}// 查询documentElement & 错误捕获const documentElement =document.documentElement ||(await new Promise((resolve, reject) => {const interval = setInterval(() => {if (max_call_count < max_call) {if (!!document.documentElement) {max_call_count = 0;clearInterval(interval);resolve(document.documentElement);} else {max_call_count++;}} else {clearInterval(interval);max_call_count = 0;resolve(null);}}, 100);}));if (documentElement || document.documentElement) {window.scrollTo(0, firstScrollTop);scrollToElement(firstScrollTop / 2, 0, firstScrollTop);} else {throw Error('无法获取document.documentElement');}} catch (e) {console.error('滚动函数失败——', e);// 兜底函数,直接滚动}};/*** 页面触底判断* @param margin 触底函数判断范围*/
function isReachBottom(margin = 36) {// 窗口高度var windowHeight = document.documentElement.clientHeight || document.body.clientHeight;// 滚动高度var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;// 页面高度var documentHeight = document.documentElement.scrollHeight || document.body.scrollHeight;if (windowHeight + scrollTop + margin > documentHeight) {return true;} else {return false;}
}
相关文章:
为自己的项目媒体资源添加固定高度
为自己的项目媒体资源添加固定高度 未媒体资源添加固定高度,不仅有利于确定懒加载后的切确位置,还可以做骨架屏、loading动画等等,但是因为历史数据中很多没有加高度的媒体资源,所以一直嫌麻烦没有做。 直到这个季度有一个自上而…...

家政小程序系统源码开发:引领智能生活新篇章
随着科技的飞速发展,小程序作为一种便捷的应用形态,已经深入到我们生活的方方面面。尤其在家庭服务领域,家政小程序的出现为人们带来了前所未有的便利。它不仅简化了家政服务的流程,提升了服务质量,还为家政服务行业注…...
多表查询
目录 统计出一张数据表中的数据量 查询 dept 表中的数据量 查询 emp 表中的数据量 实现 emp 与 dept 的多表查询 笛卡尔积 消除笛卡尔积 把数据表 emp 的别名定为 e,数据表 dept 的别名定为 d,然后在查询中分别使用 e 和 d 代替这两个表 Oracle从…...

PHP开发日志 ━━ 深入理解三元操作与一般条件语句的不同
概况 三元运算符的功能与“if…else”流程语句一致。 在一般情况下,三元操作替换if条件语句可以精简代码,并且更为直观,但是在下面的情况中使用三元操作将会返回警告。 借图: 案例 比如原代码: class classA{publ…...

多维时序 | Matlab实现RF-Adaboost随机森林结合Adaboost多变量时间序列预测
多维时序 | Matlab实现RF-Adaboost随机森林结合Adaboost多变量时间序列预测 目录 多维时序 | Matlab实现RF-Adaboost随机森林结合Adaboost多变量时间序列预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 1.Matlab实现RF-Adaboost随机森林结合Adaboost多变量时间序列预…...

vue3-内置组件-Suspense
Suspense (实验性功能) <Suspense> 是一项实验性功能。它不一定会最终成为稳定功能,并且在稳定之前相关 API 也可能会发生变化。 <Suspense> 是一个内置组件,用来在组件树中协调对异步依赖的处理。它让我们可以在组件树上层等待下层的多个嵌…...

Rust入门:如何在windows + vscode中关闭程序codelldb.exe
在windows中用vscode单步调试rust程序的时候,发现无论是按下stop键,还是运行完程序,调试器codelldb.exe一直霸占着主程序不退出,如果此时对代码进行修改,后续就没法再编译调试了。 目前我也不知道要怎么处理这个事&am…...
git错误整理
remote: Support for password authentication was removed on August 13, 2021. 参考:这篇即可 GnuTLS recv error (-110): The TLS connection was non-properly terminated. 执行下面的指令: git config --global http.sslVerify false...

跟着cherno手搓游戏引擎【22】CameraController、Resize
前置: YOTO.h: #pragma once//用于YOTO APP#include "YOTO/Application.h" #include"YOTO/Layer.h" #include "YOTO/Log.h"#include"YOTO/Core/Timestep.h"#include"YOTO/Input.h" #include"YOTO/KeyCod…...

微信小程序(四十二)wechat-http拦截器
注释很详细,直接上代码 上一篇 新增内容: 1.wechat-http请求的封装 2.wechat-http请求的拦截器的用法演示 源码: utils/http.js import http from "wechat-http"//设置全局默认请求地址 http.baseURL "https://live-api.ith…...

tomcat部署zrlog
1.下载zrlog包,并添加到虚拟机中 1)进入/opt/apache-tomcat-8.5.90/webapps目录 cd /opt/apache-tomcat-8.5.90/webapps2)下载zrlog包 wget http://dl.zrlog.com/release/zrlog-1.7.1-baaecb9-release.war 3)重命名包 mv zrlog-1.7.1-baaecb9-release zrblog 2…...
Ubuntu Desktop 开机数字小键盘
Ubuntu Desktop 开机数字小键盘 1. 开机数字小键盘References 1. 开机数字小键盘 一般情况下,Ubuntu 开机后小键盘区是控制方向键而非数字键,每次开机后若用到数字键都需要按下 NumLock 键。 References [1] Yongqiang Cheng, https://yongqiang.blog…...

树莓派编程基础与硬件控制
1.编程语言 Python 是一种泛用型的编程语言,可以用于大量场景的程序开发中。根据基于谷歌搜 索指数的 PYPL(程序语言流行指数)统计,Python 是 2019 年 2 月全球范围内最为流行 的编程语言 相比传统的 C、Java 等编程语言&#x…...

autojs通过正则表达式获取带有数字的text内容
视频连接 视频连接 参考 参考 var ctextMatches(/\d/).findOne()console.log("当前金币"c.text()) // 获取当前金币UiSelector.textMatches(reg) reg {string} | {Regex} 要满足的正则表达式。 为当前选择器附加控件"text需要满足正则表达式reg"的条件。 …...
Android java基础_类的继承
一.Android Java基础_类的继承 先封装一个persion类,在persion的基础上定义Student类,并基础persion类。 子类能访问父类的成员函数。 class Person {private int age;public void setAge(int age) {if (age < 0 || age > 200)age 0;else {thi…...
nginx stream proxy 模块的ssl连接源码分析
目录 1. 源起2. 分析验证环境的配置3. 源码分析3.1 代理模块的请求入口点分析3.2 发起与上游服务器的连接3.3 连接回调3.4 TCP连接建立成功后为上下游数据透传做准备3.5 TCP连接的ssl上下文初始化3.6 ssl握手成功后的处理3.7 连接数据的收与发1. 源起 我一直来对ssl建立连接的过…...
C#面:Static Nested Class 和 Inner Class 有什么不同
这是两种不同的类嵌套方式。 Static Nested Class : 是一个静态嵌套类,它是在外部类中定义的一个静态类。它可以访问外部类的静态成员和方法,但不能直接访问外部类的非静态成员和方法。静态嵌套类可以独立于外部类实例化,即可以…...

LeetCode、208. 实现 Trie (前缀树)【中等,自定义数据结构】
文章目录 前言LeetCode、208. 实现 Trie (前缀树)【中等,自定义数据结构】题目链接与分类思路 资料获取 前言 博主介绍:✌目前全网粉丝2W,csdn博客专家、Java领域优质创作者,博客之星、阿里云平台优质作者、专注于Java后端技术领…...

java数据结构与算法刷题-----LeetCode151. 反转字符串中的单词
java数据结构与算法刷题目录(剑指Offer、LeetCode、ACM)-----主目录-----持续更新(进不去说明我没写完):https://blog.csdn.net/grd_java/article/details/123063846 解题思路 这道题,可以理解为,将字符串颠倒…...

《Java 简易速速上手小册》第8章:Java 性能优化(2024 最新版)
文章目录 8.1 性能评估工具 - 你的性能探测仪8.1.1 基础知识8.1.2 重点案例:使用 VisualVM 监控应用性能8.1.3 拓展案例 1:使用 JProfiler 分析内存泄漏8.1.4 拓展案例 2:使用 Gatling 进行 Web 应用压力测试 8.2 JVM 调优 - 魔法引擎的调校8…...

Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility
Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility 1. 实验室环境1.1 实验室环境1.2 小测试 2. The Endor System2.1 部署应用2.2 检查现有策略 3. Cilium 策略实体3.1 创建 allow-all 网络策略3.2 在 Hubble CLI 中验证网络策略源3.3 …...

DBAPI如何优雅的获取单条数据
API如何优雅的获取单条数据 案例一 对于查询类API,查询的是单条数据,比如根据主键ID查询用户信息,sql如下: select id, name, age from user where id #{id}API默认返回的数据格式是多条的,如下: {&qu…...

如何在最短时间内提升打ctf(web)的水平?
刚刚刷完2遍 bugku 的 web 题,前来答题。 每个人对刷题理解是不同,有的人是看了writeup就等于刷了,有的人是收藏了writeup就等于刷了,有的人是跟着writeup做了一遍就等于刷了,还有的人是独立思考做了一遍就等于刷了。…...

C++ Visual Studio 2017厂商给的源码没有.sln文件 易兆微芯片下载工具加开机动画下载。
1.先用Visual Studio 2017打开Yichip YC31xx loader.vcxproj,再用Visual Studio 2022打开。再保侟就有.sln文件了。 易兆微芯片下载工具加开机动画下载 ExtraDownloadFile1Info.\logo.bin|0|0|10D2000|0 MFC应用兼容CMD 在BOOL CYichipYC31xxloaderDlg::OnIni…...

什么是Ansible Jinja2
理解 Ansible Jinja2 模板 Ansible 是一款功能强大的开源自动化工具,可让您无缝地管理和配置系统。Ansible 的一大亮点是它使用 Jinja2 模板,允许您根据变量数据动态生成文件、配置设置和脚本。本文将向您介绍 Ansible 中的 Jinja2 模板,并通…...

SAP学习笔记 - 开发26 - 前端Fiori开发 OData V2 和 V4 的差异 (Deepseek整理)
上一章用到了V2 的概念,其实 Fiori当中还有 V4,咱们这一章来总结一下 V2 和 V4。 SAP学习笔记 - 开发25 - 前端Fiori开发 Remote OData Service(使用远端Odata服务),代理中间件(ui5-middleware-simpleproxy)-CSDN博客…...
重启Eureka集群中的节点,对已经注册的服务有什么影响
先看答案,如果正确地操作,重启Eureka集群中的节点,对已经注册的服务影响非常小,甚至可以做到无感知。 但如果操作不当,可能会引发短暂的服务发现问题。 下面我们从Eureka的核心工作原理来详细分析这个问题。 Eureka的…...

2025季度云服务器排行榜
在全球云服务器市场,各厂商的排名和地位并非一成不变,而是由其独特的优势、战略布局和市场适应性共同决定的。以下是根据2025年市场趋势,对主要云服务器厂商在排行榜中占据重要位置的原因和优势进行深度分析: 一、全球“三巨头”…...
iOS性能调优实战:借助克魔(KeyMob)与常用工具深度洞察App瓶颈
在日常iOS开发过程中,性能问题往往是最令人头疼的一类Bug。尤其是在App上线前的压测阶段或是处理用户反馈的高发期,开发者往往需要面对卡顿、崩溃、能耗异常、日志混乱等一系列问题。这些问题表面上看似偶发,但背后往往隐藏着系统资源调度不当…...

uniapp 开发ios, xcode 提交app store connect 和 testflight内测
uniapp 中配置 配置manifest 文档:manifest.json 应用配置 | uni-app官网 hbuilderx中本地打包 下载IOS最新SDK 开发环境 | uni小程序SDK hbulderx 版本号:4.66 对应的sdk版本 4.66 两者必须一致 本地打包的资源导入到SDK 导入资源 | uni小程序SDK …...