index.wxs 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. // 判断是否出界
  2. var isOutRange = function(x1, y1, x2, y2, x3, y3) {
  3. return x1 < 0 || x1 >= y1 || x2 < 0 || x2 >= y2 || x3 < 0 || x3 >= y3
  4. }
  5. var edit = false
  6. function bool(str) {
  7. return str === 'true' || str === true
  8. }
  9. /**
  10. * 排序核心
  11. * @param {Object} startKey 开始时位置
  12. * @param {Object} endKey 结束时位置
  13. * @param {Object} instance wxs内的局部变量快照
  14. */
  15. var sortCore = function(startKey, endKey, state) {
  16. var basedata = state.basedata
  17. var excludeFix = function(sortKey, type) {
  18. // fixed 元素位置不会变化, 这里直接用 sortKey 获取,更加便捷
  19. if (state.list[sortKey].fixed) {
  20. var _sortKey = type ? --sortKey : ++sortKey
  21. return excludeFix(sortKey, type)
  22. }
  23. return sortKey
  24. }
  25. // 先获取到 endKey 对应的 realKey, 防止下面排序过程中该 realKey 被修改
  26. var endRealKey = -1
  27. state.list.forEach(function(item) {
  28. if (item.sortKey === endKey) endRealKey = item.realKey
  29. })
  30. return state.list.map(function(item) {
  31. if (item.fixed) return item
  32. var sortKey = item.sortKey
  33. var realKey = item.realKey
  34. if (startKey < endKey) {
  35. // 正序拖动
  36. if (sortKey > startKey && sortKey <= endKey) {
  37. --realKey
  38. sortKey = excludeFix(--sortKey, true)
  39. } else if (sortKey === startKey) {
  40. realKey = endRealKey
  41. sortKey = endKey
  42. }
  43. } else if (startKey > endKey) {
  44. // 倒序拖动
  45. if (sortKey >= endKey && sortKey < startKey) {
  46. ++realKey
  47. sortKey = excludeFix(++sortKey, false)
  48. } else if (sortKey === startKey) {
  49. realKey = endRealKey
  50. sortKey = endKey
  51. }
  52. }
  53. if (item.sortKey != sortKey) {
  54. item.translateX = (sortKey % basedata.columns) * 100 + '%'
  55. item.translateY = Math.floor(sortKey / basedata.columns) * 100 + '%'
  56. item.sortKey = sortKey
  57. item.realKey = realKey
  58. }
  59. return item
  60. })
  61. }
  62. var triggerCustomEvent = function(list, type, instance) {
  63. if (!instance) return
  64. var _list = [],
  65. listData = [];
  66. list.forEach(function(item) {
  67. _list[item.sortKey] = item
  68. })
  69. _list.forEach(function(item) {
  70. listData.push(item.data)
  71. })
  72. // 编译到小程序 funcName作为参数传递导致事件不执行
  73. switch(type) {
  74. case 'change':
  75. instance.callMethod('change', {data: listData})
  76. break
  77. case 'sortEnd':
  78. instance.callMethod('sortEnd', {data: listData})
  79. break
  80. }
  81. }
  82. var listObserver = function(newVal, oldVal, ownerInstance, instance) {
  83. var state = ownerInstance.getState()
  84. state.itemsInstance = ownerInstance.selectAllComponents('.tn-drag__item')
  85. state.list = newVal || []
  86. state.list.forEach(function(item, index) {
  87. var itemInstance = state.itemsInstance[index]
  88. if (item && itemInstance) {
  89. itemInstance.setStyle({
  90. 'transform': 'translate3d('+ item.translateX + ',' + item.translateY +', 0)'
  91. })
  92. if (item.fixed) itemInstance.addClass('tn-drag__fixed')
  93. }
  94. })
  95. }
  96. var baseDataObserver = function(newVal, oldVal, ownerInstance, instance) {
  97. var state = ownerInstance.getState()
  98. state.basedata = newVal
  99. }
  100. var longPress = function(event, ownerInstance) {
  101. var instance = event.instance
  102. var dataset = instance.getDataset()
  103. var state = ownerInstance.getState()
  104. edit = bool(dataset.edit)
  105. if (!edit) return
  106. if (!state.basedata || state.basedata === 'undefined') {
  107. state.basedata = JSON.parse(dataset.basedata)
  108. }
  109. var basedata = state.basedata
  110. var touches = event.changedTouches[0]
  111. if (!touches) return
  112. state.current = +dataset.index
  113. // 初始项是固定项则返回
  114. var item = state.list[state.current]
  115. if (item && item.fixed) return
  116. // 如果已经在 drag 中则返回, 防止多指触发 drag 动作, touchstart 事件中有效果
  117. if (state.dragging) return
  118. ownerInstance.callMethod("drag", {
  119. dragging: true
  120. })
  121. // 计算X, Y轴初始位移,使item中心移动到点击处,单列的时候X轴初始不做位移
  122. state.translateX = basedata.columns === 1 ? 0 : touches.pageX - (basedata.itemWidth / 2 + basedata.left)
  123. state.translateY = touches.pageY - (basedata.itemHeight / 2 + basedata.top)
  124. state.touchId = touches.identifier
  125. instance.setStyle({
  126. 'transform': 'translate3d(' + state.translateX + 'px,' + state.translateY +'px, 0)'
  127. })
  128. state.itemsInstance.forEach(function(item, index) {
  129. item.removeClass("tn-drag__transition").removeClass("tn-drag__current")
  130. item.addClass(index === state.current ? "tn-drag__current" : "tn-drag__transition")
  131. })
  132. ownerInstance.callMethod("vibrate")
  133. state.dragging = true
  134. }
  135. var touchStart = function(event, ownerInstance) {
  136. var instance = event.instance
  137. var dataset = instance.getDataset()
  138. edit = bool(dataset.edit)
  139. }
  140. var touchMove = function(event, ownerInstance) {
  141. var instance = event.instance
  142. var dataset = instance.getDataset()
  143. var state = ownerInstance.getState()
  144. var basedata = state.basedata
  145. if (!state.dragging || !edit) return
  146. var touches = event.changedTouches[0]
  147. if (!touches) return
  148. // 如果不是同一个触发点则返回
  149. if (state.touchId !== touches.identifier) return
  150. // 计算X,Y轴位移, 单列时候X轴初始不做位移
  151. var translateX = basedata.columns === 1 ? 0 : touches.pageX - (basedata.itemWidth / 2 + basedata.left)
  152. var translateY = touches.pageY - (basedata.itemHeight / 2 + basedata.top)
  153. // 到顶到低自动滑动
  154. if (touches.clientY > basedata.windowHeight - basedata.itemHeight - basedata.realBottomSize) {
  155. // 当前触摸点pageY + item高度 - (屏幕高度 - 底部固定区域高度)
  156. ownerInstance.callMethod('pageScroll', {
  157. scrollTop: touches.pageY + basedata.itemHeight - (basedata.windowHeight - basedata.realBottomSize)
  158. })
  159. } else if (touches.clientY < basedata.itemHeight + basedata.realTopSize) {
  160. // 当前触摸点pageY - item高度 - 顶部固定区域高
  161. ownerInstance.callMethod('pageScroll', {
  162. scrollTop: touches.pageY - basedata.itemHeight - basedata.realTopSize
  163. })
  164. }
  165. // 设置当前激活元素的偏移量
  166. instance.setStyle({
  167. 'transform': 'translate3d('+ translateX + 'px,' + translateY + 'px, 0)'
  168. })
  169. var startKey = state.list[state.current].sortKey
  170. var currentX = Math.round(translateX / basedata.itemWidth)
  171. var currentY = Math.round(translateY / basedata.itemHeight)
  172. var endKey = currentX + basedata.columns * currentY
  173. // 目标项时固定项则返回
  174. var item = state.list[endKey]
  175. if (item && item.fixed) return
  176. // X轴或者Y轴超出范围则返回
  177. if (isOutRange(currentX, basedata.columns, currentY, basedata.rows, endKey, state.list.length)) return
  178. // 防止拖拽过程中发生乱序问题
  179. if (startKey === endKey || startKey === state.preStartKey) return
  180. state.preStartKey = startKey
  181. var list = sortCore(startKey, endKey, state)
  182. state.itemsInstance.forEach(function(itemInstance, index) {
  183. var item = list[index]
  184. if (index !== state.current) {
  185. itemInstance.setStyle({
  186. 'transform': 'translate3d('+ item.translateX + ',' + item.translateY +', 0)'
  187. })
  188. }
  189. })
  190. // ownerInstance.callMethod('vibrate')
  191. ownerInstance.callMethod('listDataChange', {
  192. data: list
  193. })
  194. triggerCustomEvent(list, "change", ownerInstance)
  195. }
  196. var touchEnd = function(event, ownerInstance) {
  197. var instance = event.instance
  198. var dataset = instance.getDataset()
  199. var state = ownerInstance.getState()
  200. var basedata = state.basedata
  201. if (!state.dragging || !edit) return
  202. triggerCustomEvent(state.list, "sortEnd", ownerInstance)
  203. instance.addClass('tn-drag__transition')
  204. instance.setStyle({
  205. 'transform': 'translate3d('+ state.list[state.current].translateX + ',' + state.list[state.current].translateY + ', 0)'
  206. })
  207. state.itemsInstance.forEach(function(item, index) {
  208. item.removeClass('tn-drag__transition')
  209. })
  210. state.preStartKey = -1
  211. state.dragging = false
  212. ownerInstance.callMethod('drag', {
  213. dragging: false
  214. })
  215. state.current = -1
  216. state.translateX = 0
  217. state.translateY = 0
  218. }
  219. module.exports = {
  220. longPress: longPress,
  221. touchStart: touchStart,
  222. touchMove: touchMove,
  223. touchEnd: touchEnd,
  224. baseDataObserver: baseDataObserver,
  225. listObserver: listObserver
  226. }