ddsort.js 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. /**
  2. * DDSort: drag and drop sorting.
  3. * Documentation: https://github.com/Barrior/DDSort
  4. */
  5. +function ($) {
  6. var defaultOptions = {
  7. down: $.noop,
  8. move: $.noop,
  9. up: $.noop,
  10. target: 'li',
  11. delay: 100,
  12. cloneStyle: {
  13. 'background-color': '#eee'
  14. },
  15. floatStyle: {
  16. // 用固定定位可以防止定位父级不是Body的情况的兼容处理,表示不兼容IE6,无妨
  17. 'position': 'fixed',
  18. // 'border': '1px solid #ccc',
  19. 'background-color': '#fff'
  20. // 'box-shadow': '10px 10px 20px 0 #eee',
  21. // 'webkitTransform': 'rotate(4deg)',
  22. // 'mozTransform': 'rotate(4deg)',
  23. // 'msTransform': 'rotate(4deg)',
  24. // 'transform': 'rotate(4deg)'
  25. }
  26. };
  27. $.fn.DDSort = function (options) {
  28. var $doc = $(document);
  29. var settings = $.extend(true, {}, defaultOptions, options);
  30. return this.each(function () {
  31. var that = $(this);
  32. var height = 'height';
  33. var width = 'width';
  34. if (that.css('box-sizing') == 'border-box') {
  35. height = 'outerHeight';
  36. width = 'outerWidth';
  37. }
  38. that.on('mousedown.DDSort touchstart.DDSort', settings.target, function (e) {
  39. var startTime = new Date().getTime();
  40. // 桌面端只允许鼠标左键拖动
  41. if (e.type == 'mousedown' && e.which != 1) return;
  42. // 防止表单元素,a 链接,可编辑元素失效
  43. var tagName = e.target.tagName.toLowerCase();
  44. if (tagName == 'input' || tagName == 'textarea' || tagName == 'select' ||
  45. tagName == 'a' || $(e.target).prop('contenteditable') == 'true') {
  46. return;
  47. }
  48. var self = this;
  49. var $this = $(self);
  50. // 鼠标按下时的元素偏移
  51. var offset = $this.offset();
  52. // 鼠标按下时的光标坐标
  53. // 桌面端
  54. var pageX = e.pageX;
  55. var pageY = e.pageY;
  56. // 移动端
  57. var targetTouches = e.originalEvent.targetTouches;
  58. if (e.type == 'touchstart' && targetTouches) {
  59. pageX = targetTouches[0].pageX;
  60. pageY = targetTouches[0].pageY;
  61. }
  62. var clone = $this.clone()
  63. .css(settings.cloneStyle)
  64. .css('height', $this[height]())
  65. .empty();
  66. var hasClone = 1;
  67. // 缓存计算
  68. var thisOuterHeight = $this.outerHeight(),
  69. thisOuterWidth = $this.outerWidth(),
  70. thatOuterHeight = that.outerHeight(),
  71. thatOuterWidth = that.outerWidth();
  72. // 滚动速度
  73. var upSpeed = thisOuterHeight,
  74. downSpeed = thisOuterHeight,
  75. leftSpeed = thisOuterWidth,
  76. rightSpeed = thisOuterWidth,
  77. maxSpeed = thisOuterHeight * 3;
  78. settings.down.call(self);
  79. $doc.on('mousemove.DDSort touchmove.DDSort', function (e) {
  80. // 鼠标移动时的光标坐标
  81. // 桌面端
  82. var _pageX = e.pageX;
  83. var _pageY = e.pageY;
  84. // 移动端
  85. var targetTouches = e.originalEvent.targetTouches;
  86. if (e.type == 'touchmove' && targetTouches) {
  87. _pageX = targetTouches[0].pageX;
  88. _pageY = targetTouches[0].pageY;
  89. }
  90. if (new Date().getTime() - startTime < settings.delay) {
  91. return;
  92. }
  93. if (hasClone) {
  94. $this.before(clone)
  95. .css('width', $this[width]())
  96. .css(settings.floatStyle)
  97. .appendTo($this.parent());
  98. hasClone = 0;
  99. }
  100. var disX = pageX - _pageX;
  101. var disY = pageY - _pageY;
  102. var left = offset.left - disX;
  103. var top = offset.top - disY;
  104. $this.offset({
  105. left: left,
  106. top: top
  107. });
  108. var $left = getLeft(clone),
  109. $right = getRight(clone, $this),
  110. $top = getTop(clone),
  111. $under = getUnder(clone, $this);
  112. if ($top && $top.length && top < $top.offset().top + $top.outerHeight(true) / 2) {
  113. // 向上排序
  114. $top.before(clone);
  115. } else if ($under && $under.length && top + thisOuterHeight > $under.offset().top + $under.outerHeight(true) / 2) {
  116. // 向下排序
  117. $under.after(clone);
  118. } else if($left && $left.length && left < $left.offset().left + $left.outerWidth(true) / 2) {
  119. //向左排序
  120. $left.before(clone);
  121. } else if($right && $right.length && left + thisOuterWidth > $right.offset().left + $right.outerWidth(true) / 2) {
  122. //向右排序
  123. $right.after(clone);
  124. }
  125. // 处理滚动条,that 是带着滚动条的元素,这里默认以为 that 元素是这样的元素(正常情况就是这样),
  126. // 如果使用者事件委托的元素不是这样的元素,那么需要提供接口出来
  127. var thatScrollTop = that.scrollTop();
  128. var thatOffsetTop = that.offset().top;
  129. if (top < thatOffsetTop) {
  130. // 向上滚动
  131. downSpeed = thisOuterHeight;
  132. upSpeed = ++upSpeed > maxSpeed ? maxSpeed : upSpeed;
  133. var scrollVal = thatScrollTop - upSpeed;
  134. that.scrollTop(scrollVal);
  135. } else if (top + thisOuterHeight - thatOffsetTop > thatOuterHeight) {
  136. // 向下滚动
  137. upSpeed = thisOuterHeight;
  138. downSpeed = ++downSpeed > maxSpeed ? maxSpeed : downSpeed;
  139. var scrollVal = thatScrollTop + downSpeed;
  140. that.scrollTop(scrollVal);
  141. }
  142. var thatScrollLeft = that.scrollLeft();
  143. var thatOffsetLeft = that.offset().left;
  144. if (left < that.offset().left) {
  145. // 向左滚动
  146. rightSpeed = thisOuterWidth;
  147. leftSpeed = ++leftSpeed > maxSpeed ? maxSpeed : leftSpeed;
  148. var scrollVal = thatScrollLeft - leftSpeed;
  149. that.scrollLeft(scrollVal);
  150. } else if (left + thisOuterWidth - thatOffsetLeft > thatOuterWidth) {
  151. // 向右滚动
  152. leftSpeed = thisOuterWidth;
  153. rightSpeed = ++rightSpeed > maxSpeed ? maxSpeed : rightSpeed;
  154. var scrollVal = thatScrollLeft + rightSpeed;
  155. that.scrollLeft(scrollVal);
  156. }
  157. settings.move.call(self, left, top);
  158. })
  159. .on('mouseup.DDSort touchend.DDSort', function () {
  160. $doc.off('mousemove.DDSort mouseup.DDSort touchmove.DDSort touchend.DDSort');
  161. // click 的时候也会触发 mouseup 事件,加上判断阻止这种情况
  162. if (!hasClone) {
  163. clone.before($this.removeAttr('style')).remove();
  164. settings.up.call(self);
  165. }
  166. });
  167. return false;
  168. });
  169. });
  170. };
  171. //允许计算误差
  172. var deviation = 5;
  173. var getLeft = function (clone) {
  174. var left = clone.prev();
  175. if(left.length && clone.offset().top==left.offset().top) {
  176. var _dev = Math.abs(clone.offset().left - (left.offset().left + left.outerWidth(true)));
  177. if(_dev <= deviation) {
  178. return left;
  179. }
  180. }
  181. return undefined;
  182. }
  183. var getTop = function (clone, prev) {
  184. if(!prev){
  185. prev = clone.prev();
  186. }
  187. if(!prev.length) {
  188. return undefined;
  189. }
  190. if(clone.offset().left==prev.offset().left) {
  191. var _dev = Math.abs(clone.offset().top - (prev.offset().top+prev.outerHeight(true)));
  192. if(_dev <= deviation) {
  193. return prev;
  194. }
  195. }
  196. return getTop(clone, prev.prev());
  197. }
  198. var getRight = function (clone, $this) {
  199. var rigth = clone.next().not($this);
  200. if(rigth.length && clone.offset().top==rigth.offset().top) {
  201. var _dev = Math.abs(clone.offset().left - (rigth.offset().left-clone.outerWidth(true)));
  202. if(_dev <= deviation) {
  203. return rigth;
  204. }
  205. }
  206. return undefined;
  207. }
  208. var getUnder = function (clone, $this, next) {
  209. if(!next){
  210. next = clone.next().not($this);
  211. }
  212. if(!next.length) {
  213. return undefined;
  214. }
  215. if(clone.offset().left==next.offset().left) {
  216. var _dev = Math.abs(clone.offset().top - (next.offset().top-clone.outerHeight(true)));
  217. if(_dev <= deviation) {
  218. return next;
  219. }
  220. }
  221. return getUnder(clone, $this, next.next().not($this));
  222. }
  223. }(jQuery);