import { onActivated, onDeactivated, onMounted, onUnmounted } from "vue";
import { throttle } from "underscore";
const scrollstate = {
state: true,
_state: true,
};
const handlefn = (fn, timeout = 1000, throttleTimeout = 200) => {
Object.defineProperty(scrollstate, "state", {
set: function (newVal) {
if (newVal === false) {
this._state = newVal;
setTimeout(() => {
this._state = true;
}, timeout);
} else {
this.state = false;
console.error(
'如果你想阻止滚轮事件重复触发,请设置state为false(为了防止副作用,state已设置为false),"scrollstate.state"不被允许设置除false以外的其他值'
);
}
},
get: function () {
return this._state;
},
});
if (scrollstate.state) {
const stateboolean = fn(scrollstate);
if(stateboolean === false){
scrollstate.state = stateboolean
}else if(stateboolean){
scrollstate.state = false
console.error(
'事件函数返回值被当做阻止时间重复触发的状态,只能返回false,为防止副作用,已默认将状态设置为
false,请及时修改代码'
)
}
}
};
export function addScrollListener(fn, element = window, throttleTimeout = 200) {
const temFn = throttle(() => handlefn(fn), throttleTimeout);
function ifwindow() {
onActivated(() => {
element.addEventListener("scroll", temFn);
});
onDeactivated(() => {
element.removeEventListener("scroll", temFn);
});
onUnmounted(() => {
element.removeEventListener("scroll", temFn);
});
onMounted(() => {
element.addEventListener("scroll", temFn);
});
}
if(element === window){
ifwindow()
}else{
onMounted(() => {
element.value.addEventListener("scroll", temFn);
});
}
}
以上是工具源代码,工具依赖于underscore进行节流处理,请以下命令进行下载
npm i underscore
使用教程
// 1.通过此文件导出addScorllListener函数
import { addScrollListener } from './hooks/addScrollListener';
//2 函数传入四个参数
//2.1 第一个参数为滚动事件触发的函数,
//2.2 第二个为监听哪一个元素的滚动事件
// 如果不传默认设置为浏览器,并且在挂载组件或keep-alive时进入组件的时候添加监听,
// 卸载组件或keep-alive时离开组件的时间移除监听,防止影响其他组件正常功能
//2.3 第三个参数为节流间隔时间,默认为200毫秒
//2.4 第四个参数后面说
addScrollListener(fn,element,throttleTimeout,statetimeout)
//3 传入的第一个参数函数,也会接受一个参数,此参数为此工具状态
// 工具内部会时刻监听state值的变化,当state值变成false时,监听事件停止触发,并开启一个定时器
// 定时器结束时,才能将state状态改回为true,然后继续监听
// addScrollListinner函数的第四个参数就是这个定时器的倒计时时间,默认为 1s
// 改变状态的方法有两种,如下面代码
const fn = (state)=>{
//3.1 可以直接通过参数修改
state = false
//3.2 也可以通过return false 可以改变state为false
return false
}
//注意!!!! 在你认为会重复触发监听器时间的位置上将state改为false
// 比如监听到滚动到底部时,完成该事件,并将状态改为false,防止重复触发
//注意!!!! 不可以将state改为除false以外的任何值,会报错,报错的同时会将state修改为false,并开启定时器
//注意!!!! 使用ref对象传递dom时,请主要要传递ref对象,而不是ref.value
// 具体原因可以看我的另一篇文章《ref详解》
我的另一篇文章----ref详解
如果第一次网络请求成功之前,无列表数据,导致无法撑起浏览器窗口,会造成开始时就在浏览器底部,滚动事件会直接触发一次,解决方法可以通过settimeout,或者判断列表数据中是否有值等方式,延缓此函数执行(延缓添加监听)