手摸手,带你实现移动端H5瀑布流布局
移动端瀑布流布局是一种比较流行的网页布局方式,视觉上来看就是一种像瀑布一样垂直落下的排版。每张图片并不是显示的正正方方的,而是有的长有的短,呈现出一种不规则的形状。但是它们的宽度通常都是相同的
因为移动端瀑布流布局主要为竖向瀑布流,因此本文所探讨的是竖向瀑布流
特点
竖向瀑布流布局主要有下面几种特点:
- 一般出现在移动端 H5 页面底部
- 主要以图片或视频为主
- 降低页面复杂度,节省空间,可以容纳更多内容
- 不规则展示,不会那么枯燥,用户体验好
- 难以或者说不能滚动到页面最底部
不同于传统的分页,瀑布流因为以上这些特点一般被用在这些场景下:
推荐机制下的信息
即根据用户画像推荐或者运营人员推荐的信息大分类下的信息流
展示的信息有很多,它们的大分类都是相同的,适合用户不明确详细需要获得什么信息或商品的情况下各个信息或商品之间没有比较强的相关性
和上面一条类似,展示的不是千遍一律的东西,相对独立的信息或商品也许能让用户意外发掘到想要的东西
实现
一般来说主要分为 CSS 实现和 JS 实现
CSS 实现主要是用到一些专门的样式属性,实现起来简单,但是往往会有兼容性问题
JS 实现的方法则不存在这些问题,并且能实现比较个性化的需求,但是实现起来比较麻烦
column 多列布局方法
column 实现瀑布流主要依赖两个属性
column-count 属性是设置共有几列
column-gap 属性是设置每列之间的间隔
column 兼容性
代码
<style>
.pic {
column-count: 3;
column-gap: 5px;
}
.pic .item {
border: 1px solid #ccc;
margin-bottom: 5px;
}
.item img {
width: 100%;
}
</style>
<body>
<div class="pic">
<div class="item">
<!-- 获取 api 取到的图片地址 -->
<img src="" />
<div>001</div>
</div>
······
<div class="item">
<img src="" />
<div>008</div>
</div>
</div>
</body>
flex 弹性布局方法
flex 实现瀑布流需要给父元素设置为横向排列。然后通过设置 flex-flow: column wrap
使其换⾏
代码
<style>
.pic {
display: flex;
flex-flow: column wrap;
height: 100vh;
}
.item {
/* 每行展示 3 个 */
width: calc(100%/3 - 5px);
border: 1px solid #ccc;
margin-bottom: 5px;
}
.item img {
width: 100%;
}
</style>
<body>
<div class="pic">
<div class="item">
<!-- 获取 api 取到的图片地址 -->
<img src="" />
<div>001</div>
</div>
······
<div class="item">
<img src="" />
<div>008</div>
</div>
</div>
</body>
效果
可以发现图片排序顺序是先垂直方向,然后才是水平方向的。column 多列布局和 flex 弹性布局方法实现的效果图最终相似
JS + 懒加载方法
在不考虑兼容性或者没有特殊图片展示顺序需求下,只是实现瀑布流的话上面两种方案是够用的。如果要实现一些个性化的需求的话,还是得用 JS
主要思路就是:
- 先将第一行排满
- 计算第一行的所有图片高度,将第二行第一张图放在第一行最矮的图片后面
- 进行玩步骤 2,重新计算当前所有列高度,避免步骤 2 添加完成后,该列高度还是最矮
完整代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>JS实现瀑布流</title>
<style>
.item {
box-sizing: border-box;
border: 1px solid #ccc;
position: absolute;
/* 展示为三列,减去间隔宽度 */
width: calc(100% / 3 - 5px);
}
.item img {
width: 100%;
}
</style>
</head>
<body>
<div id="pic">
<div class="item">
<img src="..." />
<div>001</div>
</div>
<!-- 剩余图片,实际场景中应该使用for循环 -->
<div class="item">
<img src="..." />
<div>015</div>
</div>
</div>
</body>
<script>
var pic = document.getElementById('pic');
var items = pic.children;
// 相邻间距为5像素
var space = 5;
var picAmount = 15;
window.onload = function () {
function getClient() {
return {
width: window.innerWidth ||
document.documentElement.clientWidth ||
document.body.clientWidth,
height: window.innerHeight ||
document.documentElement.clientHeight ||
document.body.clientHeight,
};
}
function getScrollTop() {
return document.documentElement.scrollTop ||
window.pageYOffset ||
document.body.scrollTop;
}
waterFall();
function waterFall() {
var pageWidth = getClient().width;
var itemWidth = items[0].offsetWidth;
var columns = parseInt(pageWidth / (itemWidth + space));
var picList = [];
for (var i = 0; i < items.length; i++) {
if (i < columns) {
items[i].style.top = 0;
items[i].style.left = (itemWidth + space) * i + 'px';
picList.push(items[i].offsetHeight);
} else {
// 找到数组中最小高度的那一列,并拿到其下标
var minHeight = picList[0];
var index = 0;
for (var j = 0; j < picList.length; j++) {
if (minHeight > picList[j]) {
minHeight = picList[j];
index = j;
}
}
items[i].style.top = picList[index] + space + 'px';
items[i].style.left = items[index].offsetLeft + 'px';
// 操作列的高度 = 当前列原本高度 + 图片的高度 + 相邻的间距
picList[index] = picList[index] + items[i].offsetHeight + space;
}
}
}
window.onresize = function () {
waterFall();
};
// 监听滚动事件,模拟懒加载
window.onscroll = function () {
// 如果滚动到的位置比当前显示的最后一个图片高,则请求新的图片
if (
getClient().height + getScrollTop() >=
items[items.length - 1].offsetTop
) {
// 后续的新图片
var datas = [...];
for (var i = 0; i < datas.length; i++) {
picAmount += 1;
var div = document.createElement('div');
div.className = 'item';
div.innerHTML = `<img src="${datas[i]}" alt=""><div>0${picAmount}</div>`;
pic.appendChild(div);
}
waterFall();
}
};
};
</script>
</html>
效果
不同于上面两个 css 实现的瀑布流,JS 实现的图片排序顺序是先水平方向,然后才是垂直方向
可以看到当滚动页面的时候,新的图片会不断添加进来,这样就实现懒加载了
总结
如果实现效果简单不考虑兼容的的话可以选择使用 CSS 实现;若要兼容老版本浏览器或者实现一些个性化的需求还是得用 JS 实现
当然除了上文说的这些方法以外,也可以使用第三方库 Masonry 实现
手摸手,带你实现移动端H5瀑布流布局的更多相关文章
- 手摸手带你学移动端WEB开发
HTML常用标签总结 手摸手带你学CSS HTML5与CSS3知识点总结 手摸手带你学移动端WEB开发 好好学习,天天向上 本文已收录至我的Github仓库DayDayUP:github.com/Ro ...
- 【转】手摸手,带你用vue撸后台 系列二(登录权限篇)
前言 拖更有点严重,过了半个月才写了第二篇教程.无奈自己是一个业务猿,每天被我司的产品虐的死去活来,之前又病了一下休息了几天,大家见谅. 进入正题,做后台项目区别于做其它的项目,权限验证与安全性是非常 ...
- 【转】手摸手,带你用vue撸后台 系列三(实战篇)
前言 在前面两篇文章中已经把基础工作环境构建完成,也已经把后台核心的登录和权限完成了,现在手摸手,一起进入实操. Element 去年十月份开始用vue做管理后台的时候毫不犹豫的就选择了Elemen, ...
- 【转】手摸手,带你用vue撸后台 系列一
前言 说好的教程终于来了,第一篇文章主要来说一说在开始写业务代码前的一些准备工作吧,但这里不会教你webpack的基础配置,热更新怎么做,webpack速度优化等等,有需求的请自行google. 目录 ...
- 手摸手带你理解Vue的Computed原理
前言 computed 在 Vue 中是很常用的属性配置,它能够随着依赖属性的变化而变化,为我们带来很大便利.那么本文就来带大家全面理解 computed 的内部原理以及工作流程. 在这之前,希望你能 ...
- 【手摸手,带你搭建前后端分离商城系统】03 整合Spring Security token 实现方案,完成主业务登录
[手摸手,带你搭建前后端分离商城系统]03 整合Spring Security token 实现方案,完成主业务登录 上节里面,我们已经将基本的前端 VUE + Element UI 整合到了一起.并 ...
- 【转】手摸手,带你用vue撸后台 系列四(vueAdmin 一个极简的后台基础模板)
前言 做这个 vueAdmin-template 的主要原因是: vue-element-admin 这个项目的初衷是一个vue的管理后台集成方案,把平时用到的一些组件或者经验分享给大家,同时它也在不 ...
- 原创 | 手摸手带您学会 Elasticsearch 单机、集群、插件安装(图文教程)
欢迎关注笔者的公众号: 小哈学Java, 每日推送 Java 领域干货文章,关注即免费无套路附送 100G 海量学习.面试资源哟!! 个人网站: https://www.exception.site/ ...
- 浅谈Java中的Condition条件队列,手摸手带你实现一个阻塞队列!
条件队列是什么?可能很多人和我一样答不出来,不过今天终于搞清楚了! 什么是条件队列 条件队列:当某个线程调用了wait方法,或者通过Condition对象调用了await相关方法,线程就会进入阻塞状态 ...
随机推荐
- 二、mycat15种分片规则
一.分片枚举 通过在配置文件中配置可能的枚举 id,自己配置分片,本规则适用于特定的场景,比如有些业务需要按照省份或区县来做保存,而全国省份区县固定的,这类业务使用本条规则,配置如下: <tab ...
- spring-boot-learning-事务处理
事务处理的重要性: 面对高井发场景, 掌握数据库事务机制是至关重要的,它能够帮助我们在一定程度上保证数据的一致性,并且有效提高系统性能,避免系统产生岩机,这对于互联网企业应用的成败是至关重要的. 以 ...
- 谷歌浏览器postman插件安装,亲测可用
将谷歌浏览器进入扩展程序,将crx文件拖入即可. https://pan.baidu.com/s/1rIEe9RSby5EgTkygSx_dDA 百度云链接: https://pan.baidu.co ...
- js技术之运用"typeof()"运算符校验变量类型
一.简介 typeof();个人的理解就是可以判断出对应的变量类型,而且是用统一的类型 如:数字,小数等..... 都用Number来表示 而:所有对象都用object表示 二.探索到 typeof的 ...
- 一行代码让微信小程序支持 cookie
weapp-cookie 一行代码让微信小程序支持 cookie,传送门:github Intro 微信原生的 wx.request 网络请求接口并不支持传统的 Cookie,但有时候我们现有的后端接 ...
- 安卓性能测试之Lint测试
pre { direction: ltr; color: rgba(0, 0, 10, 1); text-align: left } pre.western { font-family: " ...
- 微信分享报错config:invalid url domain
错误类型:invalid url domain 调试返回参数: { "errMsg": "config:invalid url domain" } 截图: 环境 ...
- js判断时间格式不能超过30天
let first = this.data.date //开始时间 let second = e.detail.value //结束时间 var data1 = Date.parse(first.re ...
- FastAPI(六十九)实战开发《在线课程学习系统》接口开发--修改密码
之前我们分享了FastAPI(六十八)实战开发<在线课程学习系统>接口开发--用户 个人信息接口开发.这次我们去分享实战开发<在线课程学习系统>接口开发--修改密码 我们梳理一 ...
- Java报错:Unable to find setter method for attribute: [x]
在学习JavaWeb JSTL与自定义标签时遇到的坑,用的老师给的代码结果直接原地报错:javax.servlet.ServletException: org.apache.jasper.Jasper ...