App.js 18 KB

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