4个小时实战木桶布局
栏目: JavaScript · 发布时间: 6年前
内容简介:最近公司有个项目要用到木桶布局,找了很多插件都感觉不合适,于是决定自己撸一个。已经开源到github。(文章写的匆忙,有错别字或bug请指正)什么是木桶布局,我们随便百度一张图片就知道了。如下图。那么问题来了,要怎么实现这种效果呢?本人想了一种思路,看下图。
最近公司有个项目要用到木桶布局,找了很多插件都感觉不合适,于是决定自己撸一个。已经开源到github。(文章写的匆忙,有错别字或bug请指正)
什么是木桶布局,我们随便百度一张图片就知道了。如下图。
那么问题来了,要怎么实现这种效果呢?本人想了一种思路,看下图。
首先排列若干图片,用一个基准高度来设置他们,让后当放不下的时候在进行整体缩放。
实现
让我们愉快的coding吧~,准备把它封装成一个jQ插件。考虑设计以下方法
- loader 图片加载器
- render 图片渲染器
- template 模板渲染器
- resize 重新排版器
- loadMore 动态加载图片
那么让我们创建iboot.js。
;(function ($, root) { function Iboot() { } })(jQuery, window); 复制代码
这样实现了一个简单的jq插件模板。由于某些参数需要传递过来,我们要继续完善。
function Iboot(ele, config) { this.ele = $(ele) this.eleWidth = this.ele.width() this.config = $.extend({ // 这里会合并用户传来的参数 baseHeight: 400, // 默认基准高度 list: [ // 定义图片格式 { src: '', alt: 'xxx' } ], template: function (dom) { return dom }, scrollBox: $(document.body), afterLoad: function () { //加载之前回调 }, beforeLoad: function () { //加载之后回调 } }, config) this.innerData = { //内置的储存器 nowItemWidth: 0, //现在的增加长度 appendDoms: [], scrollBoxData: { }, saveDom: [], groupid: 0 } } 复制代码
实现图片加载器
首先我们要实现图片加载器,代码如下。
Iboot.prototype.loader = function(list, success, error, done){ var now = 0; $.each(list, function (i, v) { (function (i, v) { var img = new Image() img.onload = function () { success(v, img) now++ if(now === list.length) { done() } } img.onerror = function (err) { error(v, img, err) now++ if(now === list.length) { done() } } img.src = v.src img.alt = v.alt })(i, v); }) } 复制代码
加载传入的list,加载后分别指派给回调函数 success(成功之后)error(加载失败)done(全部加载完成)
实现模板函数
Iboot.prototype.template = function(src, alt){ var item = $('<div class="iboot-item" style="float: left"></div>'); item.append( $('<img src="'+src+'" alt="'+alt+'" style="width: 100%;height: auto;">') ); return this.config.template( item ) } 复制代码
这和函数允许使用用户传来的回调函数在渲染之前操作一下模板,用来DIYdom,比如(加边距,加文字等等)
【核心】实现render渲染函数
Iboot.prototype.render = function(cp, img){ var _this = this // 获取一下item模板 var dom = this.template(cp.src, cp.alt) // 获取加载后的图片的比例 var scale = img.width / img.height // 给item加属性,保存当前信息,用给Resize的时候读取,根据信息重新排版 dom.attr({ 'data-rew': img.width, 'data-reh': img.height, 'data-scale': scale }) // 计算根据基准高度缩放之后的信息 var comp = { width: scale * this.config.baseHeight, height: this.config.baseHeight, } // nowItemWidth的作用就是没次加元素,就把宽度累加,然后当累加的宽度大于父盒子的宽度的时候,进行整体缩放,缩放完成之后重置为0 this.innerData.nowItemWidth += comp.width // appendDoms储存当前列表,缩放之后清空 this.innerData.appendDoms.push(dom) // saveDom是全局的,所有信息都储存在这,用于之后resize this.innerData.saveDom.push(dom) // 缩放当前dom dom.css({ height: comp.height, width: comp.width }) // 添加到父盒子 this.ele.append(dom) var compW = this.innerData.nowItemWidth - this.ele.width() // 当放不下的时候,进行整体缩放 if(compW > 0) { // 超出大小整体缩放 var nowScale = this.innerData.nowItemWidth / this.getMediaHeight() var scaleHeight = this.ele.width() / nowScale // 整体缩放 $.each(this.innerData.appendDoms, function (i, v) { var data = $(v).data() $(v).css({ height: scaleHeight, width: data.scale * scaleHeight }) // 对缩放后的元素进行分组,这个分组很重要,因为当图片小于排版要求的时候就不会分组,不分组的就隐藏掉。 $(v).attr('group', _this.innerData.groupid) }) this.innerData.nowItemWidth = 0 this.innerData.appendDoms = [] this.innerData.groupid++ } } 复制代码
总结一下render的思路
- 累计添加子元素,把等比例缩放后的宽度储存起来
- 当放不下的时候进行整体缩放
- 请空储存的值
- 以此类推
关于 groupid
,因为图片会出现不符合排版要求的情况,我们不对其进行分组,隐藏它们。当resize或者loadmore的时候符合分组要求在显示它们。
实现resize排版器
resize的思想和render很像,只不过就是考虑了groupid的显示隐藏。
Iboot.prototype.resize = function(){ var baseHeight = this.getMediaHeight() var _this = this $.each(this.innerData.saveDom, function (i, v) { // 首先删除所有的group id $.each(_this.innerData.appendDoms, function (i, v) { $(v).removeAttr('groupid') $(v).show() }) var data = $(v).data() var cof = { height: baseHeight, width: baseHeight * data.scale } _this.innerData.appendDoms.push(v) _this.innerData.nowItemWidth += cof.width var compW = _this.innerData.nowItemWidth - _this.ele.width() if(compW > 0) { // 超出大小整体缩放 var nowScale = _this.innerData.nowItemWidth / _this.getMediaHeight() var scaleHeight = _this.ele.width() / nowScale $.each(_this.innerData.appendDoms, function (i, v) { var data = $(v).data() $(v).css({ height: scaleHeight, width: data.scale * scaleHeight }) $(v).attr('group', _this.innerData.groupid) }) _this.innerData.nowItemWidth = 0 _this.innerData.appendDoms = [] _this.innerData.groupid++ } }) _this.innerData.nowItemWidth = 0 _this.innerData.appendDoms = [] _this.innerData.groupid = 0 // 隐藏没有group id 的 $.each(this.innerData.saveDom, function (k, v) { var data = $(v).attr('group') if(!data) { $(v).hide() } }) } 复制代码
loadMore加载更多
Iboot.prototype.loadMore = function(list){ var _this = this // 把上次隐藏groupid的加进去 var coc = [] $.each(this.innerData.saveDom, function (i, v) { var data = $(v).attr('group') if(!data) { if(!v) { return } var img = $(v).find('img') coc.push({ src: img.attr('src'), alt: img.attr('alt'), }) _this.innerData.saveDom.splice(i, 1) } }) list = coc.concat(list) this.beforeLoad() this.loader(list, function (cp, img) { _this.render(cp, img) }, function (cp, img, error) { }, function () { _this.afterLoad() }) } 复制代码
最后把方法抛出到全局
root.Iboot = function(ele, config){ return new Iboot(ele, config).init(); } 复制代码
大功告成,前前后后大概用了4个多小时,头发要掉光了。。。学无止境,告辞!
以上所述就是小编给大家介绍的《4个小时实战木桶布局》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 「Flask实战」鱼书项目实战一
- 「Flask实战」鱼书项目实战三
- 「Flask实战」鱼书项目实战四
- 「Flask实战」鱼书项目实战六
- RocketMQ实战系列从理论到实战
- 「Flask实战」flask鱼书项目实战二
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
PHP与MySQL权威指南
吴津津、田睿、李云、刘昊 / 机械工业出版社华章公司 / 2011-10 / 118.00元
PHPChina官方出品,Discuz!创始人戴志康、UCHome创始人李国德、ThinkPHP创始人刘晨、PHPCMS项目负责人王参加等联袂推荐。 本书是目前为止最全面的关于PHP与MySQL开发技术的书籍之一,系统而全面地讲解了PHP与MySQL技术的方方面面,适合初中级的PHP程序员系统地学习;本书也是目前为止首本系统而深入地讲解UCenter、Discuz!、UCHome、ShopN......一起来看看 《PHP与MySQL权威指南》 这本书的介绍吧!