代码
import React from 'react';
import './Home.css';
class Home extends React.Component {
constructor(props) {
super(props);
this.state = {
imgList: [],
imgArr: [
require('../assets/images/100x70.png'),
require('../assets/images/100x80.png'),
require('../assets/images/100x90.png'),
require('../assets/images/100x100.png'),
require('../assets/images/100x120.png'),
require('../assets/images/100x150.png'),
require('../assets/images/100x210.png'),
require('../assets/images/100x230.png'),
require('../assets/images/100x250.png'),
],
waterfallImgList: [],
waterfallImgWidth: 100,
waterfallImgRight: 10,
waterfallImgBottom: 10,
waterfallImgCol: null,
waterfallDeviationHeight: [],
time: null,
}
this.resize.bind(this);
}
componentDidMount() {
for(let i = 0; i < 100; i ++) {
this.state.imgList.push(this.state.imgArr[Math.round(Math.random() * 8)]);
}
this.calculateWidth();
this.screenChange();
}
componentWillUnmount() {
window.removeEventListener('resize', this.resize);
}
resize() {
if (this.state.time) {
return;
}
const time = setTimeout(() => {
clearTimeout(this.state.time);
this.setState({
waterfallImgCol: null,
waterfallImgList: [],
time: null,
})
this.calculateWidth();
}, 300);
this.setState({ time });
}
screenChange() {
window.addEventListener('resize', () => {
this.resize();
});
}
calculateWidth() {
const domWidth = document.getElementById('waterfall').offsetWidth;
const col = parseInt(domWidth / (this.state.waterfallImgWidth + this.state.waterfallImgRight));
this.setState({ waterfallImgCol: col });
const heightList = new Array(col);
for(let i = 0; i < col; i ++) {
heightList[i] = 0;
}
this.setState({ waterfallDeviationHeight: heightList });
this.imgPreloading();
}
imgPreloading() {
for(let i = 0; i < this.state.imgList.length; i ++) {
const img = new Image();
img.src = this.state.imgList[i];
img.onload = img.onerror = () => {
const imgData = {};
imgData.height = (this.state.waterfallImgWidth / img.width) * img.height;
imgData.src = this.state.imgList[i];
this.state.waterfallImgList.push(imgData);
this.rankImg(imgData);
}
}
}
rankImg(imgData) {
const { waterfallImgWidth, waterfallImgRight, waterfallImgBottom, waterfallDeviationHeight } = this.state;
const minIndex = this.filterMin();
imgData.top = waterfallDeviationHeight[minIndex];
imgData.left = minIndex * (waterfallImgWidth + waterfallImgRight);
let heightList = waterfallDeviationHeight;
heightList[minIndex] += imgData.height + waterfallImgBottom;
this.setState({ waterfallDeviationHeight: heightList, waterfallImgList: this.state.waterfallImgList });
}
filterMin() {
const { waterfallDeviationHeight } = this.state;
const min = Math.min.apply(null, [...waterfallDeviationHeight]);
return this.state.waterfallDeviationHeight.indexOf(min);
}
render() {
return <div className="waterfall" id="waterfall">
{ this.state.waterfallImgList.map((img, index) => {
const {top, left, height} = img;
const {waterfallImgWidth} = this.state;
return <div className="waterfall-item" key={index} style={{ width: `${waterfallImgWidth}px`, height: height, top: `${top}px`, left: `${left}px` }}>
<img src={img.src} alt=""/>
</div>
})}
</div>
}
}
export default Home;
效果
思路
1.根据窗口宽度,计算列数n;waterfallDeviationHeight.length = n; waterfallDeviationHeight 记录每一列的当前高度
2.根据加载的图片原始宽高比以及预先设定的宽度计算图片高度;
3.遍历所有图片,waterfallDeviationHeight;更新当前列高(原始列高 + 当前图片高度)。
文档只做个人学习用,部分思路有参考其他博主的文章,勿喷。