微信

index.vue 6.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  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" v-show="!dataList.noFlag">
  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. methods: {
  71. touchStart (e) {
  72. this.startY = e.targetTouches[0].pageY
  73. this.startX = e.targetTouches[0].pageX
  74. this.startScroll = this.$el.scrollTop || 0
  75. this.touching = true // 留着有用,不能删除
  76. // this.dataList.noFlag = false
  77. // this.$el.querySelector('.load-more').style.display = 'block'
  78. },
  79. touchMove (e) {
  80. if (this.dataList.noFlag || !this.touching) {
  81. return
  82. }
  83. let diff = e.targetTouches[0].pageY - this.startY - this.startScroll
  84. if (diff > 0) e.preventDefault()
  85. this.top = Math.pow(diff, 0.8) + (this.state === 2 ? this.offset : 0)
  86. if (this.state === 2) { // in refreshing
  87. return
  88. }
  89. if (this.top >= this.offset) {
  90. this.state = 1
  91. } else {
  92. this.state = 0
  93. }
  94. let more = this.$el.querySelector('.load-more')
  95. if (!this.top && this.state === 0) {
  96. more.style.display = 'block'
  97. } else {
  98. more.style.display = 'none'
  99. }
  100. },
  101. touchEnd (e) {
  102. // if (!this.enableRefresh) {
  103. // return
  104. // }
  105. this.touching = false
  106. if (this.state === 2) { // in refreshing
  107. this.state = 2
  108. this.top = this.offset
  109. return
  110. }
  111. if (this.top >= this.offset) { // do refresh
  112. this.refresh()
  113. } else { // cancel refresh
  114. this.state = 0
  115. this.top = 0
  116. }
  117. // 用于判断滑动是否在原地 ----begin
  118. let endX = e.changedTouches[0].pageX
  119. let endY = e.changedTouches[0].pageY
  120. let dy = this.startY - endY
  121. let dx = endX - this.startX
  122. // 如果滑动距离太短
  123. if (Math.abs(dx) < 2 && Math.abs(dy) < 2) {
  124. // console.log("滑动距离太短")
  125. this.downFlag = false
  126. return
  127. }
  128. // --------end--------
  129. // if (!this.enableInfinite || this.infiniteLoading) {
  130. // return
  131. // }
  132. if (this.dataList.noFlag) {
  133. return
  134. }
  135. let outerHeight = this.$el.clientHeight
  136. let innerHeight = this.$el.querySelector('.inner').clientHeight
  137. let scrollTop = this.$el.scrollTop
  138. let ptrHeight = this.onRefresh ? this.$el.querySelector('.pull-refresh').clientHeight : 0
  139. let bottom = innerHeight - outerHeight - scrollTop - ptrHeight
  140. // console.log(bottom + " __ " + this.offset)
  141. if (bottom <= this.offset && this.state === 0) {
  142. this.downFlag = true
  143. this.infinite()
  144. } else {
  145. this.$el.querySelector('.load-more').style.display = 'none'
  146. this.downFlag = false
  147. }
  148. },
  149. refresh () {
  150. this.state = 2
  151. this.top = this.offset
  152. setTimeout(() => {
  153. this.onRefresh(this.refreshDone)
  154. }, 1000)
  155. },
  156. refreshDone () {
  157. this.state = 0
  158. this.top = 0
  159. },
  160. infinite () {
  161. this.infiniteLoading = true
  162. setTimeout(() => {
  163. this.onInfinite(this.infiniteDone)
  164. }, 2000)
  165. },
  166. infiniteDone () {
  167. this.infiniteLoading = false
  168. this.downFlag = false
  169. }
  170. }
  171. }
  172. </script>
  173. <style lang="scss" scoped>
  174. .yo-scroll {
  175. font-size: 0.24rem;
  176. position: fixed;
  177. top: 0;
  178. right: 0;
  179. bottom: 0;
  180. left: 0;
  181. overflow: auto;
  182. z-index: 100;
  183. height: auto;
  184. -webkit-overflow-scrolling: touch;
  185. .inner {
  186. position: absolute;
  187. top: -0.5rem;
  188. width: 100%;
  189. height: auto;
  190. transition-duration: 300ms;
  191. .pull-refresh {
  192. position: relative;
  193. left: 0;
  194. top: 0;
  195. width: 100%;
  196. height: 0.5rem;
  197. display: flex;
  198. display: -webkit-flex;
  199. align-items: center;
  200. justify-content: center;
  201. }
  202. .load-more {
  203. height: 0.5rem;
  204. line-height: 0.5rem;
  205. display: flex;
  206. text-align: center;
  207. align-items: center;
  208. justify-content: center;
  209. display: none;
  210. }
  211. .nullData {
  212. // 暂无更多数据样式
  213. font-size: 0.13rem;
  214. color: #999999;
  215. height: 0.5rem;
  216. line-height: 0.5rem;
  217. text-align: center;
  218. }
  219. .down-tip,
  220. .refresh-tip,
  221. .up-tip {
  222. display: none;
  223. }
  224. .up-tip:before,
  225. .refresh-tip:before {
  226. content: '';
  227. display: inline-block;
  228. width: 1.6rem;
  229. height: 0.7rem;
  230. background-size: 70% !important;
  231. position: absolute;
  232. top: 0;
  233. left: 20%;
  234. }
  235. // .up-tip:before {
  236. // background: url(./loading.gif) no-repeat center;
  237. // }
  238. // .refresh-tip:before {
  239. // background: url(./loading.gif) no-repeat center;
  240. // }
  241. }
  242. }
  243. .yo-scroll.touch .inner {
  244. transition-duration: 0;
  245. }
  246. .yo-scroll.down .down-tip {
  247. display: block;
  248. }
  249. .yo-scroll.up .up-tip {
  250. display: block;
  251. }
  252. .yo-scroll.refresh .refresh-tip {
  253. display: block;
  254. }
  255. </style>