dragact.tsx 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  1. import * as React from "react";
  2. import GridItem, { GridItemEvent } from './GridItem'
  3. import { compactLayout } from './util/compact';
  4. import { getMaxContainerHeight } from './util/sort';
  5. import { layoutCheck } from './util/collison';
  6. import { correctLayout } from './util/correction';
  7. import { getDataSet, stringJoin } from './utils';
  8. import { layoutItemForkey, syncLayout, MapLayoutTostate } from './util/initiate';
  9. import './style.css';
  10. export interface DragactLayoutItem {
  11. GridX: number
  12. GridY: number
  13. static?: Boolean
  14. w: number
  15. h: number
  16. isUserMove?: Boolean
  17. key?: number | string
  18. handle?: Boolean
  19. canDrag?: Boolean
  20. canResize?: Boolean
  21. }
  22. export interface DragactProps {
  23. layout?: DragactLayoutItem[] //暂时不推荐使用
  24. /**
  25. * 宽度切分比
  26. * 这个参数会把容器的宽度平均分为col等份
  27. * 于是容器内元素的最小宽度就等于 containerWidth/col
  28. */
  29. col: number,
  30. /**
  31. * 容器的宽度
  32. */
  33. width: number,
  34. /**容器内每个元素的最小高度 */
  35. rowHeight: number,
  36. /**
  37. * 容器内部的padding
  38. */
  39. padding?: number,
  40. children: any[] | any
  41. //
  42. // interface GridItemEvent {
  43. // event: any //浏览器拖动事件
  44. // GridX: number //在布局中的x格子
  45. // GridY: number //在布局中的y格子
  46. // w: number //元素的宽度
  47. // h: number //元素的高度
  48. // UniqueKey: string | number //元素的唯一key
  49. // }
  50. /**
  51. * 拖动开始的回调
  52. */
  53. onDragStart?: (event: GridItemEvent) => void
  54. /**
  55. * 拖动中的回调
  56. */
  57. onDrag?: (event: GridItemEvent) => void
  58. /**
  59. * 拖动结束的回调
  60. */
  61. onDragEnd?: (event: GridItemEvent) => void
  62. /**
  63. * 每个元素的margin,第一个参数是左右,第二个参数是上下
  64. */
  65. margin: [number, number]
  66. /**
  67. * layout的名字
  68. */
  69. className: number | string
  70. }
  71. export interface mapLayout {
  72. [key: string]: DragactLayoutItem
  73. }
  74. interface DragactState {
  75. GridXMoving: number
  76. GridYMoving: number
  77. wMoving: number
  78. hMoving: number
  79. placeholderShow: Boolean
  80. placeholderMoving: Boolean
  81. layout: DragactLayoutItem[]
  82. containerHeight: number
  83. dragType: 'drag' | 'resize'
  84. mapLayout: mapLayout | undefined
  85. }
  86. export class Dragact extends React.Component<DragactProps, DragactState> {
  87. constructor(props: DragactProps) {
  88. super(props)
  89. this.onDrag = this.onDrag.bind(this)
  90. this.onDragStart = this.onDragStart.bind(this)
  91. this.onDragEnd = this.onDragEnd.bind(this)
  92. const layout = props.layout ?
  93. MapLayoutTostate(props.layout, props.children)
  94. :
  95. getDataSet(props.children);
  96. this.state = {
  97. GridXMoving: 0,
  98. GridYMoving: 0,
  99. wMoving: 0,
  100. hMoving: 0,
  101. placeholderShow: false,
  102. placeholderMoving: false,
  103. layout: layout,
  104. containerHeight: 500,
  105. dragType: 'drag',
  106. mapLayout: undefined
  107. }
  108. }
  109. onResizeStart = (layoutItem: GridItemEvent) => {
  110. const { GridX, GridY, w, h } = layoutItem
  111. const sync = syncLayout(this.state.layout, layoutItem);
  112. this.setState({
  113. GridXMoving: GridX,
  114. GridYMoving: GridY,
  115. wMoving: w,
  116. hMoving: h,
  117. placeholderShow: true,
  118. placeholderMoving: true,
  119. layout: sync,
  120. dragType: 'resize'
  121. })
  122. }
  123. onResizing = (layoutItem: GridItemEvent) => {
  124. const newLayout = layoutCheck(this.state.layout, layoutItem, layoutItem.UniqueKey, layoutItem.UniqueKey, 0);
  125. const { compacted, mapLayout } = compactLayout(newLayout, layoutItem)
  126. this.setState({
  127. layout: compacted,
  128. wMoving: layoutItem.w,
  129. hMoving: layoutItem.h,
  130. mapLayout: mapLayout,
  131. containerHeight: getMaxContainerHeight(compacted, this.props.rowHeight, this.props.margin[1])
  132. })
  133. }
  134. onResizeEnd = (layoutItem: GridItemEvent) => {
  135. const { compacted, mapLayout } = compactLayout(this.state.layout, undefined)
  136. this.setState({
  137. placeholderShow: false,
  138. layout: compacted,
  139. mapLayout: mapLayout,
  140. containerHeight: getMaxContainerHeight(compacted, this.props.rowHeight, this.props.margin[1])
  141. })
  142. this.props.onDragEnd && this.props.onDragEnd(layoutItem);
  143. }
  144. onDragStart(bundles: GridItemEvent) {
  145. const { GridX, GridY, w, h } = bundles
  146. const newlayout = syncLayout(this.state.layout, bundles)
  147. this.setState({
  148. GridXMoving: GridX,
  149. GridYMoving: GridY,
  150. wMoving: w,
  151. hMoving: h,
  152. placeholderShow: true,
  153. placeholderMoving: true,
  154. layout: newlayout,
  155. dragType: 'drag'
  156. })
  157. this.props.onDragStart && this.props.onDragStart(bundles)
  158. }
  159. onDrag(layoutItem: GridItemEvent) {
  160. const { GridY, UniqueKey } = layoutItem
  161. const moving = GridY - this.state.GridYMoving
  162. const newLayout = layoutCheck(this.state.layout, layoutItem, UniqueKey, UniqueKey/*用户移动方块的key */, moving)
  163. const { compacted, mapLayout } = compactLayout(newLayout, layoutItem)
  164. this.setState({
  165. GridXMoving: layoutItem.GridX,
  166. GridYMoving: layoutItem.GridY,
  167. layout: compacted,
  168. mapLayout: mapLayout,
  169. containerHeight: getMaxContainerHeight(compacted, this.props.rowHeight, this.props.margin[1])
  170. })
  171. this.props.onDrag && this.props.onDrag(layoutItem);
  172. }
  173. onDragEnd(layoutItem: GridItemEvent) {
  174. const { compacted, mapLayout } = compactLayout(this.state.layout, undefined)
  175. this.setState({
  176. placeholderShow: false,
  177. layout: compacted,
  178. mapLayout: mapLayout,
  179. containerHeight: getMaxContainerHeight(compacted, this.props.rowHeight, this.props.margin[1])
  180. })
  181. this.props.onDragEnd && this.props.onDragEnd(layoutItem);
  182. }
  183. renderPlaceholder() {
  184. if (!this.state.placeholderShow) return null
  185. var { col, width, padding, rowHeight, margin } = this.props
  186. const { GridXMoving, GridYMoving, wMoving, hMoving, placeholderMoving, dragType } = this.state
  187. if (!padding) padding = 0;
  188. return (
  189. <GridItem
  190. margin={margin}
  191. col={col}
  192. containerWidth={width}
  193. containerPadding={[padding, padding]}
  194. rowHeight={rowHeight}
  195. GridX={GridXMoving}
  196. GridY={GridYMoving}
  197. w={wMoving}
  198. h={hMoving}
  199. style={{ background: 'rgba(15,15,15,0.3)', zIndex: dragType === 'drag' ? 1 : 10, transition: ' all .15s' }}
  200. isUserMove={!placeholderMoving}
  201. dragType={dragType}
  202. canDrag={false}
  203. canResize={false}
  204. />
  205. )
  206. }
  207. componentWillReceiveProps(nextProps: any) {
  208. const layout = getDataSet(nextProps.children);
  209. let newlayout = correctLayout(layout, this.props.col)
  210. const { compacted } = compactLayout(newlayout, undefined);
  211. console.log(layout)
  212. this.setState({
  213. layout: compacted
  214. })
  215. }
  216. componentDidMount() {
  217. setTimeout(() => {
  218. let layout = correctLayout(this.state.layout, this.props.col)
  219. const { compacted, mapLayout } = compactLayout(layout, undefined);
  220. this.setState({
  221. layout: compacted,
  222. mapLayout: mapLayout,
  223. containerHeight: getMaxContainerHeight(compacted, this.props.rowHeight, this.props.margin[1])
  224. })
  225. }, 1);
  226. }
  227. getGridItem(child: any, index: number) {
  228. const { dragType, mapLayout } = this.state
  229. var { col, width, padding, rowHeight, margin } = this.props;
  230. if (mapLayout) {
  231. const renderItem = layoutItemForkey(mapLayout, child.key);
  232. if (!padding) padding = 0;
  233. return (
  234. <GridItem
  235. margin={margin}
  236. col={col}
  237. containerWidth={width}
  238. containerPadding={[padding, padding]}
  239. rowHeight={rowHeight}
  240. GridX={renderItem.GridX}
  241. GridY={renderItem.GridY}
  242. w={renderItem.w}
  243. h={renderItem.h}
  244. onDrag={this.onDrag}
  245. onDragStart={this.onDragStart}
  246. onDragEnd={this.onDragEnd}
  247. isUserMove={renderItem.isUserMove !== void 666 ? renderItem.isUserMove : false}
  248. UniqueKey={child.key}
  249. static={renderItem.static}
  250. onResizing={this.onResizing}
  251. onResizeStart={this.onResizeStart}
  252. onResizeEnd={this.onResizeEnd}
  253. dragType={dragType}
  254. handle={renderItem.handle}
  255. canDrag={renderItem.canDrag}
  256. canResize={renderItem.canResize}
  257. >
  258. {child}
  259. </GridItem >
  260. )
  261. }
  262. }
  263. render() {
  264. const { width, className } = this.props;
  265. const { containerHeight } = this.state;
  266. return (
  267. <div
  268. className={stringJoin('DraggerLayout', className + '')}
  269. style={{ left: 100, width: width, height: containerHeight, zIndex: 1 }}
  270. >
  271. {React.Children.map(this.props.children,
  272. (child, index) => this.getGridItem(child, index)
  273. )}
  274. {this.renderPlaceholder()}
  275. </div>
  276. )
  277. }
  278. //api
  279. getLayout() {
  280. return this.state.layout;
  281. }
  282. }