实现页面滑动触底需要获取视口大小、已滚动高度、可滚动高度,可在页面注册scroll事件获取。 从下图可看出触底需要 已滚动高度 + 可视窗口高度 >= 可滚动区域 即可算出是否触底
组件中直接实现触底刷新
import {onMounted, onUnmounted } from 'vue'
const scroll = () => {
const scrollHeight = document.documentElement.scrollHeight // 可滚动区域的高
const scrollTop = document.documentElement.scrollTop // 已经滚动区域的高
const clientHeight = document.documentElement.clientHeight // 可视区高度
// 以滚动高度 + 当前视口高度 >= 可滚动高度 = 触底
if (clientHeight + scrollTop >= scrollHeight) {
// 此处可书写触底刷新代码
console.log('触底')
}
}
// 挂载dom后注册scroll事件
onMounted(() => window.addEventListener('scroll', scroll))
// 页面销毁移除scroll事件
onUnmounted(() => window.removeEventListener('scroll', scroll))
!!!注意
以上代码是基于window窗口滚动获取的值,如果组件中元素设置高度,并设置overflow-y: auto; 则滚动的是对应元素,此时需要获取滚动元素并注册scroll事件
<template>
<div class="collect" ref="coRef">
<template v-for="item in 100" :key="item">
<div class="item"></div>
</template>
</div>
</template>
<script setup>
import { ref, onMounted, onUnmounted } from 'vue'
const coRef = ref(null)
const scroll = () => {
const scrollHeight = coRef.value.scrollHeight // 可滚动区域的高
const scrollTop = coRef.value.scrollTop // 已经滚动区域的高
const clientHeight = coRef.value.clientHeight // 可视区高度
// 以滚动高度 + 当前视口高度 >= 可滚动高度 = 触底
if (clientHeight + scrollTop + 1 >= scrollHeight) { // 滚动区域很高时会有误差只需加上1px即可
// 此处可书写触底刷新代码
console.log('触底')
}
}
// 挂载dom后注册scroll事件
onMounted(() => {
coRef.value.addEventListener('scroll', scroll)
})
// 页面销毁移除scroll事件 -> 此处不用移除scroll事件,此页面销毁对应的coRef元素也随之销毁
//onUnmounted(() => coRef.value.addEventListener('scroll', scroll))
</script>
<style lang="less" scoped>
.collect {
height: 100vh;
overflow-y: auto;
background-color: #42b780;
.item {
height: 100px;
border: 1px solid #ccc;
}
}
</style>
封装hooks
将以上两种情况结合封装更加通用的hooks
import { ref, onMounted, onUnmounted } from 'vue'
import { throttle } from 'lodash'
export default function useSroll(elRef) {
// 默认监听window上的scroll事件
let el = window
const isBottom = ref(false) // 是否触底
const scrollHeight = ref(0) // 可滚动区域的高
const scrollTop = ref(0) // 已经滚动区域的高
const clientHeight = ref(0) // 可视区高度
// 使用lodash实现节流效果
const scroll = throttle(() => {
if (!elRef) {
scrollHeight.value = document.documentElement.scrollHeight
scrollTop.value = document.documentElement.scrollTop
clientHeight.value = document.documentElement.clientHeight
} else {
scrollHeight.value = el.scrollHeight
scrollTop.value = el.scrollTop
clientHeight.value = el.clientHeight
}
// 以滚动高度 + 当前视口高度 >= 可滚动高度 = 触底
if (scrollTop.value + clientHeight.value >= scrollHeight.value) {
isBottom.value = true
}
}, 100)
// 页面初始化注册scroll事件
onMounted(() => {
// dom 挂载时判断外界是否传入dom实例
if (elRef) el = elRef.value
el.addEventListener('scroll', scroll)
})
// 页面销毁时移除scroll事件
onUnmounted(() => {
el.removeEventListener('scroll', scroll)
})
return {
isBottom,
scrollHeight,
scrollTop,
clientHeight,
}
}
组件中使用
组件中使用watch监听isBottom变化即可
import { watch } from 'vue'
import useSroll from '@/hooks/useSroll'
const { isBottom, scrollHeight, scrollTop, clientHeight } = useSroll() // 此处可传入滚动的dom实例
// 监听isBottom值变化
watch(isBottom, (newIsBottom) => {
// newIsBottom如果true
if (newIsBottom) {
// 书写触底刷新代码, 记得刷新重置isBottom为false
}
})