您的位置:首页 > Web前端 > JQuery

详解网页中的瀑布流显示效果

2017-04-21 20:15 507 查看

网页实现瀑布流显示效果

本网页基于JQuery框架。

瀑布流是什么?

瀑布流,又称瀑布流式布局。是比较流行的一种网站页面布局,视觉表现为参差不齐的多栏布局,随着页面滚动条向下滚动,这种布局还会不断加载数据块并附加至当前尾部。——摘自百度百科“瀑布流”

瀑布流布局的几个特征:

1. 单元格宽固定,高不固定。

2. 每单元格从左到右依次排列,当第一行排满后,剩余的单元格依次排在当前最短的列后。

单元格为什么可以高低错落地显示?

主要运用了元素的绝对定位,而如何正确的将不同元素定位在各自的位置,就是实现瀑布流的关键。

如何实现?

先简单的搭建网页布局,这里只需写一个单元格的代码,后续会在js中添加剩余的单元格。

单元格的内容自定,这里作为一个简单的demo仅插入一张图片,图片路径同样后续在js中添加 。

<div id="wf">
<div class="unit">
<img />
</div>
</div>


设置页面的CSS样式。

*{
padding: 0;
margin: 0;
}
#wf{
margin-top: 50px;
//将外层div设为相对定位,单元格才会相对于外层进行绝对定位
position: relative;
}
#wf .unit{
position: absolute;
border: 1px solid black;
}
#wf .unit img{
//因下js中单元格宽度设为250px,故此将图片设为230px
width: 230px;
//四周各设10px内边距
padding: 10px;
}


以上完成了HTML和CSS的编写,接下来是js对于功能的实现。

设定几个全局变量

这些全局变量在接下来的编码过程中会用到,变量值可根据个人偏好酌情设置。

//单元格宽度
var unit_wid = 250;
//单元格间距
var unit_edge = 30;
//瀑布流整体大致占比
var unit_rate = 0.8;
//插入单元格个数(原HTML中已设一个,故实际个数再+1)
var unit_num = 9;


添加其余的单元格到HTML中。

//该方法需在DOM加载完成后立即执行
function set_unit(){
for (var i = 0;i < unit_num;i++){
var temp = '<div class="unit"><img /></div>';
$('#wf').append(temp);
}
}


为每个单元格设置图片路径。

//该方法需在set_unit()方法完成后执行
function set_img () {
var img = $('#wf .unit img');
for (var i = 0;i < img.length;i++){
img.eq(i).attr('src','images/' + (i+1) + '.jpg');
}
}


对瀑布流整体居中布局。

1). 确定整个瀑布流的页面大致占比;

2). 根据瀑布流整体宽度计算可容纳的单元格列数;

3). 计算出瀑布流整体左右外边距,使其居中显示。

var wf_wid = $(window).width() * 0.8;
var num = Math.floor(wf_wid / unit_wid);
//整体宽度包含num个单元格宽及num-1个间距
var wf_edge = ($(window).width() - (unit_wid * num + unit_edge * (num - 1))) / 2;


新建数组,存放每一列的列高度,并为其赋初值0。

var heightList = [];
for (var i = 0;i< num ;i++) {
heightList[i] = 0;
}


写两个接下来会用到的两个方法,一个用来获取数组中的最大值,一个用来获取数组中的最小值及最小值下标。

function getMax (arr) {
var max = arr[0];
for (var i = 1;i < arr.length;i++) {
if (arr[i] > max) {
max = arr[i];
}
}
return max;
}


function getMin (arr) {
var min = arr[0];
var index = 0;
for(var i = 1;i < arr.length;i++){
if (arr[i] < min) {
min = arr[i];
index = i;
}
}
return {min:min,index:index};
}


为每个单元格绝对定位。

每个单元格的定位位置是实现瀑布流的关键,即要先确定单元格定位样式的top与left值。

1)列高度数组中的最小值代表了当前瀑布流最短列的高度(含单元格间距),top值直接设为该值即可。

