drag-arrange.js 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. 'use strict';
  2. (function (factory) {
  3. if (typeof define === 'function' && define.amd) {
  4. define(['jquery'], factory);
  5. } else {
  6. factory(jQuery);
  7. }
  8. }
  9. (function ($) {
  10. var IS_TOUCH_DEVICE = ('ontouchstart' in document.documentElement);
  11. var DRAG_THRESHOLD = 5;
  12. var counter = 0;
  13. var dragEvents = (function () {
  14. if (IS_TOUCH_DEVICE) {
  15. return {
  16. START: 'touchstart',
  17. MOVE: 'touchmove',
  18. END: 'touchend'
  19. };
  20. } else {
  21. return {
  22. START: 'mousedown',
  23. MOVE: 'mousemove',
  24. END: 'mouseup'
  25. };
  26. }
  27. }());
  28. $.fn.arrangeable = function (options) {
  29. var dragging = false;
  30. var $clone;
  31. var dragElement;
  32. var originalClientX, originalClientY;
  33. var $elements;
  34. var touchDown = false;
  35. var leftOffset, topOffset;
  36. var eventNamespace;
  37. var $options = options;
  38. if (typeof options === "string") {
  39. if (options === 'destroy') {
  40. if (this.eq(0).data('drag-arrange-destroy')) {
  41. this.eq(0).data('drag-arrange-destroy')();
  42. }
  43. return this;
  44. }
  45. }
  46. options = $.extend({
  47. "dragEndEvent": "drag.end.arrangeable"
  48. }, options);
  49. var dragEndEvent = options["dragEndEvent"];
  50. $elements = this;
  51. eventNamespace = getEventNamespace();
  52. this.each(function () {
  53. var dragSelector = options.dragSelector;
  54. var self = this;
  55. var $this = $(this);
  56. if (dragSelector) {
  57. $this.on(dragEvents.START + eventNamespace,
  58. dragSelector, dragStartHandler);
  59. } else {
  60. $this.on(dragEvents.START + eventNamespace,
  61. dragStartHandler);
  62. }
  63. function dragStartHandler(e) {
  64. e.stopPropagation();
  65. touchDown = true;
  66. originalClientX = e.clientX
  67. || e.originalEvent.touches[0].clientX;
  68. originalClientY = e.clientY
  69. || e.originalEvent.touches[0].clientY;
  70. dragElement = self;
  71. }
  72. });
  73. $(document).on(dragEvents.MOVE + eventNamespace,
  74. dragMoveHandler).on(dragEvents.END + eventNamespace,
  75. dragEndHandler);
  76. function dragMoveHandler(e) {
  77. if (!touchDown) {
  78. return;
  79. }
  80. var $dragElement = $(dragElement);
  81. var dragDistanceX = (e.clientX || e.originalEvent.touches[0].clientX)
  82. - originalClientX;
  83. var dragDistanceY = (e.clientY || e.originalEvent.touches[0].clientY)
  84. - originalClientY;
  85. if (dragging) {
  86. e.stopPropagation();
  87. $clone.css({
  88. left: leftOffset + dragDistanceX,
  89. top: topOffset + dragDistanceY
  90. });
  91. shiftHoveredElement($clone, $dragElement, $elements);
  92. } else if (Math.abs(dragDistanceX) > DRAG_THRESHOLD
  93. || Math.abs(dragDistanceY) > DRAG_THRESHOLD) {
  94. $clone = clone($dragElement);
  95. leftOffset = dragElement.offsetLeft
  96. - parseInt($dragElement.css('margin-left'))
  97. - parseInt($dragElement.css('padding-left'));
  98. topOffset = dragElement.offsetTop
  99. - parseInt($dragElement.css('margin-top'))
  100. - parseInt($dragElement.css('padding-top'));
  101. $clone.css({
  102. left: leftOffset,
  103. top: topOffset
  104. });
  105. $dragElement.parent().append($clone);
  106. $dragElement.css('visibility', 'hidden');
  107. dragging = true;
  108. }
  109. }
  110. function dragEndHandler(e) {
  111. if (dragging) {
  112. e.stopPropagation();
  113. dragging = false;
  114. $clone.remove();
  115. dragElement.style.visibility = 'visible';
  116. $(dragElement).parent().trigger(dragEndEvent,
  117. [$(dragElement)]);
  118. //拖拽结束后执行回调,传入当前拖拽的对象
  119. if ($options.callback) $options.callback($(dragElement));
  120. }
  121. touchDown = false;
  122. }
  123. function destroy() {
  124. $elements.each(function () {
  125. var dragSelector = options.dragSelector;
  126. var $this = $(this);
  127. if (dragSelector) {
  128. $this.off(dragEvents.START + eventNamespace,
  129. dragSelector);
  130. } else {
  131. $this.off(dragEvents.START + eventNamespace);
  132. }
  133. });
  134. $(document).off(dragEvents.MOVE + eventNamespace).off(
  135. dragEvents.END + eventNamespace);
  136. $elements.eq(0).data('drag-arrange-destroy', null);
  137. $elements = null;
  138. dragMoveHandler = null;
  139. dragEndHandler = null;
  140. }
  141. this.eq(0).data('drag-arrange-destroy', destroy);
  142. };
  143. function clone($element) {
  144. var $clone = $element.clone();
  145. $clone.css({
  146. position: 'absolute',
  147. width: $element.width(),
  148. height: $element.height(),
  149. 'z-index': 100000
  150. });
  151. return $clone;
  152. }
  153. function getHoveredElement($clone, $dragElement, $movableElements) {
  154. var cloneOffset = $clone.offset();
  155. var cloneWidth = $clone.width();
  156. var cloneHeight = $clone.height();
  157. var cloneLeftPosition = cloneOffset.left;
  158. var cloneRightPosition = cloneOffset.left + cloneWidth;
  159. var cloneTopPosition = cloneOffset.top;
  160. var cloneBottomPosition = cloneOffset.top + cloneHeight;
  161. var $currentElement;
  162. var horizontalMidPosition, verticalMidPosition;
  163. var offset, overlappingX, overlappingY, inRange;
  164. for (var i = 0; i < $movableElements.length; i++) {
  165. $currentElement = $movableElements.eq(i);
  166. if ($currentElement[0] === $dragElement[0]) {
  167. continue;
  168. }
  169. offset = $currentElement.offset();
  170. horizontalMidPosition = offset.left + 0.5
  171. * $currentElement.width();
  172. verticalMidPosition = offset.top + 0.5
  173. * $currentElement.height();
  174. overlappingX = (horizontalMidPosition < cloneRightPosition)
  175. && (horizontalMidPosition > cloneLeftPosition);
  176. overlappingY = (verticalMidPosition < cloneBottomPosition)
  177. && (verticalMidPosition > cloneTopPosition);
  178. inRange = overlappingX && overlappingY;
  179. if (inRange) {
  180. return $currentElement[0];
  181. }
  182. }
  183. }
  184. function shiftHoveredElement($clone, $dragElement, $movableElements) {
  185. var hoveredElement = getHoveredElement($clone, $dragElement,
  186. $movableElements);
  187. if (hoveredElement !== $dragElement[0]) {
  188. var hoveredElementIndex = $movableElements
  189. .index(hoveredElement);
  190. var dragElementIndex = $movableElements.index($dragElement);
  191. if (hoveredElementIndex < dragElementIndex) {
  192. $(hoveredElement).before($dragElement);
  193. } else {
  194. $(hoveredElement).after($dragElement);
  195. }
  196. shiftElementPosition($movableElements, dragElementIndex,
  197. hoveredElementIndex);
  198. }
  199. }
  200. function shiftElementPosition(arr, fromIndex, toIndex) {
  201. var temp = arr.splice(fromIndex, 1)[0];
  202. return arr.splice(toIndex, 0, temp);
  203. }
  204. function getEventNamespace() {
  205. counter += 1;
  206. return '.drag-arrange-' + counter;
  207. }
  208. }));