• Vue3如何优雅的加载大量图片?


     前端面试题库 (面试必备)            推荐:★★★★★

    地址:前端面试题库

     表妹一键制作自己的五星红旗国庆头像,超好看

    最近开发了一个功能,页面首页会加载大量的图片,初次进入页面时,会导致页面性能下降,

    于是乎,我改进了这个功能,可以让所有图片自动懒加载

    🚀 原理

    这个功能主要的底层逻辑是是使用IntersectionObserver APIIntersectionObserver用于在浏览器中观察元素的可见性和位置变化。它可以帮助开发者实现一些动态行为,如图片的懒加载、无限滚动等。

    简单的示例如下:

    1. // 创建IntersectionObserver实例
    2. const observer = new IntersectionObserver((entries, observer) => {
    3. // 遍历观察的元素
    4. entries.forEach(entry => {
    5. // 如果元素可见
    6. if (entry.isIntersecting) {
    7. // 加载图片
    8. const img = entry.target;
    9. const src = img.getAttribute('data-src');
    10. img.setAttribute('src', src);
    11. // 停止观察该元素
    12. observer.unobserve(img);
    13. }
    14. });
    15. });
    16. // 获取所有需要懒加载的图片元素
    17. const lazyImages = document.querySelectorAll('.lazy-image');
    18. // 观察每个图片元素
    19. lazyImages.forEach(image => {
    20. observer.observe(image);
    21. });

    🚀 实践

    接下来我们实现一个通用的 hook,基本的功能如下:

    1. 给图片提供默认的占位图片 src,同时提供data-src属性
    2. 传入图片对应的 ref 属性。
    3. 当图片进入可视区域时,使用data-src属性替换 src 属性
    1. import { onMounted, Ref } from "vue";
    2. const options = {
    3. // root: document.querySelector(".container"), // 根元素,默认为视口
    4. rootMargin: "0px", // 根元素的边距
    5. threshold: 0.5, // 可见性比例阈值
    6. once: true,
    7. };
    8. function callback(
    9. entries: IntersectionObserverEntry[],
    10. observer: IntersectionObserver
    11. ) {
    12. entries.forEach((entry) => {
    13. // 处理每个目标元素的可见性变化
    14. if (entry.intersectionRatio <= 0) return;
    15. const img: Element = entry.target;
    16. const src = img.getAttribute("data-src");
    17. img.setAttribute("src", src ?? ""); // 将真实的图片地址赋给 src 属性
    18. observer.unobserve(img);
    19. });
    20. }
    21. export const useInView = (ref: Ref) => {
    22. const observer = new IntersectionObserver(callback, options);
    23. onMounted(() => {
    24. Object.keys(ref.value).forEach((e) => observer.observe(ref.value[e]));
    25. });
    26. };
    1. <template>
    2. <h4>公众号:萌萌哒草头将军h4>
    3. <div
    4. v-for="(_, idx) in new Array(200).fill(11)"
    5. >
    6. <img
    7. ref="imgRef"
    8. src="https://via.placeholder.com/200"
    9. :data-src="`https://picsum.photos/200/${180 + idx}`"
    10. alt="b"
    11. />
    12. div>
    13. template>

    实际效果如下

    虽然基本的功能要求已经完成了,但是现在还不够优雅!!!

    🚀 优化

    接下来,我们增加个过渡动画。每次当加载完图片,就从占位图过渡到正常图片模式。

    1. img.onload = () => {
    2. img.setAttribute('class', 'fade-in')
    3. }
    1. @keyframes fadeIn {
    2. from {
    3. opacity: 0;
    4. }
    5. to {
    6. opacity: 1;
    7. }
    8. }
    9. /* 应用淡入动画到元素 */
    10. .fade-in {
    11. animation: fadeIn 0.6s ease-in;
    12. }

     

    完整代码如下:

    1. import { onMounted, Ref } from "vue";
    2. const options = {
    3. // root: document.querySelector(".container"), // 根元素,默认为视口
    4. rootMargin: "0px", // 根元素的边距
    5. threshold: 0.5, // 可见性比例阈值
    6. once: true,
    7. };
    8. function callback(
    9. entries: IntersectionObserverEntry[],
    10. observer: IntersectionObserver
    11. ) {
    12. entries.forEach((entry) => {
    13. if (entry.intersectionRatio <= 0) return;
    14. const img = entry.target as HTMLImageElement;
    15. const src = img.getAttribute("data-src");
    16. img.setAttribute("src", src ?? ""); // 将真实的图片地址赋给 src 属性
    17. img.onload = () => {
    18. img.setAttribute("class", "fade-in");
    19. };
    20. observer.unobserve(img);
    21. });
    22. }
    23. export const useInView = (ref: Ref) => {
    24. const observer = new IntersectionObserver(
    25. callback,
    26. options
    27. );
    28. onMounted(() => {
    29. Object.keys(ref.value)
    30. .forEach((e) => observer.observe(ref.value[e]));
    31. });
    32. };
    1. <template>
    2. <h4>公众号:萌萌哒草头将军h4>
    3. <div
    4. v-for="(_, idx) in new Array(200).fill(11)"
    5. style="width: 200px height: 200px;"
    6. >
    7. <img
    8. ref="imgRef"
    9. style="height: 100%"
    10. src="https://via.placeholder.com/200"
    11. :data-src="`https://picsum.photos/200/${180 + idx}`"
    12. alt="b"
    13. />
    14. div>
    15. template>
    16. <style scoped>
    17. /* 定义淡入动画 */
    18. @keyframes fadeIn {
    19. from {
    20. opacity: 0;
    21. }
    22. to {
    23. opacity: 1;
    24. }
    25. }
    26. /* 应用淡入动画到元素 */
    27. .fade-in {
    28. animation: fadeIn 0.6s ease-in;
    29. }
    30. style>

     前端面试题库 (面试必备)            推荐:★★★★★

    地址:前端面试题库

     表妹一键制作自己的五星红旗国庆头像,超好看

  • 相关阅读:
    flink数据类型和序列化-1.13
    洛谷P1939 矩阵快速幂模板
    一文2000字手把手教你基于Python的UI自动化测试自学路线
    PowerQuery领域的经典之作“猴子书“中文版来啦!
    学习进度——附《全国青少年信息学奥林匹克系列竞赛大纲》
    基于SSM的鲜花商城系统【附源码文档】
    高并发和大数据下的高级算法与数据结构:如何快速获取给定年龄区间的微信用户数量或快速获取美团中购买量前k的品类
    京东小程序数据中心架构设计与最佳实践
    一文搞懂基于透视变换的车道线拟合
    【个人博客系统 × Redis】“最后的升级” · 连接Redis · Redis的基本使用
  • 原文地址:https://blog.csdn.net/weixin_42981560/article/details/133176189