前端中项目优化方案

871 阅读2分钟

前言: 在开发中如果遇到加载慢的问题,经常需要对项目进行优化. 常见的优化方案有资源加载优化和页面渲染优化. 这篇文章终点记录下图片懒加载 和 数据懒加载 方面的优化原理及实现方案

图片懒加载原理

1. 开始时, 不设置src属性
2. 当图片**可见**时, 设置src, 去加载图片

如何判断元素是可见?

之前: scrollTop, offsetTop, height...计算

现在: 浏览器有一个API, intersectionObserver 可以监听元素是否可见,

开发中: 有vueuse中的useIntersectionObserver这个api.

实现代码

  这里是在一个单独的文件中自定义了一个全局的指令v-lazy,
  后面要使用就直接在main.ts中引入这个文件  
  然后app.use(XXX) 注册成全局插件; 
  在要用的图片上不设置src属性;设置v-lazy="图片地址"
  

image.png

    import { useIntersectionObserver } from '@vueuse/core'
    import { App } from 'vue'
    import defaultImg from '@/assets/images/200.png'
    
    export default {
      install(app: App) {
        // 全局指令
        app.directive('lazy', {
          // mounted是v3中自定义指令的生命周期, 它会自动被调用
          // 它表示的含义和组件mounted是一致的
          // el是dom元素, binding
          mounted(el, binding) {
            // 设置默认图片
            el.src = defaultImg
            console.log('lazy', el, binding.value)
            // 实时监听el是否可见, 如果可见, 给它设置binding.value
            const { stop } =  useIntersectionObserver(el, ([{isIntersecting}]) => {
              if (isIntersecting) {
                el.src = binding.value
                // 停止
                stop()
                el.onerror = () => {
                  el.src = defaultImg
                }
              }
            })
          }
        })
      }
    }

数据懒加载

场景: 主页上有喝多模块, 每个模块都发ajax拿数据,并且是在组件创建时发的请求. 这样就有一个后果, 靠近底层的模块其实用户都看不到,这个请求发送就有点浪费了
思路: 判断当前模块是否可见, 可见就发请求
做法: 封装一个自定义的hooks,接收一个回调, 返回ref.这个ref可以用在模块外层的dom上: 当这个ref引用的dom可见时,就执行回调(发请求)
实操: 借用vueuse, useIntersectionObserver去封装.

代码实现, 单独封装一个方法, 然后在要用的地方直接引入这个方法, 传一个回调函数

image.png

    
import { useIntersectionObserver } from '@vueuse/core';
import { onMounted, ref } from 'vue';
// 接收一个回调, 返回一个ref引用
// 功能: 当ref引用的dom处于可见状态是, 调用一次回调函数

export function useLazyData( fn: () => void ) {
  const target = ref(null)
  // 当整个组件处于可见状态时才发ajax
  onMounted(() => {
    const { stop } = useIntersectionObserver(target.value, ([{ isIntersecting }]) => {
      // 可见
      if (isIntersecting) {
      // 发请求
        fn()
      // 停止监听
      stop()
      }
    })
  })
  return target
}