144 lines
4.3 KiB
JavaScript
144 lines
4.3 KiB
JavaScript
import { ref, watch, computed, nextTick, onUpdated, onMounted, defineComponent, createVNode as _createVNode } from "vue";
|
|
import { isHidden, truthProp, makeStringProp, makeNumericProp, createNamespace } from "../utils/index.mjs";
|
|
import { useRect, useScrollParent, useEventListener } from "@vant/use";
|
|
import { useExpose } from "../composables/use-expose.mjs";
|
|
import { useTabStatus } from "../composables/use-tab-status.mjs";
|
|
import { Loading } from "../loading/index.mjs";
|
|
const [name, bem, t] = createNamespace("list");
|
|
const listProps = {
|
|
error: Boolean,
|
|
offset: makeNumericProp(300),
|
|
loading: Boolean,
|
|
disabled: Boolean,
|
|
finished: Boolean,
|
|
scroller: Object,
|
|
errorText: String,
|
|
direction: makeStringProp("down"),
|
|
loadingText: String,
|
|
finishedText: String,
|
|
immediateCheck: truthProp
|
|
};
|
|
var stdin_default = defineComponent({
|
|
name,
|
|
props: listProps,
|
|
emits: ["load", "update:error", "update:loading"],
|
|
setup(props, {
|
|
emit,
|
|
slots
|
|
}) {
|
|
const loading = ref(props.loading);
|
|
const root = ref();
|
|
const placeholder = ref();
|
|
const tabStatus = useTabStatus();
|
|
const scrollParent = useScrollParent(root);
|
|
const scroller = computed(() => props.scroller || scrollParent.value);
|
|
const check = () => {
|
|
nextTick(() => {
|
|
if (loading.value || props.finished || props.disabled || props.error || // skip check when inside an inactive tab
|
|
(tabStatus == null ? void 0 : tabStatus.value) === false) {
|
|
return;
|
|
}
|
|
const {
|
|
direction
|
|
} = props;
|
|
const offset = +props.offset;
|
|
const scrollParentRect = useRect(scroller);
|
|
if (!scrollParentRect.height || isHidden(root)) {
|
|
return;
|
|
}
|
|
let isReachEdge = false;
|
|
const placeholderRect = useRect(placeholder);
|
|
if (direction === "up") {
|
|
isReachEdge = scrollParentRect.top - placeholderRect.top <= offset;
|
|
} else {
|
|
isReachEdge = placeholderRect.bottom - scrollParentRect.bottom <= offset;
|
|
}
|
|
if (isReachEdge) {
|
|
loading.value = true;
|
|
emit("update:loading", true);
|
|
emit("load");
|
|
}
|
|
});
|
|
};
|
|
const renderFinishedText = () => {
|
|
if (props.finished) {
|
|
const text = slots.finished ? slots.finished() : props.finishedText;
|
|
if (text) {
|
|
return _createVNode("div", {
|
|
"class": bem("finished-text")
|
|
}, [text]);
|
|
}
|
|
}
|
|
};
|
|
const clickErrorText = () => {
|
|
emit("update:error", false);
|
|
check();
|
|
};
|
|
const renderErrorText = () => {
|
|
if (props.error) {
|
|
const text = slots.error ? slots.error() : props.errorText;
|
|
if (text) {
|
|
return _createVNode("div", {
|
|
"role": "button",
|
|
"class": bem("error-text"),
|
|
"tabindex": 0,
|
|
"onClick": clickErrorText
|
|
}, [text]);
|
|
}
|
|
}
|
|
};
|
|
const renderLoading = () => {
|
|
if (loading.value && !props.finished && !props.disabled) {
|
|
return _createVNode("div", {
|
|
"class": bem("loading")
|
|
}, [slots.loading ? slots.loading() : _createVNode(Loading, {
|
|
"class": bem("loading-icon")
|
|
}, {
|
|
default: () => [props.loadingText || t("loading")]
|
|
})]);
|
|
}
|
|
};
|
|
watch(() => [props.loading, props.finished, props.error], check);
|
|
if (tabStatus) {
|
|
watch(tabStatus, (tabActive) => {
|
|
if (tabActive) {
|
|
check();
|
|
}
|
|
});
|
|
}
|
|
onUpdated(() => {
|
|
loading.value = props.loading;
|
|
});
|
|
onMounted(() => {
|
|
if (props.immediateCheck) {
|
|
check();
|
|
}
|
|
});
|
|
useExpose({
|
|
check
|
|
});
|
|
useEventListener("scroll", check, {
|
|
target: scroller,
|
|
passive: true
|
|
});
|
|
return () => {
|
|
var _a;
|
|
const Content = (_a = slots.default) == null ? void 0 : _a.call(slots);
|
|
const Placeholder = _createVNode("div", {
|
|
"ref": placeholder,
|
|
"class": bem("placeholder")
|
|
}, null);
|
|
return _createVNode("div", {
|
|
"ref": root,
|
|
"role": "feed",
|
|
"class": bem(),
|
|
"aria-busy": loading.value
|
|
}, [props.direction === "down" ? Content : Placeholder, renderLoading(), renderFinishedText(), renderErrorText(), props.direction === "up" ? Content : Placeholder]);
|
|
};
|
|
}
|
|
});
|
|
export {
|
|
stdin_default as default,
|
|
listProps
|
|
};
|