mirror of
https://gitee.com/baidu/amis.git
synced 2024-11-29 18:48:45 +08:00
增加自定义尺寸功能
This commit is contained in:
parent
65a32def9e
commit
de359199b8
@ -286,9 +286,8 @@
|
||||
border-color: #222;
|
||||
border-style: solid;
|
||||
border-radius: 30px;
|
||||
width: 375px;
|
||||
height: 96%;
|
||||
max-height: 812px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
flex-grow: unset;
|
||||
min-height: unset;
|
||||
min-width: unset;
|
||||
@ -1971,6 +1970,8 @@ div[class*='Form-group']:empty {
|
||||
transform: translate(-50%, -50%);
|
||||
top: 53%;
|
||||
left: 50%;
|
||||
width: 395px;
|
||||
height: 687px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -641,12 +641,6 @@ export default class Editor extends Component<
|
||||
)}
|
||||
{isMobile && (
|
||||
<MobileDevTool
|
||||
onChange={value => {
|
||||
this.setState({mobileDimensions: value});
|
||||
}}
|
||||
onScaleChange={scale => {
|
||||
this.setState({mobileScale: scale});
|
||||
}}
|
||||
container={this.mainPreviewRef.current}
|
||||
previewBody={this.mainPreviewBodyRef.current?.currentDom}
|
||||
/>
|
||||
@ -664,8 +658,6 @@ export default class Editor extends Component<
|
||||
autoFocus={autoFocus}
|
||||
toolbarContainer={this.getToolbarContainer}
|
||||
readonly={readonly}
|
||||
mobileDimensions={mobileDimensions}
|
||||
mobileScale={mobileScale}
|
||||
ref={this.mainPreviewBodyRef}
|
||||
></Preview>
|
||||
</div>
|
||||
|
@ -49,11 +49,6 @@ export interface PreviewProps {
|
||||
toolbarContainer?: () => any;
|
||||
|
||||
readonly?: boolean;
|
||||
mobileDimensions?: {
|
||||
width: number;
|
||||
height: number;
|
||||
};
|
||||
mobileScale?: number;
|
||||
ref?: any;
|
||||
}
|
||||
|
||||
@ -166,11 +161,7 @@ export default class Preview extends Component<PreviewProps> {
|
||||
requestAnimationFrame(() => {
|
||||
this.layer!.style.cssText += `transform: translate(0, -${
|
||||
this.scrollLayer!.scrollTop
|
||||
}px) ${
|
||||
this.props.isMobile
|
||||
? `scale(${(this.props.mobileScale || 100) / 100})`
|
||||
: ''
|
||||
};`;
|
||||
}px);`;
|
||||
});
|
||||
}
|
||||
|
||||
@ -571,15 +562,6 @@ export default class Preview extends Component<PreviewProps> {
|
||||
isMobile ? 'is-mobile' : 'is-pc hoverShowScrollBar'
|
||||
)}
|
||||
ref={this.contentsRef}
|
||||
style={
|
||||
isMobile
|
||||
? {
|
||||
width: this.props.mobileDimensions?.width,
|
||||
height: this.props.mobileDimensions?.height,
|
||||
transform: `scale(${(this.props.mobileScale || 100) / 100})`
|
||||
}
|
||||
: undefined
|
||||
}
|
||||
>
|
||||
<div className="ae-Preview-inner">
|
||||
{!store.ready ? (
|
||||
@ -628,13 +610,6 @@ export default class Preview extends Component<PreviewProps> {
|
||||
onDragEnter={this.handleWidgetsDragEnter}
|
||||
className="ae-Preview-widgets"
|
||||
id="aePreviewHighlightBox"
|
||||
style={
|
||||
isMobile
|
||||
? {
|
||||
transform: `scale(${(this.props.mobileScale || 100) / 100})`
|
||||
}
|
||||
: undefined
|
||||
}
|
||||
>
|
||||
{store.highlightNodes.map(node => (
|
||||
<HighlightBox
|
||||
|
@ -31,6 +31,22 @@
|
||||
&-dimension {
|
||||
span {
|
||||
margin-right: 5px;
|
||||
padding: 0 2px;
|
||||
}
|
||||
&-input {
|
||||
width: 32px;
|
||||
height: 16px;
|
||||
border: none;
|
||||
border-radius: 0.125rem;
|
||||
padding: 0 2px;
|
||||
font-size: 12px;
|
||||
text-align: center;
|
||||
margin-right: 5px;
|
||||
&:focus,
|
||||
&:hover {
|
||||
outline: none;
|
||||
border: 1px solid #2468f2;
|
||||
}
|
||||
}
|
||||
}
|
||||
&-right {
|
||||
@ -75,3 +91,85 @@
|
||||
auto !important;
|
||||
}
|
||||
}
|
||||
|
||||
.ae-MobileDevTool-rightHandle {
|
||||
cursor: ew-resize;
|
||||
position: absolute;
|
||||
right: -6px;
|
||||
top: 40%;
|
||||
width: 10px;
|
||||
height: 22px;
|
||||
z-index: 1000;
|
||||
border: 1px solid #dee2e6;
|
||||
background-color: #fff;
|
||||
border-radius: 0.125rem;
|
||||
color: #666;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
&:hover {
|
||||
color: #000;
|
||||
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.12), 0 2px 4px 0 rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
&::before {
|
||||
content: '···';
|
||||
display: block;
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
}
|
||||
.ae-MobileDevTool-bottomHandle {
|
||||
cursor: ns-resize;
|
||||
position: absolute;
|
||||
bottom: -6px;
|
||||
left: calc(50% - 11px);
|
||||
width: 22px;
|
||||
height: 10px;
|
||||
z-index: 1000;
|
||||
border: 1px solid #dee2e6;
|
||||
background-color: #fff;
|
||||
border-radius: 0.125rem;
|
||||
color: #666;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
&:hover {
|
||||
color: #000;
|
||||
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.12), 0 2px 4px 0 rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
&::before {
|
||||
content: '···';
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.height-move {
|
||||
&::before {
|
||||
content: '';
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 10000000;
|
||||
cursor: ns-resize;
|
||||
}
|
||||
* {
|
||||
user-select: none;
|
||||
}
|
||||
}
|
||||
|
||||
.width-move {
|
||||
&::before {
|
||||
content: '';
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 10000000;
|
||||
cursor: ew-resize;
|
||||
}
|
||||
* {
|
||||
user-select: none;
|
||||
}
|
||||
}
|
||||
|
@ -2,8 +2,14 @@ import React, {useEffect} from 'react';
|
||||
import {Icon} from './icons';
|
||||
import {Select} from 'amis-ui';
|
||||
import debounce from 'lodash/debounce';
|
||||
import {Portal} from 'react-overlays';
|
||||
|
||||
export const dimensions = [
|
||||
{
|
||||
name: 'custom',
|
||||
width: 375,
|
||||
height: 667
|
||||
},
|
||||
{
|
||||
name: 'iPhone SE',
|
||||
width: 375,
|
||||
@ -94,12 +100,10 @@ export const dimensions = [
|
||||
const scaleList = [50, 75, 100, 125, 150, 200];
|
||||
|
||||
export default function MobileDevTool(props: {
|
||||
onChange: (dimension: {width: number; height: number}) => void;
|
||||
onScaleChange: (scale: number) => void;
|
||||
container: HTMLElement | null;
|
||||
previewBody: HTMLElement | null;
|
||||
}) {
|
||||
const [dimension, setDimension] = React.useState(dimensions[0]);
|
||||
const [dimension, setDimension] = React.useState(dimensions[1]);
|
||||
const [scale, setScale] = React.useState(100);
|
||||
const [autoScale, setAutoScale] = React.useState(100);
|
||||
// 记录初始时100%的尺寸
|
||||
@ -108,16 +112,16 @@ export default function MobileDevTool(props: {
|
||||
height: 0
|
||||
});
|
||||
|
||||
const {onChange, onScaleChange, container, previewBody} = props;
|
||||
const {container, previewBody} = props;
|
||||
|
||||
const resizeObserver = new ResizeObserver(debounce(updateAutoScale, 300));
|
||||
|
||||
useEffect(() => {
|
||||
onChange?.({
|
||||
updatePreviewSize({
|
||||
width: dimension.width,
|
||||
height: dimension.height
|
||||
});
|
||||
onScaleChange?.(100);
|
||||
updatePreviewScale(100);
|
||||
// 初始化时获取预览区域的尺寸
|
||||
getPreviewInitialSize();
|
||||
|
||||
@ -128,6 +132,11 @@ export default function MobileDevTool(props: {
|
||||
if (container) {
|
||||
resizeObserver.unobserve(container);
|
||||
}
|
||||
if (previewBody) {
|
||||
previewBody.style.width = '';
|
||||
previewBody.style.height = '';
|
||||
previewBody.style.transform = '';
|
||||
}
|
||||
};
|
||||
}, [container, previewBody]);
|
||||
|
||||
@ -161,22 +170,66 @@ export default function MobileDevTool(props: {
|
||||
}, 500);
|
||||
}
|
||||
|
||||
function rotateScreen() {
|
||||
function handleRotateScreen() {
|
||||
setDimension({
|
||||
name: dimension.name,
|
||||
width: dimension.height,
|
||||
height: dimension.width
|
||||
});
|
||||
onChange?.({
|
||||
updatePreviewSize({
|
||||
width: dimension.height,
|
||||
height: dimension.width
|
||||
});
|
||||
getPreviewInitialSize();
|
||||
initialSize.current = {
|
||||
width: initialSize.current.height,
|
||||
height: initialSize.current.width
|
||||
};
|
||||
updateAutoScale();
|
||||
}
|
||||
|
||||
function handleAutoScale() {
|
||||
setScale(autoScale);
|
||||
onScaleChange?.(autoScale);
|
||||
updatePreviewScale(autoScale);
|
||||
}
|
||||
|
||||
function handleDimensionChange(item: any) {
|
||||
if (item) {
|
||||
const value = dimensions.find(n => n.name === item.value)!;
|
||||
setDimension(value);
|
||||
updatePreviewSize(value);
|
||||
setScale(100);
|
||||
updatePreviewScale(100);
|
||||
getPreviewInitialSize();
|
||||
}
|
||||
}
|
||||
|
||||
function handleCustomInputDimensionChange(
|
||||
value: string,
|
||||
type: 'width' | 'height'
|
||||
) {
|
||||
const number = parseInt(value || '0', 10);
|
||||
const newDimension = {
|
||||
name: 'custom',
|
||||
width: type === 'width' ? number : dimension.width,
|
||||
height: type === 'height' ? number : dimension.height
|
||||
};
|
||||
setDimension(newDimension);
|
||||
updatePreviewSize(newDimension);
|
||||
}
|
||||
|
||||
function updatePreviewSize(dimension: {width: number; height: number}) {
|
||||
if (previewBody) {
|
||||
// 预览区域宽高加上20px的padding
|
||||
previewBody.style.width = dimension.width + 20 + 'px';
|
||||
previewBody.style.height = dimension.height + 20 + 'px';
|
||||
}
|
||||
}
|
||||
|
||||
function updatePreviewScale(scale: number) {
|
||||
if (previewBody) {
|
||||
previewBody.style.transform =
|
||||
'translate(-50%, -50%) scale(' + scale / 100 + ')';
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
@ -186,30 +239,42 @@ export default function MobileDevTool(props: {
|
||||
<Select
|
||||
className="ae-MobileDevTool-select"
|
||||
value={dimension.name}
|
||||
onChange={(item: any) => {
|
||||
if (item) {
|
||||
const value = dimensions.find(n => n.name === item.value)!;
|
||||
setDimension(value);
|
||||
onChange?.({
|
||||
width: value.width,
|
||||
height: value.height
|
||||
});
|
||||
setScale(100);
|
||||
onScaleChange?.(100);
|
||||
getPreviewInitialSize();
|
||||
}
|
||||
}}
|
||||
onChange={handleDimensionChange}
|
||||
options={dimensions.map(n => ({
|
||||
label: n.name,
|
||||
label: n.name === 'custom' ? '自定义' : n.name,
|
||||
value: n.name
|
||||
}))}
|
||||
clearable={false}
|
||||
/>
|
||||
</div>
|
||||
<div className="ae-MobileDevTool-dimension">
|
||||
<span>{dimension.width}</span>
|
||||
{dimension.name === 'custom' ? (
|
||||
<input
|
||||
className="ae-MobileDevTool-dimension-input"
|
||||
value={dimension.width}
|
||||
onChange={event => {
|
||||
const value = event.currentTarget.value;
|
||||
|
||||
handleCustomInputDimensionChange(value, 'width');
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<span>{dimension.width}</span>
|
||||
)}
|
||||
<span>×</span>
|
||||
<span>{dimension.height}</span>
|
||||
{dimension.name === 'custom' ? (
|
||||
<input
|
||||
className="ae-MobileDevTool-dimension-input"
|
||||
value={dimension.height}
|
||||
onChange={event => {
|
||||
const value = event.currentTarget.value;
|
||||
|
||||
handleCustomInputDimensionChange(value, 'height');
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<span>{dimension.height}</span>
|
||||
)}
|
||||
</div>
|
||||
<div className="ae-MobileDevTool-right">
|
||||
<div className="ae-MobileDevTool-right-scale">
|
||||
@ -225,7 +290,7 @@ export default function MobileDevTool(props: {
|
||||
]}
|
||||
onChange={(item: any) => {
|
||||
setScale(item.value);
|
||||
onScaleChange?.(item.value);
|
||||
updatePreviewScale(item.value);
|
||||
}}
|
||||
/>
|
||||
{!scaleList.includes(scale) && (
|
||||
@ -240,13 +305,97 @@ export default function MobileDevTool(props: {
|
||||
自适应
|
||||
</div>
|
||||
</div>
|
||||
<div onClick={rotateScreen}>
|
||||
<div onClick={handleRotateScreen}>
|
||||
<Icon
|
||||
icon="rotate-screen"
|
||||
className="ae-MobileDevTool-right-rotate-screen"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{dimension.name === 'custom' && (
|
||||
<CustomSizeHandle
|
||||
previewBody={previewBody}
|
||||
onChange={(w, h) => {
|
||||
setDimension({
|
||||
name: 'custom',
|
||||
width: w - 20,
|
||||
height: h - 20
|
||||
});
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function CustomSizeHandle(props: {
|
||||
previewBody: HTMLElement | null;
|
||||
onChange?: (w: number, h: number) => void;
|
||||
}) {
|
||||
const {previewBody, onChange} = props;
|
||||
|
||||
function handleRightDown(e: any) {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
document.body.classList.add('width-move');
|
||||
document.addEventListener('mousemove', handleRightDragMove);
|
||||
document.addEventListener('mouseup', handleRightDragEnd);
|
||||
}
|
||||
|
||||
function handleRightDragMove(e: any) {
|
||||
e.stopPropagation();
|
||||
if (previewBody) {
|
||||
let w = previewBody.clientWidth;
|
||||
w += e.movementX;
|
||||
w = Math.max(20, w);
|
||||
previewBody.style.width = w + 'px';
|
||||
onChange?.(w, previewBody.clientHeight);
|
||||
}
|
||||
}
|
||||
|
||||
function handleRightDragEnd() {
|
||||
document.body.classList.remove('width-move');
|
||||
document.removeEventListener('mousemove', handleRightDragMove);
|
||||
document.removeEventListener('mouseup', handleRightDragEnd);
|
||||
}
|
||||
|
||||
function handleBottomDown(e: any) {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
document.body.classList.add('height-move');
|
||||
document.addEventListener('mousemove', handleBottomDragMove);
|
||||
document.addEventListener('mouseup', handleBottomDragEnd);
|
||||
}
|
||||
|
||||
function handleBottomDragMove(e: any) {
|
||||
e.stopPropagation();
|
||||
if (previewBody) {
|
||||
let h = previewBody.clientHeight;
|
||||
h += e.movementY;
|
||||
h = Math.max(20, h);
|
||||
previewBody.style.height = h + 'px';
|
||||
onChange?.(previewBody.clientWidth, h);
|
||||
}
|
||||
}
|
||||
|
||||
function handleBottomDragEnd() {
|
||||
document.body.classList.remove('height-move');
|
||||
document.removeEventListener('mousemove', handleBottomDragMove);
|
||||
document.removeEventListener('mouseup', handleBottomDragEnd);
|
||||
}
|
||||
|
||||
return (
|
||||
<Portal container={() => previewBody}>
|
||||
<>
|
||||
<div
|
||||
className="ae-MobileDevTool-rightHandle"
|
||||
onMouseDown={handleRightDown}
|
||||
></div>
|
||||
<div
|
||||
className="ae-MobileDevTool-bottomHandle"
|
||||
onMouseDown={handleBottomDown}
|
||||
></div>
|
||||
</>
|
||||
</Portal>
|
||||
);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user