react lazy load图片的懒加载的实现

用reactjs实现一个product 列表的懒加载 效果

主要文件有 product文件包含[index.jsx,style.jsx]productItem文件包含[index.jsx,style.jsx]productImage文件包含[index.jsx,style.jsx]

如下图:

product主要监听页面的scroll  和 resize 的变化获取 当前页面的top 位子和 bottom 位置然后向下传递

代码如下

监听
window.addEventListener('scroll', this.updateViewport, false);
window.addEventListener('resize', this.updateViewport, false); 
获取
updateViewport() {
this.setState({
viewport : {
viewTop: window.pageYOffset,
viewBottom: window.innerHeight + window.pageYOffset
}
})
}

product index.jsx 整体代码如下
import React,{Component} from 'react'
import ProductItem from './ProductItem'

import './style.css'
class Product extends Component {

    constructor(props) {
        super(props)
        this.updateViewport = this.updateViewport.bind(this)
    }
    render() {
        const items = [
            { title: ' 图片1', image: 'imageSrc1' },
            { title: '图片 2', image: 'imageSrc1' },
            { title: '图片 3', image: 'imageSrc1' },
            { title: '图片 4', image: 'imageSrc1' },
            { title: '图片 5', image: 'imageSrc1' },
            { title: '图片 6', image: 'imageSrc1' },
            { title: '图片 7', image: 'imageSrc1' },
            { title: '图片 8', image: 'imageSrc1' },
            { title: '图片 9', image: 'imageSrc1' },
            { title: '图片 10', image: 'imageSrc1' }
        ];
        return (

            <div>
                <h2>延迟加载</h2>
                <ul>
                    {
                        items.map((item,index) => {
                            return (
                                <ProductItem key={index}
                                             title={item.title}
                                             image={item.image}
                                             viewport={this.state.viewport}
                                />
                            )
                        })
                    }
                </ul>
            </div>

        )
    }
    updateViewport() {
        this.setState({
            viewport : {
                viewTop: window.pageYOffset,
                viewBottom: window.innerHeight + window.pageYOffset
            }
        })
    }

    componentWillMount() {

        window.addEventListener('scroll', this.updateViewport, false);
        window.addEventListener('resize', this.updateViewport, false);
        this.updateViewport();
    }
    componentDidMount() {

        this.updateViewport();
    }
    componentWillUnmount() {
        window.removeEventListener('scroll', this.updateViewport);
        window.removeEventListener('resize', this.updateViewport);
    }

}

export default Product;

 productItem 主要判断改图片是否在页面 显示区域 用state.showImage 标示向下传递给 productImage  

相关判断如下

updateImagePosition(top,height) {
if(this.state.image) {
return;
}
const {viewTop,viewBottom} = this.props.viewport;
const imageScope = top + height;

if(imageScope >= viewTop && imageScope <= viewBottom) {
this.setShowImage(true)
}
}
ProductItem 整体代码如下:
import React,{Component} from 'react'
import ProductImage from '../ProductImage'

import './style.css'
class ProductItem extends Component {
    constructor(props) {
        super(props)
        this.updateImagePosition = this.updateImagePosition.bind(this)
        this.setShowImage = this.setShowImage.bind(this)
        this.state = {
            viewport: {
                showImage: false
            }
        }
    }
    render() {
        return (
            <li>
                <div>
                    <h4>{this.props.title}</h4>
                    <ProductImage
                        showImage={this.state.showImage}
                        imageSrc={this.props.image}
                        viewport={this.props.viewport}
                        updateImagePosition={this.updateImagePosition}
                    />
                </div>
            </li>
        )
    }
    updateImagePosition(top,height) {
        if(this.state.image) {
            return;
        }
        const {viewTop,viewBottom} = this.props.viewport;
        const imageScope = top + height;

        if(imageScope >= viewTop && imageScope <= viewBottom) {
            this.setShowImage(true)
        }
    }
    setShowImage(flag) {
        this.setState({
            showImage: !!flag
        })
    }
    componentWillMount() {
        if(this.props.showImage) {
            this.setShowImage(true)
        }
    }
}

ProductItem.defauleProps = {
    title: '',
    image: '',
    showImage: false
}

export default ProductItem

 ProductImage 主要用于load 显示的图片 以及图片的现实

props.showImage 标示图片是否在显示的区域

state.showImage  标示 图片是否load 完成

props.laodimge 默认的加载图片

具体代码如下

import React,{Component} from 'react'

import './style.css'
class ProductImage extends Component {
    constructor(props) {
       super(props)
        this.state = {
           showImage:false
        }
    }
    render() {
        const imageSrc = this.props.showImage && this.state.showImage ? this.props.imageSrc : this.props.loadImage;
        return (
            <div className="product-image" ref="image">
                <img src={imageSrc} />
            </div>
        )
    }
    updatePosition() {
        const el = this.refs.image;
        this.props.updateImagePosition(el.offsetTop,el.offsetHeight)
    }
    componentDidUpdate(prevProps) {
        if(!this.props.showImage && prevProps.viewport) {
            this.updatePosition()
        }else {
          if(!this.state.showImage) this.loadImage();
        }
    }
    loadImage() {
        const img = new Image()
        img.onload = () => {
            this.setState({showImage: true})
        }
        img.src = this.props.imageSrc
    }

}

ProductImage.defaultProps = {
    showImage: false,
    loadImage: 'load.gif'
}

export default ProductImage;

 

 
 


转载于:https://www.cnblogs.com/careyyibu/p/8695205.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值