【js 实践】js 实现木桶布局
还有两个月左右就要准备实习了,所以特意练一练,今天终于搞定了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 实现木桶布局的更多相关文章
- require.js实践
ASP.NET MVC应用require.js实践 这里有更好的阅读体验和及时的更新:http://pchou.info/javascript/asp.net/2013/11/10/527f6ec41 ...
- ASP.NET MVC应用require.js实践
这里有更好的阅读体验和及时的更新:http://pchou.info/javascript/asp.net/2013/11/10/527f6ec41d6ad.html Require.js是一个支持j ...
- r.js实践
r.js合并实践 项目中用到require.js做生产时模块开发,但上线要合并压缩,幸好它配套有r.js.下面就其用法说明一下. 首先建一个目录,里面的结构如下: require.js可以到r.js项 ...
- 一个简单的 vue.js 实践教程
https://segmentfault.com/a/1190000006776243?utm_source=tuicool&utm_medium=referral 感觉需要改善的地方有: ( ...
- flexible.js + makegrid.js 自适应布局
一,flexible.js 的使用方式: (一),引用方式 1,引用cdn地址 <script src="http://g.tbcdn.cn/mtb/lib-flexible/0.3. ...
- r.js合并实践 --项目中用到require.js做生产时模块开发 r.js build.js配置详解
本文所用源代码已上传,需要的朋友自行下载:点我下载 第一步: 全局安装 npm install -g requirejs 第二步: 1.以下例子主要实现功能, 1)引用jq库获取dom中元素文本, ...
- Rollup.js 实践
音乐分享: B.o.B Ft. Marko Penn - <Roll up> ——————————————————————————————————————————————————————— ...
- 【实践】require.js + r.js 代码打包压缩初体验
第二个分享的是学校项目所接触到的新知识,代码压缩 + 代码打包 这次的项目用了require.js 这个插件做模块化管理的工具,所谓模块化就是在开发的过程中将功能划分成一个独立的模块,使代码可读性更强 ...
- js+canvas实现象棋的布局、走棋位置提示、走棋代码
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
随机推荐
- vue2 computed set与get函数
大家都知道computed简单的使用方法,这儿只分享一下setter和getter用法: setter:设置值时触发. getter:获取值时触发,与setter是没有必然联系的. <templ ...
- this与base关键字
this关键字 this关键字代表当前对象,通过this关键字可以访问当前对象的成员.(当前对象的成员:自己本身的成员+从父类继承过来的所有的成员.) this关键字可以访问:本类的所有成员和父类的非 ...
- 未知宽高图片水平垂直居中在div
<BODY> <div class="box"> <span class="car"></span> <i ...
- win10安装Tensorflow
win10安装Tensorflow 前提: 保证你的pip>=8.1版本 否则利用python -m pip install -U pip 进行升级,或下载pip源文件 确定你的显卡是否支持c ...
- linux 卸载安装node npm
1. 卸载node npm (1) 先卸载 npm: sudo npm uninstall npm -g (2) 然后卸载 Node.js. (2.1) 如果是 Ubuntu 系统并使用 apt-ge ...
- Linux 文本处理工具(grep sed awk )
^test: 以test开头; test$: 以test结尾: ^$: 表示空行,不是空格: . :代表且只代表任意一个字符(其他功能:当前目录,加载文件): \ : 代表转义字符,表示特殊字符: * ...
- 深入理解JVM(三)——配置参数
JVM配置参数分为三类参数: 1.跟踪参数 2.堆分配参数 3.栈分配参数 这三类参数分别用于跟踪监控JVM状态,分配堆内存以及分配栈内存. 跟踪参数 跟踪参数用于跟踪监控JVM,往往被开发人员用于J ...
- CentOS配置SSH免密登录
假如我们有两台CentOS机器,192.168.199.101,192.168.199.102,要想在101上远程连接102可以通过ssh命令来实现 ssh 192.168.199.102 如果没有配 ...
- DAY3-“忙里偷闲”找你玩耍2018-1-11
接触Java第三天,嘿嘿,今天近代史期末考试,提前一小时交卷,回宿舍继续学习,中午去见女神姐姐了,每次见完女神姐姐都是满满地动力.这次女神姐姐告诉我们要好好规划自己的时间,早上花20分钟规划好一天的时 ...
- EXP导出aud$报错EXP-00008,ORA-00904 解决
主题:EXP导出aud$报错EXP-00008,ORA-00904 解决 环境:Oracle 11.2.0.4 问题:在自己的测试环境,导出sys用户下的aud$表报错. 1.故障现场 2.跟踪处理 ...