Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitb604d43

Browse files
optimise canvas view/inner grid, root comp, gridLayout, gridItem and uiCompBuilder
1 parentdfc5955 commitb604d43

File tree

9 files changed

+388
-215
lines changed

9 files changed

+388
-215
lines changed

‎client/packages/lowcoder/src/comps/comps/gridLayoutComp/canvasView.tsx‎

Lines changed: 59 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import{EditorContext}from"comps/editorState";
22
import{EditorContainer}from"pages/common/styledComponent";
3-
importReact,{Profiler,useContext,useMemo,useRef,useState}from"react";
3+
importReact,{Profiler,useContext,useMemo,useRef,useState,useEffect,useCallback}from"react";
44
importstyledfrom"styled-components";
55
import{profilerCallback}from"util/cacheUtils";
66
import{
@@ -97,11 +97,44 @@ export const CanvasView = React.memo((props: ContainerBaseProps) => {
9797
constisDefaultTheme=useContext(ThemeContext)?.themeId==='default-theme-id';
9898
constisPreviewTheme=useContext(ThemeContext)?.themeId==='preview-theme';
9999
consteditorState=useContext(EditorContext);
100-
const[dragSelectedComps,setDragSelectedComp]=useState(EmptySet);
101-
constscrollContainerRef=useRef(null);
100+
const[dragSelectedComps,setDragSelectedComp]=useState<Set<string>>(newSet());
101+
constscrollContainerRef=useRef<HTMLDivElement>(null);
102+
constmountedRef=useRef(true);
102103
constappSettings=editorState.getAppSettings();
103104
constmaxWidthFromHook=useMaxWidth();
104105

106+
// Cleanup on unmount
107+
useEffect(()=>{
108+
return()=>{
109+
mountedRef.current=false;
110+
setDragSelectedComp(newSet());
111+
};
112+
},[]);
113+
114+
// Memoized drag selection handler
115+
consthandleDragSelection=useCallback((checkSelectFunc?:CheckSelectFn)=>{
116+
if(!mountedRef.current)returnnewSet<string>();
117+
118+
constselectedComps=newSet<string>();
119+
if(checkSelectFunc){
120+
Object.values(props.layout).forEach((layoutItem)=>{
121+
constkey=layoutItem.i;
122+
if(props.items.hasOwnProperty(key)){
123+
constitem=props.items[key];
124+
constname=item.name;
125+
constelement=document.getElementById(key);
126+
if(element){
127+
checkSelectFunc(
128+
elementasHTMLDivElement,
129+
(result)=>(result ?selectedComps.add(name) :selectedComps.delete(name))
130+
);
131+
}
132+
}
133+
});
134+
}
135+
returnselectedComps;
136+
},[props.items,props.layout]);
137+
105138
constmaxWidth=useMemo(
106139
()=>appSettings.maxWidth??maxWidthFromHook,
107140
[appSettings,maxWidthFromHook]
@@ -244,6 +277,25 @@ export const CanvasView = React.memo((props: ContainerBaseProps) => {
244277
rowHeight:parseInt(defaultRowHeight),
245278
}),[props.positionParams,defaultGrid,defaultRowHeight]);
246279

280+
// Memoized mouse event handlers
281+
consthandleMouseDown=useCallback(()=>{
282+
setDragSelectedComp(newSet());
283+
},[]);
284+
285+
consthandleMouseUp=useCallback(()=>{
286+
if(mountedRef.current){
287+
editorState.setSelectedCompNames(dragSelectedComps);
288+
setDragSelectedComp(newSet());
289+
}
290+
},[editorState,dragSelectedComps]);
291+
292+
consthandleMouseMove=useCallback((checkSelectFunc:CheckSelectFn)=>{
293+
if(mountedRef.current){
294+
constselectedName=handleDragSelection(checkSelectFunc);
295+
setDragSelectedComp(selectedName);
296+
}
297+
},[handleDragSelection]);
298+
247299
if(readOnly){
248300
return(
249301
<UICompContainer
@@ -291,17 +343,9 @@ export const CanvasView = React.memo((props: ContainerBaseProps) => {
291343
$bgImagePosition={bgImagePosition}
292344
>
293345
<DragSelector
294-
onMouseDown={()=>{
295-
setDragSelectedComp(EmptySet);
296-
}}
297-
onMouseUp={()=>{
298-
editorState.setSelectedCompNames(dragSelectedComps);
299-
setDragSelectedComp(EmptySet);
300-
}}
301-
onMouseMove={(checkSelectFunc)=>{
302-
constselectedName=getDragSelectedNames(props.items,props.layout,checkSelectFunc);
303-
setDragSelectedComp(selectedName);
304-
}}
346+
onMouseDown={handleMouseDown}
347+
onMouseUp={handleMouseUp}
348+
onMouseMove={handleMouseMove}
305349
>
306350
<Profilerid="Panel"onRender={profilerCallback}>
307351
<InnerGrid
@@ -318,7 +362,7 @@ export const CanvasView = React.memo((props: ContainerBaseProps) => {
318362
positionParams={positionParams}
319363
emptyRows={defaultRowCount}
320364
minHeight={defaultMinHeight}
321-
extraHeight={defaultRowCount===DEFAULT_ROW_COUNT ?rootContainerExtraHeight :undefined}
365+
extraHeight={defaultRowCount===DEFAULT_ROW_COUNT ?rootContainerExtraHeight :undefined}
322366
/>
323367
</Profiler>
324368
</DragSelector>
Lines changed: 112 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import{Layers}from"constants/Layers";
2-
importReact,{ReactNode}from"react";
2+
importReact,{ReactNode,useCallback,useRef,useState,useEffect}from"react";
33

44
exporttypeCheckSelectFn=(
55
item?:HTMLDivElement|null,
@@ -29,159 +29,154 @@ interface SectionState {
2929
mouseDown:boolean;
3030
selectionBox?:Rect;
3131
startPoint?:Point;
32+
appendMode:boolean;
3233
}
3334

34-
constInitialState={
35+
constcreateInitialState=():SectionState=>({
3536
mouseDown:false,
3637
appendMode:false,
3738
selectionBox:undefined,
3839
startPoint:undefined,
39-
};
40-
41-
classDragSelectorCompextendsReact.Component<SectionProps,SectionState>{
42-
privatereadonlyselectAreaRef:React.RefObject<HTMLDivElement>;
43-
44-
constructor(props:SectionProps){
45-
super(props);
46-
this.selectAreaRef=React.createRef<HTMLDivElement>();
47-
this.state=InitialState;
48-
this._onMouseMove=this._onMouseMove.bind(this);
49-
this._onMouseUp=this._onMouseUp.bind(this);
50-
}
51-
52-
componentWillUnmount():void{
53-
window.document.removeEventListener("mousemove",this._onMouseMove);
54-
window.document.removeEventListener("mouseup",this._onMouseUp);
55-
}
56-
57-
_onMouseDown(e:React.MouseEvent<HTMLDivElement>){
58-
if(e.button===2||e.nativeEvent.which===2){
59-
return;
60-
}
61-
letnextState:SectionState={mouseDown:false};
62-
nextState.mouseDown=true;
63-
nextState.startPoint={
64-
x:e.pageX-(this.selectAreaRef.current?.getBoundingClientRect().left??0),
65-
y:e.pageY-(this.selectAreaRef.current?.getBoundingClientRect().top??0),
40+
});
41+
42+
exportconstDragSelector=React.memo((props:SectionProps)=>{
43+
constselectAreaRef=useRef<HTMLDivElement>(null);
44+
const[state,setState]=useState<SectionState>(createInitialState());
45+
constmountedRef=useRef(true);
46+
47+
// Cleanup on unmount
48+
useEffect(()=>{
49+
return()=>{
50+
mountedRef.current=false;
51+
// Clean up any remaining event listeners
52+
window.document.removeEventListener("mousemove",handleMouseMove);
53+
window.document.removeEventListener("mouseup",handleMouseUp);
54+
};
55+
},[]);
56+
57+
consthandleMouseMove=useCallback((e:MouseEvent)=>{
58+
if(!mountedRef.current||!state.mouseDown)return;
59+
60+
constendPoint={
61+
x:e.pageX-(selectAreaRef.current?.getBoundingClientRect().left??0),
62+
y:e.pageY-(selectAreaRef.current?.getBoundingClientRect().top??0),
6663
};
67-
this.setState(nextState);
68-
window.document.addEventListener("mousemove",this._onMouseMove);
69-
window.document.addEventListener("mouseup",this._onMouseUp);
70-
this.props.onMouseDown();
71-
}
72-
73-
_onMouseUp(){
74-
window.document.removeEventListener("mousemove",this._onMouseMove);
75-
window.document.removeEventListener("mouseup",this._onMouseUp);
76-
this.props.onMouseUp();
77-
this.setState(InitialState);
78-
}
79-
80-
_onMouseMove(e:MouseEvent){
81-
if(this.state.mouseDown){
82-
letendPoint={
83-
x:e.pageX-(this.selectAreaRef.current?.getBoundingClientRect().left??0),
84-
y:e.pageY-(this.selectAreaRef.current?.getBoundingClientRect().top??0),
85-
};
86-
this.setState({
87-
selectionBox:this._calculateSelectionBox(this.state.startPoint,endPoint),
88-
});
64+
65+
setState(prevState=>({
66+
...prevState,
67+
selectionBox:calculateSelectionBox(prevState.startPoint,endPoint),
68+
}));
69+
70+
// Clean up selection properly
71+
constselection=window.getSelection();
72+
if(selection){
73+
selection.removeAllRanges();
8974
}
90-
// Disable selection of text during mouse movement
91-
varselection=window.getSelection();
92-
selection!.removeAllRanges();
93-
selection=null;
94-
this.props.onMouseMove(this.childrenViewCheckFunc);
95-
}
96-
97-
rectIntersect=(
75+
76+
props.onMouseMove(childrenViewCheckFunc);
77+
},[state.mouseDown,state.startPoint,props.onMouseMove]);
78+
79+
consthandleMouseUp=useCallback(()=>{
80+
if(!mountedRef.current)return;
81+
82+
window.document.removeEventListener("mousemove",handleMouseMove);
83+
window.document.removeEventListener("mouseup",handleMouseUp);
84+
props.onMouseUp();
85+
setState(createInitialState());
86+
},[handleMouseMove,props.onMouseUp]);
87+
88+
consthandleMouseDown=useCallback((e:React.MouseEvent<HTMLDivElement>)=>{
89+
if(!mountedRef.current||e.button===2||e.nativeEvent.which===2)return;
90+
91+
conststartPoint={
92+
x:e.pageX-(selectAreaRef.current?.getBoundingClientRect().left??0),
93+
y:e.pageY-(selectAreaRef.current?.getBoundingClientRect().top??0),
94+
};
95+
96+
setState({
97+
mouseDown:true,
98+
startPoint,
99+
selectionBox:undefined,
100+
appendMode:false,
101+
});
102+
103+
window.document.addEventListener("mousemove",handleMouseMove);
104+
window.document.addEventListener("mouseup",handleMouseUp);
105+
props.onMouseDown();
106+
},[handleMouseMove,handleMouseUp,props.onMouseDown]);
107+
108+
constrectIntersect=useCallback((
98109
selectionBox:Rect|undefined,
99110
item:HTMLElement|null|undefined
100111
):boolean=>{
101-
if(!selectionBox||!item){
102-
returnfalse;
103-
}
112+
if(!selectionBox||!item||!selectAreaRef.current)returnfalse;
113+
114+
constcontainerRect=selectAreaRef.current.getBoundingClientRect();
104115
constitemBox={
105-
top:
106-
item.getBoundingClientRect().top-
107-
(this.selectAreaRef.current?.getBoundingClientRect().top??0),
108-
left:
109-
item.getBoundingClientRect().left-
110-
(this.selectAreaRef.current?.getBoundingClientRect().left??0),
116+
top:item.getBoundingClientRect().top-containerRect.top,
117+
left:item.getBoundingClientRect().left-containerRect.left,
111118
width:item.getBoundingClientRect().width,
112119
height:item.getBoundingClientRect().height,
113120
};
121+
114122
return(
115123
selectionBox.left<=itemBox.left+itemBox.width&&
116124
selectionBox.left+selectionBox.width>=itemBox.left&&
117125
selectionBox.top<=itemBox.top+itemBox.height&&
118126
selectionBox.top+selectionBox.height>=itemBox.top
119127
);
120-
};
128+
},[]);
121129

122-
childrenViewCheckFunc=(
130+
constchildrenViewCheckFunc=useCallback((
123131
item?:HTMLDivElement|null,
124132
afterCheck?:(checkResult:boolean)=>void
125133
)=>{
126-
constresult=this.rectIntersect(this.state.selectionBox,item);
127-
if(!!afterCheck){
134+
constresult=rectIntersect(state.selectionBox,item);
135+
if(afterCheck){
128136
afterCheck(result);
129137
}
130138
returnresult;
131-
};
139+
},[state.selectionBox,rectIntersect]);
132140

133-
render(){
134-
return(
135-
<div
136-
ref={this.selectAreaRef}
137-
onMouseDown={this._onMouseDown.bind(this)}
138-
style={{position:"relative"}}
139-
>
140-
{this.props.children}
141-
{this.renderSelectionBox()}
142-
</div>
143-
);
144-
}
145-
146-
renderSelectionBox(){
147-
if(
148-
!this.state.mouseDown||
149-
!this.state.startPoint||
150-
!this.state.selectionBox||
151-
!this.selectAreaRef.current
152-
){
141+
constcalculateSelectionBox=useCallback((startPoint:Point|undefined,endPoint:Point)=>{
142+
if(!state.mouseDown||!startPoint||!endPoint)returnundefined;
143+
144+
return{
145+
left:Math.min(startPoint.x,endPoint.x),
146+
top:Math.min(startPoint.y,endPoint.y),
147+
width:Math.abs(startPoint.x-endPoint.x),
148+
height:Math.abs(startPoint.y-endPoint.y),
149+
};
150+
},[state.mouseDown]);
151+
152+
constrenderSelectionBox=useCallback(()=>{
153+
if(!state.mouseDown||!state.startPoint||!state.selectionBox||!selectAreaRef.current){
153154
returnnull;
154155
}
156+
155157
return(
156158
<div
157159
style={{
158160
background:"rgba(51, 119, 255, 0.1)",
159161
position:"absolute",
160162
zIndex:Layers.dragSelectBox,
161-
left:this.state.selectionBox.left,
162-
top:this.state.selectionBox.top,
163-
height:this.state.selectionBox.height,
164-
width:this.state.selectionBox.width,
163+
left:state.selectionBox.left,
164+
top:state.selectionBox.top,
165+
height:state.selectionBox.height,
166+
width:state.selectionBox.width,
165167
}}
166168
/>
167169
);
168-
}
169-
170-
_calculateSelectionBox(startPoint:Point|undefined,endPoint:Point){
171-
if(!this.state.mouseDown||!startPoint||!endPoint){
172-
returnundefined;
173-
}
174-
letleft=Math.min(startPoint.x,endPoint.x);
175-
lettop=Math.min(startPoint.y,endPoint.y);
176-
letwidth=Math.abs(startPoint.x-endPoint.x);
177-
letheight=Math.abs(startPoint.y-endPoint.y);
178-
return{
179-
left:left,
180-
top:top,
181-
width:width,
182-
height:height,
183-
};
184-
}
185-
}
186-
187-
exportconstDragSelector=React.memo(DragSelectorComp);
170+
},[state.mouseDown,state.startPoint,state.selectionBox]);
171+
172+
return(
173+
<div
174+
ref={selectAreaRef}
175+
onMouseDown={handleMouseDown}
176+
style={{position:"relative"}}
177+
>
178+
{props.children}
179+
{renderSelectionBox()}
180+
</div>
181+
);
182+
});

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp