index.js 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. import { use, range } from '../utils';
  2. import { preventDefault } from '../utils/event';
  3. import { TouchMixin } from '../mixins/touch';
  4. import { ClickOutsideMixin } from '../mixins/click-outside';
  5. const [sfc, bem] = use('swipe-cell');
  6. const THRESHOLD = 0.15;
  7. export default sfc({
  8. mixins: [TouchMixin, ClickOutsideMixin({
  9. event: 'touchstart',
  10. method: 'onClick'
  11. })],
  12. props: {
  13. onClose: Function,
  14. disabled: Boolean,
  15. leftWidth: Number,
  16. rightWidth: Number
  17. },
  18. data() {
  19. return {
  20. offset: 0,
  21. dragging: false
  22. };
  23. },
  24. methods: {
  25. open(position) {
  26. const offset = position === 'left' ? this.leftWidth : -this.rightWidth;
  27. this.swipeMove(offset);
  28. this.resetSwipeStatus();
  29. },
  30. close() {
  31. this.offset = 0;
  32. },
  33. resetSwipeStatus() {
  34. this.swiping = false;
  35. this.opened = true;
  36. },
  37. swipeMove(offset = 0) {
  38. this.offset = range(offset, -this.rightWidth, this.leftWidth);
  39. if (this.offset) {
  40. this.swiping = true;
  41. } else {
  42. this.opened = false;
  43. }
  44. },
  45. swipeLeaveTransition(direction) {
  46. const { offset, leftWidth, rightWidth } = this;
  47. const threshold = this.opened ? 1 - THRESHOLD : THRESHOLD;
  48. // right
  49. if (direction === 'right' && -offset > rightWidth * threshold && rightWidth > 0) {
  50. this.open('right');
  51. // left
  52. } else if (direction === 'left' && offset > leftWidth * threshold && leftWidth > 0) {
  53. this.open('left');
  54. // reset
  55. } else {
  56. this.swipeMove(0);
  57. }
  58. },
  59. startDrag(event) {
  60. if (this.disabled) {
  61. return;
  62. }
  63. this.dragging = true;
  64. this.startOffset = this.offset;
  65. this.touchStart(event);
  66. },
  67. onDrag(event) {
  68. if (this.disabled) {
  69. return;
  70. }
  71. this.touchMove(event);
  72. if (this.direction === 'horizontal') {
  73. preventDefault(event);
  74. this.swipeMove(this.deltaX + this.startOffset);
  75. }
  76. },
  77. endDrag() {
  78. if (this.disabled) {
  79. return;
  80. }
  81. this.dragging = false;
  82. if (this.swiping) {
  83. this.swipeLeaveTransition(this.offset > 0 ? 'left' : 'right');
  84. }
  85. },
  86. onClick(position = 'outside') {
  87. this.$emit('click', position);
  88. if (!this.offset) {
  89. return;
  90. }
  91. if (this.onClose) {
  92. this.onClose(position, this);
  93. } else {
  94. this.swipeMove(0);
  95. }
  96. }
  97. },
  98. render(h) {
  99. const onClick = (position, stop) => event => {
  100. if (stop) {
  101. event.stopPropagation();
  102. }
  103. this.onClick(position);
  104. };
  105. const wrapperStyle = {
  106. transform: `translate3d(${this.offset}px, 0, 0)`,
  107. transition: this.dragging ? 'none' : '.6s cubic-bezier(0.18, 0.89, 0.32, 1)'
  108. };
  109. return (
  110. <div
  111. class={bem()}
  112. onClick={onClick('cell')}
  113. onTouchstart={this.startDrag}
  114. onTouchmove={this.onDrag}
  115. onTouchend={this.endDrag}
  116. onTouchcancel={this.endDrag}
  117. >
  118. <div
  119. class={bem('wrapper')}
  120. style={wrapperStyle}
  121. onTransitionend={() => {
  122. this.swiping = false;
  123. }}
  124. >
  125. {this.leftWidth ? (
  126. <div class={bem('left')} onClick={onClick('left', true)}>
  127. {this.slots('left')}
  128. </div>
  129. ) : null}
  130. {this.slots()}
  131. {this.rightWidth ? (
  132. <div class={bem('right')} onClick={onClick('right', true)}>
  133. {this.slots('right')}
  134. </div>
  135. ) : null}
  136. </div>
  137. </div>
  138. );
  139. }
  140. });