【js 实践】js 实现木桶布局

时间:2022-09-12 16:04:29

还有两个月左右就要准备实习了,所以特意练一练,今天终于搞定了js 的木桶布局了

这一个是按照一个插件的规格去写的以防以后工作需要,详细的解释在前端网这里 http://www.qdfuns.com/notes/37573/535e6e8bf4a6ab06823943628936de87.html

这里只出示一下代码了啦,如果有什么不足的地方请指出无尽感激:

html:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>demo2</title>
</head>
<body>
<div class="container">
<div class="gallary-item-inner"><img src="data:images/1.jpg" alt=""></div>
<div class="gallary-item-inner"><img src="data:images/2.jpg" alt=""></div>
<div class="gallary-item-inner"><img src="data:images/3.jpg" alt=""></div>
<div class="gallary-item-inner"><img src="data:images/4.jpg" alt=""></div>
<div class="gallary-item-inner"><img src="data:images/5.jpg" alt=""></div>
<div class="gallary-item-inner"><img src="data:images/6.jpg" alt=""></div>
<div class="gallary-item-inner"><img src="data:images/7.jpg" alt=""></div>
<div class="gallary-item-inner"><img src="data:images/8.jpg" alt=""></div>
<div class="gallary-item-inner"><img src="data:images/9.jpg" alt=""></div>
<div class="gallary-item-inner"><img src="data:images/10.jpg" alt=""></div>
<div class="gallary-item-inner"><img src="data:images/11.jpg" alt=""></div>
<div class="gallary-item-inner"><img src="data:images/12.jpg" alt=""></div>
</div> <div class="add">+</div>
<link rel="stylesheet" type="text/css" href="css/normal.css">
<link rel="stylesheet" type="text/css" href="css/demo2.css">
<script type="text/javascript" src="js/demo2.js"></script>
<script type="text/javascript">
var container = document.querySelectorAll('.container')[],
items = document.querySelectorAll('.gallary-item-inner img'),
addBtn = document.querySelectorAll('.add')[],
barrel = null; window.addEventListener('load', function() {
barrel = new BarrelLayout(container, items, );
}); addBtn.addEventListener('click', function() { var frag = document.createDocumentFragment();
for (var i = ; i < ; i++) {
var num = Math.floor(Math.random() * + ),
path = 'images/' + num + '.jpg';
var div = document.createElement('div'),
img = document.createElement('img'); img.src = path;
div.appendChild(img);
div.className = 'gallary-item-inner';
frag.appendChild(div);
}
container.appendChild(frag);
barrel.refresh(document.querySelectorAll('.gallary-item-inner img')); });
</script>
</body>
</html>

css:

.gallary .gallary-item{
font-size:;
}
.gallary .gallary-item .gallary-item-inner{
display: inline-block;
font-size:;
}
.barrel-container .barrel-row{
line-height:;
text-align: left;
}
.add{
position: fixed;
bottom: 80px;
right: 50px;
width: 80px;
height: 80px;
line-height: 80px;
border-radius: 50%;
box-shadow: 0 0 20px rgba(0,0,0,0.3);
text-align: center;
cursor: pointer;
}

js

