diff --git a/docs/zh-CN/components/image.md b/docs/zh-CN/components/image.md index 98e0a8c5593d..411c6fbb5ba3 100755 --- a/docs/zh-CN/components/image.md +++ b/docs/zh-CN/components/image.md @@ -431,6 +431,22 @@ List 的内容、Card 卡片的内容配置同上 } ``` +## 内嵌模式 + +配置`"embed": true`,显示图片内嵌模式 + +```schema +{ + "type": "page", + "body": { + "type": "image", + "src": "https://internal-amis-res.cdn.bcebos.com/images/2020-1/1578395692722/4f3cb4202335.jpeg@s_0,w_216,l_1,f_jpg,q_80", + "embed": true, + "showToolbar": true + } +} +``` + ## 属性表 | 属性名 | 类型 | 默认值 | 说明 | 版本 | @@ -458,6 +474,7 @@ List 的内容、Card 卡片的内容配置同上 | imageMode | `string` | `thumb` | 图片展示模式,可选:`'thumb'`, `'original'` 即:缩略图模式 或者 原图模式 | | showToolbar | `boolean` | `false` | 放大模式下是否展示图片的工具栏 | `2.2.0` | | toolbarActions | `ImageAction[]` | | 图片工具栏,支持旋转,缩放,默认操作全部开启 | `2.2.0` | +| embed | `boolean` | | 内嵌模式,当是 `true` 开启内嵌显示 | `3.5.3` | | maxScale | `number` 或 [模板](../../docs/concepts/template) | | 执行调整图片比例动作时的最大百分比 | `3.4.4` | | minScale | `number` 或 [模板](../../docs/concepts/template) | | 执行调整图片比例动作时的最小百分比 | `3.4.4` | diff --git a/docs/zh-CN/components/images.md b/docs/zh-CN/components/images.md index b652bdf1a2ce..084e2da988be 100755 --- a/docs/zh-CN/components/images.md +++ b/docs/zh-CN/components/images.md @@ -418,6 +418,56 @@ Array<{ } ``` +## 内嵌模式 + +在 **images 组件** 上,配置`embed`为`true`,支持放大预览 + +```schema +{ + "type": "page", + "data": { + "images": [ + { + "image": "https://internal-amis-res.cdn.bcebos.com/images/2020-1/1578395692722/4f3cb4202335.jpeg@s_0,w_216,l_1,f_jpg,q_80", + "src": "https://internal-amis-res.cdn.bcebos.com/images/2020-1/1578395692722/4f3cb4202335.jpeg", + "title": "图片1", + "description": "图片1的描述" + }, + { + "image": "https://internal-amis-res.cdn.bcebos.com/images/2020-1/1578395692942/d8e4992057f9.jpeg@s_0,w_216,l_1,f_jpg,q_80", + "src": "https://internal-amis-res.cdn.bcebos.com/images/2020-1/1578395692722/4f3cb4202335.jpeg", + "title": "图片2", + "description": "图片2的描述" + }, + { + "image": "https://internal-amis-res.cdn.bcebos.com/images/2020-1/1578395693148/1314a2a3d3f6.jpeg@s_0,w_216,l_1,f_jpg,q_80", + "src": "https://internal-amis-res.cdn.bcebos.com/images/2020-1/1578395692722/4f3cb4202335.jpeg", + "title": "图片3", + "description": "图片3的描述" + }, + { + "image": "https://internal-amis-res.cdn.bcebos.com/images/2020-1/1578395693379/8f2e79f82be0.jpeg@s_0,w_216,l_1,f_jpg,q_80", + "src": "https://internal-amis-res.cdn.bcebos.com/images/2020-1/1578395692722/4f3cb4202335.jpeg", + "title": "图片4", + "description": "图片4的描述" + }, + { + "image": "https://internal-amis-res.cdn.bcebos.com/images/2020-1/1578395693566/552b175ef11d.jpeg@s_0,w_216,l_1,f_jpg,q_80", + "src": "https://internal-amis-res.cdn.bcebos.com/images/2020-1/1578395692722/4f3cb4202335.jpeg", + "title": "图片5", + "description": "图片5的描述" + } + ] + }, + "body": { + "type": "images", + "source": "${images}", + "embed": true + } +} +``` + + ## 用作 Field 时 当用在 Table 的列配置 Column、List 的内容、Card 卡片的内容和表单的 Static-XXX 中时,可以设置`name`属性,映射同名变量 @@ -680,3 +730,7 @@ List 的内容、Card 卡片的内容配置同上。 | thumbRatio | `string` | `1:1` | 预览图比例,可选:`'1:1'`, `'4:3'`, `'16:9'` | | showToolbar | `boolean` | `false` | 放大模式下是否展示图片的工具栏 | `2.2.0` | | toolbarActions | `ImageAction[]` | | 图片工具栏,支持旋转,缩放,默认操作全部开启 | `2.2.0` | +| embed | `boolean` | `false` | 内嵌模式,当是 `true` 开启内嵌显示 | `3.5.3` | +| imageStyle | `object` | | 设置图片列表每一项的style | `3.5.3` | +| position.toolbar | `top' \| 'bottom'` | `'bottom'` | 设置图片放大时,工具栏位置 | `3.5.3` | +| position.description | `'left' \| 'right'` | `'right'` | 设置图片放大时,描述对应显示框位置 | `3.5.3` | diff --git a/packages/amis-ui/scss/components/_image-gallery.scss b/packages/amis-ui/scss/components/_image-gallery.scss index ae3711ea123f..9eac72c2ea48 100644 --- a/packages/amis-ui/scss/components/_image-gallery.scss +++ b/packages/amis-ui/scss/components/_image-gallery.scss @@ -248,8 +248,6 @@ position: absolute; cursor: move; cursor: -webkit-grab; - max-width: 100%; - max-height: 100%; vertical-align: middle; transform-origin: center; transition: transform 0.3s cubic-bezier(0, 0, 0.25, 1) 0s; diff --git a/packages/amis-ui/src/components/DragProgress.tsx b/packages/amis-ui/src/components/DragProgress.tsx index e6396f0c16fe..8ea337f3ef75 100644 --- a/packages/amis-ui/src/components/DragProgress.tsx +++ b/packages/amis-ui/src/components/DragProgress.tsx @@ -11,6 +11,7 @@ interface DragProgrocessProp extends ThemeProps, LocaleProps { value: number; onChange?: (value?: number) => void; skin: 'light' | 'dark'; + max: number; } interface DragProgrocessState { @@ -39,14 +40,16 @@ class DragProgress extends React.PureComponent< isDragging: boolean = false; previousX: number; - static defaultProps: Pick = { - skin: 'light' + static defaultProps: Pick = { + skin: 'light', + max: 1 }; constructor(props: DragProgrocessProp) { super(props); - const left = props?.value ? getLeftByValue(props.value) : leftStartPoint; + const act = props.value / props.max; + const left = act ? getLeftByValue(act) : leftStartPoint; this.state = { left, precent: getPrecentByLeft(left) @@ -56,6 +59,17 @@ class DragProgress extends React.PureComponent< document.addEventListener('mouseup', this.handleMouseUp); } + componentDidUpdate(prevProps: Readonly): void { + if (prevProps.value !== this.props.value) { + const act = this.props.value / this.props.max; + const left = act ? getLeftByValue(act) : leftStartPoint; + this.setState({ + left, + precent: getPrecentByLeft(left) + }); + } + } + componentWillUnmount() { document.removeEventListener('mousemove', this.handleMouseMove); document.removeEventListener('mouseup', this.handleMouseUp); @@ -101,12 +115,13 @@ class DragProgress extends React.PureComponent< @autobind handleDrag(clientX: number) { this.previousX = clientX; + const max = this.props.max; const {precent} = this.state; - this.props?.onChange?.(precent); + this.props?.onChange?.(precent * max); } render() { - const {classnames: cx, skin} = this.props; + const {classnames: cx, skin, max} = this.props; const {left, precent} = this.state; return ( @@ -132,7 +147,7 @@ class DragProgress extends React.PureComponent< }} > -
{precent}%
+
{precent * max}%
); } diff --git a/packages/amis-ui/src/components/ImageGallery.tsx b/packages/amis-ui/src/components/ImageGallery.tsx index 41d8c7bacc19..1133e30da2f1 100644 --- a/packages/amis-ui/src/components/ImageGallery.tsx +++ b/packages/amis-ui/src/components/ImageGallery.tsx @@ -64,8 +64,9 @@ export interface ImageGalleryProps showToolbar?: boolean; /** 是否内嵌 */ embed?: boolean; - items: Array; + items?: Array; position?: ImageGalleryPosition; + enlargeWithGallary?: boolean; } export interface ImageGalleryState { @@ -74,6 +75,8 @@ export interface ImageGalleryState { items: Array; /** 图片缩放比例尺 */ scale: number; + /** 默认图片缩放比例尺 */ + defaultScale: number; /** 图片旋转角度 */ rotate: number; /** @@ -95,7 +98,7 @@ export interface ImageGalleryState { /** 图片是否加载中 */ imageLoading: boolean; /** 图片信息 */ - imageLoadInfo?: { + imageLoadInfo: { naturalWidth: number; naturalHeight: number; url: string; @@ -149,12 +152,18 @@ export class ImageGallery extends React.Component< tx: 0, ty: 0, scale: 1, + defaultScale: 1, rotate: 0, showToolbar: false, imageGallaryClassName: '', actions: ImageGallery.defaultProps.actions, - imageLoading: false, - isNaturalSize: false + imageLoading: true, + isNaturalSize: false, + imageLoadInfo: { + naturalWidth: 0, + naturalHeight: 0, + url: '' + } }; galleryMain?: HTMLDivElement; @@ -162,12 +171,10 @@ export class ImageGallery extends React.Component< constructor(props: ImageGalleryProps) { super(props); - const hasItems = !!props?.items; - this.state = { ...this.state, - items: hasItems ? props.items : [], - index: hasItems ? 0 : -1, + items: props.items ?? [], + index: !!props?.items ? 0 : -1, showToolbar: !!props?.showToolbar }; } @@ -175,7 +182,7 @@ export class ImageGallery extends React.Component< componentDidUpdate(prevProps: Readonly): void { if (this.props.items !== prevProps.items) { this.setState({ - items: this.props.items + items: this.props.items ?? [] }); } if (this.props?.showToolbar !== prevProps?.showToolbar) { @@ -189,6 +196,12 @@ export class ImageGallery extends React.Component< position: this.props.position }); } + + if (this.props.enlargeWithGallary !== prevProps.enlargeWithGallary) { + this.setState({ + enlargeWithGallary: this.props.enlargeWithGallary + }); + } } @autobind @@ -291,6 +304,7 @@ export class ImageGallery extends React.Component< enlargeWithGallary: info.enlargeWithGallary, imageGallaryClassName: info.imageGallaryClassName, position: info?.position, + imageLoading: true, /** 外部传入合法key值的actions才会生效 */ actions: Array.isArray(info.toolbarActions) ? info.toolbarActions.filter(action => @@ -301,8 +315,9 @@ export class ImageGallery extends React.Component< } resetImageAction() { + const {defaultScale} = this.state; this.setState({ - scale: 1, + scale: defaultScale, rotate: 0, isNaturalSize: false }); @@ -319,15 +334,13 @@ export class ImageGallery extends React.Component< @autobind prev() { const index = this.state.index; - this.setState({index: index - 1, imageLoading: true}); - this.resetImageAction(); + this.setIndex(index - 1); } @autobind next() { const index = this.state.index; - this.setState({index: index + 1, imageLoading: true}); - this.resetImageAction(); + this.setIndex(index + 1); } @autobind @@ -340,8 +353,16 @@ export class ImageGallery extends React.Component< * 设置当前选中 */ @autobind - setIndex(index: number) { - this.setState({index, imageLoading: true}); + setIndex(cIndex: number) { + const {items, index} = this.state; + const bool = items[index].originalSrc === items[cIndex].originalSrc; + console.log(bool); + this.setState({ + index: cIndex, + imageLoading: !bool, + tx: 0, + ty: 0 + }); this.resetImageAction(); } @@ -379,10 +400,11 @@ export class ImageGallery extends React.Component< return; } + const {defaultScale} = this.state; switch (action.key) { case ImageActionKey.DEFAULT_VIEW: this.setState({ - scale: 1, + scale: defaultScale, isNaturalSize: false, tx: 0, ty: 0 @@ -421,13 +443,24 @@ export class ImageGallery extends React.Component< @autobind handleImageLoad(e: React.SyntheticEvent) { const {index, items} = this.state; + const {clientWidth, clientHeight} = this.galleryMain!; + // @ts-ignore + const naturalHeight = e.target?.naturalHeight; + // @ts-ignore + const naturalWidth = e.target?.naturalWidth; + let scale = 1; + if (naturalHeight >= clientHeight || naturalWidth >= clientWidth) { + const p1 = clientHeight / naturalHeight; + const p2 = clientWidth / naturalWidth; + scale = p1 > p2 ? p2 : p1; + } this.setState({ + scale, + defaultScale: scale, imageLoadInfo: { url: items[index]?.src, - // @ts-ignore - naturalHeight: e.target?.naturalHeight, - // @ts-ignore - naturalWidth: e.target?.naturalWidth + naturalHeight, + naturalWidth }, imageLoading: false }); @@ -465,9 +498,10 @@ export class ImageGallery extends React.Component< if (action.key === ImageActionKey.DRAG) { return ( ); } @@ -559,7 +593,7 @@ export class ImageGallery extends React.Component< return [ ~index && items[index] ? ( <> -
+
-
+
+ <> + + ); + } + return (
{ const {render, data} = this.props; return render(type, str, { - data: createObject(createObject(data)) + data: createObject(data) }); }