vue-hooks-plus
Version:
Vue hooks library
115 lines (114 loc) • 2.87 kB
JavaScript
import { ref, computed, watch, shallowReadonly, readonly } from "vue";
import useBoolean from "../useBoolean";
import useEventListener from "../useEventListener";
import useRequest from "../useRequest";
import { getTargetElement } from "../utils/domTarget";
import { getScrollTop, getScrollHeight, getClientHeight } from "../utils/rect";
const useInfiniteScroll = (service, options = {}) => {
const {
target,
isNoMore,
threshold = 100,
reloadDeps = [],
manual,
onBefore,
onSuccess,
onError,
onFinally
} = options;
const finalData = ref();
const [loadingMore, { set: setLoadingMore }] = useBoolean();
const setFinalData = (mutateData) => {
finalData.value = mutateData;
};
const noMore = computed(() => {
if (!isNoMore)
return false;
return isNoMore(finalData.value);
});
const { loading, run, runAsync, cancel } = useRequest(
async (lastData) => {
const currentData = await service(lastData);
if (!lastData) {
finalData.value = currentData;
} else {
finalData.value = {
...currentData,
list: [...lastData.list, ...currentData.list]
};
}
return currentData;
},
{
manual,
onFinally: (_, d, e) => {
setLoadingMore(false);
onFinally == null ? void 0 : onFinally(d, e);
},
onBefore: () => onBefore == null ? void 0 : onBefore(),
onSuccess: (d) => {
setTimeout(() => {
scrollMethod();
});
onSuccess == null ? void 0 : onSuccess(d);
},
onError: (e) => onError == null ? void 0 : onError(e)
}
);
const loadMore = () => {
if (noMore.value)
return;
setLoadingMore(true);
run(finalData.value);
};
const loadMoreAsync = () => {
if (noMore.value)
return;
setLoadingMore(true);
return runAsync(finalData.value);
};
const reload = () => run();
const reloadAsync = () => runAsync();
const scrollMethod = () => {
const el = getTargetElement(target);
if (!el) {
return;
}
const scrollTop = getScrollTop(el);
const scrollHeight = getScrollHeight(el);
const clientHeight = getClientHeight(el);
if (scrollHeight - scrollTop <= clientHeight + threshold) {
loadMore();
}
};
useEventListener(
"scroll",
() => {
if (loading.value || loadingMore.value) {
return;
}
scrollMethod();
},
{ target }
);
watch(reloadDeps, () => {
run();
});
const _loading = computed(() => !loadingMore.value && loading.value);
return {
data: shallowReadonly(finalData),
loading: readonly(_loading),
loadingMore,
noMore,
loadMore,
loadMoreAsync,
reload,
reloadAsync,
mutate: setFinalData,
scrollMethod,
cancel
};
};
export {
useInfiniteScroll as default
};