index.js 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. import baseComponent from '../helpers/baseComponent'
  2. import classNames from '../helpers/libs/classNames'
  3. import { getTouchPoints, getPointsNumber, getSwipeDirection } from '../helpers/shared/gestures'
  4. import { useRect } from '../helpers/hooks/useDOM'
  5. baseComponent({
  6. relations: {
  7. '../swipe-action-group/index': {
  8. type: 'ancestor',
  9. },
  10. },
  11. properties: {
  12. prefixCls: {
  13. type: String,
  14. value: 'wux-swipe',
  15. },
  16. autoClose: {
  17. type: Boolean,
  18. value: false,
  19. },
  20. disabled: {
  21. type: Boolean,
  22. value: false,
  23. },
  24. left: {
  25. type: Array,
  26. value: [],
  27. observer: 'updateBtns',
  28. },
  29. right: {
  30. type: Array,
  31. value: [],
  32. observer: 'updateBtns',
  33. },
  34. useSlots: {
  35. type: Boolean,
  36. value: false,
  37. },
  38. data: {
  39. type: null,
  40. value: null,
  41. },
  42. },
  43. data: {
  44. index: 0,
  45. swiping: false,
  46. showCover: false,
  47. offsetStyle: '',
  48. },
  49. computed: {
  50. classes: ['prefixCls, swiping', function(prefixCls, swiping) {
  51. const wrap = classNames(prefixCls, {
  52. [`${prefixCls}--swiping`]: swiping,
  53. })
  54. const cover = `${prefixCls}__cover`
  55. const left = classNames(`${prefixCls}__actions`, {
  56. [`${prefixCls}__actions--left`]: true,
  57. })
  58. const right = classNames(`${prefixCls}__actions`, {
  59. [`${prefixCls}__actions--right`]: true,
  60. })
  61. const action = `${prefixCls}__action`
  62. const text = `${prefixCls}__text`
  63. const content = `${prefixCls}__content`
  64. return {
  65. wrap,
  66. cover,
  67. left,
  68. right,
  69. action,
  70. text,
  71. content,
  72. }
  73. }],
  74. },
  75. methods: {
  76. updated(index) {
  77. if (this.data.index !== index) {
  78. this.setData({ index })
  79. }
  80. },
  81. onCloseSwipe() {
  82. const parent = this.getRelationsByName('../swipe-action-group/index')[0]
  83. if (parent) {
  84. parent.onCloseSwipe(this.data.index)
  85. }
  86. },
  87. getContentEasing(value, limit) {
  88. // limit content style left when value > actions width
  89. const delta = Math.abs(value) - Math.abs(limit)
  90. const isOverflow = delta > 0
  91. const factor = limit > 0 ? 1 : -1
  92. if (isOverflow) {
  93. value = limit + Math.pow(delta, 0.85) * factor
  94. return Math.abs(value) > Math.abs(limit) ? limit : value
  95. }
  96. return value
  97. },
  98. setStyle(value) {
  99. const limit = value > 0 ? this.btnsLeftWidth : -this.btnsRightWidth
  100. const left = this.getContentEasing(value, limit)
  101. const offsetStyle = `left: ${left}px`
  102. const showCover = Math.abs(value) > 0
  103. if (this.data.offsetStyle !== offsetStyle || this.data.showCover !== showCover) {
  104. this.setData({ offsetStyle, showCover })
  105. }
  106. },
  107. updateBtns() {
  108. const { prefixCls } = this.data
  109. useRect([`.${prefixCls}__actions--left`, `.${prefixCls}__actions--right`], this)
  110. .then((rects) => {
  111. const [left, right] = rects
  112. this.btnsLeftWidth = left ? left.width : 0
  113. this.btnsRightWidth = right ? right.width : 0
  114. })
  115. },
  116. onTap(e) {
  117. const { type } = e.currentTarget.dataset
  118. const params = {
  119. ...e.currentTarget.dataset,
  120. buttons: this.data[type],
  121. data: this.data.data,
  122. }
  123. if (this.data.autoClose) {
  124. this.onClose()
  125. }
  126. this.triggerEvent('click', params)
  127. },
  128. onAcitons() {
  129. if (this.data.autoClose) {
  130. this.onClose()
  131. }
  132. },
  133. onOpen(value, openedLeft, openedRight) {
  134. if (!this.openedLeft && !this.openedRight) {
  135. this.triggerEvent('open')
  136. }
  137. this.openedLeft = openedLeft
  138. this.openedRight = openedRight
  139. this.setStyle(value)
  140. },
  141. onClose() {
  142. if (this.openedLeft || this.openedRight) {
  143. this.triggerEvent('close')
  144. }
  145. this.openedLeft = false
  146. this.openedRight = false
  147. this.setStyle(0)
  148. },
  149. onOpenLeft() {
  150. this.onOpen(this.btnsLeftWidth, true, false)
  151. },
  152. onOpenRight() {
  153. this.onOpen(-this.btnsRightWidth, true, false)
  154. },
  155. onTouchStart(e) {
  156. if (this.data.disabled || getPointsNumber(e) > 1) return
  157. this.start = getTouchPoints(e)
  158. this.onCloseSwipe()
  159. },
  160. onTouchMove(e) {
  161. if (this.data.disabled || getPointsNumber(e) > 1) return
  162. this.move = getTouchPoints(e)
  163. const deltaX = this.move.x - this.start.x
  164. const direction = getSwipeDirection(this.start.x, this.move.x, this.start.y, this.move.y)
  165. const isLeft = direction === 'Left'
  166. const isRight = direction === 'Right'
  167. if (!isLeft && !isRight) return
  168. const { left, right, useSlots } = this.data
  169. this.needShowRight = isLeft && (useSlots || right.length > 0)
  170. this.needShowLeft = isRight && (useSlots || left.length > 0)
  171. if (this.needShowLeft || this.needShowRight) {
  172. this.swiping = true
  173. this.setData({ swiping: true })
  174. this.setStyle(deltaX)
  175. }
  176. },
  177. onTouchEnd(e) {
  178. if (this.data.disabled || getPointsNumber(e) > 1 || !this.swiping) return
  179. this.end = getTouchPoints(e)
  180. const deltaX = this.end.x - this.start.x
  181. const needOpenRight = this.needShowRight && Math.abs(deltaX) > this.btnsRightWidth / 2
  182. const needOpenLeft = this.needShowLeft && Math.abs(deltaX) > this.btnsLeftWidth / 2
  183. if (needOpenRight) {
  184. this.onOpenRight()
  185. } else if (needOpenLeft) {
  186. this.onOpenLeft()
  187. } else {
  188. this.onClose()
  189. }
  190. this.swiping = false
  191. this.setData({ swiping: false })
  192. this.needShowLeft = false
  193. this.needShowRight = false
  194. },
  195. noop() {},
  196. },
  197. created() {
  198. this.btnsLeftWidth = 0
  199. this.btnsRightWidth = 0
  200. this.openedLeft = false
  201. this.openedRight = false
  202. this.needShowLeft = false
  203. this.needShowRight = false
  204. },
  205. ready() {
  206. this.updateBtns()
  207. },
  208. })