瀑布流页面设计最初我是在“花瓣”这个产品上看到的,最近一个电商网站也运用了这一设计方式,可能会显得产品更有特色吧。今天我们就讨论下怎么实现一个图片的瀑布流。
通常数据以分页的形式从后端获取,前端加载图片,一行显示两个图片,图片高度要按比例显示。如果左侧图片高就把下一张图片放到右侧,相反如果右侧图片高,就把下一张图片放到左侧,这样可以保持整个页面的布局和谐。同时,在页面滚动到距下方50px时触发滚动加载下一页数据。
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>瀑布流title>
<style>
html, body{
margin: 0;
padding: 0;
width: 100%;
}
ul{
margin: 0;
padding: 0;
list-style: none;
float: left;
}
li{
float: left;
}
style>
head>
<body>
<div>
<ul id="left">ul>
<ul id="right">ul>
div>
<script>
// src需要替换成实际的图片地址
const data = [
[{
src: 'xxx',
name: 'test1'
}, {
src: 'xxx',
name: 'test2'
}, {
src: 'xxx',
name: 'test3'
}, {
src: 'xxx',
name: 'test4'
}, {
src: 'xxx',
name: 'test5'
}, {
src: 'xxx',
name: 'test6'
}],
[{
src: 'xxx',
name: 'test21'
}, {
src: 'xxx',
name: 'test22'
}, {
src: 'xxx',
name: 'test23'
}, {
src: 'xxx',
name: 'test24'
}, {
src: 'xxx',
name: 'test25'
}, {
src: 'xxx',
name: 'test26'
}],
[{
src: 'xxx',
name: 'test31'
}, {
src: 'xxx',
name: 'test32'
}, {
src: 'xxx',
name: 'test33'
}, {
src: 'xxx',
name: 'test34'
}, {
src: 'xxx',
name: 'test35'
}, {
src: 'xxx',
name: 'test36'
}]
];
//模拟远程加载数据
const mockQuery = function (currentPage) {
if (currentPage < 3) {
return {
totalPages: data.length,
content: data[currentPage]
}
}
return {
totalPages: data.length,
content: []
}
}
const width = Math.floor((window.innerWidth - 30) / 2);
const imagesLeft = document.getElementById('left');
const imagesRight = document.getElementById('right');
imagesLeft.style = 'width: ' + width + 'px; margin: 0 5px 10px 10px';
imagesRight.style = 'width: ' + width + 'px; margin: 0 10px 10px 5px';
//动态插入图片到左侧ul或右侧ul中
const insertImages = function (data, width) {
let leftHeight = 0;
let rightHeight = 0;
for(let image of data.content){
const li = document.createElement("li");
const img = document.createElement('img');
img.src = image.src;
img.style = 'width: 100%';
img.onload = function(){
if(leftHeight <= rightHeight){
imagesLeft.appendChild(li);
leftHeight += this.height * width / this.width;
}else{
imagesRight.appendChild(li);
rightHeight += this.height * width / this.width;
}
}
li.appendChild(img);
}
}
//判断是否滑动到页面底部
function isScrollToPageBottom(){
//文档高度
var documentHeight = document.documentElement.offsetHeight;
var viewPortHeight = window.innerHeight;
var scrollHeight = window.pageYOffset ||
document.documentElement.scrollTop ||
document.body.scrollTop || 0;
return documentHeight - viewPortHeight - scrollHeight < 50;
}
//监听页面滚动事件
document.addEventListener('scroll', function (event) {
if(isScrollToPageBottom()){
if(currentPage < 2){
currentPage++;
insertImages(mockQuery(currentPage), width);
}
}
});
let currentPage = 0;
insertImages(mockQuery(currentPage), width);
script>
body>
html>
这里面需要注意的是图片是远程加载的,加载的顺序不定,所以图片的排序是按图片网络加载的顺序来显示的。在实际项目中图片通常是需要按创建时间来显示,我们会在下一次文章中做讨论。
上面是使用js来实现瀑布流,当然现在css3技术也很成熟,我们可以只用css3就能实现瀑布流效果。下面要介绍的是Multi-columns布局。关于Multi-columns如果不了解可以查看文末资料介绍。这种实现代码简单很多。
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>瀑布流title>
<style>
html, body{
margin: 0;
padding: 0;
width: 100%;
}
ul{
margin: 0;
padding: 0;
list-style: none;
column-count: 2;
column-gap: 0;
column-gap: 10px;
}
img{
margin-bottom: 10px;
}
style>
head>
<body>
<ul id="images">ul>
<script>
const data = [
[{
src: '',
name: 'test1'
}, {
src: '',
name: 'test2'
}, {
src: '',
name: 'test3'
}, {
src: '',
name: 'test4'
}, {
src: '',
name: 'test5'
}, {
src: '',
name: 'test6'
}],
[{
src: '',
name: 'test21'
}, {
src: '',
name: 'test22'
}, {
src: '',
name: 'test23'
}, {
src: '',
name: 'test24'
}, {
src: '',
name: 'test25'
}, {
src: '',
name: 'test26'
}],
[{
src: '',
name: 'test31'
}, {
src: '',
name: 'test32'
}, {
src: '',
name: 'test33'
}, {
src: '',
name: 'test34'
}, {
src: '',
name: 'test35'
}, {
src: '',
name: 'test36'
}]
];
const mockQuery = function (currentPage) {
if (currentPage < 3) {
return {
totalPages: data.length,
content: data[currentPage]
}
}
return {
totalPages: data.length,
content: []
}
}
const images = document.getElementById('images');
const insertImages = function (data) {
for(let image of data.content){
const li = document.createElement("li");
const img = document.createElement('img');
img.src = image.src;
img.style = 'width: 100%';
li.appendChild(img);
images.appendChild(li);
}
}
function isScrollToPageBottom(){
//文档高度
var documentHeight = document.documentElement.offsetHeight;
var viewPortHeight = window.innerHeight;
var scrollHeight = window.pageYOffset ||
document.documentElement.scrollTop ||
document.body.scrollTop || 0;
return documentHeight - viewPortHeight - scrollHeight < 50;
}
//listner document scroll
document.addEventListener('scroll', function (event) {
if(isScrollToPageBottom()){
if(currentPage < 2){
currentPage++;
insertImages(mockQuery(currentPage));
}
}
});
let currentPage = 0;
insertImages(mockQuery(currentPage));
script>
body>
html>
- 有个瀑布流插件很好用, 大家可以试用一下: masonry.desandro.com
- 使用CSS多列布局: developer.mozilla.org/zh-CN/docs/Web/Guide/CSS/Using_multi-column_layouts