微信

index.vue 6.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. <template>
  2. <div
  3. class="yo-scroll"
  4. :class="{'down':(state===0),'up':(state==1),refresh:(state===2),touch:touching}"
  5. @touchstart="touchStart($event)"
  6. @touchmove="touchMove($event)"
  7. @touchend="touchEnd($event)"
  8. >
  9. <section class="inner" :style="{ transform: 'translate3d(0, 0px, 0)' }">
  10. <header class="pull-refresh">
  11. <slot name="pull-refresh">
  12. <span class="down-tip">下拉更新</span>
  13. <span class="up-tip">松开刷新数据</span>
  14. <span class="refresh-tip">加载中……</span>
  15. </slot>
  16. </header>
  17. <slot></slot>
  18. <footer class="load-more">
  19. <slot name="load-more">
  20. <span v-show="downFlag === false">上拉加载更多</span>
  21. <span v-show="downFlag === true">加载中……</span>
  22. </slot>
  23. </footer>
  24. <div class="nullData" v-show="dataList.noFlag">暂无更多数据</div>
  25. </section>
  26. </div>
  27. </template>
  28. <script>
  29. export default {
  30. props: {
  31. offset: { // 默认高度
  32. type: Number,
  33. default: 100
  34. },
  35. enableInfinite: { // 上拉加载
  36. type: Boolean,
  37. default: true
  38. },
  39. enableRefresh: { // 下拉刷新
  40. type: Boolean,
  41. default: false
  42. },
  43. dataList: { // 数据列表
  44. default: undefined,
  45. required: false
  46. },
  47. onRefresh: { // 加载方法
  48. type: Function,
  49. default: undefined,
  50. required: false
  51. },
  52. onInfinite: { // 刷新方法
  53. type: Function,
  54. default: undefined,
  55. require: false
  56. }
  57. },
  58. data () {
  59. return {
  60. top: 0,
  61. state: 0,
  62. startX: 0,
  63. startY: 0,
  64. touching: false,
  65. infiniteLoading: false,
  66. downFlag: false // 用来显示是否加载中
  67. }
  68. },
  69. created () {
  70. console.log(this.dataList)
  71. },
  72. methods: {
  73. touchStart (e) {
  74. this.startY = e.targetTouches[0].pageY
  75. this.startX = e.targetTouches[0].pageX
  76. this.startScroll = this.$el.scrollTop || 0
  77. this.touching = true // 留着有用,不能删除
  78. this.dataList.noFlag = false
  79. this.$el.querySelector('.load-more').style.display = 'block'
  80. },
  81. touchMove (e) {
  82. if (this.dataList.noFlag || !this.touching) {
  83. return
  84. }
  85. let diff = e.targetTouches[0].pageY - this.startY - this.startScroll
  86. if (diff > 0) e.preventDefault()
  87. this.top = Math.pow(diff, 0.8) + (this.state === 2 ? this.offset : 0)
  88. if (this.state === 2) { // in refreshing
  89. return
  90. }
  91. if (this.top >= this.offset) {
  92. this.state = 1
  93. } else {
  94. this.state = 0
  95. }
  96. let more = this.$el.querySelector('.load-more')
  97. if (!this.top && this.state === 0) {
  98. more.style.display = 'block'
  99. } else {
  100. more.style.display = 'none'
  101. }
  102. },
  103. touchEnd (e) {
  104. // if (!this.enableRefresh) {
  105. // return
  106. // }
  107. this.touching = false
  108. if (this.state === 2) { // in refreshing
  109. this.state = 2
  110. this.top = this.offset
  111. return
  112. }
  113. if (this.top >= this.offset) { // do refresh
  114. this.refresh()
  115. } else { // cancel refresh
  116. this.state = 0
  117. this.top = 0
  118. }
  119. // 用于判断滑动是否在原地 ----begin
  120. let endX = e.changedTouches[0].pageX
  121. let endY = e.changedTouches[0].pageY
  122. let dy = this.startY - endY
  123. let dx = endX - this.startX
  124. // 如果滑动距离太短
  125. if (Math.abs(dx) < 2 && Math.abs(dy) < 2) {
  126. // console.log("滑动距离太短")
  127. this.downFlag = false
  128. return
  129. }
  130. // --------end--------
  131. // if (!this.enableInfinite || this.infiniteLoading) {
  132. // return
  133. // }
  134. let outerHeight = this.$el.clientHeight
  135. let innerHeight = this.$el.querySelector('.inner').clientHeight
  136. let scrollTop = this.$el.scrollTop
  137. let ptrHeight = this.onRefresh ? this.$el.querySelector('.pull-refresh').clientHeight : 0
  138. let bottom = innerHeight - outerHeight - scrollTop - ptrHeight
  139. // console.log(bottom + " __ " + this.offset)
  140. if (bottom <= this.offset && this.state === 0) {
  141. this.downFlag = true
  142. this.infinite()
  143. } else {
  144. this.$el.querySelector('.load-more').style.display = 'none'
  145. this.downFlag = false
  146. }
  147. },
  148. refresh () {
  149. this.state = 2
  150. this.top = this.offset
  151. setTimeout(() => {
  152. this.onRefresh(this.refreshDone)
  153. }, 1000)
  154. },
  155. refreshDone () {
  156. this.state = 0
  157. this.top = 0
  158. },
  159. infinite () {
  160. this.infiniteLoading = true
  161. setTimeout(() => {
  162. this.onInfinite(this.infiniteDone)
  163. }, 2000)
  164. },
  165. infiniteDone () {
  166. this.infiniteLoading = false
  167. this.downFlag = false
  168. }
  169. }
  170. }
  171. </script>
  172. <style lang="scss" scoped>
  173. .yo-scroll {
  174. font-size: 0.24rem;
  175. position: absolute;
  176. top: 0;
  177. right: 0;
  178. bottom: 0;
  179. left: 0;
  180. overflow: auto;
  181. z-index: 100;
  182. height: auto;
  183. -webkit-overflow-scrolling: touch;
  184. .inner {
  185. position: absolute;
  186. top: -0.5rem;
  187. width: 100%;
  188. height: auto;
  189. transition-duration: 300ms;
  190. .pull-refresh {
  191. position: relative;
  192. left: 0;
  193. top: 0;
  194. width: 100%;
  195. height: 0.5rem;
  196. display: flex;
  197. display: -webkit-flex;
  198. align-items: center;
  199. justify-content: center;
  200. }
  201. .load-more {
  202. height: 0.5rem;
  203. line-height: 0.5rem;
  204. display: flex;
  205. text-align: center;
  206. align-items: center;
  207. justify-content: center;
  208. display: none;
  209. }
  210. .nullData {
  211. // 暂无更多数据样式
  212. font-size: 0.13rem;
  213. color: #999999;
  214. height: 0.5rem;
  215. line-height: 0.5rem;
  216. text-align: center;
  217. }
  218. .down-tip,
  219. .refresh-tip,
  220. .up-tip {
  221. display: none;
  222. }
  223. .up-tip:before,
  224. .refresh-tip:before {
  225. content: '';
  226. display: inline-block;
  227. width: 1.6rem;
  228. height: 0.7rem;
  229. background-size: 70% !important;
  230. position: absolute;
  231. top: 0;
  232. left: 20%;
  233. }
  234. // .up-tip:before {
  235. // background: url(./loading.gif) no-repeat center;
  236. // }
  237. // .refresh-tip:before {
  238. // background: url(./loading.gif) no-repeat center;
  239. // }
  240. }
  241. }
  242. .yo-scroll.touch .inner {
  243. transition-duration: 0;
  244. }
  245. .yo-scroll.down .down-tip {
  246. display: block;
  247. }
  248. .yo-scroll.up .up-tip {
  249. display: block;
  250. }
  251. .yo-scroll.refresh .refresh-tip {
  252. display: block;
  253. }
  254. </style>