4个小时实战木桶布局
栏目: JavaScript · 发布时间: 7年前
内容简介:最近公司有个项目要用到木桶布局,找了很多插件都感觉不合适,于是决定自己撸一个。已经开源到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鱼书项目实战二
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Programming Python
Mark Lutz / O'Reilly Media / 2006-8-30 / USD 59.99
Already the industry standard for Python users, "Programming Python" from O'Reilly just got even better. This third edition has been updated to reflect current best practices and the abundance of chan......一起来看看 《Programming Python》 这本书的介绍吧!
Base64 编码/解码
Base64 编码/解码
RGB CMYK 转换工具
RGB CMYK 互转工具