index.js 6.8 KB

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