微信

index.vue 6.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  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. 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. if (this.dataList.noFlag) {
  135. return
  136. }
  137. let outerHeight = this.$el.clientHeight
  138. let innerHeight = this.$el.querySelector('.inner').clientHeight
  139. let scrollTop = this.$el.scrollTop
  140. let ptrHeight = this.onRefresh ? this.$el.querySelector('.pull-refresh').clientHeight : 0
  141. let bottom = innerHeight - outerHeight - scrollTop - ptrHeight
  142. // console.log(bottom + " __ " + this.offset)
  143. if (bottom <= this.offset && this.state === 0) {
  144. this.downFlag = true
  145. this.infinite()
  146. } else {
  147. this.$el.querySelector('.load-more').style.display = 'none'
  148. this.downFlag = false
  149. }
  150. },
  151. refresh () {
  152. this.state = 2
  153. this.top = this.offset
  154. setTimeout(() => {
  155. this.onRefresh(this.refreshDone)
  156. }, 1000)
  157. },
  158. refreshDone () {
  159. this.state = 0
  160. this.top = 0
  161. },
  162. infinite () {
  163. this.infiniteLoading = true
  164. setTimeout(() => {
  165. this.onInfinite(this.infiniteDone)
  166. }, 2000)
  167. },
  168. infiniteDone () {
  169. this.infiniteLoading = false
  170. this.downFlag = false
  171. }
  172. }
  173. }
  174. </script>
  175. <style lang="scss" scoped>
  176. .yo-scroll {
  177. font-size: 0.24rem;
  178. position: fixed;
  179. top: 0;
  180. right: 0;
  181. bottom: 0;
  182. left: 0;
  183. overflow: auto;
  184. z-index: 100;
  185. height: auto;
  186. -webkit-overflow-scrolling: touch;
  187. .inner {
  188. position: absolute;
  189. top: -0.5rem;
  190. width: 100%;
  191. height: auto;
  192. transition-duration: 300ms;
  193. .pull-refresh {
  194. position: relative;
  195. left: 0;
  196. top: 0;
  197. width: 100%;
  198. height: 0.5rem;
  199. display: flex;
  200. display: -webkit-flex;
  201. align-items: center;
  202. justify-content: center;
  203. }
  204. .load-more {
  205. height: 0.5rem;
  206. line-height: 0.5rem;
  207. display: flex;
  208. text-align: center;
  209. align-items: center;
  210. justify-content: center;
  211. display: none;
  212. }
  213. .nullData {
  214. // 暂无更多数据样式
  215. font-size: 0.13rem;
  216. color: #999999;
  217. height: 0.5rem;
  218. line-height: 0.5rem;
  219. text-align: center;
  220. }
  221. .down-tip,
  222. .refresh-tip,
  223. .up-tip {
  224. display: none;
  225. }
  226. .up-tip:before,
  227. .refresh-tip:before {
  228. content: '';
  229. display: inline-block;
  230. width: 1.6rem;
  231. height: 0.7rem;
  232. background-size: 70% !important;
  233. position: absolute;
  234. top: 0;
  235. left: 20%;
  236. }
  237. // .up-tip:before {
  238. // background: url(./loading.gif) no-repeat center;
  239. // }
  240. // .refresh-tip:before {
  241. // background: url(./loading.gif) no-repeat center;
  242. // }
  243. }
  244. }
  245. .yo-scroll.touch .inner {
  246. transition-duration: 0;
  247. }
  248. .yo-scroll.down .down-tip {
  249. display: block;
  250. }
  251. .yo-scroll.up .up-tip {
  252. display: block;
  253. }
  254. .yo-scroll.refresh .refresh-tip {
  255. display: block;
  256. }
  257. </style>