我正在寻求帮助。我正在做一个可排序和可调整大小的布局,但是现在我必须为每个布局添加一个按钮才能删除它们,但我看不到该怎么做,因为我看不到该怎么做钥匙。也是添加新布局的按钮。 我正在使用Rnd库,reactjs和打字稿。在这里,我让我已经执行过的代码,欢迎大家的帮助,谢谢^^
代码:
Multicontroller.tsx
import * as React from "react";
import { Rnd } from "./index";
import { style } from "./styles";
import ClearIcon from '@material-ui/icons/Clear';
type State = {
rnds: {
x: number;
y: number;
width: number;
height: number;
}[];
}
export default class Example extends React.Component<{}, State> {
constructor(props:any) {
super(props);
this.state = {
rnds: [0,1,2].map(i => ({
width: 680,
height: 180,
x: 100,
y: 100,
})),
}
}
add(){
let z: number;
z=3
{[z].map(i => (
<Rnd
key={`rnd${i}`}
style={style}
size={{
width: this.state.rnds[i].width,
height: this.state.rnds[i].height,
}}
position={{
x: this.state.rnds[i].x,
y: this.state.rnds[i].y,
}}
onDragStop={(e, d) => {
const rnds = [...this.state.rnds];
rnds[i] = { ...rnds[i], x: d.x, y: d.y };
this.setState({ rnds });
}}
onResize={(e, direction, ref, delta, position) => {
const rnds = [...this.state.rnds];
rnds[i] = {
...rnds[i],
width: ref.offsetWidth,
height: ref.offsetHeight,
...position,
};
this.setState({
rnds,
});
}}
>
<button onClick={(e) => this.remove(e)} value={`rnd${i}`}><ClearIcon></ClearIcon></button>
</Rnd>
))}
}
remove(e: React.MouseEvent<HTMLButtonElement>){
const index = e.currentTarget.getAttribute("value")
let id: string;
index ? id = index : id = "no value"
console.log(id)
}
render() {
return (
<div style={{ padding: '70px' }}>
<button onClick={() => this.add()}>Add</button>
{[0].map(i => (
<Rnd
key={`rnd${i}`}
style={style}
size={{
width: this.state.rnds[i].width,
height: this.state.rnds[i].height,
}}
position={{
x: this.state.rnds[i].x,
y: this.state.rnds[i].y,
}}
onDragStop={(e, d) => {
const rnds = [...this.state.rnds];
rnds[i] = { ...rnds[i], x: d.x, y: d.y };
this.setState({ rnds });
}}
onResize={(e, direction, ref, delta, position) => {
const rnds = [...this.state.rnds];
rnds[i] = {
...rnds[i],
width: ref.offsetWidth,
height: ref.offsetHeight,
...position,
};
this.setState({
rnds,
});
}}
>
<button onClick={(e) => this.remove(e)} value={`rnd${i}`}><ClearIcon></ClearIcon></button>
</Rnd>
))}
{[1].map(i => (
<Rnd
key={`rnd${i}`}
style={style}
size={{
width: this.state.rnds[i].width -380,
height: this.state.rnds[i].height +120,
}}
position={{
x: this.state.rnds[i].x,
y: this.state.rnds[i].y,
}}
onDragStop={(e, d) => {
const rnds = [...this.state.rnds];
rnds[i] = { ...rnds[i], x: d.x, y: d.y };
this.setState({ rnds });
}}
onResize={(e, direction, ref, delta, position) => {
const rnds = [...this.state.rnds];
rnds[i] = {
...rnds[i],
width: ref.offsetWidth +380,
height: ref.offsetHeight -120,
...position,
};
this.setState({
rnds,
});
}}
>
<button onClick={(e) => this.remove(e)} value={`rnd${i}`}><ClearIcon></ClearIcon></button>
</Rnd>
))}
{[2].map(i => (
<Rnd
key={`rnd${i}`}
style={style}
size={{
width: this.state.rnds[i].width-80,
height: this.state.rnds[i].height+100,
}}
position={{
x: this.state.rnds[i].x,
y: this.state.rnds[i].y,
}}
onDragStop={(e, d) => {
const rnds = [...this.state.rnds];
rnds[i] = { ...rnds[i], x: d.x, y: d.y };
this.setState({ rnds });
}}
onResize={(e, direction, ref, delta, position) => {
const rnds = [...this.state.rnds];
rnds[i] = {
...rnds[i],
width: ref.offsetWidth+80,
height: ref.offsetHeight-100,
...position,
};
this.setState({
rnds,
});
}}
>
<button onClick={(e) => this.remove(e)} value={`rnd${i}`}><ClearIcon></ClearIcon></button>
</Rnd>
))}
</div>
)
}
}
style.ts
export const style = {
display: "flex",
alignItems: "center",
justifyContent: "center",
border: "solid 1px #ddd",
background: "#AAAAAA",
};
export const parentBoundary = {
background: "#eee",
width: "100%",
height: "100%",
};
export const selectorBoundary = {
background: "#d1d8ff",
padding: "20px",
width: "100%",
height: "100%",
};
export const Xbuttons ={
alignItems:top
};
index.tsx
import * as React from "react";
import Draggable from "react-draggable";
import Resizable, { ResizableDirection } from "re-resizable";
export type Grid = [number, number];
export type Position = {
x: number;
y: number;
};
export type DraggableData = {
node: HTMLElement;
deltaX: number;
deltaY: number;
lastX: number;
lastY: number;
} & Position;
export type RndDragCallback = (e: Event, data: DraggableData) => void | false;
export type RndResizeStartCallback = (
e: React.MouseEvent<HTMLDivElement> | React.TouchEvent<HTMLDivElement>,
dir: ResizableDirection,
elementRef: HTMLDivElement,
) => void;
export type ResizableDelta = {
width: number;
height: number;
};
export type RndResizeCallback = (
e: MouseEvent | TouchEvent,
dir: ResizableDirection,
elementRef: HTMLDivElement,
delta: ResizableDelta,
position: Position,
) => void;
type Size = {
width: string | number;
height: string | number;
};
type State = {
original: Position;
bounds: {
top: number;
right: number;
bottom: number;
left: number;
};
maxWidth?: number | string;
maxHeight?: number | string;
};
type MaxSize = {
maxWidth: number | string;
maxHeight: number | string;
};
export type ResizeEnable = {
bottom?: boolean;
bottomLeft?: boolean;
bottomRight?: boolean;
left?: boolean;
right?: boolean;
top?: boolean;
topLeft?: boolean;
topRight?: boolean;
};
export type HandleClasses = {
bottom?: string;
bottomLeft?: string;
bottomRight?: string;
left?: string;
right?: string;
top?: string;
topLeft?: string;
topRight?: string;
};
export type HandleStyles = {
bottom?: React.CSSProperties;
bottomLeft?: React.CSSProperties;
bottomRight?: React.CSSProperties;
left?: React.CSSProperties;
right?: React.CSSProperties;
top?: React.CSSProperties;
topLeft?: React.CSSProperties;
topRight?: React.CSSProperties;
};
export interface Props {
dragGrid?: Grid;
default?: {
x: number;
y: number;
} & Size;
position?: {
x: number;
y: number;
};
size?: Size;
resizeGrid?: Grid;
bounds?: string;
onMouseDown?: (e: MouseEvent) => void;
onResizeStart?: RndResizeStartCallback;
onResize?: RndResizeCallback;
onResizeStop?: RndResizeCallback;
onDragStart?: RndDragCallback;
onDrag?: RndDragCallback;
onDragStop?: RndDragCallback;
className?: string;
style?: React.CSSProperties;
children?: React.ReactNode;
enableResizing?: ResizeEnable;
resizeHandleClasses?: HandleClasses;
resizeHandleStyles?: HandleStyles;
resizeHandleWrapperClass?: string;
resizeHandleWrapperStyle?: React.CSSProperties;
lockAspectRatio?: boolean | number;
lockAspectRatioExtraWidth?: number;
lockAspectRatioExtraHeight?: number;
maxHeight?: number | string;
maxWidth?: number | string;
minHeight?: number | string;
minWidth?: number | string;
dragAxis?: "x" | "y" | "both" | "none";
dragHandleClassName?: string;
disableDragging?: boolean;
cancel?: string;
enableUserSelectHack?: boolean;
[key: string]: any;
}
const resizableStyle = {
width: "auto" as "auto",
height: "auto" as "auto",
display: "inline-block" as "inline-block",
position: "absolute" as "absolute",
top: 0,
left: 0,
};
export class Rnd extends React.Component<Props, State> {
static defaultProps = {
maxWidth: Number.MAX_SAFE_INTEGER,
maxHeight: Number.MAX_SAFE_INTEGER,
onResizeStart: () => {},
onResize: () => {},
onResizeStop: () => {},
onDragStart: () => {},
onDrag: () => {},
onDragStop: () => {},
};
resizable!: Resizable;
draggable!: Draggable;
isResizing = false;
constructor(props: Props) {
super(props);
this.state = {
original: {
x: 0,
y: 0,
},
bounds: {
top: 0,
right: 0,
bottom: 0,
left: 0,
},
maxWidth: props.maxWidth,
maxHeight: props.maxHeight,
};
this.onResizeStart = this.onResizeStart.bind(this);
this.onResize = this.onResize.bind(this);
this.onResizeStop = this.onResizeStop.bind(this);
this.onDragStart = this.onDragStart.bind(this);
this.onDrag = this.onDrag.bind(this);
this.onDragStop = this.onDragStop.bind(this);
this.getMaxSizesFromProps = this.getMaxSizesFromProps.bind(this);
}
componentDidMount() {
const { left, top } = this.getOffsetFromParent();
const { x, y } = this.getDraggablePosition();
this.draggable.setState({
x: x - left,
y: y - top,
});
// HACK: Apply position adjustment
this.forceUpdate();
}
// HACK: To get `react-draggable` state x and y.
getDraggablePosition(): { x: number; y: number } {
const { x, y } = (this.draggable as any).state;
return { x, y };
}
getParent() {
return this.resizable && (this.resizable as any).parentNode;
}
getParentSize(): { width: number; height: number } {
return (this.resizable as any).getParentSize();
}
getMaxSizesFromProps(): MaxSize {
const maxWidth = typeof this.props.maxWidth === "undefined" ? Number.MAX_SAFE_INTEGER : this.props.maxWidth;
const maxHeight = typeof this.props.maxHeight === "undefined" ? Number.MAX_SAFE_INTEGER : this.props.maxHeight;
return { maxWidth, maxHeight };
}
getSelfElement(): Element {
return this.resizable && this.resizable.resizable;
}
onDragStart(e: Event, data: DraggableData) {
if (this.props.onDragStart) {
this.props.onDragStart(e, data);
}
if (!this.props.bounds) return;
const parent = this.getParent();
let boundary;
if (this.props.bounds === "parent") {
boundary = parent;
} else if (this.props.bounds === "body") {
boundary = document.body;
} else if (this.props.bounds === "window") {
if (!this.resizable) return;
return this.setState({
bounds: {
top: 0,
right: window.innerWidth - this.resizable.size.width,
bottom: window.innerHeight - this.resizable.size.height,
left: 0,
},
});
} else {
boundary = document.querySelector(this.props.bounds);
}
if (!(boundary instanceof HTMLElement) || !(parent instanceof HTMLElement)) {
return;
}
const boundaryRect = boundary.getBoundingClientRect();
const boundaryLeft = boundaryRect.left;
const boundaryTop = boundaryRect.top;
const parentRect = parent.getBoundingClientRect();
const parentLeft = parentRect.left;
const parentTop = parentRect.top;
const left = boundaryLeft - parentLeft;
const top = boundaryTop - parentTop;
if (!this.resizable) return;
const offset = this.getOffsetFromParent();
this.setState({
bounds: {
top: top - offset.top,
right: left + (boundary.offsetWidth - this.resizable.size.width) - offset.left,
bottom: top + (boundary.offsetHeight - this.resizable.size.height) - offset.top,
left: left - offset.left,
},
});
}
onDrag(e: Event, data: DraggableData) {
if (this.props.onDrag) {
const offset = this.getOffsetFromParent();
this.props.onDrag(e, { ...data, x: data.x - offset.left, y: data.y - offset.top });
}
}
onDragStop(e: Event, data: DraggableData) {
if (this.props.onDragStop) {
const { left, top } = this.getOffsetFromParent();
this.props.onDragStop(e, { ...data, x: data.x + left, y: data.y + top });
}
}
onResizeStart(
e: React.MouseEvent<HTMLDivElement> | React.TouchEvent<HTMLDivElement>,
dir: ResizableDirection,
elementRef: HTMLDivElement,
) {
e.stopPropagation();
this.isResizing = true;
this.setState({
original: this.getDraggablePosition(),
});
if (this.props.bounds) {
const parent = this.getParent();
let boundary;
if (this.props.bounds === "parent") {
boundary = parent;
} else if (this.props.bounds === "body") {
boundary = document.body;
} else if (this.props.bounds === "window") {
boundary = window;
} else {
boundary = document.querySelector(this.props.bounds);
}
const self = this.getSelfElement();
if (
self instanceof Element &&
(boundary instanceof HTMLElement || boundary === window) &&
parent instanceof HTMLElement
) {
let { maxWidth, maxHeight } = this.getMaxSizesFromProps();
const parentSize = this.getParentSize();
if (maxWidth && typeof maxWidth === "string") {
if (maxWidth.endsWith("%")) {
const ratio = Number(maxWidth.replace("%", "")) / 100;
maxWidth = parentSize.width * ratio;
} else if (maxWidth.endsWith("px")) {
maxWidth = Number(maxWidth.replace("px", ""));
}
}
if (maxHeight && typeof maxHeight === "string") {
if (maxHeight.endsWith("%")) {
const ratio = Number(maxHeight.replace("%", "")) / 100;
maxHeight = parentSize.width * ratio;
} else if (maxHeight.endsWith("px")) {
maxHeight = Number(maxHeight.replace("px", ""));
}
}
const selfRect = self.getBoundingClientRect();
const selfLeft = selfRect.left;
const selfTop = selfRect.top;
const boundaryRect = this.props.bounds === "window" ? { left: 0, top: 0 } : boundary.getBoundingClientRect();
const boundaryLeft = boundaryRect.left;
const boundaryTop = boundaryRect.top;
const offsetWidth = this.props.bounds === "window" ? window.innerWidth : boundary.offsetWidth;
const offsetHeight = this.props.bounds === "window" ? window.innerHeight : boundary.offsetHeight;
const hasLeft = dir.toLowerCase().endsWith("left");
const hasRight = dir.toLowerCase().endsWith("right");
const hasTop = dir.startsWith("top");
const hasBottom = dir.startsWith("bottom");
if (hasLeft && this.resizable) {
const max = selfLeft - boundaryLeft + this.resizable.size.width;
this.setState({ maxWidth: max > Number(maxWidth) ? maxWidth : max });
}
// INFO: To set bounds in `lock aspect ratio with bounds` case. See also that story.
if (hasRight || (this.props.lockAspectRatio && !hasLeft)) {
const max = offsetWidth + (boundaryLeft - selfLeft);
this.setState({ maxWidth: max > Number(maxWidth) ? maxWidth : max });
}
if (hasTop && this.resizable) {
const max = selfTop - boundaryTop + this.resizable.size.height;
this.setState({
maxHeight: max > Number(maxHeight) ? maxHeight : max,
});
}
// INFO: To set bounds in `lock aspect ratio with bounds` case. See also that story.
if (hasBottom || (this.props.lockAspectRatio && !hasTop)) {
const max = offsetHeight + (boundaryTop - selfTop);
this.setState({
maxHeight: max > Number(maxHeight) ? maxHeight : max,
});
}
}
} else {
this.setState({
maxWidth: this.props.maxWidth,
maxHeight: this.props.maxHeight,
});
}
if (this.props.onResizeStart) {
this.props.onResizeStart(e, dir, elementRef);
}
}
onResize(
e: MouseEvent | TouchEvent,
direction: ResizableDirection,
elementRef: HTMLDivElement,
delta: { height: number; width: number },
) {
let x;
let y;
const offset = this.getOffsetFromParent();
if (/left/i.test(direction)) {
x = this.state.original.x - delta.width;
// INFO: If uncontrolled component, apply x position by resize to draggable.
if (!this.props.position) {
this.draggable.setState({ x });
}
x += offset.left;
}
if (/top/i.test(direction)) {
y = this.state.original.y - delta.height;
// INFO: If uncontrolled component, apply y position by resize to draggable.
if (!this.props.position) {
this.draggable.setState({ y });
}
y += offset.top;
}
if (this.props.onResize) {
if (typeof x === "undefined") {
x = this.getDraggablePosition().x + offset.left;
}
if (typeof y === "undefined") {
y = this.getDraggablePosition().y + offset.top;
}
this.props.onResize(e, direction, elementRef, delta, {
x,
y,
});
}
}
onResizeStop(
e: MouseEvent | TouchEvent,
direction: ResizableDirection,
elementRef: HTMLDivElement,
delta: { height: number; width: number },
) {
this.isResizing = false;
const { maxWidth, maxHeight } = this.getMaxSizesFromProps();
this.setState({ maxWidth, maxHeight });
if (this.props.onResizeStop) {
const position: Position = this.getDraggablePosition();
this.props.onResizeStop(e, direction, elementRef, delta, position);
}
}
updateSize(size: { width: number | string; height: number | string }) {
if (!this.resizable) return;
this.resizable.updateSize({ width: size.width, height: size.height });
}
updatePosition(position: Position) {
this.draggable.setState(position);
}
getOffsetFromParent(): { top: number; left: number } {
const parent = this.getParent();
if (!parent) {
return {
top: 0,
left: 0,
};
}
const parentRect = parent.getBoundingClientRect();
const parentLeft = parentRect.left;
const parentTop = parentRect.top;
const selfRect = this.getSelfElement().getBoundingClientRect();
const position = this.getDraggablePosition();
return {
left: selfRect.left - parentLeft - position.x,
top: selfRect.top - parentTop - position.y,
};
}
render() {
const {
disableDragging,
style,
dragHandleClassName,
position,
onMouseDown,
dragAxis,
dragGrid,
bounds,
enableUserSelectHack,
cancel,
children,
onResizeStart,
onResize,
onResizeStop,
onDragStart,
onDrag,
onDragStop,
resizeHandleStyles,
resizeHandleClasses,
enableResizing,
resizeGrid,
resizeHandleWrapperClass,
resizeHandleWrapperStyle,
...resizableProps
} = this.props;
const defaultValue = this.props.default ? { ...this.props.default } : undefined;
// Remove unknown props, see also https://reactjs.org/warnings/unknown-prop.html
delete resizableProps.default;
const cursorStyle = disableDragging || dragHandleClassName ? { cursor: "normal" } : { cursor: "move" };
const innerStyle = {
...resizableStyle,
...cursorStyle,
...style,
};
const { left, top } = this.getOffsetFromParent();
let draggablePosition;
if (position) {
draggablePosition = {
x: position.x - left,
y: position.y - top,
};
}
return (
<Draggable
ref={c => {
if (c) {
this.draggable = c;
}
}}
handle={dragHandleClassName ? `.${dragHandleClassName}` : undefined}
defaultPosition={defaultValue}
onMouseDown={onMouseDown}
onStart={this.onDragStart}
onDrag={this.onDrag}
onStop={this.onDragStop}
axis={dragAxis}
disabled={disableDragging}
grid={dragGrid}
bounds={bounds ? this.state.bounds : undefined}
position={draggablePosition}
enableUserSelectHack={enableUserSelectHack}
cancel={cancel}
>
<Resizable
{...resizableProps}
ref={c => {
if (c) {
this.resizable = c;
}
}}
defaultSize={defaultValue}
size={this.props.size}
enable={enableResizing}
onResizeStart={this.onResizeStart}
onResize={this.onResize}
onResizeStop={this.onResizeStop}
style={innerStyle}
minWidth={this.props.minWidth}
minHeight={this.props.minHeight}
maxWidth={this.isResizing ? this.state.maxWidth : this.props.maxWidth}
maxHeight={this.isResizing ? this.state.maxHeight : this.props.maxHeight}
grid={resizeGrid}
handleWrapperClass={resizeHandleWrapperClass}
handleWrapperStyle={resizeHandleWrapperStyle}
lockAspectRatio={this.props.lockAspectRatio}
lockAspectRatioExtraWidth={this.props.lockAspectRatioExtraWidth}
lockAspectRatioExtraHeight{this.props.lockAspectRatioExtraHeight}
handleStyles={resizeHandleStyles}
handleClasses={resizeHandleClasses}
>
{children}
</Resizable>
</Draggable>
);
}
}
感谢您的帮助!