文章目录
- 使用
- 实现
- waterfall index文件
- kl-waterfall-item
使用
<kl-waterfall
@touchBottom="touchBottom"
:distant="50"
:cope="4"
:margin="10"
:sleep="200"
>
<kl-waterfall-item v-for="(item, index) in state.imgs" :key="index" border>
<div class="item">
<img :src="item.url" alt="" />
<p>
{{ item.content }}
</p>
</div>
</kl-waterfall-item>
</kl-waterfall>
实现
waterfall index文件
<template>
<div class="kl-waterfall" ref="waterRef">
<slot></slot>
</div>
</template>
<script lang="ts" setup>
import {
onMounted,
reactive,
ref,
onBeforeUpdate,
onBeforeUnmount,
} from "vue-demi";
import { throttle } from "../../utils/tool";
const props = defineProps({
cope: {
type: Number,
default: 5,
required: false,
},
margin: {
type: Number,
default: 10,
required: false,
},
sleep: {
type: Number,
default: 200,
required: false,
},
distant: {
type: Number,
default: 200,
required: false,
},
});
const emits = defineEmits(["touchBottom"]);
const waterRef = ref();
interface i_state {
childWidth: number;
heightArr: number[];
max: number;
top: number;
clientHeight: number;
isBottom: boolean;
lastLength: number;
timer: any;
}
const state = reactive<i_state>({
childWidth: 0,
heightArr: [],
max: 0,
top: 0,
clientHeight: 0,
isBottom: false,
lastLength: 0,
timer: null,
});
const handleScroll = throttle(() => {
var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
if (
state.max + state.top <= scrollTop + state.clientHeight + props.distant &&
!state.isBottom
) {
state.isBottom = true;
emits("touchBottom", {
code: 200,
msg: "触底了",
});
}
}, 50);
onMounted(() => {
const width = waterRef.value.clientWidth;
state.top = waterRef.value.offsetTop;
state.clientHeight = document.documentElement.clientHeight;
let childWidth = Math.ceil(
(width - (props.cope + 1) * props.margin) / props.cope
);
state.childWidth = childWidth;
handleEvent();
window.addEventListener("scroll", handleScroll, true);
});
onBeforeUnmount(() => {
clearTimeout(state.timer);
state.timer = null;
});
function handleEvent() {
clearTimeout(state.timer);
state.timer = null;
state.timer = setTimeout(() => {
let childs = waterRef.value.children;
let childLength = childs.length;
for (let i = state.lastLength; i < childLength; i++) {
childs[i].style.width = state.childWidth + "px";
}
state.isBottom = false;
for (let i = state.lastLength; i < childLength; i++) {
let height: number = Number(childs[i].offsetHeight) || 0;
if (i < props.cope) {
childs[i].style.top = props.margin + "px";
childs[i].style.left =
(i + 1) * props.margin + i * state.childWidth + "px";
state.heightArr.push(props.margin + height);
} else {
let minHeight = Math.min(...state.heightArr);
let minHeightIndex = state.heightArr.findIndex((item) => {
return item == minHeight;
});
childs[i].style.top =
state.heightArr[minHeightIndex] + props.margin + "px";
childs[i].style.left =
(minHeightIndex + 1) * props.margin +
minHeightIndex * state.childWidth +
"px";
state.heightArr[minHeightIndex] = minHeight + props.margin + height;
}
}
let max = Math.max(...state.heightArr);
state.max = max;
waterRef.value.style.height = max + props.margin + "px";
state.lastLength = childLength;
}, props.sleep);
}
onBeforeUpdate(() => {
handleEvent();
});
</script>
<style lang="scss" scoped>
.kl-waterfall {
display: block;
position: relative;
}
.kl-loading {
height: 50px;
text-align: center;
color: #666;
}
</style>
kl-waterfall-item
<template>
<div
:class="[
'kl-clearFix',
'kl-waterfall-item',
border ? 'kl-waterfall-item-border' : '',
]"
>
<slot />
</div>
</template>
<script lang="ts" setup>
defineProps({
border: {
type: Boolean,
default: false,
required: false,
},
});
</script>
<style lang="scss" scoped>
.kl-waterfall-item-border {
box-shadow: 0 0 5px #555;
display: block;
position: absolute;
}
</style>
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)