common-list.uvue 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. <template>
  2. <list-view
  3. class="common-list"
  4. :scroll-y="true"
  5. @scrolltolower="handleLoadMore"
  6. :refresher-enabled="refresherEnabled"
  7. :refresher-triggered="refreshing"
  8. @refresherrefresh="handleRefresh"
  9. >
  10. <!-- 列表项 - 使用插槽自定义内容 -->
  11. <list-item
  12. v-for="(item, index) in dataList"
  13. :key="getItemKey(item, index)"
  14. class="common-list-item"
  15. @click="handleItemClick(item, index)"
  16. >
  17. <slot :item="item" :index="index"></slot>
  18. </list-item>
  19. <!-- 加载更多提示 -->
  20. <list-item class="load-more">
  21. <slot name="loadMore" :loading="loading" :hasMore="hasMore" :loadingText="loadingText">
  22. <text class="load-more-text">{{ loadingText }}</text>
  23. </slot>
  24. </list-item>
  25. </list-view>
  26. </template>
  27. <script setup lang="uts">
  28. import { computed } from 'vue'
  29. // Props 定义
  30. type Props = {
  31. // 数据列表
  32. dataList: any[]
  33. // 是否正在加载
  34. loading?: boolean
  35. // 是否正在刷新
  36. refreshing?: boolean
  37. // 是否还有更多数据
  38. hasMore?: boolean
  39. // 是否启用下拉刷新
  40. refresherEnabled?: boolean
  41. // 自定义加载提示文本
  42. customLoadingText?: string
  43. // 列表项的 key 字段名
  44. itemKey?: string
  45. }
  46. const props = withDefaults(defineProps<Props>(), {
  47. loading: false,
  48. refreshing: false,
  49. hasMore: true,
  50. refresherEnabled: true,
  51. customLoadingText: '',
  52. itemKey: 'id'
  53. })
  54. // 事件定义
  55. type Emits = {
  56. (e: 'refresh'): void
  57. (e: 'loadMore'): void
  58. (e: 'itemClick', item: any, index: number): void
  59. }
  60. const emit = defineEmits<Emits>()
  61. // 加载提示文本
  62. const loadingText = computed((): string => {
  63. if (props.customLoadingText.length > 0) {
  64. return props.customLoadingText
  65. }
  66. if (props.loading) {
  67. return '加载中...'
  68. }
  69. if (!props.hasMore) {
  70. return '没有更多数据了'
  71. }
  72. return '上拉加载更多'
  73. })
  74. // 获取列表项的 key
  75. const getItemKey = (item: any, index: number): string => {
  76. // 直接使用 index 作为 key,避免类型转换问题
  77. // 响应式对象无法安全转换为 UTSJSONObject
  78. return `item-${index}`
  79. }
  80. // 下拉刷新
  81. const handleRefresh = (): void => {
  82. emit('refresh')
  83. }
  84. // 加载更多
  85. const handleLoadMore = (): void => {
  86. if (!props.hasMore || props.loading) {
  87. return
  88. }
  89. emit('loadMore')
  90. }
  91. // 列表项点击
  92. const handleItemClick = (item: any, index: number): void => {
  93. emit('itemClick', item, index)
  94. }
  95. </script>
  96. <style lang="scss">
  97. .common-list {
  98. flex: 1;
  99. }
  100. .common-list-item {
  101. // 默认样式,具体样式由使用方通过插槽内容定义
  102. }
  103. .load-more {
  104. padding: 30rpx;
  105. justify-content: center;
  106. align-items: center;
  107. &-text {
  108. font-size: 26rpx;
  109. color: #999999;
  110. }
  111. }
  112. </style>