You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

183 lines
5.9 KiB

5 months ago
  1. <template>
  2. <!-- #ifdef APP-NVUE -->
  3. <list
  4. class="u-list"
  5. :enableBackToTop="enableBackToTop"
  6. :loadmoreoffset="lowerThreshold"
  7. :showScrollbar="showScrollbar"
  8. :style="[listStyle]"
  9. :offset-accuracy="Number(offsetAccuracy)"
  10. @scroll="onScroll"
  11. @loadmore="scrolltolower"
  12. >
  13. <slot />
  14. </list>
  15. <!-- #endif -->
  16. <!-- #ifndef APP-NVUE -->
  17. <scroll-view
  18. class="u-list"
  19. :scroll-into-view="scrollIntoView"
  20. :style="[listStyle]"
  21. :scroll-y="scrollable"
  22. :scroll-top="Number(scrollTop)"
  23. :lower-threshold="Number(lowerThreshold)"
  24. :upper-threshold="Number(upperThreshold)"
  25. :show-scrollbar="showScrollbar"
  26. :enable-back-to-top="enableBackToTop"
  27. :scroll-with-animation="scrollWithAnimation"
  28. @scroll="onScroll"
  29. @scrolltolower="scrolltolower"
  30. @scrolltoupper="scrolltoupper"
  31. :refresher-enabled="refresherEnabled"
  32. :refresher-threshold="refresherThreshold"
  33. :refresher-default-style="refresherDefaultStyle"
  34. :refresher-background="refresherBackground"
  35. :refresher-triggered="refresherTriggered"
  36. @refresherpulling="refresherpulling"
  37. @refresherrefresh="refresherrefresh"
  38. @refresherrestore="refresherrestore"
  39. @refresherabort="refresherabort"
  40. :scroll-anchoring="true"
  41. >
  42. <view>
  43. <slot />
  44. </view>
  45. </scroll-view>
  46. <!-- #endif -->
  47. </template>
  48. <script>
  49. import { props } from './props';
  50. import { mpMixin } from '../../libs/mixin/mpMixin';
  51. import { mixin } from '../../libs/mixin/mixin';
  52. import { addUnit, addStyle, deepMerge, sleep, sys } from '../../libs/function/index';
  53. // #ifdef APP-NVUE
  54. const dom = uni.requireNativePlugin('dom')
  55. // #endif
  56. /**
  57. * List 列表
  58. * @description 该组件为高性能列表组件
  59. * @tutorial https://ijry.github.io/uview-plus/components/list.html
  60. * @property {Boolean} showScrollbar 控制是否出现滚动条仅nvue有效 默认 false
  61. * @property {String Number} lowerThreshold 距底部多少时触发scrolltolower事件 默认 50
  62. * @property {String Number} upperThreshold 距顶部多少时触发scrolltoupper事件非nvue有效 默认 0
  63. * @property {String Number} scrollTop 设置竖向滚动条位置默认 0
  64. * @property {String Number} offsetAccuracy 控制 onscroll 事件触发的频率仅nvue有效默认 10
  65. * @property {Boolean} enableFlex 启用 flexbox 布局开启后当前节点声明了display: flex就会成为flex container并作用于其孩子节点仅微信小程序有效默认 false
  66. * @property {Boolean} pagingEnabled 是否按分页模式显示List默认 false
  67. * @property {Boolean} scrollable 是否允许List滚动默认 true
  68. * @property {String} scrollIntoView 值应为某子元素idid不能以数字开头
  69. * @property {Boolean} scrollWithAnimation 在设置滚动条位置时使用动画过渡 默认 false
  70. * @property {Boolean} enableBackToTop iOS点击顶部状态栏安卓双击标题栏时滚动条返回顶部只对微信小程序有效 默认 false
  71. * @property {String Number} height 列表的高度 默认 0
  72. * @property {String Number} width 列表宽度 默认 0
  73. * @property {String Number} preLoadScreen 列表前后预渲染的屏数1代表一个屏幕的高度1.5代表1个半屏幕高度 默认 1
  74. * @property {Object} customStyle 定义需要用到的外部样式
  75. *
  76. * @example <u-list @scrolltolower="scrolltolower"></u-list>
  77. */
  78. export default {
  79. name: 'u-list',
  80. mixins: [mpMixin, mixin, props],
  81. watch: {
  82. scrollIntoView(n) {
  83. this.scrollIntoViewById(n)
  84. }
  85. },
  86. data() {
  87. return {
  88. // 记录内部滚动的距离
  89. innerScrollTop: 0,
  90. // vue下,scroll-view在上拉加载时的偏移值
  91. offset: 0,
  92. sys: sys()
  93. }
  94. },
  95. computed: {
  96. listStyle() {
  97. const style = {};
  98. if (this.width != 0) style.width = addUnit(this.width)
  99. if (this.height != 0) style.height = addUnit(this.height)
  100. // 如果没有定义列表高度,则默认使用屏幕高度
  101. if (!style.height) style.height = addUnit(this.sys.windowHeight, 'px')
  102. return deepMerge(style, addStyle(this.customStyle))
  103. }
  104. },
  105. provide() {
  106. return {
  107. uList: this
  108. }
  109. },
  110. created() {
  111. this.refs = []
  112. this.children = []
  113. this.anchors = []
  114. },
  115. mounted() {},
  116. emits: ["scroll", "scrolltolower", "scrolltoupper",
  117. "refresherpulling", "refresherrefresh", "refresherrestore", "refresherabort"],
  118. methods: {
  119. updateOffsetFromChild(top) {
  120. this.offset = top
  121. },
  122. onScroll(e) {
  123. let scrollTop = 0
  124. // #ifdef APP-NVUE
  125. scrollTop = e.contentOffset.y
  126. // #endif
  127. // #ifndef APP-NVUE
  128. scrollTop = e.detail.scrollTop
  129. // #endif
  130. this.innerScrollTop = scrollTop
  131. this.$emit('scroll', Math.abs(scrollTop))
  132. },
  133. scrollIntoViewById(id) {
  134. // #ifdef APP-NVUE
  135. // 根据id参数,找到所有u-list-item中匹配的节点,再通过dom模块滚动到对应的位置
  136. const item = this.refs.find(item => item.$refs[id] ? true : false)
  137. dom.scrollToElement(item.$refs[id], {
  138. // 是否需要滚动动画
  139. animated: this.scrollWithAnimation
  140. })
  141. // #endif
  142. },
  143. // 滚动到底部触发事件
  144. scrolltolower(e) {
  145. sleep(30).then(() => {
  146. this.$emit('scrolltolower')
  147. })
  148. },
  149. // #ifndef APP-NVUE
  150. // 滚动到底部时触发,非nvue有效
  151. scrolltoupper(e) {
  152. sleep(30).then(() => {
  153. this.$emit('scrolltoupper')
  154. // 这一句很重要,能绝对保证在性功能障碍的webview,滚动条到顶时,取消偏移值,让页面置顶
  155. this.offset = 0
  156. })
  157. },
  158. refresherpulling(e) {
  159. this.$emit('refresherpulling', e)
  160. },
  161. refresherrefresh(e) {
  162. this.$emit('refresherrefresh', e)
  163. },
  164. refresherrestore(e) {
  165. this.$emit('refresherrestore', e)
  166. },
  167. refresherabort(e) {
  168. this.$emit('refresherabort', e)
  169. }
  170. // #endif
  171. },
  172. }
  173. </script>
  174. <style lang="scss" scoped>
  175. @import "../../libs/css/components.scss";
  176. .u-list {
  177. @include flex(column);
  178. }
  179. </style>