原生js实现图片瀑布流布局,注释超详细
完整代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>瀑布流</title>
<style type="text/css">
img {
width: 300px; } li {
position: absolute;
s left: 0;
top: 0;
list-style: none;
} ul {
margin: 0 auto;
position: relative;
} * {
margin: 0;
padding: 0;
}
</style>
</head>
<body>
<ul></ul>
</body>
<script src="utils.js"></script>
<script>
let ul = document.querySelector('ul'), //获取ul标签
list = ul.children, //动态更新ul里面的子元素
teep = 10, //间距
width = 300, //每张图片的宽度
cols = Math.floor(document.documentElement.clientWidth / (width + teep)), //计算有多少列
hh = [], //存取每一列的高度
num = 0, //记录加载完成图片数量
om = 0 //记录已经排版完成的li数量
ul.style.width = cols * (width + teep) - teep + 'px' //计算ul的宽度
get({ //提前封装好的方法
url: 'http://rap2.taobao.org:38080/app/mock/256901/json'
})
.then(a => { //请求数据
a = JSON.parse(a).img
let dom = document.createDocumentFragment() //创建文档碎片
a.forEach((item, index) => { //有多少条数据就创建多少个li
let li = document.createElement('li')
li.innerHTML = `<img src="${item.src}">`
dom.appendChild(li) //把li添加到文档碎片中
})
ul.appendChild(dom) //将文档碎片添加到ul中
let imgs = Array.from(list).reduce((curr, item, index) => { //将每张img节点组成数组
if (om <= index) {
curr.push(item.querySelector('img'))
}
return curr
}, []) Array.from(imgs).forEach(item => { //遍历每张图片
item.onload = () => { //该图片加载完成
num++
if (num === imgs.length) { //图片都加载完成了
for (let i = om; i < list.length; i++) { //遍历ul下的每个li
if (i < cols) { //给第一行每个li设置left/top值
list[i].style.left = (width + teep) * i + 'px'
list[i].style.top = teep + 'px'
hh.push(list[i].offsetHeight + teep * 2)
} else { //除了第一行剩下的li
let minHeight = Math.min(...hh) //求出最小高度
let minIndex = hh.indexOf(minHeight) //求出最小高度的索引值
list[i].style.left = (width + teep) * minIndex + 'px'
list[i].style.top = minHeight + 'px'
hh[minIndex] = list[i].offsetHeight + minHeight + teep //将最小高度更新
}
}
om = list.length //更新排版完成数量
ul.style.height = ul.scrollHeight + 'px' //给ul设置高度
}
}
})
})
</script>
</html>
如果要复制运行看效果的话,需要引入我已经封装好的get请求方法
代码如下:
function ajax(obj, fn) {
let ajx = new XMLHttpRequest() //创建ajax实例
obj.type = obj.type ? obj.type : 'get' //判断type存不存在,不存在默认等于get
let data = '' //向后端发送的数据
if (obj.data) { //判断是否存在
for (let i in obj.data) {
data += i + '=' + obj.data[i] + '&' //键值拼接成name=zhagnsan&age=18形式
}
let k = data.split('')
k.splice(data.length - 1, 1)
data = k.join('')
}
if (obj.type == 'get') { //处理get请求发送数据
ajx.open(obj.type, obj.url + '?' + data) //地址上拼接数据
ajx.send()
} else if (obj.type == 'post') { //处理post请求发送数据
ajx.open(obj.type, obj.url)
ajx.setRequestHeader('content-type', 'application/x-www-form-urlencoded') //设置请求头
ajx.send(data) //发送数据
}
ajx.onreadystatechange = () => {
if (ajx.readyState == 4) {
if (ajx.status == 200) {
/*
将得到的数据传给回调函数
短路写法,如果不传fn为空不会执行,有值就执行
*/
fn && fn(ajx.responseText)
}
}
}
}
// ajax({ //调用封装的方法
// type: 'get', //可以不写,默认get
// url: 'http://localhost/day02/api/gouwu.php', //请求地址
// data: { //需要传输的数据,可选
// name: 'zhangsan',
// age: 18
// }
// },a=>{//处理的到的数据
// console.log(a)
// })
function jsonp(obj) {
let sc = document.createElement('script')
let data = ''
if (obj.data) {
for (let i in obj.data) {
data += `${i}=${obj.data[i]}&`
}
data = data.slice(0, -1)
sc.setAttribute('src', obj.url + `?cd=${obj.cd}&${data}`)
} else {
sc.setAttribute('src', obj.url + `?cd=${obj.cd}`)
}
document.body.appendChild(sc)
}
// jsonp({
// url:'http://localhost/day02/api/gouwu.php',
// cd:'fn'
// },a=>{
// console.log(a)
// })
function get(obj) {
return new Promise((resolve, reject) => {
let a = new XMLHttpRequest()
let data = ''
if (obj.data) {
for (let i in obj.data) {
data += i + '=' + obj.data[i] + '&'
}
data = data.slice(0, -1)
a.open('get', obj.url + '?' + data)
}else{
a.open('get', obj.url)
}
a.send()
a.onreadystatechange = () => {
if (a.readyState === 4) {
if (a.status === 200) {
resolve(a.responseText)
} else {
reject()
}
}
}
})
}
// get({//调用格式
// url:'http://localhost/day02/api/gouwu.php',//获取的地址
// data:{ //可不写
// a:1,
// b:2
// }
// }).then(a=>{//获取数据成功
// console.log(a)
// }).catch(err=>{ //获取数据失败
// console.log(err)
// })
原生js实现图片瀑布流布局,注释超详细的更多相关文章
- 原生js实现的瀑布流布局
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- js 实现图片瀑布流效果,可更改配置参数 带完整版解析代码[waterFall.js]
前言: 本人纯小白一个,有很多地方理解的没有各位大牛那么透彻,如有错误,请各位大牛指出斧正!小弟感激不尽. 本篇文章为您分析一下原生JS实现图片瀑布流效果 页面需求 1 ...
- 原生JS—实现图片循环切换的两种方法
今天我们主要讲讲如何使用原生JS实现图片的循环切换的方法.多余的话我们就不多说了,我们一个一个开始讲吧. 1 原生JS实现图片循环切换 -- 方法一 在上栗子之前我们先简单介绍一下所用的一些知识点. ...
- 原生JS—实现图片循环切换及监测鼠标滚动切换图片
今天我们主要讲讲如何使用原生JS实现图片的循环切换的方法以及如何检测鼠标滚动循环切换图片.多余的话我们就不多说了,我们一个一个开始讲吧. 1 原生JS实现图片循环切换 -- 方法一 在上栗子之前我们 ...
- 页面性能优化-原生JS实现图片懒加载
在项目开发中,我们往往会遇到一个页面需要加载很多图片的情况.我们可以一次性加载全部的图片,但是考虑到用户有可能只浏览部分图片.所以我们需要对图片加载进行优化,只加载浏览器窗口内的图片,当用户滚动时,再 ...
- 原生js实现图片轮播思路分析
一.复习原生js实现图片轮播 1.要点 自动轮播 点击小圆圈按钮,显示相应图片 点击左右箭头,实现向前向后轮播图片 2.实现思路 <div id="container"> ...
- 原生JS实现图片循环切换
<!-- <!DOCTYPE html> <html> <head> <title>原生JS实现图片循环切换 —— 方法一</title&g ...
- 原生 JS 实现一个瀑布流插件
更好的阅读体验,点击 原文地址 瀑布流布局中的图片有一个核心特点 -- 等宽不定等高,瀑布流布局在国内网网站都有一定规模的使用,比如pinterest.花瓣网等等.那么接下来就基于这个特点开始瀑布流探 ...
- 基于原生js的图片延迟加载
当页面图片比较多的时候,我们通常会做一个延迟加载,避免页面打开时一下子的请求数太多,加载过慢影响用户体验. 如果项目用了jquery框架,则可以直接用 jquery.lazyload.可在jquery ...
随机推荐
- Rasa init报错:AttributeError: type object 'Callable' has no attribute '_abc_registry'
错误:Rasa init --no-prompt 报错 原因:Python升级到3.7后会遇到该问题 解决:pip uninstall typing
- NetCore项目实战篇07---服务保护之polly
1. 为什么要用polly 前面的项目中,一个服务调用另一个(Zhengwei.Identity调用Zhengwei.Use.Api)服务时是直接调用的,在这个调用的过程中可能会发生各种瞬态故障,这 ...
- 【雕爷学编程】Arduino动手做(58)---SR04超声波传感器
37款传感器与执行器的提法,在网络上广泛流传,其实Arduino能够兼容的传感器模块肯定是不止这37种的.鉴于本人手头积累了一些传感器和执行器模块,依照实践出真知(一定要动手做)的理念,以学习和交流为 ...
- React-Router 4 两个常用路由变量
讲真我个人不太喜欢4.x版本,虽然作者自信动态路由的形式符合React组件化的哲学,但是路由和一般组件耦合太深,而且后期组件分片也麻烦,以后需要重构的话怕是会一番折腾.同学公司用的还是3.x版本. 不 ...
- LTC6804读写配置寄存器
一.写配置寄存器步骤及函数封装 写配置寄存器 1.把CSB拉低至低电平: 2.发送WRCFG命令(0x00 0x01)及其PEC(0x3D 0x6E): 3.发送配置寄存器的CFGR0字节,然后继续发 ...
- pipeline的使用示例
搭建就不说了,直接示例如何使用pipeline. 一.以下输入参数:版本号为字符参数,按文档更新的是文本参数. 二.脚本对更新内容的处理如下: file_update_list="/home ...
- Java多线程相关面试题及答案-整理
1.什么是线程? 线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位.程序员可以通过它进行多处理器编程,你可以使用多线程对 运算密集型任务提速.比如,如果一个线程完成 ...
- 推荐一款复式记账软件——GnuCash
本文需要搞清楚两个事情,第一,什么是复式记账:第二,GnuCash操作 复式记账,来自百度百科的解释:复式记账法是以资产与权益平衡关系作为记账基础,对于每一笔经济业务,都要以相等的金额在两个或两个以上 ...
- Linux下VCS2014和Verdi2015的联合使用
VCS和Verdi是IC设计中常用的两款开发工具.VCS是Synopsys公司的产品,和大家所熟知的ModeSim一样的都是EDA仿真工具.Verdi是Nocas公司(已经被Synopsys公司收购) ...
- Spring Boot集成Shrio实现权限管理
Spring Boot集成Shrio实现权限管理 项目地址:https://gitee.com/dsxiecn/spring-boot-shiro.git Apache Shiro是一个强大且 ...