原生js实现图片瀑布流布局,注释超详细

时间:2024-08-18 17:35:20

完整代码:

<!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)
// })