先上github地址:插件源码
百度前端在几个月前发布了一个针对前端技术培训的任务:IFE(百度前端技术学院)。和几个小伙伴一起完成了部分任务,第四阶段是三个综合性的任务,博主先完成了其中的相册布局任务。写的并不是很完善,博主技术有限,大家就随便看看吧。
瀑布流布局
布局方式
顾名思义,瀑布流布局就是相册中图片像瀑布一样,从高到低按顺序插入到相册中。如下图,一直保证下一张图片会被插入到当前最短的一道图片流当中。如果博主没有记错的话,在Instagram没有被墙的时候用的就是这种布局方式,这种布局方式非常适合动态加载图片,当滚动条拉到最下面的时候可以通过Ajax动态加载下一轮图片。
目标布局方式:
布局方式的实现效果:
实现方法
由于插件设计的时候采用的API方式:
<div class="lucas-album" category="WATERFALL">
<img src="./images/img1.jpg" />
<img src="./images/img2.jpg" />
<img src="./images/img3.jpg" />
<img src="./images/img4.jpg" />
</div>
为div元素添加类以及category属性,当category为WATERFALL的时候自动调用瀑布流的构造函数,提取所有img元素的URL,并且移除所有的图片元素来进行重新挂载。对于每一张图片,只需要简单的计算当前所有列的高度并且返回最短列,将这张图片挂载到该列的下方就可以了。
有一点需要注意的是,如果采用这种方法,需要让图片的宽度恒定,高度进行自动缩放。尽量所有高度以及宽度采用相对形式,对于以后的分辨率适配有很大帮助。
并且在进行最短列计算的时候,一定要注意window.onload,如果不是在文档加载完毕之后执行脚本,你会发现在chrome和opera里面很多的高度都被计算为18px。博主因为这个问题郁闷了好久。
//瀑布流的less代码
.waterfall-layout (@image-gap,@columns){
width: (100%-@image-gap*(@columns+1))/@columns;
height: auto;
padding-left: @image-gap;
padding-top: @image-gap;
float: left;
}
木桶布局
实际上木桶布局这种布局方式是百度前端部门自己起的一个名字,如果你搜索一下的话就会发现并没有和这种布局方式有关的内容。这种布局方式在很多图片网站上很常见,比如500px,flickr这种图片网站。这种布局的主要形式是将所有图片都保持其原本的长宽比,并且每一行的所有图片都具有相同的高度,并且所有的行高度都相近。
目标布局方式:
布局方式的实现效果
实现方法
这种布局方式主要需要保证每张图片的长宽比保持恒定,所以在提取每个图片元素的时候需要计算该图片的长宽比并且保存下来,并且通过保证每行的总长宽比保持在一个可控的范围之内,使每张图片不会有比较大的拉伸。通过动态设置每行的高度来保证行内图片长宽比不变(这里虽然不建议在js中修改元素的样式,但是博主还没有想到不使用js来实现这种布局的方法,所以只能尽量少的使用这种方法来控制样式了)。
Barrel.prototype.setRows = function() {
var count,
tmp = imgRatio; //图片长宽比数组
for (var i = 0; i<rows ; i++) {
rowsArray[i] = document.createElement('ul');
rowsArray[i].setAttribute('class','barrel');
contentElement.appendChild(rowsArray[i]);
count = 0;
for (var j=0;j<imageCount;j++) {
if (tmp[j] !== null && ((count + tmp[j].ratio) < rowsWidth)) {
this.createImage(tmp[j].id, i);
count += tmp[j].ratio;
tmp[j] = null;
}
}
rowsArray[i].style.height = width/count+'px';
//设置每一行的高度,使行内所有的图片都保持其原本的长宽比
}
};
拼图布局
这种布局方式是将几个图片拼成一个矩形,我这里的实现方法是自动计算图片数量自动布局,当然也可以提供接口让用户选择布局方式,因为只设计了1-6张图片的拼图方式,所以当图片大于六张的话,每六张图片采用一次6图布局,剩余的自动计算布局。为了尽量少的使用js来控制样式,这里采用为每个图片组添加类的方法来实现布局。
比如当图片为5张的时候,这些图片的包裹div就设置puzzle-5类,其中的图片使用css选择器来修改样式。
5张图片时的less
.puzzle-div {
div {
float: left;
overflow: hidden;
}
.vertical {
background-repeat: no-repeat;
background-size: 100% auto;
background-position: center center;
}
.horizontal {
background-repeat: no-repeat;
background-size: auto 100%;
background-position: center center;
}
}
.puzzle-size (@height,@width) {
height: @height;
width: @width;
}
.puzzle-5 {
.puzzle-div();
div:nth-child(1) {
.puzzle-size(66.5%,66.7%);
}
div:nth-child(2),div:nth-child(3) {
.puzzle-size(50%,33.3%);
}
div:nth-child(3) {
float:right;
}
div:nth-child(4),div:nth-child(5){
.puzzle-size(33.3%,33.3%);
}
}
对于图片来说,为了保证图片的长宽比,必须要对图片进行裁剪,否则图片会在对应的div里面被拉伸的很丑。。这就需要考虑裁剪的位置。如果裁剪的不好,就会使图片需要显示的地方被裁剪掉。如果直接使用img元素,由于其父元素div需要左浮动来保证布局,这样的话img元素的右侧都会被裁剪掉,如何保证其被居中裁剪呢?博主采用了一个取巧的办法:拼图布局时,将图片的url设置为浮动div元素的背景图片,这样可以使用上面less中的.puzzle-div类中的background-position属性来设置背景图片居中,这样就可以裁剪出来棒棒哒图片啦。
上面less中的.vertical和.horizontal可能会让大家疑惑,这两个类是用来保证图片可以充满整个浮动div的。如果图片是竖屏的,那么就要保证其宽度为100%(也就是和div的宽度一样),高度设置为auto(自动),相反,如果图片是横屏的,就要保证其高度为100%。
下图左半部分是六图和两图的两种布局方式,两图中采用的clip进行斜角裁剪,具体裁剪方法请移步这里:裁剪出你想要的形状
遮罩
全屏遮罩就比较简单了,大家可以下载源码下来看看就好,遮罩动画效果采用我另一篇博文里面的css transition动画效果,依然是JavaScript为元素添加类,css控制动画的方法。为.overlay添加hidden或者overlayShow类来隐藏和弹出遮罩。
.overlay {
width: 0;
height: 100%;
background-color: grey;
position:fixed;
z-index: 20;
opacity: 0;
.transition(all,1s);
}
.overlayShow {
.show(0.5,100%);
}
.transition (@action,@seconds) {
-webkit-transition: @action @seconds;
-moz-transition: @action @seconds;
-ms-transition: @action @seconds;
-o-transition: @action @seconds;
transition: @action @seconds;
}
.show (@opacity,@width) {
.transition(all,1s);
opacity: @opacity;
width: @width;
}
.hidden {
.transition(all,1s);
opacity: 0;
width: 0;
}
总结
其实相册布局是一个很基础的东西,但是需要脚本和CSS的配合来完成,博主为了尽可能少的使用element.style这样的方式来设置样式费尽脑筋,诚然这样可以很简单的完成许多计算,但是大神N. Zakas的Maintainable JavaScript中讲了UI层的松耦合,尽量将CSS从JavaScript中抽离出来,这样在以后进行代码维护的时候会很方便,所以现在多动动脑筋可能以后会少许多麻烦。