load-refresh.vue 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. <template>
  2. <view class="load-refresh">
  3. <!-- 刷新动画 -->
  4. <animation :type="refreshType" :color="color" :playState="playState"></animation>
  5. <view class="cover-container" :style="[{
  6. background: backgroundCover,
  7. transform: coverTransform,
  8. transition: coverTransition
  9. }]"
  10. @touchstart="coverTouchstart" @touchmove="coverTouchmove" @touchend="coverTouchend">
  11. <scroll-view scroll-y show-scrollbar="true" class="list" :scroll-top="scrollTop" @scrolltolower="loadMore" :style="getHeight">
  12. <!-- 数据集插槽 -->
  13. <slot name="content-list"></slot>
  14. <!-- 上拉加载 -->
  15. <view class="load-more" v-if="isPaging">{{loadText}}</view>
  16. </scroll-view>
  17. </view>
  18. </view>
  19. </template>
  20. <script>
  21. import animation from './animation.vue'
  22. export default {
  23. name: 'loadRefresh',
  24. components: {
  25. animation
  26. },
  27. props: {
  28. isRefresh: {
  29. type: Boolean,
  30. default: true
  31. },
  32. refreshTime: {
  33. type: String,
  34. default: '1000'
  35. },
  36. refreshType: {
  37. type: String,
  38. default: 'hollowDots'
  39. },
  40. heightReduce: {
  41. type: String,
  42. default: '0'
  43. },
  44. color: {
  45. type: String,
  46. default: '#04C4C4'
  47. },
  48. backgroundCover: {
  49. type: String,
  50. default: 'white'
  51. },
  52. pageNo: {
  53. type: Number,
  54. default: 0
  55. },
  56. totalPageNo: {
  57. type: Number,
  58. default: 0
  59. },
  60. isPaging: {
  61. type: Boolean,
  62. default: true
  63. }
  64. },
  65. data() {
  66. return {
  67. startY: 0,
  68. moveY: 0,
  69. hasMore: true,
  70. moving: false,
  71. refresh: false,
  72. loading: false,
  73. scrollTop: -1,
  74. coverTransform: 'translateY(0px)',
  75. coverTransition: '0s',
  76. playState: 'paused' // 动画的状态 暂停/开始
  77. }
  78. },
  79. computed: {
  80. // 计算组件所占屏幕高度
  81. getHeight() {
  82. let height = uni.getSystemInfoSync().windowHeight - uni.upx2px(0 + this.heightReduce)
  83. return `height: ${height}px;`
  84. },
  85. // 判断loadText
  86. // 可以根据需求自定义
  87. loadText() {
  88. const {
  89. pageNo,
  90. totalPageNo,
  91. loading
  92. } = this
  93. if (loading) {
  94. return '加载中...'
  95. } else if (pageNo < totalPageNo) {
  96. return '上拉加载更多'
  97. } else {
  98. return '已经到底啦~'
  99. }
  100. }
  101. },
  102. watch: {
  103. // 监听refresh值 避免多次触发@refresh
  104. 'refresh'(val) {
  105. if (val) {
  106. this.$emit('refresh')
  107. }
  108. }
  109. },
  110. methods: {
  111. // 根据pageNo和totalPageNo的值来判断 是否触发@loadMore
  112. loadMore() {
  113. const {
  114. pageNo,
  115. totalPageNo
  116. } = this
  117. if (pageNo < totalPageNo) {
  118. this.loading = true
  119. this.$emit('loadMore')
  120. }
  121. },
  122. // 单次加载结束
  123. loadOver() {
  124. this.loading = false
  125. },
  126. // 回弹效果
  127. coverTouchstart(e) {
  128. if (!this.isRefresh) {
  129. return
  130. }
  131. this.coverTransition = 'transform .1s linear'
  132. this.startY = e.touches[0].clientY
  133. },
  134. coverTouchmove(e) {
  135. if (!this.isRefresh || this.refresh) {
  136. return
  137. }
  138. this.moveY = e.touches[0].clientY
  139. let moveDistance = this.moveY - this.startY
  140. if (moveDistance < 0) {
  141. this.moving = false
  142. return
  143. }
  144. this.moving = true
  145. if (moveDistance >= 60) {
  146. this.refresh = true
  147. this.coverTransform = `translateY(60px)`
  148. this.playState = 'running'
  149. }
  150. },
  151. coverTouchend() {
  152. if (!(this.isRefresh && this.refresh)) {
  153. return
  154. }
  155. setTimeout(() => {
  156. if (this.moving === false) {
  157. return
  158. }
  159. this.moving = false
  160. this.refresh = false
  161. this.coverTransition = 'transform 0.3s cubic-bezier(.21,1.93,.53,.64)'
  162. this.coverTransform = 'translateY(0px)'
  163. this.playState = 'paused'
  164. }, this.refreshTime)
  165. },
  166. runRefresh() {
  167. // 开始
  168. this.scrollTop = 0
  169. this.refresh = true
  170. this.coverTransition = 'transform .1s linear'
  171. this.coverTransform = `translateY(60px)`
  172. this.playState = 'running'
  173. // 结束
  174. setTimeout(() => {
  175. this.scrollTop = -1
  176. this.refresh = false
  177. this.coverTransition = 'transform 0.3s cubic-bezier(.21,1.93,.53,.64)'
  178. this.coverTransform = 'translateY(0px)'
  179. this.playState = 'paused'
  180. }, this.refreshTime)
  181. }
  182. }
  183. }
  184. </script>
  185. <style lang="scss" scoped>
  186. .load-refresh {
  187. margin: 0;
  188. padding: 0;
  189. width: 100%;
  190. .cover-container {
  191. width: 100%;
  192. margin-top: -100rpx;
  193. .list {
  194. width: 100%;
  195. .load-more {
  196. font-size: 28rpx;
  197. text-align: center;
  198. color: #AAAAAA;
  199. padding: 35rpx;
  200. }
  201. }
  202. }
  203. }
  204. </style>