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