fix drag bug

add ignore
This commit is contained in:
yehuozhili 2020-08-30 11:13:42 +08:00
parent 15d8e8e6e6
commit eee468a1c3
4 changed files with 246 additions and 212 deletions

2
.gitignore vendored
View File

@ -102,3 +102,5 @@ dist
# TernJS port file
.tern-port
/**/*.umi

View File

@ -1,165 +1,190 @@
import React, { useState, useEffect, memo } from 'react'
import { Input, Slider, Result, Tabs } from 'antd'
import React, { useState, useEffect, memo, useMemo } from 'react';
import { Input, Slider, Result, Tabs } from 'antd';
import {
PieChartOutlined,
ExpandOutlined,
PlayCircleOutlined,
HighlightOutlined
} from '@ant-design/icons'
import { connect } from 'dva'
import HeaderComponent from './components/Header'
import SourceBox from './SourceBox'
import TargetBox from './TargetBox'
import Calibration from 'components/Calibration'
import DynamicEngine from 'components/DynamicEngine'
import FormEditor from 'components/FormEditor'
import template from 'components/DynamicEngine/template'
import mediaTpl from 'components/DynamicEngine/mediaTpl'
import graphTpl from 'components/DynamicEngine/graphTpl'
import schema from 'components/DynamicEngine/schema'
HighlightOutlined,
} from '@ant-design/icons';
import { connect } from 'dva';
import HeaderComponent from './components/Header';
import SourceBox from './SourceBox';
import TargetBox from './TargetBox';
import Calibration from 'components/Calibration';
import DynamicEngine from 'components/DynamicEngine';
import FormEditor from 'components/FormEditor';
import template from 'components/DynamicEngine/template';
import mediaTpl from 'components/DynamicEngine/mediaTpl';
import graphTpl from 'components/DynamicEngine/graphTpl';
import schema from 'components/DynamicEngine/schema';
import styles from './index.less'
import styles from './index.less';
const { Search } = Input;
const { TabPane } = Tabs;
const Container = memo((props) => {
const [ scaleNum , setScale ] = useState(1)
const Container = memo(props => {
const [scaleNum, setScale] = useState(1);
const { pointData, curPoint, dispatch } = props
const { pointData, curPoint, dispatch } = props;
// 指定画布的id
let canvasId = 'js_canvas'
let canvasId = 'js_canvas';
const backSize = () => {
setScale(1)
}
setScale(1);
};
const CpIcon = {
base: <HighlightOutlined />,
media: <PlayCircleOutlined />,
visible: <PieChartOutlined />
}
visible: <PieChartOutlined />,
};
const generateHeader = (type, text) => {
return <div>{ CpIcon[type] } { text }</div>
}
return (
<div>
{CpIcon[type]} {text}
</div>
);
};
const handleSliderChange = (v) => {
setScale(prev => v >= 150 ? 1.5 : (v / 100))
}
const handleSliderChange = v => {
setScale(prev => (v >= 150 ? 1.5 : v / 100));
};
const handleSlider = (type) => {
if(type) {
setScale(prev => prev >= 1.5 ? 1.5 : (prev + 0.1))
}else {
setScale(prev => prev <= 0.5 ? 0.5 : (prev - 0.1))
const handleSlider = type => {
if (type) {
setScale(prev => (prev >= 1.5 ? 1.5 : prev + 0.1));
} else {
setScale(prev => (prev <= 0.5 ? 0.5 : prev - 0.1));
}
}
};
const handleFormSave = (data) => {
const handleFormSave = data => {
dispatch({
type: 'editorModal/modPointData',
payload: { ...curPoint, item: {...curPoint.item, config: data} }
})
}
payload: { ...curPoint, item: { ...curPoint.item, config: data } },
});
};
const handleDel = (id) => {
const handleDel = id => {
dispatch({
type: 'editorModal/delPointData',
payload: { id }
})
}
payload: { id },
});
};
useEffect(() => {
if(window.innerWidth < 1024) {
props.history.push('/mobileTip')
if (window.innerWidth < 1024) {
props.history.push('/mobileTip');
}
}, [])
}, []);
const allType = useMemo(() => {
let arr = [];
template.forEach(v => {
arr.push(v.type);
});
mediaTpl.forEach(v => {
arr.push(v.type);
});
graphTpl.forEach(v => {
arr.push(v.type);
});
return arr;
}, []);
return (
<div className={styles.editorWrap}>
<HeaderComponent pointData={pointData} location={props.location} />
<div className={styles.container}>
<div className={styles.list} >
<div className={styles.list}>
<div className={styles.searchBar}>
<Search placeholder="搜索组件" onSearch={value => console.log(value)} enterButton />
</div>
<div className={styles.componentList}>
<Tabs defaultActiveKey="1">
<TabPane tab={generateHeader("base","基础组件")} key="1">
{
template.map((value,i) =>
<TargetBox item={value} key={i} canvasId={canvasId}>
<DynamicEngine {...value} config={schema[value.type].config} />
</TargetBox>
)
}
<TabPane tab={generateHeader('base', '基础组件')} key="1">
{template.map((value, i) => (
<TargetBox item={value} key={i} canvasId={canvasId}>
<DynamicEngine {...value} config={schema[value.type].config} />
</TargetBox>
))}
</TabPane>
<TabPane tab={generateHeader("media","媒体组件")} key="2">
{
mediaTpl.map((value,i) =>
<TargetBox item={value} key={i} canvasId={canvasId}>
<DynamicEngine {...value} config={schema[value.type].config} />
</TargetBox>
)
}
<TabPane tab={generateHeader('media', '媒体组件')} key="2">
{mediaTpl.map((value, i) => (
<TargetBox item={value} key={i} canvasId={canvasId}>
<DynamicEngine {...value} config={schema[value.type].config} />
</TargetBox>
))}
</TabPane>
<TabPane tab={generateHeader("visible","可视化组件")} key="3">
{
graphTpl.map((value,i) =>
<TargetBox item={value} key={i} canvasId={canvasId}>
<DynamicEngine {...value} config={schema[value.type].config} />
</TargetBox>
)
}
<TabPane tab={generateHeader('visible', '可视化组件')} key="3">
{graphTpl.map((value, i) => (
<TargetBox item={value} key={i} canvasId={canvasId}>
<DynamicEngine {...value} config={schema[value.type].config} />
</TargetBox>
))}
</TabPane>
</Tabs>
</div>
</div>
<div className={styles.tickMark} id='calibration'>
<div className={styles.tickMark} id="calibration">
<div className={styles.tickMarkTop}>
<Calibration direction='up' id='calibrationUp' multiple={scaleNum} />
</div>
<Calibration direction="up" id="calibrationUp" multiple={scaleNum} />
</div>
<div className={styles.tickMarkLeft}>
<Calibration direction='right' id='calibrationRight' multiple={scaleNum} />
<Calibration direction="right" id="calibrationRight" multiple={scaleNum} />
</div>
<SourceBox scaleNum={scaleNum} canvasId={canvasId} />
<SourceBox scaleNum={scaleNum} canvasId={canvasId} allType={allType} />
<div className={styles.sliderWrap}>
<span className={styles.sliderBtn} onClick={handleSlider.bind(this, 1)}>+</span>
<Slider vertical defaultValue={100} className={styles.slider} onChange={handleSliderChange} min={50} max={150} value={scaleNum * 100} />
<span className={styles.sliderBtn} onClick={handleSlider.bind(this, 0)}>-</span>
<span className={styles.sliderBtn} onClick={handleSlider.bind(this, 1)}>
+
</span>
<Slider
vertical
defaultValue={100}
className={styles.slider}
onChange={handleSliderChange}
min={50}
max={150}
value={scaleNum * 100}
/>
<span className={styles.sliderBtn} onClick={handleSlider.bind(this, 0)}>
-
</span>
</div>
<div className={styles.backSize}>
<ExpandOutlined onClick={backSize} />
</div>
<div className={styles.backSize}><ExpandOutlined onClick={backSize} /></div>
</div>
<div className={styles.attrSetting}>
{
pointData.length && curPoint ?
{pointData.length && curPoint ? (
<>
<div className={styles.tit}>属性设置</div>
<FormEditor
<FormEditor
config={curPoint.item.editableEl}
uid={curPoint.id}
defaultValue={curPoint.item.config}
uid={curPoint.id}
defaultValue={curPoint.item.config}
onSave={handleFormSave}
onDel={handleDel}
/>
</> :
<div style={{paddingTop: '100px'}}>
</>
) : (
<div style={{ paddingTop: '100px' }}>
<Result
status="404"
title="还没有数据哦"
subTitle="赶快拖拽组件来生成你的H5页面吧"
/>
</div>
}
)}
</div>
</div>
</div>
)
})
);
});
export default connect(({ editorModal: { pointData, curPoint } }) => ({
pointData, curPoint
}))(Container)
pointData,
curPoint,
}))(Container);

