XZ_HTML5之实现瀑布流的3种方式

瀑布流的特点是:1、等宽;2、高度不一样;2、每一个盒子相对于父标签定位;4、第二行第一个元素拼接到第一行最矮的盒子底下;

瀑布流的布局原理:子盒子相对于父盒子的一个定位,所以,先将第一行排列好,求出每个盒子的高度,如果是第一行的盒子,加入到数组中,如果是其他行的,遍历查找上一行的最矮盒子,把当前盒子相对于最矮盒子进行一下定位,然后更新数组最矮盒子的高度;

实现思路:每一个盒子,包含上边距和左边距,这样就省去计算图片与图片之间的间距了。这是比较简单一点的,如果需要在图片上添加赞或者购买等按钮或其他介绍信息的话,再当前的基础上再进行一些修改即可。


因为每个盒子都是等宽的,所以,布局的时候,只需要知道每个盒子距离浏览器的上边距和左边距是多少,左边距只需要当前盒子的索引 * 每个盒子的宽度即可,上边距就是最矮盒子的高度;

实现方式
1、用JS实现瀑布流布局
2、用CSS3
3、用jQuery

代码的地址

方式一:JS实现瀑布流布局
js实现瀑布流布局代码:
// 实现瀑布流布局
function waterFall ( parent , child ) {
// 最需要的两个参数:父盒子和子盒子
// -----子盒子在父盒子中居中-----
// 获取屏幕宽度,然后除以图片宽度,得到图片的列数
// 1.1 拿到父盒子中所有的子盒子
var allbox = $(parent).getElementsByClassName(child);

// 1.2 求出盒子的宽度 202
var boxWidth = allbox[ 0 ].offsetWidth;

// 1.3 动态求出浏览器的宽度,包括边线的宽
var screenWidth = document .body.offsetWidth;

// 1.4 求出列数并取整
var columns = Math.floor(screenWidth / boxWidth);

// 1.5 让父标签居中
$(parent). style .width = boxWidth * columns + 'px' ;
$(parent). style .margin = '0 auto' ;

// ---- 子盒子定位 ----
// 1.1 高度数组
var heightArr = [];
// 1.2 遍历所有的盒子,将每个盒子的高度放在数组中
for ( var i = 0 ;i < allbox.length;i ++ ) {
// 1.2.1 求出单个盒子的高度
var boxHeight = allbox[i].offsetHeight;
if (i < columns) {
// 取出第一行的盒子
heightArr.push(boxHeight);
} else
// 需要定位的盒子
// 1.2.1 求出最矮盒子的高度
var minBoxHeight = Math.min.apply( this ,heightArr);
// 1.2.2 求出最矮盒子对应的索引
var minBoxIndex = getMinBoxIndex(minBoxHeight,heightArr);
// 1.2.3 盒子定位
allbox[i]. style . position = 'absolute' ;
allbox[i]. style .top = minBoxHeight + 'px' ;
allbox[i]. style .left = minBoxIndex * boxWidth + 'px' ;
// 1.2.4 更新数组中最矮盒子的高度
heightArr[minBoxIndex] += boxHeight;
}
}

console .log(heightArr);
}

// 取出数据中最矮盒子对应的索引
function getMinBoxIndex ( val , arr ) {
for ( var i in arr) {
if (val == arr[i]) return i;
}
}

实现瀑布流布局页面滚动加载的原理:
当(最后一个盒子高度的一半 + 头部偏离位置) > (浏览器的高度+页面偏离屏幕的高度)时,就加载下一页的数据,从最外层往里一层一层的创建盒子,将里层盒子加到外层盒子的里面,然后再将下一页的数据进行瀑布流布局;
// 滚动加载盒子
window . onscroll = function () {
// alert(0);
// 条件是否加载
if (checkWillLoad()) {
// 假数据
var data = { 'dataImg' : [{ 'img' : '1.jpg' },{ 'img' : '10.jpg' },{ 'img' : '13.jpg' },{ 'img' : '15.jpg' },{ 'img' : '17.jpg' },{ 'img' : '19.jpg' }]}
// 加载数据
for ( var i = 0 ;i < data.dataImg.length;i ++ ) {
// 创建最外面的盒子
var newBox = document .createElement( 'div' );
newBox.className = 'box' ;
// 拿到父盒子,并插入
$( 'main' ).appendChild(newBox);
// 创建里面的盒子
var newPic = document .createElement( 'div' );
newPic.className = 'pic' ;
// 插入到父盒子,
newBox.appendChild(newPic);
// 创建img
var newImg = document .createElement( 'img' );
newImg.src = 'imgs/' + data.dataImg[i].img;
newPic.appendChild(newImg);
}
// 瀑布流布局
waterFall( 'main' , 'box' );
}
}
}