/*
木桶布局类
参数:
wrapper:
类型: HTMLElement
描述: 木桶布局的初始化包裹层由用户自己定义 items:
类型: HTMLElementList
描述: 需要木桶布局的子项 baseHeight:
类型: Integer
描述: 用户规定木桶布局每一行的基础高度 实际输出时会与这个高度有差异 流程:
计算 ==> 整理 ==> 渲染dom 属性:
barrelWrap:
类型: HTMLElement
描述: 保存用户传进来的外包裹层 items:
类型: HTMLElementList
描述: 保存用户传进来的所有需要木桶布局的子元素集 baseHeight:
类型: Integer
描述: 接收用户设置的基本高度 lastRow:
类型: Array
描述: 保存上一次渲染木桶布局后最后一行的元素 lastItemIndex:
类型: Integer 方法:
calc:
参数:
itemList: (Array) 接收需要木桶布局的dom 元素列
返回值: Object
{
elemArr: 二维数组,保存每一行应有的元素
rowHeightArr: 一维数组,保存每一行的实际宽度
}
类型: HTMLElementList
描述: 将需要进行木桶布局的 dom 元素(通常是img) 传入这个函数中
首先会根据元素的宽高比例计算出每一个元素按比例缩放的宽度
根据宽度计算出一行能够放入多少个元素
当计算完一行应有元素时再计算出该行的高度, 公式为:
该行所有元素宽度总和 / 用户定义的基本高 = 该行在浏览器显示的宽度 / y
y 为最后的运算结果
最后,将每一个木桶布局元素的高度设置为 y 其宽度总和便会自动填充满整行 render:
参数: rowsArr: (Array) 每一行需要渲染的dom 元素
rowHeightArr: (Array) 每一行的实际行高
返回值: void
描述: 对calc 方法返回的数据进行渲染dom
此方法会首先判断有没有 class="barrel-container" 这个元素存在
如果不存在证明是第一次初始化
为用户指定的 wrapper 元素下生成一个ul类名为barrel-container
在container 下面输出dom 如果barrel-container 存在证明是重新渲染
那么将最后一个li 移除再紧接着输出 init:
参数: null
返回值: void
描述: 调用上面两个方法渲染dom refresh:
参数: newItemsList: (HTMLElemsList)
描述: 为了减少dom 的渲染
当从服务器将加载图片添加到包裹层中时可调用此方法
此方法会根据上一次渲染后的 lastItemIndex 对新元素数组进行切割
切割完成后和上一次渲染后的最后一行元素列合并组成新的渲染数组
之后依次调用 calc() render() 完成输出
*注意一点:
上一次渲染后最后一行的元素已经设置好了高度所以在计算前要将
最后一行的元素清空样式防止布局错乱 */ function BarrelLayout(wrapper, items, baseHeight) {
this.barrelWrap = wrapper;
this.items = items;
this.baseHeight = baseHeight;
// 下面是函数附带的属性
this.lastRow = []; // 保存上一次加载元素中最后一行的元素
this.lastItemIndex = 0; // 保存最后一个元素的下标
this.init();
}
BarrelLayout.prototype.init = function(){
var layoutData = this.calc(this.items);
// 保存最后一行的元素
this.lastRow = layoutData.elemArr[layoutData.elemArr.length - 1];
// 保存最后一个元素的index
this.lastItemIndex = this.items.length;
this.render(layoutData.elemArr, layoutData.rowHeightArr);
}; BarrelLayout.prototype.calc = function(itemsList){
// 私有变量
var resultElemArr = [], // 最终返回的保存每一行的数组
resultRowHeightArr = [], // 最终返回的保存每一行的基本行高的数组
tempElemArr = [], // 保存每一行应有元素的数组
widthRate = 0, // 元素的宽度比例
heightRate = 0, // 元素的高度比例
totalWidth = 0; // 行元素的宽度总和 var len = itemsList.length; for (var i = 0; i < len; i++) {
// 计算元素宽高比例
// 再求出缩放下的宽度
widthRate = itemsList[i].offsetWidth / itemsList[i].offsetHeight;
var curElemWidth = this.baseHeight * widthRate;
totalWidth += curElemWidth; // 如果当元素相加宽度小于容器宽度将它推进 tempElemArr 数组
// totalWidth 加上这个元素的宽度
if(totalWidth <= this.barrelWrap.offsetWidth) {
tempElemArr.push(itemsList[i]); // 如果当前的元素是最后一个且总宽度没有超过容器宽度
// 将此时的tempElemArr 放入 this.rows 数组中 if(i === len - 1) {
resultElemArr.push(tempElemArr);
// 行高设置为默认的baseHeight
resultRowHeightArr.push(this.baseHeight);
} }else {
// 如果当前元素宽度相加大于容器宽度 进行如下操作
// 1.计算当前元素宽度总和与baseHeight 的比率 根据比率设置当前行的高度
// 从而设置行内的每一个元素的高度 调整到最适合的宽度
heightRate = this.baseHeight / (totalWidth - curElemWidth);
// 精确高度到两位小数
var curColHeight = Math.floor(((this.barrelWrap.offsetWidth * heightRate) * 10)) / 10;
// 2.将这一行的行高推入 rowHeight 数组
resultRowHeightArr.push(curColHeight);
// 3.将这一行应有的元素推入
resultElemArr.push(tempElemArr);
// 4.tempElemArr 数组重新填入这个超出容器宽度的元素
tempElemArr = [itemsList[i]];
// 5.重设totalWidth 为这个元素的宽度
totalWidth = curElemWidth if(i === len - 1) {
resultElemArr.push(tempElemArr);
// 行高设置为默认的baseHeight
resultRowHeightArr.push(this.baseHeight);
} }
} return {
elemArr: resultElemArr,
rowHeightArr: resultRowHeightArr
}
}; BarrelLayout.prototype.render = function(rowsArr, rowHeightArr){
var container = document.querySelectorAll('.barrel-container')[0];
if(container === undefined) {
container = document.createElement('ul');
container.className = 'barrel-container';
}else {
// 如果barrel-container 存在证明是刷新操作
// 此时要将视图中容器里面最后一行的li 删掉
// 然后再生成元素 加入到容器中
var rows = container.querySelectorAll('.barrel-row');
container.removeChild(rows[rows.length - 1]);
} for (var i = 0; i < rowsArr.length; i++) {
var li = document.createElement('li');
li.className = 'barrel-row';
for (var k = 0; k < rowsArr[i].length; k++) {
rowsArr[i][k].style.height = rowHeightArr[i] + 'px';
rowsArr[i][k].parentNode.style.display = 'inline-block'; li.appendChild(rowsArr[i][k].parentNode);
container.appendChild(li);
}
} this.barrelWrap.appendChild(container);
}; BarrelLayout.prototype.refresh = function(newItemsList){
// 1. 首先调整最后一行的元素排列
// 对新的元素列表进行切割 分离出新加入的元素 根据this.lastItemIndex进行切割
var newList = Array.prototype.slice.call(newItemsList, this.lastItemIndex),
lastRow = this.lastRow; for (var i = 0; i < lastRow.length; i++) {
lastRow[i].style = '';
}
// 将新加入的元素与上一次渲染后最后一个行的元素列连接起来
var totalList = lastRow.concat(newList);
var layoutData = this.calc(totalList);
this.render(layoutData.elemArr, layoutData.rowHeightArr);
// 对 this.lastItemIndex 重新赋值为下一次刷新做准备
this.lastItemIndex += totalList.length - lastRow.length;
this.lastRow = layoutData.elemArr[layoutData.elemArr.length - 1]; console.log(lastItemIndex);
console.log(lastRow);
};

