Skip to content

Commit

Permalink
feat(imageViewer): Custom Download Callback (#5134)
Browse files Browse the repository at this point in the history
* feat: docs & props & type

* feat: support referrerpolicy API

* feat: custom download callback

* fix: lint
  • Loading branch information
Wesley-0808 authored Mar 4, 2025
1 parent 820ce8f commit c859d4e
Show file tree
Hide file tree
Showing 8 changed files with 64 additions and 7 deletions.
4 changes: 4 additions & 0 deletions packages/components/image-viewer/base/ImageItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { PropType, computed, defineComponent, onMounted, ref, toRefs, watch } fr
import { useConfig, usePrefixClass } from '../../hooks/useConfig';
import { useImagePreviewUrl } from '../../hooks/useImagePreviewUrl';
import { useDrag } from '../hooks';
import { TdImageViewerProps } from '../type';

export default defineComponent({
name: 'TImageItem',
Expand All @@ -13,6 +14,7 @@ export default defineComponent({
src: [String, Object] as PropType<string | File>,
placementSrc: [String, Object] as PropType<string | File>,
isSvg: Boolean,
imageReferrerpolicy: String as PropType<TdImageViewerProps['imageReferrerpolicy']>,
},

setup(props) {
Expand Down Expand Up @@ -139,6 +141,7 @@ export default defineComponent({
}}
src={placementImagePreviewUrl.value}
style={placementImgStyle.value}
referrerpolicy={props.imageReferrerpolicy}
alt="image"
draggable="false"
/>
Expand All @@ -155,6 +158,7 @@ export default defineComponent({
onLoad={() => (loaded.value = true)}
onError={() => (error.value = true)}
style={imgStyle.value}
referrerpolicy={props.imageReferrerpolicy}
alt="image"
draggable="false"
/>
Expand Down
4 changes: 4 additions & 0 deletions packages/components/image-viewer/base/ImageViewerModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export default defineComponent({
onMirror: Function as PropType<() => void>,
onReset: Function as PropType<() => void>,
onClose: props.onClose,
onDownload: props.onDownload,
draggable: {
type: Boolean,
default: true,
Expand All @@ -42,6 +43,7 @@ export default defineComponent({
},
showOverlay: Boolean,
closeBtn: props.closeBtn,
imageReferrerpolicy: props.imageReferrerpolicy,
},
setup(props) {
const classPrefix = usePrefixClass();
Expand Down Expand Up @@ -77,6 +79,7 @@ export default defineComponent({
onRotate={props.onRotate}
onMirror={props.onMirror}
onReset={props.onReset}
onDownload={props.onDownload}
/>
</div>
)}
Expand All @@ -89,6 +92,7 @@ export default defineComponent({
src={props.currentImage.mainImage}
placementSrc={props.currentImage.thumbnail}
isSvg={props.currentImage.isSvg}
imageReferrerpolicy={props.imageReferrerpolicy}
/>
</div>
</TDialog>
Expand Down
4 changes: 2 additions & 2 deletions packages/components/image-viewer/base/ImageViewerUtils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { ImageIcon, ZoomInIcon, ZoomOutIcon, DownloadIcon, MirrorIcon, RotationI
import TImageViewerIcon from './ImageModalIcon';
import TToolTip from '../../tooltip';
import { usePrefixClass, useConfig } from '../../hooks/useConfig';
import { downloadFile } from '../utils';
import { useImagePreviewUrl } from '../../hooks';
import { ImageInfo } from '../type';
import { largeNumberToFixed } from '@tdesign/common-js/input-number/large-number';
Expand All @@ -17,6 +16,7 @@ export default defineComponent({
onZoomOut: Function as PropType<() => void>,
onMirror: Function as PropType<() => void>,
onReset: Function as PropType<() => void>,
onDownload: Function as PropType<(url: string) => void>,
currentImage: {
type: Object as PropType<ImageInfo>,
default() {
Expand Down Expand Up @@ -78,7 +78,7 @@ export default defineComponent({
<TImageViewerIcon
icon={() => <DownloadIcon size="medium" />}
onClick={() => {
downloadFile(previewUrl.value);
props.onDownload(previewUrl.value);
}}
/>
)}
Expand Down
3 changes: 3 additions & 0 deletions packages/components/image-viewer/image-viewer.en-US.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ closeBtn | Boolean / Slot / Function | true | Typescript:`boolean \| TNode`。
closeOnEscKeydown | Boolean | true | trigger image viewer close event on `ESC` keydown | N
closeOnOverlay | Boolean | - | \- | N
draggable | Boolean | undefined | \- | N
imageReferrerpolicy | String | - | attribute of `<img>`, [MDN Definition](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy)。options: no-referrer/no-referrer-when-downgrade/origin/origin-when-cross-origin/same-origin/strict-origin/strict-origin-when-cross-origin/unsafe-url | N
imageScale | Object | - | Typescript:`ImageScale` `interface ImageScale { max: number; min: number; step: number; defaultScale?: number; }`[see more ts definition](https://github.com/Tencent/tdesign-vue-next/blob/develop/packages/components/image-viewer/type.ts) | N
images | Array | [] | Typescript:`Array<string \| File \| ImageInfo>` `interface ImageInfo { mainImage: string \| File; thumbnail?: string \| File; download?: boolean; isSvg?: boolean }`[see more ts definition](https://github.com/Tencent/tdesign-vue-next/blob/develop/packages/components/image-viewer/type.ts) | N
index | Number | 0 | `v-model:index` is supported | N
Expand All @@ -25,11 +26,13 @@ visible | Boolean | false | hide or show image viewer。`v-model` and `v-model:v
defaultVisible | Boolean | false | hide or show image viewer。uncontrolled property | N
zIndex | Number | - | \- | N
onClose | Function | | Typescript:`(context: { trigger: 'close-btn' \| 'overlay' \| 'esc'; e: MouseEvent \| KeyboardEvent }) => void`<br/> | N
onDownload | Function | | Typescript:`(url: string) => void`<br/> | N
onIndexChange | Function | | Typescript:`(index: number, context: { trigger: 'prev' \| 'next' \| 'current' }) => void`<br/> | N

### ImageViewer Events

name | params | description
-- | -- | --
close | `(context: { trigger: 'close-btn' \| 'overlay' \| 'esc'; e: MouseEvent \| KeyboardEvent })` | \-
download | `(url: string \| File)` | \-
index-change | `(index: number, context: { trigger: 'prev' \| 'next' \| 'current' })` | \-
5 changes: 4 additions & 1 deletion packages/components/image-viewer/image-viewer.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@

名称 | 类型 | 默认值 | 描述 | 必传
-- | -- | -- | -- | --
attach | String / Function | 'body' | 制定挂载节点。数据类型为 String 时,会被当作选择器处理,进行节点查询。示例:'body' 或 () => document.body。TS 类型:`AttachNode`[通用类型定义](https://github.com/Tencent/tdesign-vue-next/blob/develop/packages/components/common.ts) | N
attach | String / Function | 'body' | 指定挂载节点。数据类型为 String 时,会被当作选择器处理,进行节点查询。示例:'body' 或 () => document.body。TS 类型:`AttachNode`[通用类型定义](https://github.com/Tencent/tdesign-vue-next/blob/develop/packages/components/common.ts) | N
closeBtn | Boolean / Slot / Function | true | 是否展示关闭按钮,值为 `true` 显示默认关闭按钮;值为 `false` 则不显示关闭按钮;也可以完全自定义关闭按钮。TS 类型:`boolean \| TNode`[通用类型定义](https://github.com/Tencent/tdesign-vue-next/blob/develop/packages/components/common.ts) | N
closeOnEscKeydown | Boolean | true | 按下 ESC 时是否触发图片预览器关闭事件 | N
closeOnOverlay | Boolean | - | 是否在点击遮罩层时,触发预览关闭 | N
draggable | Boolean | undefined | 是否允许拖拽调整位置。`mode=modal` 时,默认不允许拖拽;`mode=modeless` 时,默认允许拖拽 | N
imageReferrerpolicy | String | - | 图片预览中的 `<img>` 标签的原生属性,[MDN 定义](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy)。可选项:no-referrer/no-referrer-when-downgrade/origin/origin-when-cross-origin/same-origin/strict-origin/strict-origin-when-cross-origin/unsafe-url | N
imageScale | Object | - | 图片缩放相关配置。`imageScale.max` 缩放的最大比例;`imageScale.min` 缩放的最小比例;`imageScale.step` 缩放的步长速度; `imageScale.defaultScale` 默认的缩放比例。TS 类型:`ImageScale` `interface ImageScale { max: number; min: number; step: number; defaultScale?: number; }`[详细类型定义](https://github.com/Tencent/tdesign-vue-next/blob/develop/packages/components/image-viewer/type.ts) | N
images | Array | [] | 图片数组。`mainImage` 表示主图,必传;`thumbnail` 表示缩略图,如果不存在,则使用主图显示;`download` 是否允许下载图片,默认允许下载。示例: `['img_url_1', 'img_url_2']``[{ thumbnail: 'small_image_url', mainImage: 'big_image_url', download: false }]`。TS 类型:`Array<string \| File \| ImageInfo>` `interface ImageInfo { mainImage: string \| File; thumbnail?: string \| File; download?: boolean; isSvg?: boolean }`[详细类型定义](https://github.com/Tencent/tdesign-vue-next/blob/develop/packages/components/image-viewer/type.ts) | N
index | Number | 0 | 当前预览图片所在的下标。支持语法糖 `v-model:index` | N
Expand All @@ -25,11 +26,13 @@ visible | Boolean | false | 隐藏/显示预览。支持语法糖 `v-model` 或
defaultVisible | Boolean | false | 隐藏/显示预览。非受控属性 | N
zIndex | Number | - | 层级,默认为 2000 | N
onClose | Function | | TS 类型:`(context: { trigger: 'close-btn' \| 'overlay' \| 'esc'; e: MouseEvent \| KeyboardEvent }) => void`<br/>关闭时触发,事件参数包含触发关闭的来源:关闭按钮、遮罩层、ESC 键 | N
onDownload | Function | | TS 类型:`(url: string) => void`<br/>自定义预览图片下载操作,url为图片链接 | N
onIndexChange | Function | | TS 类型:`(index: number, context: { trigger: 'prev' \| 'next' \| 'current' }) => void`<br/>预览图片切换时触发,`context.prev` 切换到上一张图片,`context.next` 切换到下一张图片 | N

### ImageViewer Events

名称 | 参数 | 描述
-- | -- | --
close | `(context: { trigger: 'close-btn' \| 'overlay' \| 'esc'; e: MouseEvent \| KeyboardEvent })` | 关闭时触发,事件参数包含触发关闭的来源:关闭按钮、遮罩层、ESC 键
download | `(url: string \| File)` | 自定义预览图片下载操作,url为图片链接
index-change | `(index: number, context: { trigger: 'prev' \| 'next' \| 'current' })` | 预览图片切换时触发,`context.prev` 切换到上一张图片,`context.next` 切换到下一张图片
12 changes: 10 additions & 2 deletions packages/components/image-viewer/image-viewer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { EVENT_CODE } from './consts';
import { useMirror, useRotate, useScale } from './hooks';
import props from './props';
import { TdImageViewerProps } from './type';
import { formatImages, getOverlay } from './utils';
import { downloadFile, formatImages, getOverlay } from './utils';

export default defineComponent({
name: 'TImageViewer',
Expand All @@ -28,7 +28,7 @@ export default defineComponent({
const isExpand = ref(true);
const showOverlayValue = computed(() => getOverlay(props));

const { index, visible, modelValue } = toRefs(props);
const { index, visible, modelValue, imageReferrerpolicy } = toRefs(props);
const [indexValue, setIndexValue] = useDefaultValue(index, props.defaultIndex ?? 0, props.onIndexChange, 'index');
const [visibleValue, setVisibleValue] = useVModel(visible, modelValue, props.defaultVisible, () => {}, 'visible');
const animationEnd = ref(true);
Expand Down Expand Up @@ -86,6 +86,10 @@ export default defineComponent({
setIndexValue(i, { trigger: 'current' });
};

const onDownloadClick = (url: string) => {
props.onDownload ? props.onDownload(url) : downloadFile(url);
};

const openHandler = () => {
setVisibleValue(true);
};
Expand Down Expand Up @@ -239,9 +243,11 @@ export default defineComponent({
onMirror={onMirror}
onReset={onRest}
onClose={onClose}
onDownload={onDownloadClick}
draggable={props.draggable}
showOverlay={showOverlayValue.value}
title={props.title}
imageReferrerpolicy={imageReferrerpolicy.value}
/>
</>
);
Expand Down Expand Up @@ -283,6 +289,7 @@ export default defineComponent({
onMirror={onMirror}
onReset={onRest}
onRotate={onRotate}
onDownload={onDownloadClick}
scale={scale.value}
currentImage={currentImage.value}
/>
Expand All @@ -293,6 +300,7 @@ export default defineComponent({
src={currentImage.value.mainImage}
placementSrc={currentImage.value.thumbnail}
isSvg={currentImage.value.isSvg}
imageReferrerpolicy={imageReferrerpolicy.value}
/>
</div>
)}
Expand Down
21 changes: 20 additions & 1 deletion packages/components/image-viewer/props.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { PropType } from 'vue';
import { TdImageViewerProps } from './type';

export default {
/** 制定挂载节点。数据类型为 String 时,会被当作选择器处理,进行节点查询。示例:'body' 或 () => document.body */
/** 指定挂载节点。数据类型为 String 时,会被当作选择器处理,进行节点查询。示例:'body' 或 () => document.body */
attach: {
type: [String, Function] as PropType<TdImageViewerProps['attach']>,
default: 'body' as TdImageViewerProps['attach'],
Expand All @@ -30,6 +30,23 @@ export default {
type: Boolean,
default: undefined,
},
/** 图片预览中的 `<img>` 标签的原生属性,[MDN 定义](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy) */
imageReferrerpolicy: {
type: String as PropType<TdImageViewerProps['imageReferrerpolicy']>,
validator(val: TdImageViewerProps['imageReferrerpolicy']): boolean {
if (!val) return true;
return [
'no-referrer',
'no-referrer-when-downgrade',
'origin',
'origin-when-cross-origin',
'same-origin',
'strict-origin',
'strict-origin-when-cross-origin',
'unsafe-url',
].includes(val);
},
},
/** 图片缩放相关配置。`imageScale.max` 缩放的最大比例;`imageScale.min` 缩放的最小比例;`imageScale.step` 缩放的步长速度; `imageScale.defaultScale` 默认的缩放比例 */
imageScale: {
type: Object as PropType<TdImageViewerProps['imageScale']>,
Expand Down Expand Up @@ -97,6 +114,8 @@ export default {
},
/** 关闭时触发,事件参数包含触发关闭的来源:关闭按钮、遮罩层、ESC 键 */
onClose: Function as PropType<TdImageViewerProps['onClose']>,
/** 自定义预览图片下载操作,url为图片链接 */
onDownload: Function as PropType<TdImageViewerProps['onDownload']>,
/** 预览图片切换时触发,`context.prev` 切换到上一张图片,`context.next` 切换到下一张图片 */
onIndexChange: Function as PropType<TdImageViewerProps['onIndexChange']>,
};
18 changes: 17 additions & 1 deletion packages/components/image-viewer/type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { AttachNode, TNode } from '../common';

export interface TdImageViewerProps {
/**
* 制定挂载节点。数据类型为 String 时,会被当作选择器处理,进行节点查询。示例:'body' 或 () => document.body
* 指定挂载节点。数据类型为 String 时,会被当作选择器处理,进行节点查询。示例:'body' 或 () => document.body
* @default 'body'
*/
attach?: AttachNode;
Expand All @@ -30,6 +30,18 @@ export interface TdImageViewerProps {
* 是否允许拖拽调整位置。`mode=modal` 时,默认不允许拖拽;`mode=modeless` 时,默认允许拖拽
*/
draggable?: boolean;
/**
* 图片预览中的 `<img>` 标签的原生属性,[MDN 定义](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy)
*/
imageReferrerpolicy?:
| 'no-referrer'
| 'no-referrer-when-downgrade'
| 'origin'
| 'origin-when-cross-origin'
| 'same-origin'
| 'strict-origin'
| 'strict-origin-when-cross-origin'
| 'unsafe-url';
/**
* 图片缩放相关配置。`imageScale.max` 缩放的最大比例;`imageScale.min` 缩放的最小比例;`imageScale.step` 缩放的步长速度; `imageScale.defaultScale` 默认的缩放比例
*/
Expand Down Expand Up @@ -98,6 +110,10 @@ export interface TdImageViewerProps {
* 关闭时触发,事件参数包含触发关闭的来源:关闭按钮、遮罩层、ESC 键
*/
onClose?: (context: { trigger: 'close-btn' | 'overlay' | 'esc'; e: MouseEvent | KeyboardEvent }) => void;
/**
* 自定义预览图片下载操作,url为图片链接
*/
onDownload?: (url: string) => void;
/**
* 预览图片切换时触发,`context.prev` 切换到上一张图片,`context.next` 切换到下一张图片
*/
Expand Down

0 comments on commit c859d4e

Please sign in to comment.