方正 пре 7 година
родитељ
комит
34b47e37ea
2 измењених фајлова са 105 додато и 28 уклоњено
  1. 104 27
      app/src/App.js
  2. 1 1
      app/src/GridItem.js

+ 104 - 27
app/src/App.js

@@ -27,12 +27,6 @@ const syncLayout = (layout, key, GridX, GridY, isUserMove) => {
             item.GridY = GridY
             item.isUserMove = isUserMove
             return item
-            // return {
-            //     ...item,
-            //     GridX: GridX,
-            //     GridY: GridY,
-            //     isUserMove: isUserMove
-            // }
         }
         return item
     })
@@ -42,7 +36,9 @@ const syncLayout = (layout, key, GridX, GridY, isUserMove) => {
 const collision = (a, b) => {
     if (a.GridX === b.GridX && a.GridY === b.GridY &&
         a.w === b.w && a.h === b.h) {
+            
         return true
+
     }
 
     if (a.GridX + a.w <= b.GridX) return false
@@ -54,7 +50,6 @@ const collision = (a, b) => {
 
 const sortLayout = (layout) => {
     return [].concat(layout).sort((a, b) => {
-        // console.log('排序中:', a, b)
         if (a.GridY > b.GridY || (a.GridY === b.GridY && a.GridX > b.GridX)) {
             return 1
         } else if (a.GridY === b.GridY && a.GridX === b.GridX) {
@@ -66,42 +61,53 @@ const sortLayout = (layout) => {
 
 /**获取layout中,item第一个碰撞到的物体 */
 const getFirstCollison = (layout, item) => {
+    
     for (let i = 0, length = layout.length; i < length; i++) {
+        
         if (collision(layout[i], item)) {
+            
             return layout[i]
         }
+        
     }
     return null
 }
 
 const compactItem = (finishedLayout, item) => {
-    let newItem = { ...item }
+    const newItem = { ...item }
+    
     if (finishedLayout.length === 0) {
+        
         return { ...newItem, GridY: 0 }
     }
-
+    /**
+     * 类似一个递归调用
+     * 
+     */
     while (true) {
+        
         let FirstCollison = getFirstCollison(finishedLayout, newItem)
+        
         if (FirstCollison) {
             newItem.GridY = FirstCollison.GridY + FirstCollison.h
             return newItem
-        }else{
-            if (newItem.GridY <= 0) return {...newItem,GridY:0}
         }
         newItem.GridY--
+        
+        if (newItem.GridY < 0) {
+            
+            return { ...newItem, GridY: 0 }
+        }
     }
     return newItem
 }
 
 const compactLayout = (layout) => {
-    // console.log('排序前', layout)
     let sorted = sortLayout(layout)
-    // console.log('排序后', sorted)
     const needCompact = Array(layout.length)
     const compareList = []
     for (let i = 0, length = sorted.length; i < length; i++) {
         let finished = compactItem(compareList, sorted[i])
-
         finished.isUserMove = false
         compareList.push(finished)
         needCompact[layout.indexOf(sorted[i])] = finished
@@ -110,15 +116,58 @@ const compactLayout = (layout) => {
     return needCompact
 }
 
-const layoutCheck = (layout, layoutItem, key, fristItemkey) => {
-    let i, movedItem
+const layoutCheck = (layout, layoutItem, key, fristItemkey, moving) => {
+    let i = [], movedItem = []
     let newlayout = layout.map((item, idx) => {
         if (item.key !== key) {
             if (collision(item, layoutItem)) {
-                i = item.key
-                let offsetY = layoutItem.GridY + layoutItem.h
-                movedItem = { ...item, GridY: offsetY, isUserMove: false }
-                return movedItem
+                i.push(item.key)
+                let offsetY = layoutItem.GridY
+                if (layoutItem.GridY > item.GridY && layoutItem.GridY < item.GridY + item.h) {
+                    /**
+                     * 元素向上移动时,元素的上面空间不足,则不移动这个元素
+                     * 当元素移动到GridY>所要向上交换的元素时,就不会进入这里,直接交换元素
+                     * 
+                     */
+                    offsetY = item.GridY
+                }
+                if (moving > 0) {
+                    /**
+                     * 这个地方的实现有点奇妙了,moving用于检查最开始移动的方块
+                     * layoutItem.GridY > item.h*(3/4) 这个做会让方块移动比较准确和精确
+                     * 如果是其他数字,很可能会出现不可预计的效果
+                     * 建议取值范围在1/2 ~ 3/4之间
+                     */
+
+                    if (layoutItem.GridY < item.GridY) {
+                        let collision;
+                        let copy = { ...item }
+                        while (true) {
+                            let newLayout = layout.filter((item) => {
+                                if (item.key !== key && (item.key !== copy.key) ) {
+                                    return item
+                                }
+                            })
+                            collision = getFirstCollison(newLayout, copy)
+                            if (collision) {
+                                offsetY = collision.GridY + collision.h
+                                // console.log('移动到', offsetY, '操纵的物体底部', copy.key, '碰撞顶部', copy.GridY,'key',collision.key)
+                                break
+                            } else {
+                                copy.GridY--
+                            }
+                            if(copy.GridY < 0){
+                                // console.log('移动到', offsetY, '操纵的物体底部', copy.key, '碰撞顶部', copy.GridY,)
+                                offsetY = 0
+                                break
+                            }
+                        }
+                    }
+                    
+                }
+                
+                movedItem.push({ ...item, GridY: offsetY, isUserMove: false })
+                return { ...item, GridY: offsetY, isUserMove: false }
             }
         } else if (fristItemkey === key) {
             return { ...item, GridX: layoutItem.GridX, GridY: layoutItem.GridY, isUserMove: true }
@@ -126,10 +175,11 @@ const layoutCheck = (layout, layoutItem, key, fristItemkey) => {
         return item
     })
     /** 递归调用,将layout中的所有重叠元素全部移动 */
-    if (typeof i === 'string' && typeof movedItem === 'object') {
-        newlayout = layoutCheck(newlayout, movedItem, i, fristItemkey)
+    if (i.length > 0 && movedItem.length > 0) {
+        for (let c = 0; c < Math.min(movedItem.length, i.length); c++) {
+            newlayout = layoutCheck(newlayout, movedItem[c], i[c], fristItemkey, undefined)
+        }
     }
-
     return newlayout
 }
 
@@ -180,9 +230,24 @@ class DraggerLayout extends React.Component {
 
     onDrag(layoutItem, key) {
         const { GridX, GridY } = layoutItem
-        const newLayout = layoutCheck(this.state.layout, layoutItem, key, key/*用户移动方块的key */)
+        const moving = GridY - this.state.GridYMoving
+
+        const newLayout = layoutCheck(this.state.layout, layoutItem, key, key/*用户移动方块的key */, moving)
         // const compactedLayout = compactLayout(newLayout)
-        // const sy = syncLayout(compactedLayout, key, layoutItem.GridX, layoutItem.GridY, true)
+        // for (let i = 0; i < compactedLayout.length; i++) {
+        //     if (key === compactedLayout[i].key) {
+        //         /**
+        //          * 特殊点:当我们移动元素的时候,元素在layout中的位置不断改变
+        //          * 但是当isUserMove=true的时候,鼠标拖拽的元素不会随着位图变化而变化
+        //          * 但是实际layout中的位置还是会改变
+        //          * (isUserMove=true用于接触placeholder和元素的绑定)
+        //          */
+        //         compactedLayout[i].isUserMove = true
+        //         layoutItem.GridX = compactedLayout[i].GridX
+        //         layoutItem.GridY = compactedLayout[i].GridY
+        //         break
+        //     }
+        // }
 
         this.setState({
             GridXMoving: layoutItem.GridX,
@@ -221,7 +286,7 @@ class DraggerLayout extends React.Component {
     }
     componentDidMount() {
         let that = this
-        setTimeout(function() {
+        setTimeout(function () {
             that.setState({
                 layout: compactLayout(that.state.layout)
             })
@@ -283,13 +348,25 @@ export const LayoutDemo = () => {
         GridX: 3, GridY: 6, w: 2, h: 1
     }, {
         GridX: 3, GridY: 8, w: 1, h: 4
+    }, {
+        GridX: 3, GridY: 8, w: 3, h: 4
+    }, {
+        GridX: 3, GridY: 8, w: 6, h: 2
+    }, {
+        GridX: 3, GridY: 8, w: 2, h: 1
+    }, {
+        GridX: 3, GridY: 8, w: 7, h: 4
     }]
     return (
-        <DraggerLayout layout={layout} width={500}>
+        <DraggerLayout layout={layout} width={1000}>
             <p key='a'>a</p>
             <p key='b'>b</p>
             <p key='c'>c</p>
             <p key='d'>d</p>
+            <p key='e'>e</p>
+            <p key='f'>f</p>
+            <p key='g'>g</p>
+            <p key='h'>h</p>
         </DraggerLayout>
     )
 }

+ 1 - 1
app/src/GridItem.js

@@ -37,7 +37,7 @@ export default class GridItem extends Component {
     }
 
     static defaultProps = {
-        col: 6,
+        col: 12,
         containerWidth: 500,
         containerPadding: [0, 0],
         margin: [10, 10],