|
|
@@ -0,0 +1,156 @@
|
|
|
+<template>
|
|
|
+ <div class="list-container">
|
|
|
+ <view id="mylisttop" ref="listTopRef" />
|
|
|
+ <scroll-view class="scroll-view" scroll-y :refresher-enabled="pullDown" :refresher-triggered="inRefresh"
|
|
|
+ :style="{ height: height + 'px' }" :triggered="true" @refresherrefresh="pullToRefresh"
|
|
|
+ :scroll-into-view="scrollIntoView" :lower-threshold="300" :scroll-with-animation="true"
|
|
|
+ @scrolltolower="loadThePage">
|
|
|
+ <view id="header" class="list-header">
|
|
|
+ <slot />
|
|
|
+ </view>
|
|
|
+ <view v-if="empty" style="margin-top: 200rpx;">
|
|
|
+ <up-empty :mode="mode" />
|
|
|
+ </view>
|
|
|
+ <view id="bottom" />
|
|
|
+ </scroll-view>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup>
|
|
|
+import { ref, onMounted, nextTick, getCurrentInstance } from 'vue'
|
|
|
+
|
|
|
+const props = defineProps({
|
|
|
+ getlist: Function,
|
|
|
+ empty: Boolean,
|
|
|
+ mode: {
|
|
|
+ type: String,
|
|
|
+ default: "data"
|
|
|
+ },
|
|
|
+ pullDown: {
|
|
|
+ type: Boolean,
|
|
|
+ default: true
|
|
|
+ },
|
|
|
+ occupyHeight: {
|
|
|
+ type: Number,
|
|
|
+ default: 50
|
|
|
+ }
|
|
|
+})
|
|
|
+
|
|
|
+const emit = defineEmits(['getlist'])
|
|
|
+
|
|
|
+const inRefresh = ref(false)
|
|
|
+const height = ref(0)
|
|
|
+const scrollIntoView = ref("")
|
|
|
+const listTopRef = ref(null)
|
|
|
+
|
|
|
+// 获取当前组件实例
|
|
|
+const instance = getCurrentInstance()
|
|
|
+
|
|
|
+/* 下拉刷新 */
|
|
|
+const pullToRefresh = () => {
|
|
|
+ try {
|
|
|
+ inRefresh.value = true
|
|
|
+ if (getlist) emit("getlist", true)
|
|
|
+ } catch (error) {
|
|
|
+ setTimeout(() => {
|
|
|
+ inRefresh.value = false
|
|
|
+ }, 500)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/* 刷新完成 */
|
|
|
+const RefreshToComplete = () => {
|
|
|
+ setTimeout(() => {
|
|
|
+ inRefresh.value = false
|
|
|
+ }, 500)
|
|
|
+}
|
|
|
+
|
|
|
+/* 加载分页 */
|
|
|
+const loadThePage = () => {
|
|
|
+ emit("getlist", false)
|
|
|
+}
|
|
|
+
|
|
|
+/* 修复元素查询方法 */
|
|
|
+const getHeight = (selector, calculate = true) => {
|
|
|
+ return new Promise((resolve, reject) => {
|
|
|
+ // 使用 nextTick 确保 DOM 更新完成
|
|
|
+ nextTick(() => {
|
|
|
+ if (calculate) {
|
|
|
+ uni.getSystemInfo({
|
|
|
+ success(s) {
|
|
|
+ uni.createSelectorQuery()
|
|
|
+ .in(instance) // 使用当前组件实例
|
|
|
+ .select(selector)
|
|
|
+ .boundingClientRect()
|
|
|
+ .exec(res => {
|
|
|
+ if (!res[0]) {
|
|
|
+ console.warn(`元素查询失败: ${selector}`)
|
|
|
+ reject('没有查询到元素')
|
|
|
+ } else {
|
|
|
+ resolve(s.windowHeight - res[0].bottom)
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+ })
|
|
|
+ } else {
|
|
|
+ uni.createSelectorQuery()
|
|
|
+ .in(instance)
|
|
|
+ .select(selector)
|
|
|
+ .boundingClientRect()
|
|
|
+ .exec(res => {
|
|
|
+ if (!res[0]) {
|
|
|
+ console.warn(`元素查询失败: ${selector}`)
|
|
|
+ reject('没有查询到元素')
|
|
|
+ } else {
|
|
|
+ resolve(res[0])
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+ })
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+/* 设置组件高度 */
|
|
|
+const setHeight = (mode, num) => {
|
|
|
+ return new Promise((resolve) => {
|
|
|
+ getHeight("#mylisttop", true).then(res => {
|
|
|
+ let newHeight = res;
|
|
|
+ switch (mode) {
|
|
|
+ case 'add':
|
|
|
+ newHeight = res + num;
|
|
|
+ break;
|
|
|
+ case 'minus':
|
|
|
+ newHeight = res - num;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ if (height.value !== newHeight) height.value = newHeight;
|
|
|
+ resolve(newHeight)
|
|
|
+ }).catch(err => {
|
|
|
+ console.error(err)
|
|
|
+ // 提供默认高度作为备选
|
|
|
+ height.value = 500
|
|
|
+ resolve(500)
|
|
|
+ })
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+// 初始化高度
|
|
|
+onMounted(() => {
|
|
|
+ // 添加延迟确保元素已渲染
|
|
|
+ setTimeout(() => {
|
|
|
+ getHeight("#mylisttop", true).then(res => {
|
|
|
+ height.value = res
|
|
|
+ }).catch(err => {
|
|
|
+ console.error("初始化高度失败:", err)
|
|
|
+ // 设置默认高度
|
|
|
+ height.value = window.innerHeight - 100
|
|
|
+ })
|
|
|
+ }, 100)
|
|
|
+})
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="scss" scoped>
|
|
|
+.scroll-view {
|
|
|
+ position: relative;
|
|
|
+}
|
|
|
+</style>
|