index.js 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. // Utils
  2. import { createNamespace } from '../utils';
  3. import { preventDefault } from '../utils/dom/event';
  4. import { getScrollTop, getScroller } from '../utils/dom/scroll'; // Mixins
  5. import { TouchMixin } from '../mixins/touch'; // Components
  6. import Loading from '../loading';
  7. var _createNamespace = createNamespace('pull-refresh'),
  8. createComponent = _createNamespace[0],
  9. bem = _createNamespace[1],
  10. t = _createNamespace[2];
  11. var DEFAULT_HEAD_HEIGHT = 50;
  12. var TEXT_STATUS = ['pulling', 'loosing', 'success'];
  13. export default createComponent({
  14. mixins: [TouchMixin],
  15. props: {
  16. disabled: Boolean,
  17. successText: String,
  18. pullingText: String,
  19. loosingText: String,
  20. loadingText: String,
  21. pullDistance: [Number, String],
  22. value: {
  23. type: Boolean,
  24. required: true
  25. },
  26. successDuration: {
  27. type: [Number, String],
  28. default: 500
  29. },
  30. animationDuration: {
  31. type: [Number, String],
  32. default: 300
  33. },
  34. headHeight: {
  35. type: [Number, String],
  36. default: DEFAULT_HEAD_HEIGHT
  37. }
  38. },
  39. data: function data() {
  40. return {
  41. status: 'normal',
  42. distance: 0,
  43. duration: 0
  44. };
  45. },
  46. computed: {
  47. touchable: function touchable() {
  48. return this.status !== 'loading' && this.status !== 'success' && !this.disabled;
  49. },
  50. headStyle: function headStyle() {
  51. if (this.headHeight !== DEFAULT_HEAD_HEIGHT) {
  52. return {
  53. height: this.headHeight + "px"
  54. };
  55. }
  56. }
  57. },
  58. watch: {
  59. value: function value(loading) {
  60. this.duration = this.animationDuration;
  61. if (loading) {
  62. this.setStatus(+this.headHeight, true);
  63. } else if (this.slots('success') || this.successText) {
  64. this.showSuccessTip();
  65. } else {
  66. this.setStatus(0, false);
  67. }
  68. }
  69. },
  70. mounted: function mounted() {
  71. this.bindTouchEvent(this.$refs.track);
  72. this.scrollEl = getScroller(this.$el);
  73. },
  74. methods: {
  75. checkPullStart: function checkPullStart(event) {
  76. this.ceiling = getScrollTop(this.scrollEl) === 0;
  77. if (this.ceiling) {
  78. this.duration = 0;
  79. this.touchStart(event);
  80. }
  81. },
  82. onTouchStart: function onTouchStart(event) {
  83. if (this.touchable) {
  84. this.checkPullStart(event);
  85. }
  86. },
  87. onTouchMove: function onTouchMove(event) {
  88. if (!this.touchable) {
  89. return;
  90. }
  91. if (!this.ceiling) {
  92. this.checkPullStart(event);
  93. }
  94. this.touchMove(event);
  95. if (this.ceiling && this.deltaY >= 0 && this.direction === 'vertical') {
  96. preventDefault(event);
  97. this.setStatus(this.ease(this.deltaY));
  98. }
  99. },
  100. onTouchEnd: function onTouchEnd() {
  101. var _this = this;
  102. if (this.touchable && this.ceiling && this.deltaY) {
  103. this.duration = this.animationDuration;
  104. if (this.status === 'loosing') {
  105. this.setStatus(+this.headHeight, true);
  106. this.$emit('input', true); // ensure value change can be watched
  107. this.$nextTick(function () {
  108. _this.$emit('refresh');
  109. });
  110. } else {
  111. this.setStatus(0);
  112. }
  113. }
  114. },
  115. ease: function ease(distance) {
  116. var pullDistance = +(this.pullDistance || this.headHeight);
  117. if (distance > pullDistance) {
  118. if (distance < pullDistance * 2) {
  119. distance = pullDistance + (distance - pullDistance) / 2;
  120. } else {
  121. distance = pullDistance * 1.5 + (distance - pullDistance * 2) / 4;
  122. }
  123. }
  124. return Math.round(distance);
  125. },
  126. setStatus: function setStatus(distance, isLoading) {
  127. var status;
  128. if (isLoading) {
  129. status = 'loading';
  130. } else if (distance === 0) {
  131. status = 'normal';
  132. } else {
  133. status = distance < (this.pullDistance || this.headHeight) ? 'pulling' : 'loosing';
  134. }
  135. this.distance = distance;
  136. if (status !== this.status) {
  137. this.status = status;
  138. }
  139. },
  140. genStatus: function genStatus() {
  141. var h = this.$createElement;
  142. var status = this.status,
  143. distance = this.distance;
  144. var slot = this.slots(status, {
  145. distance: distance
  146. });
  147. if (slot) {
  148. return slot;
  149. }
  150. var nodes = [];
  151. var text = this[status + "Text"] || t(status);
  152. if (TEXT_STATUS.indexOf(status) !== -1) {
  153. nodes.push(h("div", {
  154. "class": bem('text')
  155. }, [text]));
  156. }
  157. if (status === 'loading') {
  158. nodes.push(h(Loading, {
  159. "attrs": {
  160. "size": "16"
  161. }
  162. }, [text]));
  163. }
  164. return nodes;
  165. },
  166. showSuccessTip: function showSuccessTip() {
  167. var _this2 = this;
  168. this.status = 'success';
  169. setTimeout(function () {
  170. _this2.setStatus(0);
  171. }, this.successDuration);
  172. }
  173. },
  174. render: function render() {
  175. var h = arguments[0];
  176. var trackStyle = {
  177. transitionDuration: this.duration + "ms",
  178. transform: this.distance ? "translate3d(0," + this.distance + "px, 0)" : ''
  179. };
  180. return h("div", {
  181. "class": bem()
  182. }, [h("div", {
  183. "ref": "track",
  184. "class": bem('track'),
  185. "style": trackStyle
  186. }, [h("div", {
  187. "class": bem('head'),
  188. "style": this.headStyle
  189. }, [this.genStatus()]), this.slots()])]);
  190. }
  191. });