总体思路
经过一系列操作用 <math xmlns="http://www.w3.org/1998/Math/MathML"> "计算属性" \color{red}{"计算属性"} </math>"计算属性"算出来,得到渲染数据列表renderList,在模版中用v-for将数据渲染出来
所需要数据
- 图片渲染数据列表renderList[],里面包含位置信息(top,left);
- 原始数据imageList[] ;
- 当前item宽度itemWidth ;
- 高度列表heightsArray[] ,这里记录着每一列的高度
正文
理解数据是怎么排列的:初始高度列表为[0,0,0,0]这里列表的项数取决于你屏幕的宽度,你想要他是几列(这里你可以根据屏幕的宽度来设置)瀑布流就是几列。
1.高度列表heightsArray[]的计算
原始数据imageList里面第一条数据计算出他的高度(这里讨论数据里面有图片的高度信息),再计算出高度列表里面的最小值的index,更新这个位置上的值(就是原值加上间距),那么此时列表就会变成 [ 200 , 0 , 0 , 0 ]重复上述步骤,最后的这个高度列表heightsArray[]里面的最大值就会是外层container的高度。
获取当前每一项item的宽度:
js
/**
*
* @param {*} containerWidth 容器宽度
* @param {*} colomn 列数
* @param {*} spacing 列间距与行间距相等
* @returns itemwidth 每列的宽度
*/
export function getColumns(containerWidth, colomn, spacing) {
const itemwidth =Math.floor((containerWidth-(colomn+1) * spacing)/colomn)
return itemwidth;
}
2.item位置坐标(left top)
为每一个item添加left,top值
js
/**
* 获取容器的高度以及每一张图片的left top值 坐标值
* !!注意: 图片的坐标值是相对于容器的坐标值
* @param {*} imageList 图片列表[{url:'',width},{}]
* @param imageWidth 图片宽度固定的 按照容器宽度 每列多少来确定
*/
export function getContainerHeightAndImageCoordinate(
imageList,
heightsArray,
spacing,
imageWidth
) {
// 循环遍历图片更新图片的坐标值 top left
imageList.forEach((item, index) => {
const minHeightIndex = getMinHeightIndex(heightsArray);
// 更新图片的坐标值
item.left = minHeightIndex * imageWidth + (minHeightIndex + 1) * spacing;
item.top = heightsArray[minHeightIndex];
// 更新高度列表
// (实际宽度 / 图片宽度) * 图片高度
heightsArray[minHeightIndex] +=(imageWidth/item.width)*item.height+ spacing;
});
return { imageList1:imageList, heightsArray };
}
// 获取最小列的index
/**
*
* @param {*} heights 高度列表Array
* @returns index 返回最小高度的index
*/
export function getMinHeightIndex(heightArray) {
const index = heightArray.findIndex(
(item) => item === Math.min(...heightArray)
);
return index;
}
// 获取最大列的最大高度
/**
*
* @param {*} heights 高度列表Array
* @returns index 返回最小高度的index
*/
export function getMaxHeight(heightArray) {
const index = heightArray.findIndex(
(item) => item === Math.max(...heightArray)
);
return heightArray[index];
}
3.监听原始数据的变化添加位置坐标以及索引值
监听原始数据的变化添加位置坐标以及索引值,同时更新containerheight
js
// 监测props的变化 传入原始数据 部分改变
watch(
() => props.data,
() => {
// 获取当前itemwidth
itemWidth.value = getColumns(
containerwidth(),
colomns.value,
props.rowSpace
);
// 获取加了坐标的数据 以及更新的高度列表
const { imageList1, heightsArray } = getContainerHeightAndImageCoordinate(
props.data,
heightsList.value,
props.rowSpace,
itemWidth.value
);
// 获取高度列表
heightsList.value = heightsArray;
// 获取包含坐标的图像数据列表
newImagelist.value = imageList1;
// 最高高度 这里
containerheight.value = getMaxHeight(heightsList.value);
// 为每一个渲染数据排序
let startlength = 0;
if (image.value.length <= 19) {
props.data.map((item, index) => {
item.idx = index;
image.value.push(item);
});
} else {
startlength = image.value.length;
props.data.map((item, index) => {
item.idx = startlength + index;
image.value.push(item);
});
}
getrenderList();
}
);
4.确定对于原始数据需要截取的startindex,endindex的区间item
确定原始startindex,endindex,初始值可以是你获取第一页数据的个数,比如你第一页展示的图片数据20个,那么就可以设置startindex,endindex为0,19。
根据我们滑动的距离动态的改变startindex,endindex的值 这里会用到上面为每一项图片添加的索引值idx.
这里是核心代码 startindex计算逻辑是取----只要正在滑动过程完结后,当此时有一个item的bottom与上刻线相交那么这个item的idx就是startindex,下刻线同理。上下刻线就是取当前视口高度的一倍,避免在用户缓慢滑动时出现空白。
js
// 获取上下index 核心代码
/**
*
* @param {*} imageList 当前所有图片列表 从你打开页面开始,就一直的增加的图片列表这个列表会随你滑动页面不断push数据进去
* @param {*} scrollTop 这个是当前页面滑动了多少的值
* @param {*} itemwidth 当前屏幕宽度下计算出来的itemwidth
* @returns
*/
export function getIndex(imageList,scrollTop,itemwidth) {
// 获取当前视口高度
const containerWidth = window.innerHeight
let startindex
let endindex
for (let i = 0; i < imageList.length; i++) {
const itemheight = (itemwidth*imageList[i].height) / imageList[i].width;
if (scrollTop-imageList[i].top-itemheight<containerWidth) {
startindex = imageList[i].idx
break;
}
}
for (let i = 0; i < imageList.length; i++) {
const itemheight = (itemwidth*imageList[i].height) / imageList[i].width;
if (imageList[i].top-scrollTop-2*containerWidth>0) {
endindex = imageList[i].idx
break;
}else{
endindex = imageList.length-1
}
}
if(endindex<19){
endindex = 19
}
return{
startindex,endindex
}
}
5.根据startindex,endindex截取image
render1就是我们最终得到的渲染数据,使用v-for渲染数据即可,在v-for数据上添加style
js
const render1 = computed(() => {
return image.value.slice(s1.value, en1.value);
});
总结
逻辑推导:
1.需要有一个渲染列表,这个列表包含元素需要在哪里展示的定位坐标,left,top
2.坐标值怎么来呢?循环遍历每一项,根据每一项的高度累加到一个高度列表中得到left,top。
3.滑动屏幕时怎么动态展示我们想要的某一部分item
4.就需要动态改变startindex,endindex,对元数据进行截取操作赋值给渲染列表。
这里赋值需要用计算属性计算出来不能直接赋值,直接赋值会有闪烁!!!切记,不知道什么原因,有知道的道友望告知!!!!
此致!