react lazy load圖片的懶加載的實現

用reactjs實現一個product 列表的懶加載 效果javascript

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

以下圖:java

product主要監聽頁面的scroll  和 resize 的變化獲取 當前頁面的top 位子和 bottom 位置而後向下傳遞react

代碼以下this

監聽
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  component

相關判斷以下blog

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 標示圖片是否在顯示的區域ip

state.showImage  標示 圖片是否load 完成jsx

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;
相關文章
相關標籤/搜索