2)列高度数组中的最小值的下标代表了最短列是哪一列(列号=下标+1),将列号-1后再乘以每一列所占宽度(含列之间边距),再加上瀑布流整体的左边距即为left最后的值。

for (var j = 0;j < $('#wf .unit').length;j++) {
var col_minHeight = getMin(heightList).min;
var col_minIndex = getMin(heightList).index;
var initial_top = col_minHeight;
//计算left值
var initial_left = col_minIndex * (unit_wid + unit_edge) + wf_edge;
var unit = $('#wf .unit');
//为单元格定位
unit.eq(j).css({'top': initial_top + 'px','left': initial_left + 'px'});
//单元格定位完成后更新数组值保证后续定位
//原列高度数组最小值加上当前单元格高度及一个间距为新最小值
heightList[col_minIndex] = col_minHeight + unit.eq(j).height() + unit_edge;
}


所有单元格定位完成后设外层div(#wf)高度。

因所有单元格均采用绝对定位,而绝对定位后的元素会脱离文档流,外层div(#wf)高度不进行设置的话默认为0,如果后续在网页中添加其他内容,新增内容会被瀑布流单元格所遮挡。

//该方法需在所有单元格定位完成后执行,传参:列高度数组的最大值
function set_wfHeight (max) {
//为美观,使瀑布流最高列与底部留有50px间距
var wf_height = max + 50;
$('#wf').css('height',wf_height + 'px');
}


至此瀑布流的初始定位全部完成,把相应代码放入同一个方法内,如下:

//该方法需在set_img()方法完成后执行
function initial_position () {
var wf_wid = $(window).width() * 0.8;
var num = Math.floor(wf_wid / unit_wid);
var wf_edge = ($(window).width() - (unit_wid * num + unit_edge * (num - 1))) / 2;
var heightList = []; for (var i = 0;i< num ;i++) { heightList[i] = 0; }
for (var j = 0;j < $('#wf .unit').length;j++) {
var col_minHeight = getMin(heightList).min;
var col_minIndex = getMin(heightList).index;
var initial_top = col_minHeight;
var initial_left = col_minIndex * (unit_wid + unit_edge) + wf_edge;
var unit = $('#wf .unit');
unit.eq(j).css({'top': initial_top + 'px','left': initial_left + 'px'});
heightList[col_minIndex] = col_minHeight + unit.eq(j).height() + unit_edge;
}
set_wfHeight(getMax(heightList));
}


在浏览器DOM加载完成后按次序执行各方法,如下:

$(document).ready(function(){
set_unit();
set_img();
//设置定位方法延时加载,以确保之前方法都执行完成
setTimeout("initial_position()",500);
});


定位完成后的截图



还可以改进吗?

毫无疑问,现在的瀑布流还有不足,最突出的一点就是:当浏览器可视窗口变化时,我们的瀑布流依然保持原样,要改变其布局只有刷新网页。

所以,接下来我们就使瀑布流可以随着浏览器窗口的变化而变化。

1)要使瀑布流可以变化,首先要解决的就是窗口变化后新的位置的top值与left值,用initial_position()中方法获取即可。

2)获得位置后如何使单元格移动到新位置上?直接修改CSS属性可以,但太过生硬,这里我采用JQuery提供的animate()方法为这一过程设一简单的动画。

$(window).resize(function(){
var wf_wid = $(window).width()*unit_rate;
var num = Math.floor(wf_wid / unit_wid);
var wf_edge = ($(window).width() - (unit_wid * num + unit_edge * (num - 1))) / 2;
var heightList = []; for (var i = 0;i< num ;i++) { heightList[i] = 0; }
for (var j = 0;j < $('#wf .unit').length;j++) {
var col_minHeight = getMin(heightList).min;
var col_minIndex = getMin(heightList).index;
//-----------------------与initial_position()中不同的代码段-----------------------
var new_top = col_minHeight;
var new_left = col_minIndex * (unit_wid + unit_edge) + wf_edge;
var unit = $('#wf .unit');
//为防止窗口变化过快导致动画冲突,在执行动画前,先用stop()方法停止未完成动画
unit.eq(j).stop().animate({'top': new_top + 'px','left': new_left + 'px'},300);
//-----------------------与initial_position()中不同的代码段-----------------------
heightList[col_minIndex] = col_minHeight + unit.eq(j).height() + unit_edge;
}
set_wfHeight(getMax(heightList));
});


