图片懒加载

306 阅读2分钟

准备工作:

  • 了解各个高度的猫腻
    • window对象 innerWidth、innerHeight、pageXOffset、pageYOffset、scrollX、scrollY
    • window.screen
    • document对象 document.documentElement/body.clientHeight、clientWidth
    • HTMLElement的 offsetTop、offsetLeft、offsetHeight、offsetWidth
    • document.scrollingElement
  • 滚动监听

window.pageYOffset == window.scrollY

在标准模式下, 这是文档的根元素, document.documentElement。 当在怪异模式下, scrollingElement 属性返回 HTML body 元素(若不存在返回 null )。

window尺寸

ex. 说明 兼容
window.innerHeight[innerWidth] 浏览器窗口的内部高度(包括滚动条),可见高度 Internet Explorer、Chrome、Firefox、Opera 以及 Safari
window.pageYOffset[X] 是 window.scrollY[X] 的别名 文档从顶部开始滚动过的像素值 为了跨浏览器兼容,请使用 window.pageYOffset 代替 window.scrollY。另外,旧版本IE(<9)两个属性都不支持
document.documentElement.clientHeight[clientWidth] document.documentElement为当前文档的直接子节点,可见高度 Internet Explorer 8、7、6、5
document.body.clientHeight[clientWidth] 当前文档的 <body><frameset> 节点,可见高度 Internet Explorer 8、7、6、5
HTMLElement.offsetHeight[offsetWidth] 返回该元素的像素高度,高度包含该元素的垂直内边距、边框和元素的水平滚动条(如果存在且渲染的话),不包含:before或:after等伪类元素的高度,且是一个整数。如果被隐藏,display:none,则返回0
HTMLElement.offsetLeft[offsetTop] 它返回当前元素相对于其 offsetParent 元素的顶部内边距的距离

完整兼容性代码

窗口内可见高度

let w = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
let h = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;

文档从顶部[左侧边]开始滚动过的像素值

let supportPageOffset = window.pageXOffset !== undefined;
let isCSS1Compat = ((document.compatMode || "") === "CSS1Compat");

let x = supportPageOffset ? window.pageXOffset : isCSS1Compat ? document.documentElement.scrollLeft : document.body.scrollLeft;
let y = supportPageOffset ? window.pageYOffset : isCSS1Compat ? document.documentElement.scrollTop : document.body.scrollTop;

图片懒加载

实现图片懒加载的React组件

支持单张图片懒加载,需要固定宽高的占位,没有加节流

/**
 * loadImage: 占位图片
 * imageSrc: 实际图片地址
 * height: 确定图片高度
 */
import React, { Component } from 'react'
import tempImage from './icon-loading.gif'
import styles from './style.less'

class lazyloadImage extends Component {
  constructor(props) {
    super(props)
    this.state = {
      showImage: false,
    }
  }

// 一定要有占位图片,有一个占位高度
  render() {
    const imageSrc = this.state.showImage ? this.props.imageSrc : this.props.loadImage
    return (
      <div className={styles.imageBox} ref="image" style={{ height: this.props.height }}>
        <img src={imageSrc} alt="" />
      </div>
    )
  }

  componentDidMount() {
    <!-- 首屏加载,在没有滚动的情况下保证首屏的加载 -->
    this.scrollEvent()
    <!--添加滚动监听,需要的话,可以自己加节流-->
    window.addEventListener('scroll', this.scrollEvent, false)
  }

  scrollEvent = () => {
    const el = this.refs.image
    
    <!--文档从顶部开始滚动过的像素值-->
    const viewTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop
    <!--视口可见高度-->
    const viewHeight = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight
    <!--当前元素相对于其 offsetParent 元素的顶部内边距的距离-->
    const elTop = el.offsetTop
    <!--当前组件中div的占位高度-->
    const elHeight = el.offsetHeight  
    
    if (elTop + elHeight >= viewTop && elTop + elHeight <= viewHeight + viewTop) {
      this.loadImage()
    }
  }

  loadImage = () => {
    this.setState({ showImage: true })
    window.removeEventListener('scroll', this.scrollEvent)
  }
}

lazyloadImage.defaultProps = {
  loadImage: tempImage,
  imageSrc: '',
  height: 400,
}

export default lazyloadImage

学习向大佬源码致敬 react-lazyload