View File

@ -1,79 +1,105 @@
import React, { memo, useEffect, useState } from 'react'
import { useDrop } from 'react-dnd'
import Draggable from 'react-draggable'
import GridLayout from 'react-grid-layout'
import { Tooltip } from 'antd'
import { connect } from 'dva'
import DynamicEngine from 'components/DynamicEngine'
import styles from './index.less'
const SourceBox = memo((props) => {
const { pointData, scaleNum, canvasId, dispatch } = props
const [canvasRect, setCanvasRect] = useState([])
const [isShowTip, setIsShowTip] = useState(true)
import React, { memo, useEffect, useState } from 'react';
import { useDrop } from 'react-dnd';
import Draggable from 'react-draggable';
import GridLayout from 'react-grid-layout';
import { Tooltip } from 'antd';
import { connect } from 'dva';
import DynamicEngine from 'components/DynamicEngine';
import styles from './index.less';
import { uuid } from '@/utils/tool';
const SourceBox = memo(props => {
const { pointData, scaleNum, canvasId, allType, dispatch } = props;
const [canvasRect, setCanvasRect] = useState([]);
const [isShowTip, setIsShowTip] = useState(true);
const [{ isOver }, drop] = useDrop({
accept: [],
collect: (monitor) => ({
accept: allType,
drop: (item, monitor) => {
let parentDiv = document.getElementById(canvasId),
pointRect = parentDiv.getBoundingClientRect(),
top = pointRect.top,
pointEnd = monitor.getSourceClientOffset(),
y = pointEnd.y - top,
col = 24, // 网格列数
cellHeight = 2;
// 转换成网格规则的坐标和大小
let gridY = Math.ceil(y / cellHeight);
dispatch({
type: 'editorModal/addPointData',
payload: {
id: uuid(6, 10),
item,
point: { i: `x-${pointData.length}`, x: 0, y: gridY, w: col, h: item.h, isBounded: true },
},
});
},
collect: monitor => ({
isOver: monitor.isOver(),
canDrop: monitor.canDrop(),
item: monitor.getItem()
})
})
item: monitor.getItem(),
}),
});
const dragStop = (layout, oldItem, newItem, placeholder, e, element) => {
const curPointData = pointData.filter(item => item.id === newItem.i)[0]
const curPointData = pointData.filter(item => item.id === newItem.i)[0];
dispatch({
type: 'editorModal/modPointData',
payload: { ...curPointData, point: newItem }
})
}
payload: { ...curPointData, point: newItem },
});
};
const onDragStart = (layout, oldItem, newItem, placeholder, e, element) => {
const curPointData = pointData.filter(item => item.id === newItem.i)[0]
const curPointData = pointData.filter(item => item.id === newItem.i)[0];
dispatch({
type: 'editorModal/modPointData',
payload: { ...curPointData }
})
}
payload: { ...curPointData },
});
};
const onResizeStop = (layout, oldItem, newItem, placeholder, e, element) => {
const curPointData = pointData.filter(item => item.id === newItem.i)[0]
const curPointData = pointData.filter(item => item.id === newItem.i)[0];
dispatch({
type: 'editorModal/modPointData',
payload: { ...curPointData, point: newItem }
})
}
payload: { ...curPointData, point: newItem },
});
};
useEffect(() => {
let { width, height } = document.getElementById(canvasId).getBoundingClientRect()
setCanvasRect([width, height])
}, [canvasId])
let { width, height } = document.getElementById(canvasId).getBoundingClientRect();
setCanvasRect([width, height]);
}, [canvasId]);
useEffect(() => {
setTimeout(() => {
setIsShowTip(false)
}, 3000)
}, [])
setIsShowTip(false);
}, 3000);
}, []);
const opacity = isOver ? 0.7 : 1
const backgroundColor = isOver ? 1 : 0.7
const opacity = isOver ? 0.7 : 1;
const backgroundColor = isOver ? 1 : 0.7;
return (
<Draggable handle=".js_box">
<div className={styles.canvasBox}>
<div style={{transform: `scale(${scaleNum})`, position: 'relative', width: '100%', height: '100%'}}>
<div
<div
style={{
transform: `scale(${scaleNum})`,
position: 'relative',
width: '100%',
height: '100%',
}}
>
<div
id={canvasId}
className={styles.canvas}
style={{
opacity, backgroundColor
}}
ref={drop}
className={styles.canvas}
style={{
opacity,
backgroundColor,
}}
ref={drop}
>
<Tooltip placement="right" title="鼠标按住此处拖拽画布" visible={isShowTip}>
<div
className="js_box"
<div
className="js_box"
style={{
width: '12px',
height: '100%',
@ -83,39 +109,36 @@ const SourceBox = memo((props) => {
right: '-12px',
top: '0',
color: '#fff',
cursor: 'move'
cursor: 'move',
}}
/>
/>
</Tooltip>
{
pointData.length > 0 ?
<GridLayout
className={styles.layout}
cols={24}
rowHeight={2}
width={canvasRect[0]}
margin={[0,0]}
{pointData.length > 0 ? (
<GridLayout
className={styles.layout}
cols={24}
rowHeight={2}
width={canvasRect[0]}
margin={[0, 0]}
onDragStop={dragStop}
onDragStart={onDragStart}
onResizeStop={onResizeStop}
>
{
pointData.map(value =>
<div className={styles.dragItem} key={value.id} data-grid={value.point}>
<DynamicEngine {...value.item} />
</div>
)
}
</GridLayout> : null
}
{pointData.map(value => (
<div className={styles.dragItem} key={value.id} data-grid={value.point}>
<DynamicEngine {...value.item} />
</div>
))}
</GridLayout>
) : null}
</div>
</div>
</div>
</Draggable>
)
})
);
});
export default connect(({ editorModal: { pointData } }) => ({
pointData
}))(SourceBox)
pointData,
}))(SourceBox);