最后放一张可动态变化的瀑布流截图



HTML代码:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<style>
*{
margin: 0;
padding: 0;
}
#wf{
margin-top: 50px;
position: relative;
}
#wf .unit{
position: absolute;
border: 1px solid black;
}
#wf .unit img{
width: 230px;
padding: 10px;
}
</style>
</head>
<body>
<div id="wf"> <div class="unit"> <img /> </div> </div>
<script type="text/javascript" src="js/jquery-3.2.0.min.js" ></script>
<script type="text/javascript" src="js/new_file.js" ></script>
</body>
</html>


JavaScript代码:

var unit_wid = 250;
var unit_edge = 30;
var unit_rate = 0.8;
var unit_num = 9;

$(document).ready(function(){
set_unit();
set_img();
setTimeout("initial_position()",500);
});

function initial_position(){
var wf_wid = $(window).width()*unit_rate;
var num = Math.floor(wf_wid / unit_wid);
var wf_edge = ($(window).width() - (unit_wid * num + unit_edge * (num - 1))) / 2;
var heightList = [];

a164
for (var i = 0;i< num ;i++) {
heightList[i] = 0;
}
for (var j = 0;j < $('#wf .unit').length;j++) {
var col_minHeight = getMin(heightList).min;
var col_minIndex = getMin(heightList).index;
var initial_top = col_minHeight;
var initial_left = col_minIndex * (unit_wid + unit_edge) + wf_edge;
var unit = $('#wf .unit');
unit.eq(j).css({'top': initial_top + 'px','left': initial_left + 'px'});
heightList[col_minIndex] = col_minHeight + unit.eq(j).height() + unit_edge;
}
set_wfHeight(getMax(heightList));
}

$(window).resize(function(){
var wf_wid = $(window).width()*unit_rate;
var num = Math.floor(wf_wid / unit_wid);
var wf_edge = ($(window).width() - (unit_wid * num + unit_edge * (num - 1))) / 2;
var heightList = []; for (var i = 0;i< num ;i++) { heightList[i] = 0; }
for (var j = 0;j < $('#wf .unit').length;j++) {
var col_minHeight = getMin(heightList).min;
var col_minIndex = getMin(heightList).index;
var new_top = col_minHeight;
var new_left = col_minIndex * (unit_wid + unit_edge) + wf_edge;
var unit = $('#wf .unit');
unit.eq(j).stop().animate({'top': new_top + 'px','left': new_left + 'px'},300);
heightList[col_minIndex] = col_minHeight + unit.eq(j).height() + unit_edge;
}
set_wfHeight(getMax(heightList));
});

function set_wfHeight (max) {
var wf_height = max + 50;
$('#wf').css('height',wf_height + 'px');
}

function set_img () {
var img = $('#wf .unit img');
for (var i = 0;i < img.length;i++){
img.eq(i).attr('src','images/' + (i+1) + '.jpg');
}
}

function set_unit(){
for (var i=0;i<unit_num;i++) {
var temp = '<div class="unit"><img /></div>';
$("#wf").append(temp);
}
}

function getMax (arr) {
var max = arr[0];
for (var i=1;i<arr.length;i++) {
if (arr[i] > max) {
max = arr[i];
}
}
return max;
}

function getMin(arr){
var min = arr[0];
var index = 0;
for(var i=1;i<arr.length;i++){
if (arr[i] < min) {
min = arr[i];
index = i;
}
}
return {min:min,index:index};
}


如有不足,还请各位看官见谅~
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