My_listbox.vue 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. <template>
  2. <div class="list-container">
  3. <view id="mylisttop" ref="listTopRef" />
  4. <scroll-view class="scroll-view" scroll-y :refresher-enabled="pullDown" :refresher-triggered="inRefresh"
  5. :style="{ height: height + 'px' }" :triggered="true" @refresherrefresh="pullToRefresh"
  6. :scroll-into-view="scrollIntoView" :lower-threshold="300" :scroll-with-animation="true"
  7. @scrolltolower="loadThePage">
  8. <view id="header" class="list-header">
  9. <slot />
  10. </view>
  11. <view v-if="empty" style="margin-top: 200rpx;">
  12. <up-empty :mode="mode" />
  13. </view>
  14. <view id="bottom" />
  15. <view v-if="safety" class="safety" />
  16. </scroll-view>
  17. </div>
  18. </template>
  19. <script setup>
  20. import { ref, onMounted, nextTick, getCurrentInstance } from 'vue'
  21. const props = defineProps({
  22. getlist: Function,
  23. empty: Boolean,
  24. safety: {
  25. type: Boolean,
  26. default: true
  27. },
  28. mode: {
  29. type: String,
  30. default: "data"
  31. },
  32. pullDown: {
  33. type: Boolean,
  34. default: true
  35. },
  36. occupyHeight: {
  37. type: Number,
  38. default: 50
  39. }
  40. })
  41. const emit = defineEmits(['getlist'])
  42. const inRefresh = ref(false)
  43. const height = ref(0)
  44. const scrollIntoView = ref("")
  45. const listTopRef = ref(null)
  46. // 获取当前组件实例
  47. const instance = getCurrentInstance()
  48. /* 下拉刷新 */
  49. const pullToRefresh = () => {
  50. inRefresh.value = true
  51. emit("getlist", true)
  52. }
  53. /* 刷新完成 */
  54. const refreshToComplete = () => {
  55. setTimeout(() => {
  56. inRefresh.value = false
  57. }, 500)
  58. }
  59. /* 加载分页 */
  60. const loadThePage = () => {
  61. emit("getlist", false)
  62. }
  63. /* 修复元素查询方法 */
  64. const getHeight = (selector, calculate = true) => {
  65. return new Promise((resolve, reject) => {
  66. // 使用 nextTick 确保 DOM 更新完成
  67. nextTick(() => {
  68. if (calculate) {
  69. uni.getSystemInfo({
  70. success(s) {
  71. uni.createSelectorQuery()
  72. .in(instance) // 使用当前组件实例
  73. .select(selector)
  74. .boundingClientRect()
  75. .exec(res => {
  76. if (!res[0]) {
  77. console.warn(`元素查询失败: ${selector}`)
  78. reject('没有查询到元素')
  79. } else {
  80. resolve(s.windowHeight - res[0].bottom)
  81. }
  82. })
  83. }
  84. })
  85. } else {
  86. uni.createSelectorQuery()
  87. .in(instance)
  88. .select(selector)
  89. .boundingClientRect()
  90. .exec(res => {
  91. if (!res[0]) {
  92. console.warn(`元素查询失败: ${selector}`)
  93. reject('没有查询到元素')
  94. } else {
  95. resolve(res[0])
  96. }
  97. })
  98. }
  99. })
  100. })
  101. }
  102. /* 设置组件高度 */
  103. const setHeight = (mode, num) => {
  104. return new Promise((resolve) => {
  105. getHeight("#mylisttop", true).then(res => {
  106. let newHeight = res;
  107. switch (mode) {
  108. case 'add':
  109. newHeight = res + num;
  110. break;
  111. case 'minus':
  112. newHeight = res - num;
  113. break;
  114. }
  115. if (height.value !== newHeight) height.value = newHeight;
  116. resolve(newHeight)
  117. }).catch(err => {
  118. console.error(err)
  119. // 提供默认高度作为备选
  120. height.value = 500
  121. resolve(500)
  122. })
  123. })
  124. }
  125. // 初始化高度
  126. onMounted(() => {
  127. // 添加延迟确保元素已渲染
  128. setTimeout(() => {
  129. setHeight()
  130. }, 100)
  131. })
  132. // 使用 defineExpose 暴露方法给父组件
  133. defineExpose({
  134. refreshToComplete,
  135. setHeight
  136. })
  137. </script>
  138. <style lang="scss" scoped>
  139. .scroll-view {
  140. position: relative;
  141. }
  142. .safety {
  143. height: constant(safe-area-inset-bottom);
  144. height: env(safe-area-inset-bottom);
  145. width: 100%;
  146. }
  147. </style>