【js 实践】js 实现木桶布局的更多相关文章

  1. require&period;js实践

    ASP.NET MVC应用require.js实践 这里有更好的阅读体验和及时的更新:http://pchou.info/javascript/asp.net/2013/11/10/527f6ec41 ...

  2. ASP&period;NET MVC应用require&period;js实践

    这里有更好的阅读体验和及时的更新:http://pchou.info/javascript/asp.net/2013/11/10/527f6ec41d6ad.html Require.js是一个支持j ...

  3. r&period;js实践

    r.js合并实践 项目中用到require.js做生产时模块开发,但上线要合并压缩,幸好它配套有r.js.下面就其用法说明一下. 首先建一个目录,里面的结构如下: require.js可以到r.js项 ...

  4. 一个简单的 vue&period;js 实践教程

    https://segmentfault.com/a/1190000006776243?utm_source=tuicool&utm_medium=referral 感觉需要改善的地方有: ( ...

  5. flexible&period;js &plus; makegrid&period;js 自适应布局

    一,flexible.js 的使用方式: (一),引用方式 1,引用cdn地址 <script src="http://g.tbcdn.cn/mtb/lib-flexible/0.3. ...

  6. r&period;js合并实践 --项目中用到require&period;js做生产时模块开发 r&period;js build&period;js配置详解

    本文所用源代码已上传,需要的朋友自行下载:点我下载 第一步: 全局安装  npm install -g requirejs 第二步: 1.以下例子主要实现功能, 1)引用jq库获取dom中元素文本, ...

  7. Rollup&period;js 实践

    音乐分享: B.o.B Ft. Marko Penn - <Roll up> ——————————————————————————————————————————————————————— ...

  8. 【实践】require&period;js &plus; r&period;js 代码打包压缩初体验

    第二个分享的是学校项目所接触到的新知识,代码压缩 + 代码打包 这次的项目用了require.js 这个插件做模块化管理的工具,所谓模块化就是在开发的过程中将功能划分成一个独立的模块,使代码可读性更强 ...

  9. js&plus;canvas实现象棋的布局、走棋位置提示、走棋代码

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

随机推荐

  1. 【Win10 应用开发】解决VS 2015 RC不能调试手机应用的问题

    VS2015 RC已发布,当然这个版本还不能用于实际生产中,如果你没有测试环境,就等正式版出来,RC都来了,RTM就不远了. 如果你也像老周一样,已经在耍RC版了,你可能会遇到下面问题: 安装Win ...

  2. WEB测试方法及注意地方

    1页面部分(1) 页面清单是否完整(是否已经将所需要的页面全部都列出来了)(2) 页面是否显示(在不同分辨率下页面是否存在,在不同浏览器版本中页面是是否显示)(3) 页面在窗口中的显示是否正确.美观( ...

  3. Android中向SD卡读写数据,读SD卡和手机内存

    package com.example.sdoperation; import java.io.BufferedReader; import java.io.File; import java.io. ...

  4. Android 动画animation 深入分析

    转载请注明出处:http://blog.csdn.net/farmer_cc/article/details/18259117 Android 动画animation 深入分析 前言:本文试图通过分析 ...

  5. HTML-标签:图片 超链接

    [img图片标签] 1,src属性:表示图片所在的路径. [路径的表示方式] ① 网络图片地址.并不建议使用. ② 可以使用图片的绝对路径.但是严禁使用绝对路径,因为绝对路径使用file://协议,网 ...

  6. Beta冲刺置顶随笔

    项目名称:城市安全风险管控系统 小组成员: 张梨贤.林静.周静平.黄腾飞 Beta冲刺随笔 Beta预备 Beta冲刺Day1 Beta冲刺Day2 Beta冲刺Day3 Beta冲刺Day4 Bet ...

  7. Windows系统封装教程

    Windows系统封装教程

  8. Session 常见操作

    对于敏感.重要的信息,建议要存储在服务器端(Session是存储在服务器端的),不能存储在浏览器中,如用户名.余额.等级.验证码等信息 Session依赖于Cookie session数据的获取 se ...

  9. data&period;frame类型数据如何将第一列值替换为行号

    data.frame类型数据如何将第一列值替换为行号 row.names(data) <- data[, 1]data <- data[, -1]

  10. 《Node&period;js 高级编程》简介与第二章笔记

    <Node.js 高级编程> 作者简介 Pedro Teixerra 高产,开源项目程序员 Node 社区活跃成员,Node公司的创始人之一. 10岁开始编程,Visual Basic.C ...