App.js 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496
  1. import _Object$getPrototypeOf from 'babel-runtime/core-js/object/get-prototype-of';
  2. import _classCallCheck from 'babel-runtime/helpers/classCallCheck';
  3. import _createClass from 'babel-runtime/helpers/createClass';
  4. import _possibleConstructorReturn from 'babel-runtime/helpers/possibleConstructorReturn';
  5. import _inherits from 'babel-runtime/helpers/inherits';
  6. import _extends from 'babel-runtime/helpers/extends';
  7. import React from 'react';
  8. import PropTypes from 'prop-types';
  9. import GridItem from './GridItem';
  10. import './style.css';
  11. var correctLayout = function correctLayout(layout) {
  12. for (var i = 0; i < layout.length; i++) {
  13. if (collision(layout[i], layout[i + 1])) {
  14. return layoutCheck(layout, layout[i], layout[i].key, layout[i].key, -1);
  15. }
  16. }
  17. };
  18. var layoutItemForkey = function layoutItemForkey(layout, key) {
  19. for (var i = 0, length = layout.length; i < length; i++) {
  20. if (key === layout[i].key) {
  21. return layout[i];
  22. }
  23. }
  24. };
  25. var MapLayoutTostate = function MapLayoutTostate(layout, children) {
  26. return layout.map(function (child, index) {
  27. var newChild = _extends({}, child, { isUserMove: true, key: children[index].key });
  28. return newChild;
  29. });
  30. };
  31. var syncLayout = function syncLayout(layout, key, GridX, GridY, isUserMove) {
  32. var newlayout = layout.map(function (item) {
  33. if (item.key === key) {
  34. item.GridX = GridX;
  35. item.GridY = GridY;
  36. item.isUserMove = isUserMove;
  37. return item;
  38. }
  39. return item;
  40. });
  41. return newlayout;
  42. };
  43. var collision = function collision(a, b) {
  44. if (a.GridX === b.GridX && a.GridY === b.GridY && a.w === b.w && a.h === b.h) {
  45. return true;
  46. }
  47. if (a.GridX + a.w <= b.GridX) return false;
  48. if (a.GridX >= b.GridX + b.w) return false;
  49. if (a.GridY + a.h <= b.GridY) return false;
  50. if (a.GridY >= b.GridY + b.h) return false;
  51. return true;
  52. };
  53. var sortLayout = function sortLayout(layout) {
  54. return [].concat(layout).sort(function (a, b) {
  55. if (a.GridY > b.GridY || a.GridY === b.GridY && a.GridX > b.GridX) {
  56. return 1;
  57. } else if (a.GridY === b.GridY && a.GridX === b.GridX) {
  58. return 0;
  59. }
  60. return -1;
  61. });
  62. };
  63. /**获取layout中,item第一个碰撞到的物体 */
  64. var getFirstCollison = function getFirstCollison(layout, item) {
  65. for (var i = 0, length = layout.length; i < length; i++) {
  66. if (collision(layout[i], item)) {
  67. return layout[i];
  68. }
  69. }
  70. return null;
  71. };
  72. var compactItem = function compactItem(finishedLayout, item) {
  73. var newItem = _extends({}, item);
  74. if (finishedLayout.length === 0) {
  75. return _extends({}, newItem, { GridY: 0 });
  76. }
  77. /**
  78. * 类似一个递归调用
  79. */
  80. while (true) {
  81. var FirstCollison = getFirstCollison(finishedLayout, newItem);
  82. if (FirstCollison) {
  83. newItem.GridY = FirstCollison.GridY + FirstCollison.h;
  84. return newItem;
  85. }
  86. newItem.GridY--;
  87. if (newItem.GridY < 0) return _extends({}, newItem, { GridY: 0 });
  88. }
  89. return newItem;
  90. };
  91. var compactLayout = function compactLayout(layout) {
  92. var sorted = sortLayout(layout);
  93. var needCompact = Array(layout.length);
  94. var compareList = [];
  95. for (var i = 0, length = sorted.length; i < length; i++) {
  96. var finished = compactItem(compareList, sorted[i]);
  97. finished.isUserMove = false;
  98. compareList.push(finished);
  99. needCompact[layout.indexOf(sorted[i])] = finished;
  100. }
  101. return needCompact;
  102. };
  103. var layoutCheck = function layoutCheck(layout, layoutItem, key, fristItemkey, moving) {
  104. var i = [],
  105. movedItem = [];
  106. var newlayout = layout.map(function (item, idx) {
  107. if (item.key !== key) {
  108. if (collision(item, layoutItem)) {
  109. i.push(item.key);
  110. /**
  111. * 这里就是奇迹发生的地方,如果向上移动,那么必须注意的是
  112. * 一格一格的移动,而不是一次性移动
  113. */
  114. var offsetY = item.GridY + 1;
  115. /**这一行也非常关键,当向上移动的时候,碰撞的元素必须固定 */
  116. if (moving < 0 && layoutItem.GridY > 0) offsetY = item.GridY;
  117. if (layoutItem.GridY > item.GridY && layoutItem.GridY < item.GridY + item.h) {
  118. /**
  119. * 元素向上移动时,元素的上面空间不足,则不移动这个元素
  120. * 当元素移动到GridY>所要向上交换的元素时,就不会进入这里,直接交换元素
  121. *
  122. */
  123. offsetY = item.GridY;
  124. console.log('移动到', offsetY, '操纵的物体key', layoutItem.key, '移动的key', item.key);
  125. }
  126. if (moving > 0) {
  127. /**
  128. * 这个地方的实现有点奇妙了,moving用于检查最开始移动的方块
  129. * layoutItem.GridY > item.h*(3/4) 这个做会让方块移动比较准确和精确
  130. * 如果是其他数字,很可能会出现不可预计的效果
  131. * 建议取值范围在1/2 ~ 3/4之间
  132. */
  133. if (layoutItem.GridY + layoutItem.h < item.GridY) {
  134. (function () {
  135. var collision = void 0;
  136. var copy = _extends({}, item);
  137. while (true) {
  138. var newLayout = layout.filter(function (item) {
  139. if (item.key !== key && item.key !== copy.key) {
  140. return item;
  141. }
  142. });
  143. collision = getFirstCollison(newLayout, copy);
  144. if (collision) {
  145. offsetY = collision.GridY + collision.h;
  146. console.log('移动到', offsetY, '操纵的物体底部', copy.key, '碰撞顶部', copy.GridY, 'key', collision.key);
  147. break;
  148. } else {
  149. copy.GridY--;
  150. }
  151. if (copy.GridY < 0) {
  152. console.log('移动到', offsetY, '操纵的物体底部', copy.key, '碰撞顶部', copy.GridY);
  153. offsetY = 0;
  154. break;
  155. }
  156. }
  157. })();
  158. }
  159. }
  160. movedItem.push(_extends({}, item, { GridY: offsetY, isUserMove: false }));
  161. return _extends({}, item, { GridY: offsetY, isUserMove: false });
  162. }
  163. } else if (fristItemkey === key) {
  164. return _extends({}, item, { GridX: layoutItem.GridX, GridY: layoutItem.GridY, isUserMove: true });
  165. }
  166. return item;
  167. });
  168. /** 递归调用,将layout中的所有重叠元素全部移动 */
  169. if (i.length > 0 && movedItem.length > 0) {
  170. for (var c = 0; c < Math.min(movedItem.length, i.length); c++) {
  171. newlayout = layoutCheck(newlayout, movedItem[c], i[c], fristItemkey, undefined);
  172. }
  173. }
  174. return newlayout;
  175. };
  176. var DraggerLayout = function (_React$Component) {
  177. _inherits(DraggerLayout, _React$Component);
  178. function DraggerLayout(props) {
  179. _classCallCheck(this, DraggerLayout);
  180. var _this = _possibleConstructorReturn(this, (DraggerLayout.__proto__ || _Object$getPrototypeOf(DraggerLayout)).call(this, props));
  181. _this.state = {
  182. GridXMoving: 0,
  183. GridYMoving: 0,
  184. wMoving: 0,
  185. hMoving: 0,
  186. placeholderShow: false,
  187. placeholderMoving: false,
  188. layout: MapLayoutTostate(_this.props.layout, _this.props.children)
  189. };
  190. _this.onDrag = _this.onDrag.bind(_this);
  191. _this.onDragStart = _this.onDragStart.bind(_this);
  192. _this.onDragEnd = _this.onDragEnd.bind(_this);
  193. return _this;
  194. }
  195. _createClass(DraggerLayout, [{
  196. key: 'onDragStart',
  197. value: function onDragStart(bundles) {
  198. var GridX = bundles.GridX,
  199. GridY = bundles.GridY,
  200. w = bundles.w,
  201. h = bundles.h,
  202. UniqueKey = bundles.UniqueKey;
  203. var newlayout = syncLayout(this.state.layout, UniqueKey, GridX, GridY, true);
  204. this.setState({
  205. GridXMoving: GridX,
  206. GridYMoving: GridY,
  207. wMoving: w,
  208. hMoving: h,
  209. placeholderShow: true,
  210. placeholderMoving: true,
  211. layout: newlayout
  212. });
  213. }
  214. }, {
  215. key: 'onDrag',
  216. value: function onDrag(layoutItem, key) {
  217. var GridX = layoutItem.GridX,
  218. GridY = layoutItem.GridY;
  219. var moving = GridY - this.state.GridYMoving;
  220. var newLayout = layoutCheck(this.state.layout, layoutItem, key, key /*用户移动方块的key */, moving);
  221. var compactedLayout = compactLayout(newLayout);
  222. for (var i = 0; i < compactedLayout.length; i++) {
  223. if (key === compactedLayout[i].key) {
  224. /**
  225. * 特殊点:当我们移动元素的时候,元素在layout中的位置不断改变
  226. * 但是当isUserMove=true的时候,鼠标拖拽的元素不会随着位图变化而变化
  227. * 但是实际layout中的位置还是会改变
  228. * (isUserMove=true用于接触placeholder和元素的绑定)
  229. */
  230. compactedLayout[i].isUserMove = true;
  231. layoutItem.GridX = compactedLayout[i].GridX;
  232. layoutItem.GridY = compactedLayout[i].GridY;
  233. break;
  234. }
  235. }
  236. this.setState({
  237. GridXMoving: layoutItem.GridX,
  238. GridYMoving: layoutItem.GridY,
  239. layout: compactedLayout
  240. });
  241. }
  242. }, {
  243. key: 'onDragEnd',
  244. value: function onDragEnd(key) {
  245. var compactedLayout = compactLayout(this.state.layout);
  246. this.setState({
  247. placeholderShow: false,
  248. layout: compactedLayout
  249. });
  250. }
  251. }, {
  252. key: 'placeholder',
  253. value: function placeholder() {
  254. if (!this.state.placeholderShow) return null;
  255. var _props = this.props,
  256. col = _props.col,
  257. width = _props.width,
  258. padding = _props.padding,
  259. rowHeight = _props.rowHeight;
  260. var _state = this.state,
  261. GridXMoving = _state.GridXMoving,
  262. GridYMoving = _state.GridYMoving,
  263. wMoving = _state.wMoving,
  264. hMoving = _state.hMoving,
  265. placeholderMoving = _state.placeholderMoving;
  266. return React.createElement(GridItem, {
  267. col: col,
  268. containerWidth: width,
  269. containerPadding: padding,
  270. rowHeight: rowHeight,
  271. GridX: GridXMoving,
  272. GridY: GridYMoving,
  273. w: wMoving,
  274. h: hMoving,
  275. style: { background: '#a31', zIndex: -1, transition: ' all .15s' },
  276. isUserMove: !placeholderMoving
  277. });
  278. }
  279. }, {
  280. key: 'componentDidMount',
  281. value: function componentDidMount() {
  282. var that = this;
  283. setTimeout(function () {
  284. var layout = correctLayout(that.state.layout);
  285. that.setState({
  286. layout: compactLayout(layout)
  287. });
  288. }, 1);
  289. }
  290. }, {
  291. key: 'getGridItem',
  292. value: function getGridItem(child, index) {
  293. var layout = this.state.layout;
  294. var _props2 = this.props,
  295. col = _props2.col,
  296. width = _props2.width,
  297. padding = _props2.padding,
  298. rowHeight = _props2.rowHeight;
  299. var renderItem = layoutItemForkey(layout, child.key);
  300. return React.createElement(
  301. GridItem,
  302. {
  303. col: col,
  304. containerWidth: width,
  305. containerPadding: padding,
  306. rowHeight: rowHeight,
  307. GridX: renderItem.GridX,
  308. GridY: renderItem.GridY,
  309. w: renderItem.w,
  310. h: renderItem.h,
  311. onDrag: this.onDrag,
  312. onDragStart: this.onDragStart,
  313. onDragEnd: this.onDragEnd,
  314. index: index,
  315. isUserMove: renderItem.isUserMove,
  316. style: { background: '#329' },
  317. UniqueKey: child.key
  318. },
  319. child
  320. );
  321. }
  322. }, {
  323. key: 'render',
  324. value: function render() {
  325. var _this2 = this;
  326. var _props3 = this.props,
  327. layout = _props3.layout,
  328. col = _props3.col,
  329. width = _props3.width,
  330. padding = _props3.padding,
  331. rowHeight = _props3.rowHeight;
  332. return React.createElement(
  333. 'div',
  334. {
  335. className: 'DraggerLayout',
  336. style: { position: 'absolute', left: 100, width: this.props.width, height: 1000, border: '1px solid black' }
  337. },
  338. React.Children.map(this.props.children, function (child, index) {
  339. return _this2.getGridItem(child, index);
  340. }),
  341. this.placeholder()
  342. );
  343. }
  344. }]);
  345. return DraggerLayout;
  346. }(React.Component);
  347. DraggerLayout.PropTypes = {
  348. /**外部属性 */
  349. layout: PropTypes.array,
  350. col: PropTypes.number,
  351. width: PropTypes.number,
  352. /**每个元素的最小高度 */
  353. rowHeight: PropTypes.number,
  354. padding: PropTypes.number
  355. };
  356. export var LayoutDemo = function LayoutDemo() {
  357. var layout = [{
  358. GridX: 0, GridY: 0, w: 3, h: 3
  359. }, {
  360. GridX: 0, GridY: 0, w: 3, h: 3
  361. }, {
  362. GridX: 0, GridY: 0, w: 3, h: 3
  363. }, {
  364. GridX: 0, GridY: 0, w: 3, h: 3
  365. }, {
  366. GridX: 3, GridY: 8, w: 3, h: 3
  367. }, {
  368. GridX: 3, GridY: 8, w: 3, h: 3
  369. }, {
  370. GridX: 3, GridY: 8, w: 3, h: 3
  371. }, {
  372. GridX: 3, GridY: 8, w: 3, h: 3
  373. }];
  374. return React.createElement(
  375. DraggerLayout,
  376. { layout: layout, width: 1000, col: 12 },
  377. React.createElement(
  378. 'p',
  379. { key: 'a' },
  380. 'a'
  381. ),
  382. React.createElement(
  383. 'p',
  384. { key: 'b' },
  385. 'b'
  386. ),
  387. React.createElement(
  388. 'p',
  389. { key: 'c' },
  390. 'c'
  391. ),
  392. React.createElement(
  393. 'p',
  394. { key: 'd' },
  395. 'd'
  396. ),
  397. React.createElement(
  398. 'p',
  399. { key: 'e' },
  400. 'e'
  401. ),
  402. React.createElement(
  403. 'p',
  404. { key: 'f' },
  405. 'f'
  406. ),
  407. React.createElement(
  408. 'p',
  409. { key: 'g' },
  410. 'g'
  411. ),
  412. React.createElement(
  413. 'p',
  414. { key: 'h' },
  415. 'h'
  416. )
  417. );
  418. };
  419. ;
  420. var _temp = function () {
  421. if (typeof __REACT_HOT_LOADER__ === 'undefined') {
  422. return;
  423. }
  424. __REACT_HOT_LOADER__.register(correctLayout, 'correctLayout', 'app/src/App.js');
  425. __REACT_HOT_LOADER__.register(layoutItemForkey, 'layoutItemForkey', 'app/src/App.js');
  426. __REACT_HOT_LOADER__.register(MapLayoutTostate, 'MapLayoutTostate', 'app/src/App.js');
  427. __REACT_HOT_LOADER__.register(syncLayout, 'syncLayout', 'app/src/App.js');
  428. __REACT_HOT_LOADER__.register(collision, 'collision', 'app/src/App.js');
  429. __REACT_HOT_LOADER__.register(sortLayout, 'sortLayout', 'app/src/App.js');
  430. __REACT_HOT_LOADER__.register(getFirstCollison, 'getFirstCollison', 'app/src/App.js');
  431. __REACT_HOT_LOADER__.register(compactItem, 'compactItem', 'app/src/App.js');
  432. __REACT_HOT_LOADER__.register(compactLayout, 'compactLayout', 'app/src/App.js');
  433. __REACT_HOT_LOADER__.register(layoutCheck, 'layoutCheck', 'app/src/App.js');
  434. __REACT_HOT_LOADER__.register(DraggerLayout, 'DraggerLayout', 'app/src/App.js');
  435. __REACT_HOT_LOADER__.register(LayoutDemo, 'LayoutDemo', 'app/src/App.js');
  436. }();
  437. ;