View File

@ -1,61 +1,45 @@
import React, { useMemo, memo } from 'react'
import { useDrag } from 'react-dnd'
import { connect } from 'dva'
import schema from 'components/DynamicEngine/schema'
import { uuid } from '@/utils/tool';
import styles from './index.less'
import React, { useMemo, memo } from 'react';
import { useDrag, DragPreviewImage } from 'react-dnd';
import { connect } from 'dva';
import schema from 'components/DynamicEngine/schema';
const TargetBox = memo((props) => {
const { item, dispatch, canvasId, pointData } = props
const [{ isDragging }, drag] = useDrag({
item: { type: item.type, config: schema[item.type].config, h: item.h, editableEl: schema[item.type].editData },
collect: (monitor) => ({
import styles from './index.less';
const TargetBox = memo(props => {
const { item, dispatch, canvasId, pointData } = props;
const [{ isDragging }, drag, preview] = useDrag({
item: {
type: item.type,
config: schema[item.type].config,
h: item.h,
editableEl: schema[item.type].editData,
},
collect: monitor => ({
isDragging: monitor.isDragging(),
}),
// begin(monitor) {
// getStartPoint(monitor.getSourceClientOffset())
// },
end(item, monitor) {
let parentDiv = document.getElementById(canvasId),
pointRect = parentDiv.getBoundingClientRect(),
top = pointRect.top,
pointEnd = monitor.getSourceClientOffset(),
y = pointEnd.y - top,
col = 24, // 网格列数
cellHeight = 2
// 转换成网格规则的坐标和大小
let gridY = Math.ceil(y / cellHeight)
dispatch({
type: 'editorModal/addPointData',
payload: {
id: uuid(6, 10),
item,
point: { i: `x-${pointData.length}`, x: 0, y: gridY, w: col, h: item.h, isBounded: true }
}
})
}
})
});
const containerStyle = useMemo(
() => ({
opacity: isDragging ? 0.4 : 1,
cursor: 'move'
cursor: 'move',
}),
[isDragging],
)
);
return (
<div
className={styles.module}
style={{ ...containerStyle}}
ref={drag}
>
{ props.children }
<div className={styles.module} style={{ ...containerStyle }} ref={drag}>
{props.children}
{item.type === 'Carousel' && (
<DragPreviewImage
connect={preview}
src={'https://www.easyicon.net/api/resizeApi.php?id=1200841&size=32'}
></DragPreviewImage>
)}
</div>
)
})
);
});
export default connect(({ editorModal: { pointData } }) => ({
pointData
}))(TargetBox)
pointData,
}))(TargetBox);