App.js 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. import React from 'react'
  2. import PropTypes from 'prop-types'
  3. import GridItem, { checkInContainer } from './GridItem'
  4. import { compactLayout, compactItem } from './util/compact';
  5. import { quickSort, getMaxContainerHeight } from './util/sort';
  6. import { layoutCheck } from './util/collison';
  7. import { correctLayout } from './util/correction';
  8. import { getDataSet, stringJoin } from './utils';
  9. import { layoutItemForkey, syncLayout } from './util/initiate';
  10. import './style.css';
  11. export class DraggerLayout extends React.Component {
  12. constructor(props) {
  13. super(props)
  14. this.onDrag = this.onDrag.bind(this)
  15. this.onDragStart = this.onDragStart.bind(this)
  16. this.onDragEnd = this.onDragEnd.bind(this)
  17. const layout = props.layout ?
  18. MapLayoutTostate(props.layout, props.children)
  19. :
  20. getDataSet(props.children);
  21. this.state = {
  22. GridXMoving: 0,
  23. GridYMoving: 0,
  24. wMoving: 0,
  25. hMoving: 0,
  26. placeholderShow: false,
  27. placeholderMoving: false,
  28. layout: layout,
  29. containerHeight: 500
  30. }
  31. }
  32. static propTypes = {
  33. /**外部属性 */
  34. layout: PropTypes.array,
  35. col: PropTypes.number,
  36. width: PropTypes.number,
  37. /**每个元素的最小高度 */
  38. rowHeight: PropTypes.number,
  39. padding: PropTypes.number,
  40. }
  41. onDragStart(bundles) {
  42. const { GridX, GridY, w, h, UniqueKey } = bundles
  43. const newlayout = syncLayout(this.state.layout, UniqueKey, GridX, GridY, true)
  44. this.setState({
  45. GridXMoving: GridX,
  46. GridYMoving: GridY,
  47. wMoving: w,
  48. hMoving: h,
  49. placeholderShow: true,
  50. placeholderMoving: true,
  51. layout: newlayout,
  52. })
  53. this.props.onDragStart && this.props.onDragStart({ GridX, GridY })
  54. }
  55. onDrag(layoutItem, key) {
  56. const { GridX, GridY } = layoutItem
  57. const moving = GridY - this.state.GridYMoving
  58. const newLayout = layoutCheck(this.state.layout, layoutItem, key, key/*用户移动方块的key */, moving)
  59. const compactedLayout = compactLayout(newLayout)
  60. for (let i = 0; i < compactedLayout.length; i++) {
  61. const compactedItem = compactedLayout[i];
  62. if (key === compactedItem.key) {
  63. /**
  64. * 特殊点:当我们移动元素的时候,元素在layout中的位置不断改变
  65. * 但是当isUserMove=true的时候,鼠标拖拽的元素不会随着位图变化而变化
  66. * 但是实际layout中的位置还是会改变
  67. * (isUserMove=true用于解除placeholder和元素的绑定)
  68. */
  69. compactedItem.isUserMove = true
  70. layoutItem.GridX = compactedItem.GridX
  71. layoutItem.GridY = compactedItem.GridY
  72. break
  73. }
  74. }
  75. this.setState({
  76. GridXMoving: layoutItem.GridX,
  77. GridYMoving: layoutItem.GridY,
  78. layout: compactedLayout,
  79. containerHeight: getMaxContainerHeight(compactedLayout, this.props.rowHeight, this.props.margin[1])
  80. })
  81. this.props.onDrag && this.props.onDrag({ GridX, GridY });
  82. }
  83. onDragEnd(key) {
  84. const compactedLayout = compactLayout(this.state.layout)
  85. this.setState({
  86. placeholderShow: false,
  87. layout: compactedLayout,
  88. containerHeight: getMaxContainerHeight(compactedLayout, this.props.rowHeight, this.props.margin[1])
  89. })
  90. this.props.onDragEnd && this.props.onDragEnd();
  91. }
  92. renderPlaceholder() {
  93. if (!this.state.placeholderShow) return null
  94. const { col, width, padding, rowHeight, margin } = this.props
  95. const { GridXMoving, GridYMoving, wMoving, hMoving, placeholderMoving } = this.state
  96. return (
  97. <GridItem
  98. margin={margin}
  99. col={col}
  100. containerWidth={width}
  101. containerPadding={padding}
  102. rowHeight={rowHeight}
  103. GridX={GridXMoving}
  104. GridY={GridYMoving}
  105. w={wMoving}
  106. h={hMoving}
  107. style={{ background: '#d6e4ff', zIndex: 1, transition: ' all .15s' }}
  108. isUserMove={!placeholderMoving}
  109. >
  110. </GridItem >
  111. )
  112. }
  113. componentDidMount() {
  114. setTimeout(() => {
  115. let layout = correctLayout(this.state.layout, this.props.col)
  116. const compacted = compactLayout(layout);
  117. this.setState({
  118. layout: compacted,
  119. containerHeight: getMaxContainerHeight(compacted, this.props.rowHeight, this.props.margin[1])
  120. })
  121. }, 1);
  122. }
  123. getGridItem(child, index) {
  124. const { layout } = this.state
  125. const { col, width, padding, rowHeight, margin } = this.props;
  126. const renderItem = layoutItemForkey(layout, child.key);//TODO:可以优化速度,这一步不是必须;
  127. return (
  128. <GridItem
  129. margin={margin}
  130. col={col}
  131. containerWidth={width}
  132. containerPadding={padding}
  133. rowHeight={rowHeight}
  134. GridX={renderItem.GridX}
  135. GridY={renderItem.GridY}
  136. w={renderItem.w}
  137. h={renderItem.h}
  138. onDrag={this.onDrag}
  139. onDragStart={this.onDragStart}
  140. onDragEnd={this.onDragEnd}
  141. index={index}
  142. isUserMove={renderItem.isUserMove}
  143. UniqueKey={child.key}
  144. style={{ zIndex: 2 }}
  145. static={renderItem.static}
  146. >
  147. {child}
  148. </GridItem >
  149. )
  150. }
  151. render() {
  152. const { layout, col, width, padding, rowHeight, className } = this.props;
  153. const { containerHeight } = this.state;
  154. return (
  155. <div
  156. className={stringJoin('DraggerLayout', className)}
  157. style={{ left: 100, width: width, height: containerHeight, zIndex: 1 }}
  158. >
  159. {React.Children.map(this.props.children,
  160. (child, index) => this.getGridItem(child, index)
  161. )}
  162. {this.renderPlaceholder()}
  163. </div>
  164. )
  165. }
  166. }