From 7d3a73a7110242395090479addfc1aa2707fa3db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=8E=E4=BC=9F=E6=9D=B0?= <674416404@qq.com> Date: Tue, 19 Nov 2024 22:10:18 +0800 Subject: [PATCH 1/3] feat(image): support referrerpolicy --- src/image/image.en-US.md | 11 ++++++----- src/image/image.md | 10 ++++++---- src/image/image.tsx | 6 +++--- src/image/props.ts | 19 ++++++++++++++++++- src/image/type.ts | 14 +++++++++++++- 5 files changed, 46 insertions(+), 14 deletions(-) diff --git a/src/image/image.en-US.md b/src/image/image.en-US.md index ed116611f..76a325017 100644 --- a/src/image/image.en-US.md +++ b/src/image/image.en-US.md @@ -8,13 +8,14 @@ name | type | default | description | required -- | -- | -- | -- | -- alt | String | - | \- | N error | String / Slot / Function | - | Typescript:`string \| TNode`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N -fit | String | fill | options:contain/cover/fill/none/scale-down | N +fit | String | fill | options: contain/cover/fill/none/scale-down | N lazy | Boolean | false | \- | N loading | String / Slot / Function | - | Typescript:`string \| TNode`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N position | String | center | \- | N -shape | String | square | options:circle/round/square | N +referrerpolicy | String | - | attribute of ``, [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 +shape | String | square | options: circle/round/square | N src | String | - | \- | N -srcset | Object | - | for `.avif` and `.webp` image url。Typescript:`ImageSrcset` `interface ImageSrcset { 'image/avif': string; 'image/webp': string; }`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/image/type.ts) | N +srcset | Object | - | for `.avif` and `.webp` image url, load `srcset` before `src`。Typescript:`ImageSrcset` `interface ImageSrcset { 'image/avif': string; 'image/webp': string; }`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/image/type.ts) | N onError | Function | | Typescript:`(context: { e: ImageEvent }) => void`
trigger on image load failed | N onLoad | Function | | Typescript:`(context: { e: ImageEvent }) => void`
trigger on image loaded | N @@ -25,12 +26,12 @@ name | params | description error | `(context: { e: ImageEvent })` | trigger on image load failed load | `(context: { e: ImageEvent })` | trigger on image loaded - ### CSS Variables + The component provides the following CSS variables, which can be used to customize styles. Name | Default Value | Description -- | -- | -- --td-image-color | @font-gray-3 | - --td-image-loading-bg-color | @bg-color-secondarycontainer | - --td-image-loading-color | @font-gray-3 | - ---td-image-round-radius | @radius-default | - +--td-image-round-radius | @radius-default | - \ No newline at end of file diff --git a/src/image/image.md b/src/image/image.md index 4fedd6865..7f31ffb8d 100644 --- a/src/image/image.md +++ b/src/image/image.md @@ -1,9 +1,10 @@ :: BASE_DOC :: ## API + ### Image Props -名称 | 类型 | 默认值 | 说明 | 必传 +名称 | 类型 | 默认值 | 描述 | 必传 -- | -- | -- | -- | -- alt | String | - | 图片描述 | N error | String / Slot / Function | - | 自定义图片加载失败状态下的显示内容。TS 类型:`string \| TNode`。[通用类型定义](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N @@ -11,9 +12,10 @@ fit | String | fill | 图片填充模式。可选项:contain/cover/fill/none/s lazy | Boolean | false | 是否开启图片懒加载 | N loading | String / Slot / Function | - | 自定义加载中状态的图片内容,如:“加载中”。TS 类型:`string \| TNode`。[通用类型定义](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N position | String | center | 等同于原生的 object-position 属性,可选值为 top right bottom left 或 string,可以自定义任何单位,px 或者 百分比 | N +referrerpolicy | String | - | `` 标签的原生属性,[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 shape | String | square | 图片圆角类型。可选项:circle/round/square | N src | String | - | 图片链接 | N -srcset | Object | - | 图片地址,支持特殊格式的图片,如 `.avif` 和 `.webp`。TS 类型:`ImageSrcset` `interface ImageSrcset { 'image/avif': string; 'image/webp': string; }`。[详细类型定义](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/image/type.ts) | N +srcset | Object | - | 图片链接集合,用于支持特殊格式的图片,如 `.avif` 和 `.webp`。会优先加载 `srcset` 中的图片格式,浏览器不支持的情况下,加载 `src` 设置的图片地址。TS 类型:`ImageSrcset` `interface ImageSrcset { 'image/avif': string; 'image/webp': string; }`。[详细类型定义](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/image/type.ts) | N onError | Function | | TS 类型:`(context: { e: ImageEvent }) => void`
图片加载失败时触发 | N onLoad | Function | | TS 类型:`(context: { e: ImageEvent }) => void`
图片加载完成时触发 | N @@ -24,12 +26,12 @@ onLoad | Function | | TS 类型:`(context: { e: ImageEvent }) => void`
error | `(context: { e: ImageEvent })` | 图片加载失败时触发 load | `(context: { e: ImageEvent })` | 图片加载完成时触发 - ### CSS Variables + 组件提供了下列 CSS 变量,可用于自定义样式。 名称 | 默认值 | 描述 -- | -- | -- --td-image-color | @font-gray-3 | - --td-image-loading-bg-color | @bg-color-secondarycontainer | - --td-image-loading-color | @font-gray-3 | - ---td-image-round-radius | @radius-default | - +--td-image-round-radius | @radius-default | - \ No newline at end of file diff --git a/src/image/image.tsx b/src/image/image.tsx index c1b76022c..1cf85eed6 100644 --- a/src/image/image.tsx +++ b/src/image/image.tsx @@ -2,7 +2,7 @@ import { ref, computed, defineComponent, watchEffect } from 'vue'; import { useIntersectionObserver } from '@vueuse/core'; import { CloseIcon } from 'tdesign-icons-vue-next'; -import Loading from '../loading'; +import TLoading from '../loading'; import config from '../config'; import { useTNodeJSX } from '../hooks/tnode'; import { usePrefixClass } from '../hooks/useClass'; @@ -13,7 +13,6 @@ const { prefix } = config; export default defineComponent({ name: `${prefix}-image`, - components: { CloseIcon, Loading }, props, setup(props, context) { const imageClass = usePrefixClass('image'); @@ -21,7 +20,7 @@ export default defineComponent({ // 默认loading和error状态展示,slot支持Node和Function const closeIcon = ; - const LoadingIcon = ; + const LoadingIcon = ; // 记录图片的loading、error状态 const isLoading = ref(true); @@ -109,6 +108,7 @@ export default defineComponent({ style={imageStyles.value} src={realSrc.value} alt={props.alt} + referrerpolicy={props.referrerpolicy} onLoad={handleImgLoadCompleted} onError={handleImgLoadError} /> diff --git a/src/image/props.ts b/src/image/props.ts index 19190ce0e..863b1e65f 100644 --- a/src/image/props.ts +++ b/src/image/props.ts @@ -37,6 +37,23 @@ export default { type: String, default: 'center', }, + /** `` 标签的原生属性,[MDN 定义](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy) */ + referrerpolicy: { + type: String as PropType, + validator(val: TdImageProps['referrerpolicy']): 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); + }, + }, /** 图片圆角类型 */ shape: { type: String as PropType, @@ -51,7 +68,7 @@ export default { type: String, default: '', }, - /** 图片地址,支持特殊格式的图片,如 `.avif` 和 `.webp` */ + /** 图片链接集合,用于支持特殊格式的图片,如 `.avif` 和 `.webp`。会优先加载 `srcset` 中的图片格式,浏览器不支持的情况下,加载 `src` 设置的图片地址 */ srcset: { type: Object as PropType, }, diff --git a/src/image/type.ts b/src/image/type.ts index e473443f5..b5929dea6 100644 --- a/src/image/type.ts +++ b/src/image/type.ts @@ -35,6 +35,18 @@ export interface TdImageProps { * @default center */ position?: string; + /** + * `` 标签的原生属性,[MDN 定义](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy) + */ + referrerpolicy?: + | 'no-referrer' + | 'no-referrer-when-downgrade' + | 'origin' + | 'origin-when-cross-origin' + | 'same-origin' + | 'strict-origin' + | 'strict-origin-when-cross-origin' + | 'unsafe-url'; /** * 图片圆角类型 * @default square @@ -46,7 +58,7 @@ export interface TdImageProps { */ src?: string; /** - * 图片地址,支持特殊格式的图片,如 `.avif` 和 `.webp` + * 图片链接集合,用于支持特殊格式的图片,如 `.avif` 和 `.webp`。会优先加载 `srcset` 中的图片格式,浏览器不支持的情况下,加载 `src` 设置的图片地址 */ srcset?: ImageSrcset; /** From b0b8e3ec7e2966876fbfd303c2bef1be7524851a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=8E=E4=BC=9F=E6=9D=B0?= <674416404@qq.com> Date: Tue, 19 Nov 2024 22:20:22 +0800 Subject: [PATCH 2/3] feat(image): support fallback --- src/image/image.en-US.md | 1 + src/image/image.md | 1 + src/image/image.tsx | 4 ++++ src/image/props.ts | 5 +++++ src/image/type.ts | 5 +++++ 5 files changed, 16 insertions(+) diff --git a/src/image/image.en-US.md b/src/image/image.en-US.md index 76a325017..f92617e3b 100644 --- a/src/image/image.en-US.md +++ b/src/image/image.en-US.md @@ -8,6 +8,7 @@ name | type | default | description | required -- | -- | -- | -- | -- alt | String | - | \- | N error | String / Slot / Function | - | Typescript:`string \| TNode`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N +fallback | String | - | display `fallback` image on `src` loading failed. you can also use `error` to define more complex error content | N fit | String | fill | options: contain/cover/fill/none/scale-down | N lazy | Boolean | false | \- | N loading | String / Slot / Function | - | Typescript:`string \| TNode`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N diff --git a/src/image/image.md b/src/image/image.md index 7f31ffb8d..3545dc77c 100644 --- a/src/image/image.md +++ b/src/image/image.md @@ -8,6 +8,7 @@ -- | -- | -- | -- | -- alt | String | - | 图片描述 | N error | String / Slot / Function | - | 自定义图片加载失败状态下的显示内容。TS 类型:`string \| TNode`。[通用类型定义](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N +fallback | String | - | 图片加载失败时,显示当前链接设置的图片地址。如果要使用组件图标或完全自定义加载失败时显示的内容,请更为使用 `error` | N fit | String | fill | 图片填充模式。可选项:contain/cover/fill/none/scale-down | N lazy | Boolean | false | 是否开启图片懒加载 | N loading | String / Slot / Function | - | 自定义加载中状态的图片内容,如:“加载中”。TS 类型:`string \| TNode`。[通用类型定义](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N diff --git a/src/image/image.tsx b/src/image/image.tsx index 1cf85eed6..a7d40680b 100644 --- a/src/image/image.tsx +++ b/src/image/image.tsx @@ -66,6 +66,10 @@ export default defineComponent({ props.onError?.({ e }); isLoading.value = false; isError.value = true; + if (props.fallback) { + realSrc.value = props.fallback; + isError.value = false; + } }; const maskContent = computed(() => { diff --git a/src/image/props.ts b/src/image/props.ts index 863b1e65f..32b305ed1 100644 --- a/src/image/props.ts +++ b/src/image/props.ts @@ -17,6 +17,11 @@ export default { error: { type: [String, Function] as PropType, }, + /** 图片加载失败时,显示当前链接设置的图片地址。如果要使用组件图标或完全自定义加载失败时显示的内容,请更为使用 `error` */ + fallback: { + type: String, + default: '', + }, /** 图片填充模式 */ fit: { type: String as PropType, diff --git a/src/image/type.ts b/src/image/type.ts index b5929dea6..dab08bf58 100644 --- a/src/image/type.ts +++ b/src/image/type.ts @@ -16,6 +16,11 @@ export interface TdImageProps { * 自定义图片加载失败状态下的显示内容 */ error?: string | TNode; + /** + * 图片加载失败时,显示当前链接设置的图片地址。如果要使用组件图标或完全自定义加载失败时显示的内容,请更为使用 `error` + * @default '' + */ + fallback?: string; /** * 图片填充模式 * @default fill From 0373f6823d6a0f36ff670433deab204c48898b75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=8E=E4=BC=9F=E6=9D=B0?= <674416404@qq.com> Date: Tue, 19 Nov 2024 22:36:50 +0800 Subject: [PATCH 3/3] test: add fallback test case --- src/image/__test__/index.test.jsx | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/image/__test__/index.test.jsx b/src/image/__test__/index.test.jsx index 9e60b70e4..41b4a62ea 100644 --- a/src/image/__test__/index.test.jsx +++ b/src/image/__test__/index.test.jsx @@ -114,6 +114,16 @@ describe('Image', () => { expect(onError).toBeCalledTimes(0); }); + it(': fallback', async () => { + const onError = vi.fn(); + const wrapper = mount(() => ); + await nextTick(); + const $image = wrapper.find(`.${name}__img`); + // 手动触发 图片加载失败的回调函数 + await $image.trigger('error'); + expect($image.attributes('src')).toBe(IMAGE); + }); + it(': onError', async () => { const onError = vi.fn(); const slots = {