mirror of
https://github.com/Tencent/tmagic-editor.git
synced 2025-04-06 03:57:56 +08:00
feat(stage,editor): 增肌删除快捷按钮
This commit is contained in:
parent
b4bee9eb82
commit
c9bacb96cd
@ -1,6 +1,6 @@
|
||||
import { computed } from 'vue';
|
||||
|
||||
import StageCore, { GuidesType, SortEventData, UpdateEventData } from '@tmagic/stage';
|
||||
import StageCore, { GuidesType, RemoveEventData, SortEventData, UpdateEventData } from '@tmagic/stage';
|
||||
|
||||
import editorService from '../services/editor';
|
||||
import uiService from '../services/ui';
|
||||
@ -73,6 +73,14 @@ export const useStage = (stageOptions: StageOptions) => {
|
||||
editorService.sort(ev.src, ev.dist);
|
||||
});
|
||||
|
||||
stage.on('remove', (ev: RemoveEventData) => {
|
||||
editorService.remove(
|
||||
ev.data.map(({ el }) => ({
|
||||
id: el.id,
|
||||
})),
|
||||
);
|
||||
});
|
||||
|
||||
stage.on('select-parent', () => {
|
||||
const parent = editorService.get('parent');
|
||||
if (!parent) throw new Error('父节点为空');
|
||||
|
@ -39,6 +39,7 @@ import {
|
||||
GetTargetElement,
|
||||
IsContainer,
|
||||
Point,
|
||||
RemoveEventData,
|
||||
SelectStatus,
|
||||
StageDragStatus,
|
||||
UpdateEventData,
|
||||
@ -454,6 +455,14 @@ export default class ActionManager extends EventEmitter {
|
||||
})
|
||||
.on('select-parent', () => {
|
||||
this.emit('select-parent');
|
||||
})
|
||||
.on('remove', () => {
|
||||
const drTarget = this.dr.getTarget();
|
||||
if (!drTarget) return;
|
||||
const data: RemoveEventData = {
|
||||
data: [{ el: drTarget }],
|
||||
};
|
||||
this.emit('remove', data);
|
||||
});
|
||||
|
||||
this.multiDr
|
||||
|
109
packages/stage/src/MoveableActionsAble.ts
Normal file
109
packages/stage/src/MoveableActionsAble.ts
Normal file
@ -0,0 +1,109 @@
|
||||
import { MoveableManagerInterface, Renderer } from 'moveable';
|
||||
|
||||
import { AbleActionEventType } from './types';
|
||||
|
||||
export default (handler: (type: AbleActionEventType) => void) => ({
|
||||
name: 'actions',
|
||||
props: {
|
||||
selectParent: Boolean,
|
||||
},
|
||||
events: {},
|
||||
render(moveable: MoveableManagerInterface<any, any>, React: Renderer) {
|
||||
const rect = moveable.getRect();
|
||||
const { pos2 } = moveable.state;
|
||||
|
||||
// use css for able
|
||||
const editableViewer = moveable.useCSS(
|
||||
'div',
|
||||
`
|
||||
{
|
||||
position: absolute;
|
||||
left: 0px;
|
||||
top: 0px;
|
||||
will-change: transform;
|
||||
transform-origin: 0px 0px;
|
||||
display: flex;
|
||||
}
|
||||
.moveable-button {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
background: #4af;
|
||||
border-radius: 4px;
|
||||
appearance: none;
|
||||
border: 0;
|
||||
color: white;
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
margin-left: 2px;
|
||||
position: relative;
|
||||
}
|
||||
.moveable-remove-button:before, .moveable-remove-button:after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%) rotate(45deg);
|
||||
width: 14px;
|
||||
height: 2px;
|
||||
background: #fff;
|
||||
border-radius: 1px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.moveable-remove-button:after {
|
||||
transform: translate(-50%, -50%) rotate(-45deg);
|
||||
}
|
||||
`,
|
||||
);
|
||||
// Add key (required)
|
||||
// Add class prefix moveable-(required)
|
||||
return React.createElement(
|
||||
editableViewer,
|
||||
{
|
||||
className: 'moveable-editable',
|
||||
style: {
|
||||
transform: `translate(${pos2[0] - 48}px, ${pos2[1] - 28}px) rotate(${rect.rotation}deg) translate(10px)`,
|
||||
},
|
||||
},
|
||||
[
|
||||
React.createElement(
|
||||
'button',
|
||||
{
|
||||
className: 'moveable-button',
|
||||
title: '选中父组件',
|
||||
onClick: () => {
|
||||
handler(AbleActionEventType.SELECT_PARENT);
|
||||
},
|
||||
},
|
||||
React.createElement(
|
||||
'svg',
|
||||
{
|
||||
width: '20px',
|
||||
height: '20px',
|
||||
viewBox: '0 0 16 16',
|
||||
fill: 'none',
|
||||
xmlns: 'http://www.w3.org/2000/svg',
|
||||
style: {
|
||||
transform: 'rotate(90deg)',
|
||||
position: 'absolute',
|
||||
left: 0,
|
||||
top: 0,
|
||||
},
|
||||
},
|
||||
React.createElement('path', {
|
||||
d: 'M13.0001 4V10H4.20718L5.85363 8.35355L5.14652 7.64645L2.64652 10.1464C2.45126 10.3417 2.45126 10.6583 2.64652 10.8536L5.14652 13.3536L5.85363 12.6464L4.20718 11H13.0001C13.5524 11 14.0001 10.5523 14.0001 10V4H13.0001Z',
|
||||
fill: 'currentColor',
|
||||
fillOpacity: '0.9',
|
||||
}),
|
||||
),
|
||||
),
|
||||
React.createElement('button', {
|
||||
className: 'moveable-button moveable-remove-button',
|
||||
title: '删除',
|
||||
onClick: () => {
|
||||
handler(AbleActionEventType.REMOVE);
|
||||
},
|
||||
}),
|
||||
],
|
||||
);
|
||||
},
|
||||
});
|
@ -22,8 +22,8 @@ import { merge } from 'lodash-es';
|
||||
import { MoveableOptions } from 'moveable';
|
||||
|
||||
import { GuidesType, Mode } from './const';
|
||||
import selectParentAbles from './MoveableSelectParentAble';
|
||||
import { GetRootContainer, MoveableOptionsManagerConfig } from './types';
|
||||
import MoveableActionsAble from './MoveableActionsAble';
|
||||
import { AbleActionEventType, GetRootContainer, MoveableOptionsManagerConfig } from './types';
|
||||
import { getOffset } from './util';
|
||||
|
||||
/**
|
||||
@ -173,10 +173,10 @@ export default class MoveableOptionsManager extends EventEmitter {
|
||||
isDisplayInnerSnapDigit: true,
|
||||
|
||||
props: {
|
||||
selectParent: true,
|
||||
actions: true,
|
||||
},
|
||||
|
||||
ables: [selectParentAbles(this.selectParentHandler.bind(this))],
|
||||
ables: [MoveableActionsAble(this.actionHandler.bind(this))],
|
||||
};
|
||||
}
|
||||
|
||||
@ -208,8 +208,8 @@ export default class MoveableOptionsManager extends EventEmitter {
|
||||
/**
|
||||
* 这是给selectParentAbles的回调函数,用于触发选中父元素事件
|
||||
*/
|
||||
private selectParentHandler(): void {
|
||||
this.emit('select-parent');
|
||||
private actionHandler(type: AbleActionEventType): void {
|
||||
this.emit(type);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,76 +0,0 @@
|
||||
import { MoveableManagerInterface, Renderer } from 'moveable';
|
||||
|
||||
export default (selectParentHandler: () => void) => ({
|
||||
name: 'selectParent',
|
||||
props: {},
|
||||
events: {},
|
||||
render(moveable: MoveableManagerInterface<any, any>, React: Renderer) {
|
||||
const rect = moveable.getRect();
|
||||
const { pos2 } = moveable.state;
|
||||
|
||||
// use css for able
|
||||
const editableViewer = moveable.useCSS(
|
||||
'div',
|
||||
`
|
||||
{
|
||||
position: absolute;
|
||||
left: 0px;
|
||||
top: 0px;
|
||||
will-change: transform;
|
||||
transform-origin: 0px 0px;
|
||||
display: flex;
|
||||
}
|
||||
.moveable-button {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
background: #4af;
|
||||
border-radius: 4px;
|
||||
appearance: none;
|
||||
border: 0;
|
||||
color: white;
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
}
|
||||
`,
|
||||
);
|
||||
// Add key (required)
|
||||
// Add class prefix moveable-(required)
|
||||
return React.createElement(
|
||||
editableViewer,
|
||||
{
|
||||
className: 'moveable-editable',
|
||||
style: {
|
||||
transform: `translate(${pos2[0] - 25}px, ${pos2[1] - 30}px) rotate(${rect.rotation}deg) translate(10px)`,
|
||||
},
|
||||
},
|
||||
React.createElement(
|
||||
'button',
|
||||
{
|
||||
className: 'moveable-button',
|
||||
title: '选中父组件',
|
||||
onClick: () => {
|
||||
selectParentHandler();
|
||||
},
|
||||
},
|
||||
React.createElement(
|
||||
'svg',
|
||||
{
|
||||
width: '1em',
|
||||
height: '1em',
|
||||
viewBox: '0 0 16 16',
|
||||
fill: 'none',
|
||||
xmlns: 'http://www.w3.org/2000/svg',
|
||||
style: {
|
||||
transform: 'rotate(90deg)',
|
||||
},
|
||||
},
|
||||
React.createElement('path', {
|
||||
d: 'M13.0001 4V10H4.20718L5.85363 8.35355L5.14652 7.64645L2.64652 10.1464C2.45126 10.3417 2.45126 10.6583 2.64652 10.8536L5.14652 13.3536L5.85363 12.6464L4.20718 11H13.0001C13.5524 11 14.0001 10.5523 14.0001 10V4H13.0001Z',
|
||||
fill: 'currentColor',
|
||||
fillOpacity: '0.9',
|
||||
}),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
});
|
@ -30,6 +30,7 @@ import {
|
||||
GuidesEventData,
|
||||
Point,
|
||||
RemoveData,
|
||||
RemoveEventData,
|
||||
Runtime,
|
||||
StageCoreConfig,
|
||||
UpdateData,
|
||||
@ -313,6 +314,9 @@ export default class StageCore extends EventEmitter {
|
||||
})
|
||||
.on('select-parent', () => {
|
||||
this.emit('select-parent');
|
||||
})
|
||||
.on('remove', (data: RemoveEventData) => {
|
||||
this.emit('remove', data);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -63,6 +63,10 @@ export default class StageDragResize extends MoveableOptionsManager {
|
||||
});
|
||||
}
|
||||
|
||||
public getTarget() {
|
||||
return this.target;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将选中框渲染并覆盖到选中的组件Dom节点上方
|
||||
* 当选中的节点不是absolute时,会创建一个新的节点出来作为拖拽目标
|
||||
|
@ -190,6 +190,12 @@ export interface UpdateEventData {
|
||||
parentEl: HTMLElement | null;
|
||||
}
|
||||
|
||||
export interface RemoveEventData {
|
||||
data: {
|
||||
el: HTMLElement;
|
||||
}[];
|
||||
}
|
||||
|
||||
export interface SortEventData {
|
||||
src: Id;
|
||||
dist: Id;
|
||||
@ -244,3 +250,8 @@ export interface TargetShadowConfig {
|
||||
updateDragEl?: UpdateDragEl;
|
||||
idPrefix?: string;
|
||||
}
|
||||
|
||||
export enum AbleActionEventType {
|
||||
SELECT_PARENT = 'select-parent',
|
||||
REMOVE = 'remove',
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user