实现的页面效果:


方式二:CSS实现瀑布流布局
css实现瀑布局布局的大致框架的一个代码,在最外层的div的css布局中写如下代码即可,这只能实现一个瀑布流布局:
# main {
/*多栏布局:设置栏宽*/
- webkit - column - width : 202 px;
- moz - column - width : 202 px;
column - width : 202 px;
}

方式三:jQuery实现瀑布流布局
jQuery实现瀑布流布局与CSS的不同在于,语言的的不同,思路都是一样的,只是js代码中换了一种写法

实现代码:
// 当页面加载完毕
$( window ).on( 'load' , function () {
// 1.实现瀑布流布局
waterFall();
// 2.实现滚动加载
$( window ).on( 'scroll' , function () {
// 判断是否加载
if (checkWillLoad()) {
// 造数据
var data = { 'dataImg' :[{ 'img' : '1.jpg' },{ 'img' : '10.jpg' },{ 'img' : '13.jpg' },{ 'img' : '15.jpg' },{ 'img' : '17.jpg' },{ 'img' : '19.jpg' }]};
// 遍历创建盒子,创建了一个div,设置类名为box,
$.each(data.dataImg, function ( index , value ) {
var newBox = $( '<div>' ).addClass( 'box' ).appendTo($( '#main' ));
var newPic = $( '<div>' ).addClass( 'pic' ).appendTo($(newBox));
$( '<img />' ). attr ( 'src' , 'imgs/' + $(value). attr ( 'img' )).appendTo($(newPic));
})
// 实现瀑布流布局
waterFall();
}
});

// alert(134);
});

// 实现瀑布流布局
function waterFall (){
// 拿到所有的盒子
var allBox = $( '#main .box' );
// alert($(allBox).length);
// 取出其中一个盒子的宽度,outerWidth带边距的宽度 202
var boxWidth = $(allBox).eq( 0 ).outerWidth();
// 取出屏幕的宽度
var screenWidth = $( window ).width();
// 求出列数
var cols = Math.floor(screenWidth / boxWidth);
// 父标签居中
$( '#main' ). css ({
width:cols * boxWidth + 'px' ,
margin: '0 auto' })
// 对子盒子定位
var heightArr = [];
// 遍历
$.each(allBox, function ( index , value ) {
// 取出单独的盒子高度
var boxHeight = $(value).outerHeight();
// 判断,
if (index < cols) { 
// 第一行盒子
heightArr[index] = boxHeight;
} else
// 剩余行的盒子 // 取出高度数组中最矮的高度
var minBoxHeight = Math.min.apply( null ,heightArr);
// 取出最矮高度对应的索引
var minBoxIndex = $.inArray(minBoxHeight,heightArr);
// 定位
$(value). css ({
position : 'absolute' ,
top:minBoxHeight + 'px' ,
left:minBoxIndex * boxWidth + 'px' });
// 更新数组中最矮的高度
heightArr[minBoxIndex] += boxHeight;
}
});
// alert(cols);
}

// 设置滚动条件
function checkWillLoad () {
// 拿到最后一个盒子
var lastBox = $( '#main>div' ).last();
// 取出最后一个盒子高度的一半 + 头部偏离位置
var lastBoxDis = $(lastBox).outerHeight() + $(lastBox).offset().top;
// 求出浏览器高度
var clientHeight = $( window ).height();
// 求出页面偏离浏览器的高度
var scrollTopHeight = $( window ).scrollTop();

console .log(lastBoxDis,clientHeight,scrollTopHeight);
// 比较返回
return lastBoxDis <= clientHeight + scrollTopHeight;
}


`xz_dec_run` 是 XZ 解压缩库中的一个关键函数,用于执行实际的解压缩操作。在某些情况下,调用 `xz_dec_run` 时可能会遇到错误,例如返回 `XZ_DATA_ERROR` 或 `XZ_BUF_ERROR`,这通常表示输入数据损坏、缓冲区不足或解压缩程配置不当。这类问题在嵌入式系统中尤为关键,尤其是在使用 MTD(Memory Technology Device)设备时,如 NAND 或 NOR Flash 存储器,数据完整性问题可能导致解压缩失败 [^3]。 ### 常见问题与解决方法 #### 1. **输入数据损坏或不完整** 如果输入在传输或存储过程中被损坏,`xz_dec_run` 会返回 `XZ_DATA_ERROR`。这通常发生在固件更新失败、文件系统损坏或存储介质错误的情况下。 **解决方法:** - 确保输入数据完整无损,可以通过校验和(如 CRC32)验证数据完整性。 - 在嵌入式系统中,启用 MTD 层的 ECC 校正功能,确保数据读取过程中能够自动修复位翻转问题 [^3]。 #### 2. **缓冲区大小不足** `xz_dec_run` 需要足够的输入和输出缓冲区来处理数据。如果缓冲区太小,可能导致 `XZ_BUF_ERROR`。 **解决方法:** - 确保输入缓冲区 (`in` 指针) 和输出缓冲区 (`out` 指针) 足够大,建议使用 4KB 或更大的缓冲区。 - 动态分配缓冲区以适应不同大小的数据块。 #### 3. **解压缩器未正确初始化** 调用 `xz_dec_run` 前必须正确调用 `xz_dec_init()` 初始化解压缩器。如果跳过此步骤或初始化失败,可能导致运行时错误。 **解决方法:** - 在调用 `xz_dec_run` 之前,确保 `xz_dec_init()` 成功执行。 - 检查返回值,如果初始化失败,应释放资源并返回错误码。 #### 4. **流式处理不当** `xz_dec_run` 支持流式解压缩,但如果未正确处理输入/输出指针和缓冲区状态,可能导致解压缩不完整或死循环。 **解决方法:** - 正确管理 `in_pos` 和 `out_pos` 指针,确保每次调用 `xz_dec_run` 时更新缓冲区偏移量。 - 在读取完所有输入数据后,检查是否所有输出数据都已处理完毕。 #### 5. **内存分配失败** `xz_dec_run` 可能依赖动态内存分配,如果内存不足,可能导致解压缩失败。 **解决方法:** - 使用自定义内存分配器(如 `ISzAlloc` 接口)来管理内存分配,确保在资源受限的环境中也能正常工作 [^2]。 - 在嵌入式系统中预留足够的内存用于解压缩操作。 ### 示例代码:使用 xz_dec_run 解压缩 ```c #include <stdio.h> #include <stdlib.h> #include "xz.h" #define BUF_SIZE 4096 int decompress_xz(const char *in_file, const char *out_file) { FILE *fin = fopen(in_file, "rb"); FILE *fout = fopen(out_file, "wb"); if (!fin || !fout) { return -1; } struct xz_dec *state; struct xz_buf buf; uint8_t in[BUF_SIZE]; uint8_t out[BUF_SIZE]; state = xz_dec_init(XZ_DYNALLOC, 0); if (!state) { fclose(fin); fclose(fout); return -1; } buf.in = in; buf.in_size = 0; buf.out = out; buf.out_size = BUF_SIZE; while (1) { size_t in_read = fread((void *)buf.in + buf.in_pos, 1, BUF_SIZE - buf.in_pos, fin); buf.in_size = buf.in_pos + in_read; enum xz_ret ret = xz_dec_run(state, &buf); fwrite(out, 1, buf.out_pos, fout); buf.out_pos = 0; if (ret == XZ_STREAM_END) { break; } else if (ret != XZ_OK) { xz_dec_end(state); fclose(fin); fclose(fout); return -1; } if (in_read == 0 && buf.in_pos == buf.in_size) { break; } } xz_dec_end(state); fclose(fin); fclose(fout); return 0; } ``` ### 调试建议 - 使用日志记录每次调用 `xz_dec_run` 的返回值和缓冲区状态,有助于定位问题。 - 在嵌入式设备中,可以尝试使用 `xz` 工具链在主机端验证压缩文件的完整性。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值