用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;