This commit is contained in:
tamaina 2023-07-11 07:53:56 +00:00
parent 48d3341462
commit 9f246e3dc7
1 changed files with 54 additions and 19 deletions

View File

@ -54,7 +54,17 @@ const APPEAR_MINIMUM_INTERVAL = 600;
export type Paging<E extends keyof misskey.Endpoints = keyof misskey.Endpoints> = {
endpoint: E;
/**
* 一度にAPIへ取得する件数
*/
limit: number;
/**
* タイムラインに表示する最大件数
*/
displayLimit?: number;
params?: misskey.Endpoints[E]['req'] | ComputedRef<misskey.Endpoints[E]['req']>;
/**
@ -89,9 +99,7 @@ import { infoImageUrl } from '@/instance';
const props = withDefaults(defineProps<{
pagination: Paging;
disableAutoLoad?: boolean;
displayLimit?: number;
}>(), {
displayLimit: 20,
});
const emit = defineEmits<{
@ -124,17 +132,23 @@ const offset = ref(0);
*/
const fetching = ref(true);
/**
* onActivatedでtrue, onDeactivatedでfalseになる
*/
const active = ref(false);
const moreFetching = ref(false);
const more = ref(false);
const preventAppearFetchMore = ref(false);
const preventAppearFetchMoreTimer = ref<number | null>(null);
const isBackTop = ref(false);
const empty = computed(() => items.value.size === 0);
const error = ref(false);
const {
enableInfiniteScroll,
} = defaultStore.reactiveState;
const displayLimit = computed(() => props.pagination.displayLimit ?? props.pagination.limit * 2);
const contentEl = $computed(() => props.pagination.pageEl ?? rootEl);
const scrollableElement = $computed(() => contentEl ? getScrollContainer(contentEl) : document.body);
@ -339,9 +353,9 @@ const appearFetchMoreAhead = async (): Promise<void> => {
fetchMoreAppearTimeout();
};
const isTop = (): boolean => isBackTop.value || (props.pagination.reversed ? isBottomVisible : isTopVisible)(contentEl!, TOLERANCE);
const isTop = (): boolean => (props.pagination.reversed ? isBottomVisible : isTopVisible)(contentEl!, TOLERANCE);
watch(visibility, () => {
function visibilityChange() {
if (visibility.value === 'hidden') {
timerForSetPause = window.setTimeout(() => {
isPausingUpdate = true;
@ -354,13 +368,24 @@ watch(visibility, () => {
timerForSetPause = null;
} else {
isPausingUpdate = false;
if (isTop()) {
if (isTop() && active.value) {
executeQueue();
}
}
}
}
onActivated(() => {
active.value = true;
visibilityChange();
});
onDeactivated(() => {
active.value = false;
});
watch(visibility, visibilityChange);
/**
* 最新のものとして1つだけアイテムを追加する
* ストリーミングから降ってきたアイテムはこれで追加する
@ -373,19 +398,28 @@ const prepend = (item: MisskeyEntity): void => {
return;
}
if (isTop() && !isPausingUpdate) unshiftItems([item]);
else prependQueue(item);
if (
isTop() && //
!isPausingUpdate && //
active.value // keepAlive
) {
if (!items.value.has(item.id)) return; //
unshiftItems([item]);
} else {
prependQueue(item);
}
};
/**
* 新着アイテムをitemsの先頭に追加しdisplayLimitを適用する
* 新着アイテムをitemsの先頭に追加しlimitを適用する
* @param newItems 新しいアイテムの配列
* @param limit デフォルトはdisplayLimit
*/
function unshiftItems(newItems: MisskeyEntity[]) {
function unshiftItems(newItems: MisskeyEntity[], limit = displayLimit.value) {
const length = newItems.length + items.value.size;
items.value = new Map([...arrayToEntries(newItems), ...items.value].slice(0, props.displayLimit));
items.value = new Map([...arrayToEntries(newItems), ...items.value].slice(0, limit));
if (length >= props.displayLimit) more.value = true;
if (length >= displayLimit.value) more.value = true;
}
/**
@ -394,18 +428,19 @@ function unshiftItems(newItems: MisskeyEntity[]) {
*/
function concatItems(oldItems: MisskeyEntity[]) {
const length = oldItems.length + items.value.size;
items.value = new Map([...items.value, ...arrayToEntries(oldItems)].slice(0, props.displayLimit));
items.value = new Map([...items.value, ...arrayToEntries(oldItems)].slice(0, displayLimit.value));
if (length >= props.displayLimit) more.value = true;
if (length >= displayLimit.value) more.value = true;
}
function executeQueue() {
unshiftItems(Array.from(queue.value.values()));
queue.value = new Map();
const queueArr = Array.from(queue.value.entries());
unshiftItems(queueArr.slice(-1 * props.pagination.limit).map(v => v[1]));
queue.value = new Map(queueArr.slice(0, -1 * props.pagination.limit));
}
function prependQueue(newItem: MisskeyEntity) {
queue.value = new Map([[newItem.id, newItem], ...queue.value].slice(0, props.displayLimit) as [string, MisskeyEntity][]);
queue.value = new Map([[newItem.id, newItem], ...queue.value] as [string, MisskeyEntity][]);
}
/*
@ -431,11 +466,11 @@ const updateItem = (id: MisskeyEntity['id'], replacer: (old: MisskeyEntity) => M
const inited = init();
onActivated(() => {
isBackTop.value = false;
// nothing to do
});
onDeactivated(() => {
isBackTop.value = props.pagination.reversed ? window.scrollY >= (rootEl ? rootEl.scrollHeight - window.innerHeight : 0) : window.scrollY === 0;
// nothing to do
});
function toBottom() {