用IntersectionObserver实现图片懒加载

懒加载的基本思路

当dom元素进入可视区域时,才去加载它

利用浏览器提供的 IntersectionObserver,监听图片元素是否进入可视区域,进入后才真正去设置图片元素的 src 属性进行图片加载

格式:

var dom = dom元素
// 实例化一个观察者
// 它的参数1是一个回调:当被观察的目标进入视口/离开视口就会调用
var observer = new IntersectionObserver((entries)=>{
  console.log(entries[0].isIntersecting)
  console.log(entries[0].intersectionRatio)
  if(entries[0].isIntersecting) {
    
  }
}, 其他配置)

// 观察者观察dom
observer.observe(dom)
observer.disconnect()   // 停止观察者
observer.unobserve(dom) // 观察者停止对dom的观察

回调里有一个参数 entries, entries里有 isIntersecting这么一个属性,他一个布尔值 false表示还没有在可视范围内,未加载,反之true表示在可视范围内已加载
用IntersectionObserver实现图片懒加载_第1张图片

  <div style='height:100px'>123123</div>
  <div style='height:100px'>123123</div>
  <div style='height:100px'>123123</div>
  <div style='height:100px'>123123</div>
  <div style='height:100px'>123123</div>
  <div style='height:100px'>123123</div>
  <div style='height:100px'>123123</div>
  <div style='height:100px'>123123</div>
  <div style='height:100px'>123123</div>
  <div style='height:100px'>123123</div>
  <div style='height:100px'>123123</div>
  <div style='height:100px'>123123</div>
  <div style='height:100px'>123123</div>
  <button style='height:100px'> 123</button>
  <div style='height:100px'>123123</div>
  <script>
    var btn = document.querySelector('button')
    var io = new IntersectionObserver((entries)=>{
      console.log(entries);
      console.log('按钮要加载了....');
      if(entries[0].isIntersecting){
        console.log('资源已在可视范围内....加载资源');
        //清除监听
        io.disconnect()
        // io.unobserve()
      }
    } ,{rootMargin: "100px"})//距离资源100px的时候加载
    io.observe(btn)
  
  </script>

用IntersectionObserver实现图片懒加载_第2张图片
进而封装一个Image懒加载组件 传入url 和className

import classnames from 'classnames'
import { useEffect, useRef, useState } from 'react'
import Icon from '../Icon'
import styles from './index.module.scss'

/**
 * 拥有懒加载特性的图片组件
 * @param {String} props.src 图片地址
 * @param {String} props.className 样式类
 */
type Porps = {
  src: string
  className?: string
}
const Image = ({ src, className }: Porps) => {
  // 记录图片加载是否出错的状态
  const [isError, setIsError] = useState(false)

  // 记录图片是否正在加载的状态
  const [isLoading, setIsLoading] = useState(true)

  // 对图片元素的引用
  const imgRef = useRef<HTMLImageElement>(null)
  // 图片懒加载的副作用
  useEffect(() => {
    const ib = new IntersectionObserver((entries) => {
      console.log('entries', entries)
      // isIntersecting
      if (entries[0].isIntersecting) {
        imgRef.current!.src = imgRef.current!.getAttribute('data-src')!
        ib.disconnect()
      }
    })
    ib.observe(imgRef.current!)
    return () => {
      ib.disconnect()
    }
  }, [])

  return (
    <div className={classnames(styles.root, className)}>
      {/* 正在加载时显示的内容 */}
      {isLoading && (
        <div className="image-icon">
          <Icon type="iconphoto" />
        </div>
      )}

      {/* 加载出错时显示的内容 */}
      {isError && (
        <div className="image-icon">
          <Icon type="iconphoto-fail" />
        </div>
      )}

      {/* 加载成功时显示的内容 */}
      {!isError && (
        <img
          alt=""
          data-src={src}
          ref={imgRef}
          // 图片加载完成事件
          onLoad={() => setIsLoading(false)}
          // 图片加载失败事件
          onError={() => setIsError(true)}
        />
      )}
    </div>
  )
}

export default Image

你可能感兴趣的:(前端,javascript,vue.js)