| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160 |
- <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" />
- <view v-if="safety" class="safety" />
- </scroll-view>
- </div>
- </template>
- <script setup>
- import { ref, onMounted, nextTick, getCurrentInstance } from 'vue'
- const props = defineProps({
- getlist: Function,
- empty: Boolean,
- safety: {
- type: Boolean,
- default: true
- },
- 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 = () => {
- inRefresh.value = true
- emit("getlist", true)
- }
- /* 刷新完成 */
- 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(() => {
- setHeight()
- }, 100)
- })
- // 使用 defineExpose 暴露方法给父组件
- defineExpose({
- refreshToComplete,
- setHeight
- })
- </script>
- <style lang="scss" scoped>
- .scroll-view {
- position: relative;
- }
- .safety {
- height: constant(safe-area-inset-bottom);
- height: env(safe-area-inset-bottom);
- width: 100%;
- }
- </style>
|