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;
 
                    
                 
 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号