horizontal-scroll.vue 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. <template>
  2. <div class="nut-hor-scroll" rel="wrapper">
  3. <div class="nut-hor-list" ref="list">
  4. <slot name="list"></slot>
  5. <div class="nut-hor-control" v-if="isUnMore && $slots.more && isShowLoadMore()">
  6. <slot name="more"></slot>
  7. </div>
  8. </div>
  9. </div>
  10. </template>
  11. <script>
  12. export default {
  13. name:'nut-hor-scroll',
  14. props: {
  15. listData: {
  16. type: Array,
  17. required: true,
  18. default: () => []
  19. },
  20. lineSpacing: {
  21. type: Number,
  22. default: 210
  23. },
  24. stretch: {
  25. type: Number,
  26. default: 200
  27. },
  28. isUnMore: {
  29. type: Boolean,
  30. default: false
  31. },
  32. isLoading: {
  33. type: Boolean,
  34. default: false
  35. }
  36. },
  37. data() {
  38. return {
  39. touchParams: {
  40. startX: 0,
  41. endX: 0,
  42. startTime: 0,
  43. endTime: 0
  44. },
  45. transformX: 0,
  46. scrollDistance: 0,
  47. timer: null
  48. }
  49. },
  50. methods: {
  51. isShowLoadMore() {
  52. this.$nextTick(() => {
  53. let wrapH = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
  54. let listH = this.listData.length * this.lineSpacing;
  55. if (wrapH <= listH) {
  56. return true;
  57. } else {
  58. return false;
  59. }
  60. });
  61. },
  62. setTransform(translateX = 0, type, time = 500) {
  63. if (type === 'end') {
  64. this.$refs.list.style.webkitTransition = `transform ${time}ms cubic-bezier(0.19, 1, 0.22, 1)`;
  65. } else {
  66. this.$refs.list.style.webkitTransition = '';
  67. }
  68. this.$refs.list.style.webkitTransform = `translate3d(${translateX}px, 0, 0)`;
  69. this.scrollDistance = translateX;
  70. },
  71. setMove(move, type, time) {
  72. let updateMove = move + this.transformX;
  73. let w = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
  74. let offsetWidth = this.lineSpacing * this.listData.length;
  75. if (type === 'end') {
  76. if (updateMove > 0) {
  77. updateMove = 0;
  78. } else if (updateMove < -offsetWidth + w) {
  79. if (-offsetWidth + w <= 0) {
  80. updateMove = -offsetWidth + w;
  81. } else {
  82. updateMove = 0;
  83. }
  84. }
  85. this.setTransform(updateMove, type, time)
  86. } else {
  87. let maxMove = -offsetWidth + w;
  88. if (updateMove > 0 && updateMove > this.stretch) {
  89. updateMove = this.stretc;
  90. } else if (updateMove < maxMove - this.stretch) {
  91. if (maxMove <= 0) {
  92. updateMove = maxMove - this.stretch;
  93. } else {
  94. updateMove = updateMove < -this.stretch ? -this.stretch : updateMove;
  95. }
  96. }
  97. this.setTransform(updateMove, null, null);
  98. }
  99. },
  100. touchStart(event) {
  101. event.preventDefault();
  102. let changedTouches = event.changedTouches[0];
  103. this.touchParams.startX = changedTouches.pageX;
  104. this.touchParams.startTime = event.timestamp || Date.now();
  105. this.transformX = this.scrollDistance;
  106. },
  107. touchMove(event) {
  108. let changedTouches = event.changedTouches[0];
  109. this.touchParams.lastX = changedTouches.pageX;
  110. this.touchParams.lastTime = event.timestamp || Date.now();
  111. let move = this.touchParams.lastX - this.touchParams.startX;
  112. this.setMove(move);
  113. },
  114. touchEnd(event) {
  115. event.preventDefault();
  116. let changedTouches = event.changedTouches[0];
  117. this.touchParams.lastX = changedTouches.pageX;
  118. this.touchParams.lastTime = event.timestamp || Date.now();
  119. let move = this.touchParams.lastX - this.touchParams.startX;
  120. let moveTime = this.touchParams.lastTime - this.touchParams.startTime;
  121. let w = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
  122. let maxMove = -this.lineSpacing * this.listData.length + w;
  123. // 释放跳转之类
  124. if (this.isUnMore && move < 0 && (move + this.transformX) < maxMove - 50) {
  125. //this.$emit('jump');
  126. }
  127. // 加载更多
  128. if (!this.isLoading && !this.isUnMore && move < 0 && (move + this.transformX) < maxMove + 2 * w) {
  129. this.$emit('loadMore');
  130. }
  131. if (moveTime <= 300) {
  132. move = move * 2;
  133. if (move < 0 && move + this.transformX < maxMove) {
  134. move = maxMove - this.transformX;
  135. }
  136. moveTime = moveTime + 500;
  137. this.setMove(move, 'end', moveTime);
  138. } else {
  139. this.setMove(move, 'end');
  140. }
  141. }
  142. },
  143. mounted() {
  144. this.$nextTick(() => {
  145. // 监听
  146. this.$el.addEventListener('touchstart', this.touchStart);
  147. this.$el.addEventListener('touchmove', this.touchMove);
  148. this.$el.addEventListener('touchend', this.touchEnd);
  149. });
  150. },
  151. beforeDestroy() {
  152. // 移除监听
  153. this.$el.removeEventListener('touchstart', this.touchStart);
  154. this.$el.removeEventListener('touchmove', this.touchMove);
  155. this.$el.removeEventListener('touchend', this.touchEnd);
  156. clearTimeout(this.timer);
  157. }
  158. }
  159. </script>