index.js 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. import { use } from '../utils';
  2. import { preventDefault } from '../utils/event';
  3. import { TouchMixin } from '../mixins/touch';
  4. import { getScrollTop, getScrollEventTarget } from '../utils/scroll';
  5. import Loading from '../loading';
  6. const [sfc, bem, t] = use('pull-refresh');
  7. const TEXT_STATUS = ['pulling', 'loosing', 'success'];
  8. export default sfc({
  9. mixins: [TouchMixin],
  10. props: {
  11. disabled: Boolean,
  12. successText: String,
  13. pullingText: String,
  14. loosingText: String,
  15. loadingText: String,
  16. value: {
  17. type: Boolean,
  18. required: true
  19. },
  20. successDuration: {
  21. type: Number,
  22. default: 500
  23. },
  24. animationDuration: {
  25. type: Number,
  26. default: 300
  27. },
  28. headHeight: {
  29. type: Number,
  30. default: 50
  31. }
  32. },
  33. data() {
  34. return {
  35. status: 'normal',
  36. height: 0,
  37. duration: 0
  38. };
  39. },
  40. computed: {
  41. untouchable() {
  42. return this.status === 'loading' || this.status === 'success' || this.disabled;
  43. }
  44. },
  45. watch: {
  46. value(loading) {
  47. this.duration = this.animationDuration;
  48. if (!loading && this.successText) {
  49. this.status = 'success';
  50. setTimeout(() => {
  51. this.setStatus(0);
  52. }, this.successDuration);
  53. } else {
  54. this.setStatus(loading ? this.headHeight : 0, loading);
  55. }
  56. }
  57. },
  58. mounted() {
  59. this.scrollEl = getScrollEventTarget(this.$el);
  60. },
  61. methods: {
  62. onTouchStart(event) {
  63. if (!this.untouchable && this.getCeiling()) {
  64. this.duration = 0;
  65. this.touchStart(event);
  66. }
  67. },
  68. onTouchMove(event) {
  69. if (this.untouchable) {
  70. return;
  71. }
  72. this.touchMove(event);
  73. if (!this.ceiling && this.getCeiling()) {
  74. this.duration = 0;
  75. this.startY = event.touches[0].clientY;
  76. this.deltaY = 0;
  77. }
  78. if (this.ceiling && this.deltaY >= 0) {
  79. if (this.direction === 'vertical') {
  80. this.setStatus(this.ease(this.deltaY));
  81. preventDefault(event);
  82. }
  83. }
  84. },
  85. onTouchEnd() {
  86. if (!this.untouchable && this.ceiling && this.deltaY) {
  87. this.duration = this.animationDuration;
  88. if (this.status === 'loosing') {
  89. this.setStatus(this.headHeight, true);
  90. this.$emit('input', true);
  91. this.$emit('refresh');
  92. } else {
  93. this.setStatus(0);
  94. }
  95. }
  96. },
  97. getCeiling() {
  98. this.ceiling = getScrollTop(this.scrollEl) === 0;
  99. return this.ceiling;
  100. },
  101. ease(height) {
  102. const { headHeight } = this;
  103. return height < headHeight
  104. ? height
  105. : height < headHeight * 2
  106. ? Math.round(headHeight + (height - headHeight) / 2)
  107. : Math.round(headHeight * 1.5 + (height - headHeight * 2) / 4);
  108. },
  109. setStatus(height, isLoading) {
  110. this.height = height;
  111. const status = isLoading
  112. ? 'loading'
  113. : height === 0
  114. ? 'normal'
  115. : height < this.headHeight
  116. ? 'pulling'
  117. : 'loosing';
  118. if (status !== this.status) {
  119. this.status = status;
  120. }
  121. }
  122. },
  123. render(h) {
  124. const { status } = this;
  125. const text = this[`${status}Text`] || t(status);
  126. const style = {
  127. transition: `${this.duration}ms`,
  128. transform: this.height ? `translate3d(0,${this.height}px, 0)` : ''
  129. };
  130. const Status = this.slots(status) || [
  131. TEXT_STATUS.indexOf(status) !== -1 && <div class={bem('text')}>{text}</div>,
  132. status === 'loading' && (
  133. <div class={bem('loading')}>
  134. <Loading />
  135. <span>{text}</span>
  136. </div>
  137. )
  138. ];
  139. return (
  140. <div class={bem()}>
  141. <div
  142. class={bem('track')}
  143. style={style}
  144. onTouchstart={this.onTouchStart}
  145. onTouchmove={this.onTouchMove}
  146. onTouchend={this.onTouchEnd}
  147. onTouchcancel={this.onTouchEnd}
  148. >
  149. <div class={bem('head')}>{Status}</div>
  150. {this.slots()}
  151. </div>
  152. </div>
  153. );
  154. }
  155. });