一篇文章搞定滚动加载、图片懒加载原理并代码实现

一篇文章搞定滚动加载、图片懒加载原理并代码实现

「前言」

列表滚动加载、图片懒加载,这些都是目前流行的技术方案。本文从原理到代码实现,完整记录整个思考过程。


「知识准备」

  • 可视区
    • clientWidth、clientHeight 网页可视区宽高
    • offsetWidth、offsetHeight 网页可视区宽高(包括边线的宽)
  • 实际内容
    • scrollWidth、scrollHeight 网页正文全文宽高
  • 滚动条距离
    • scrollTop、scrollLeft
  • DOM 距离屏幕
    • screenTop、screenLeft

「滚动加载」

首先确定触发加载数据的时机:列表滚动至触底。那么判断列表触底的条件是什么呢? 可视区高度 + 滚动距离 >= 内容实际高度

列表无限加载
React代码

import React, { Component } from 'react';
import './index.css';

export default class Scroll extends Component {
  constructor(props) {
    super(props);
    this.state = {
      list: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
    };
    this.ref = React.createRef();
  }

  componentDidMount() {
    this.ref.current.addEventListener('scroll', this.scrollEvent);
  }

  scrollEvent = (e) => {
  	//可视区高度
    let scrollHeight = e.target.scrollHeight;
    //滚动高度
    let scrollTop = e.target.scrollTop;
    //列表内容实际高度
    let offsetHeight = e.target.offsetHeight;
    if (offsetHeight + scrollTop >= scrollHeight) {
      console.log('列表触底');
    }
  };

  render() {
    const { list } = this.state;
    return (
      <div ref={this.ref} className="scroll">
        {list.map((item, index) => {
          return (
            <div key={index} className="scroll-item">
              「{index}」
            </div>
          );
        })}
      </div>
    );
  }
}

在列表触底的时候请求接口,无限滚动加载便实现了。

 scrollEvent = async (e) => {
    let scrollHeight = e.target.scrollHeight;
    let scrollTop = e.target.scrollTop;
    let offsetHeight = e.target.offsetHeight;
    if (offsetHeight + scrollTop >= scrollHeight) {
      console.log('列表触底,触发接口请求数据');
      this.setState({ loading: true });
      let result = await this.loadData();
      this.setState({
        loading: false,
        list: this.state.list.concat(result),
      });
    }
  };
	//模拟数据请求,数据处理时间 1s
  loadData = () => {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve([1, 1, 1, 1, 1]);
      }, 1000);
    });
  };


「图片懒加载」

图片资源一般都比较大,页面中引入大量图片,加载页面时会占用大量的宽带资源。

「图片懒加载原理」 大量的图片第一时间并未进入可视区,未进入可视区的图片可以先不加载源图片,只有当图片进入可视区,再将图片标签 src 设置成真正的源图片 url 地址。

判断 「图片进入可视区」 的条件:每张图片具体顶部的距离 < 可视区高度 + 滚动距离

「关键操作」 当判断图片进入可视区时,将图片的 data-src 属性赋给图片的 src,即可完成图片的加载。

import React, { Component } from 'react';
import './index.css';

export default class Scroll extends Component {
  constructor(props) {
    super(props);
    this.state = {
      list: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
    };
    this.ref = React.createRef();
  }

  componentDidMount() {
  	//获取所有的图片元素
    const images = document.getElementsByTagName('img');
    this.ref.current.addEventListener(
      'scroll',
      this.scrollEvent.bind(null, images),
    );
    //初始化加载图片
    this.scrollEvent(images);
  }

  scrollEvent = (images) => {
    // 可视区
    let clientHeight = this.ref.current.clientHeight;
    // 滚动距离
    let scrollTop = this.ref.current.scrollTop;
    for (let image of images) {
      //图片距离顶部距离
      let top = image.offsetTop;
      if (top < clientHeight + scrollTop) {
      	// 设置图片源地址,完成目标图片加载
        image.src = image.dataset.src;
      }
    }
  };

  render() {
    const { list } = this.state;
    return (
      <div ref={this.ref} className="scroll">
        {list.map((item, index) => {
          return (
            <div key={index} className="scroll-item">
              <img
                style={{ width: '100%', height: '100%' }}
                src="http://s4.sinaimg.cn/mw690/006uWPTUgy72CNFYNjB93&690"
                data-src="https://blog.levenx.com/levenxBlog/8ec4f4a0b502443b8f2ae620a5cd30cf.jpg"
              />
            </div>
          );
        })}
      </div>
    );
  }
}

效果图
图片懒加载

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

乐闻x

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值