环保主题静态网站,php 手机网站源码,凡科网站建设注册,营销型网站单页面为自己的项目媒体资源添加固定高度
未媒体资源添加固定高度#xff0c;不仅有利于确定懒加载后的切确位置#xff0c;还可以做骨架屏、loading动画等等#xff0c;但是因为历史数据中很多没有加高度的媒体资源#xff0c;所以一直嫌麻烦没有做。
直到这个季度有一个自上而…为自己的项目媒体资源添加固定高度
未媒体资源添加固定高度不仅有利于确定懒加载后的切确位置还可以做骨架屏、loading动画等等但是因为历史数据中很多没有加高度的媒体资源所以一直嫌麻烦没有做。
直到这个季度有一个自上而下不可抗力的push。一个需求需要在懒加载的情况下跳转到底部的一个坐标。
一开始我们拟定的方案是中途查询边查询边修改目标高度但是这样做无法避免有些很大的图片加载慢的情况跳转到正确位置后整整12秒才加载出来这时候我们已经跳转到目标地在那里正常浏览了页面突然被顶下去的效果是我们无法接受的。尤其是在移动端真机测试上表现得更加明显。
于是不得已之下必须还是得选择固定高度的方案翻找了一下网上的建议最后找到了一个比较快捷的方式如下只需要设定好每个媒体资源的宽高比例以及宽度即可自动设定好高度。 根据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}跳转/buttonconst 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;}
}