分享web开发知识

注册/登录|最近发布|今日推荐

主页 IT知识网页技术软件开发前端开发代码编程运营维护技术分享教程案例
当前位置:首页 > 技术分享

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

发布时间:2023-09-06 01:18责任编辑:赖小花关键词: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="images/1.jpg" alt=""></div> ???????<div class="gallary-item-inner"><img src="images/2.jpg" alt=""></div> ???????<div class="gallary-item-inner"><img src="images/3.jpg" alt=""></div> ???????<div class="gallary-item-inner"><img src="images/4.jpg" alt=""></div> ???????<div class="gallary-item-inner"><img src="images/5.jpg" alt=""></div> ???????<div class="gallary-item-inner"><img src="images/6.jpg" alt=""></div> ???????<div class="gallary-item-inner"><img src="images/7.jpg" alt=""></div> ???????<div class="gallary-item-inner"><img src="images/8.jpg" alt=""></div> ???????<div class="gallary-item-inner"><img src="images/9.jpg" alt=""></div> ???????<div class="gallary-item-inner"><img src="images/10.jpg" alt=""></div> ???????<div class="gallary-item-inner"><img src="images/11.jpg" alt=""></div> ???????<div class="gallary-item-inner"><img src="images/12.jpg" alt=""></div> ???</div> ???????<div class="add">+12</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‘)[0], ???????????items = document.querySelectorAll(‘.gallary-item-inner img‘), ???????????addBtn = document.querySelectorAll(‘.add‘)[0], ???????????barrel = null; ???????window.addEventListener(‘load‘, function() { ???????????barrel = new BarrelLayout(container, items, 150); ???????}); ???????addBtn.addEventListener(‘click‘, function() { ???????????????????????var frag = document.createDocumentFragment(); ???????????for (var i = 0; i < 20; i++) { ???????????????var num = Math.floor(Math.random() * 12 + 1), ???????????????????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: 0;}.gallary .gallary-item .gallary-item-inner{ ???display: inline-block; ???font-size: 0;}.barrel-container .barrel-row{ ???line-height: 0; ???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 实现木桶布局

原文地址:http://www.cnblogs.com/stitchgogo/p/7678441.html

知识推荐

我的编程学习网——分享web前端后端开发技术知识。 垃圾信息处理邮箱 tousu563@163.com 网站地图
icp备案号 闽ICP备2023006418号-8 不良信息举报平台 互联网安全管理备案 Copyright 2023 www.wodecom.cn All Rights Reserved