From f393dd19be01a8260178666a1f66bb9d921bbc7d Mon Sep 17 00:00:00 2001
From: skiyee <319619193@qq.com>
Date: Wed, 22 Oct 2025 16:17:08 +0800
Subject: [PATCH] =?UTF-8?q?feat(image):=20=E5=AE=9E=E7=8E=B0=20Image=20?=
=?UTF-8?q?=E5=9B=BE=E7=89=87=E7=BB=84=E4=BB=B6?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
examples/uni/src/pages-basic/image/base.vue | 53 ++++
examples/uni/src/pages-basic/image/error.vue | 119 +++++++
examples/uni/src/pages-basic/image/lazy.vue | 46 +++
examples/uni/src/pages-basic/image/mode.vue | 107 +++++++
.../uni/src/pages-basic/image/placeholder.vue | 94 ++++++
.../uni/src/pages-basic/image/preview.vue | 139 ++++++++
examples/uni/src/pages-basic/image/radius.vue | 103 ++++++
examples/uni/src/pages.json | 28 ++
examples/uni/types/components.d.ts | 22 +-
examples/uni/types/pages.d.ts | 7 +
.../skiyee-uni-ui/src/components/sk-image.vue | 296 ++++++++++++++++++
packages/skiyee-uni-ui/src/styles/index.ts | 5 +-
packages/skiyee-uni-ui/src/styles/sk-image.ts | 36 +++
packages/skiyee-uni-ui/src/types/common.ts | 25 ++
packages/skiyee-uni-ui/src/utils/format.ts | 2 +-
15 files changed, 1059 insertions(+), 23 deletions(-)
create mode 100644 examples/uni/src/pages-basic/image/base.vue
create mode 100644 examples/uni/src/pages-basic/image/error.vue
create mode 100644 examples/uni/src/pages-basic/image/lazy.vue
create mode 100644 examples/uni/src/pages-basic/image/mode.vue
create mode 100644 examples/uni/src/pages-basic/image/placeholder.vue
create mode 100644 examples/uni/src/pages-basic/image/preview.vue
create mode 100644 examples/uni/src/pages-basic/image/radius.vue
create mode 100644 packages/skiyee-uni-ui/src/components/sk-image.vue
create mode 100644 packages/skiyee-uni-ui/src/styles/sk-image.ts
diff --git a/examples/uni/src/pages-basic/image/base.vue b/examples/uni/src/pages-basic/image/base.vue
new file mode 100644
index 0000000..0973f39
--- /dev/null
+++ b/examples/uni/src/pages-basic/image/base.vue
@@ -0,0 +1,53 @@
+
+
+
+
+
+
+ 基础用法
+
+
+
+
+
+
+
+ 指定尺寸
+
+
+
+
+
+
+
+
+
+
+
+ 全宽图片
+
+
+
+
+
+
diff --git a/examples/uni/src/pages-basic/image/error.vue b/examples/uni/src/pages-basic/image/error.vue
new file mode 100644
index 0000000..5ebaf96
--- /dev/null
+++ b/examples/uni/src/pages-basic/image/error.vue
@@ -0,0 +1,119 @@
+
+
+
+
+
+
+ 默认错误提示
+
+
+ 图片加载失败时显示默认错误提示
+
+
+
+
+
+
+
+ 自定义错误图
+
+
+ 使用自定义图片作为错误状态
+
+
+
+
+
+
+
+ 自定义错误插槽
+
+
+ 使用插槽自定义错误状态显示
+
+
+
+
+
+ ❌
+
+
+ 加载失败
+
+
+
+
+
+
+
+
+
+ 隐藏错误提示
+
+
+ 设置 isShowError 为 false 隐藏错误提示
+
+
+
+
+
+
+
+ 错误图片列表
+
+
+ 批量显示带错误处理的图片
+
+
+
+
+
+
+
+
+
+ 空 src
+
+
+ 未提供图片地址时的错误状态
+
+
+
+
+
+
diff --git a/examples/uni/src/pages-basic/image/lazy.vue b/examples/uni/src/pages-basic/image/lazy.vue
new file mode 100644
index 0000000..288592c
--- /dev/null
+++ b/examples/uni/src/pages-basic/image/lazy.vue
@@ -0,0 +1,46 @@
+
+
+
+
+
+
+ 懒加载示例
+
+
+ 滚动页面查看图片懒加载效果,图片进入可视区域时才会加载
+
+
+
+
+
+
+ 普通加载
+
+
+
+
+
+
+
+ 懒加载图片列表
+
+
+
+
+
+
+
+
diff --git a/examples/uni/src/pages-basic/image/mode.vue b/examples/uni/src/pages-basic/image/mode.vue
new file mode 100644
index 0000000..d028638
--- /dev/null
+++ b/examples/uni/src/pages-basic/image/mode.vue
@@ -0,0 +1,107 @@
+
+
+
+
+
+
+ scaleToFill - 不保持纵横比缩放
+
+
+
+
+
+
+
+ aspectFit - 保持纵横比,长边完整显示
+
+
+
+
+
+
+
+ aspectFill - 保持纵横比,短边完整显示
+
+
+
+
+
+
+
+ widthFix - 宽度不变,高度自动变化
+
+
+
+
+
+
+
+ heightFix - 高度不变,宽度自动变化
+
+
+
+
+
+
+
+ top - 不缩放,显示顶部区域
+
+
+
+
+
+
+
+ center - 不缩放,显示中间区域
+
+
+
+
+
+
+
+ bottom - 不缩放,显示底部区域
+
+
+
+
+
+
diff --git a/examples/uni/src/pages-basic/image/placeholder.vue b/examples/uni/src/pages-basic/image/placeholder.vue
new file mode 100644
index 0000000..17f4375
--- /dev/null
+++ b/examples/uni/src/pages-basic/image/placeholder.vue
@@ -0,0 +1,94 @@
+
+
+
+
+
+
+
+
+ 默认占位图
+
+
+ 图片加载时显示占位图
+
+
+
+
+
+
+
+ 自定义占位图
+
+
+
+
+
+
+
+ 模拟慢速加载
+
+
+ 点击按钮后 2 秒后加载图片
+
+
+
+
+
+
+
+
+ 图片网格
+
+
+
+
+
+
+
+
diff --git a/examples/uni/src/pages-basic/image/preview.vue b/examples/uni/src/pages-basic/image/preview.vue
new file mode 100644
index 0000000..e67b5e7
--- /dev/null
+++ b/examples/uni/src/pages-basic/image/preview.vue
@@ -0,0 +1,139 @@
+
+
+
+
+
+
+ 单图预览
+
+
+ 点击图片可放大预览
+
+
+
+
+
+
+
+ 多图预览
+
+
+ 点击任意图片,可左右滑动查看其他图片
+
+
+
+
+
+
+
+
+
+ 圆形头像预览
+
+
+ 点击头像可预览大图
+
+
+
+
+
+
+
+
+
+ 商品图预览
+
+
+ 模拟商品详情页的图片预览功能
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 禁用预览
+
+
+ isPreview 为 false 时,点击图片无反应
+
+
+
+
+
+
diff --git a/examples/uni/src/pages-basic/image/radius.vue b/examples/uni/src/pages-basic/image/radius.vue
new file mode 100644
index 0000000..7bcf81d
--- /dev/null
+++ b/examples/uni/src/pages-basic/image/radius.vue
@@ -0,0 +1,103 @@
+
+
+
+
+
+
+ none - 无圆角
+
+
+
+
+
+
+
+ small - 小圆角
+
+
+
+
+
+
+
+ medium - 中等圆角
+
+
+
+
+
+
+
+ large - 大圆角
+
+
+
+
+
+
+
+ full - 圆形
+
+
+
+
+
+
+
+ 圆形头像组合
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/uni/src/pages.json b/examples/uni/src/pages.json
index bb82f30..a8e9279 100644
--- a/examples/uni/src/pages.json
+++ b/examples/uni/src/pages.json
@@ -123,6 +123,34 @@
"path": "icon/size",
"type": "page"
},
+ {
+ "path": "image/base",
+ "type": "page"
+ },
+ {
+ "path": "image/error",
+ "type": "page"
+ },
+ {
+ "path": "image/lazy",
+ "type": "page"
+ },
+ {
+ "path": "image/mode",
+ "type": "page"
+ },
+ {
+ "path": "image/placeholder",
+ "type": "page"
+ },
+ {
+ "path": "image/preview",
+ "type": "page"
+ },
+ {
+ "path": "image/radius",
+ "type": "page"
+ },
{
"path": "overlay/animation",
"type": "page"
diff --git a/examples/uni/types/components.d.ts b/examples/uni/types/components.d.ts
index 9a8dd13..c756799 100644
--- a/examples/uni/types/components.d.ts
+++ b/examples/uni/types/components.d.ts
@@ -7,26 +7,6 @@ export {}
declare module 'vue' {
export interface GlobalComponents {
- SkBadge: typeof import('@skiyee/uni-ui/components/sk-badge.vue')['default']
- SkButton: typeof import('@skiyee/uni-ui/components/sk-button.vue')['default']
- SkCheckbox: typeof import('@skiyee/uni-ui/components/sk-checkbox.vue')['default']
- SkCheckboxGroup: typeof import('@skiyee/uni-ui/components/sk-checkbox-group.vue')['default']
- SkDialog: typeof import('@skiyee/uni-ui/components/sk-dialog.vue')['default']
- SkField: typeof import('@skiyee/uni-ui/components/sk-field.vue')['default']
- SkForm: typeof import('@skiyee/uni-ui/components/sk-form.vue')['default']
- SkIcon: typeof import('@skiyee/uni-ui/components/sk-icon.vue')['default']
- SkInput: typeof import('@skiyee/uni-ui/components/sk-input.vue')['default']
- SkNumberInput: typeof import('@skiyee/uni-ui/components/sk-number-input.vue')['default']
- SkOverlay: typeof import('@skiyee/uni-ui/components/sk-overlay.vue')['default']
- SkPicker: typeof import('@skiyee/uni-ui/components/sk-picker.vue')['default']
- SkRadio: typeof import('@skiyee/uni-ui/components/sk-radio.vue')['default']
- SkRadioGroup: typeof import('@skiyee/uni-ui/components/sk-radio-group.vue')['default']
- SkRoller: typeof import('@skiyee/uni-ui/components/sk-roller.vue')['default']
- SkRollerGroup: typeof import('@skiyee/uni-ui/components/sk-roller-group.vue')['default']
- SkSlider: typeof import('@skiyee/uni-ui/components/sk-slider.vue')['default']
- SkSpinner: typeof import('@skiyee/uni-ui/components/sk-spinner.vue')['default']
- SkSwitch: typeof import('@skiyee/uni-ui/components/sk-switch.vue')['default']
- SkTextarea: typeof import('@skiyee/uni-ui/components/sk-textarea.vue')['default']
- SkToast: typeof import('@skiyee/uni-ui/components/sk-toast.vue')['default']
+ SkImage: typeof import('@skiyee/uni-ui/components/sk-image.vue')['default']
}
}
diff --git a/examples/uni/types/pages.d.ts b/examples/uni/types/pages.d.ts
index 8cb447c..289d9e0 100644
--- a/examples/uni/types/pages.d.ts
+++ b/examples/uni/types/pages.d.ts
@@ -31,6 +31,13 @@ interface NavigateToOptions {
"/pages-basic/icon/color" |
"/pages-basic/icon/name" |
"/pages-basic/icon/size" |
+ "/pages-basic/image/base" |
+ "/pages-basic/image/error" |
+ "/pages-basic/image/lazy" |
+ "/pages-basic/image/mode" |
+ "/pages-basic/image/placeholder" |
+ "/pages-basic/image/preview" |
+ "/pages-basic/image/radius" |
"/pages-basic/overlay/animation" |
"/pages-basic/overlay/backdrop" |
"/pages-basic/overlay/base" |
diff --git a/packages/skiyee-uni-ui/src/components/sk-image.vue b/packages/skiyee-uni-ui/src/components/sk-image.vue
new file mode 100644
index 0000000..4f33167
--- /dev/null
+++ b/packages/skiyee-uni-ui/src/components/sk-image.vue
@@ -0,0 +1,296 @@
+
+
+
+
+
+
+
+
+
+
+
+ 加载中...
+
+
+
+
+
+
+
+
+
+
+
+ 加载失败
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/skiyee-uni-ui/src/styles/index.ts b/packages/skiyee-uni-ui/src/styles/index.ts
index cd3dee8..7495dd2 100644
--- a/packages/skiyee-uni-ui/src/styles/index.ts
+++ b/packages/skiyee-uni-ui/src/styles/index.ts
@@ -24,6 +24,9 @@ export { SkDialogUcv } from './sk-dialog'
export type { SkFieldUcvProps } from './sk-field'
export { SkFieldUcv } from './sk-field'
+export type { SkImageUcvProps } from './sk-image'
+export { SkImageUcv } from './sk-image'
+
export type { SkInputUcvProps } from './sk-input'
export { SkInputUcv } from './sk-input'
@@ -55,7 +58,7 @@ export type { SkSwitchUcvProps } from './sk-switch'
export { SkSwitchUcv } from './sk-switch'
export type { SkTextareaUcvProps } from './sk-textarea'
-export { SkTextareaUcv } from './sk-textarea'
+export { SkTextareaUcv } from './sk-textarea'
export type { SkToastUcvProps } from './sk-toast'
export { SkToastUcv } from './sk-toast'
diff --git a/packages/skiyee-uni-ui/src/styles/sk-image.ts b/packages/skiyee-uni-ui/src/styles/sk-image.ts
new file mode 100644
index 0000000..d844ba7
--- /dev/null
+++ b/packages/skiyee-uni-ui/src/styles/sk-image.ts
@@ -0,0 +1,36 @@
+// @unocss-include
+/**
+ * sk-image 由 @skiyee/ucv 生成的样式组件
+ *
+ * @author sKy(skiyee)
+ * @qq 319619193
+ * @github https://github.com/skiyee
+ *
+ * @example
+ * ```ts
+ * const classes = SkImageUcv(props)
+ * ```
+ *
+ * @see 更多示例请参考文档: https://skiyee-ui.netlify.app/docs/components/basic/image
+ */
+import type { InferProps } from '@skiyee/ucv'
+
+import { ucv } from '@skiyee/ucv'
+
+export const SkImageUcv = ucv({
+ element: 'sk-image:(relative inline-block overflow-hidden bg-neutral-100)',
+ variants: {
+ radius: {
+ none: '',
+ small: 'rounded-small',
+ medium: 'rounded-medium',
+ large: 'rounded-large',
+ full: 'rounded-full',
+ },
+ },
+ defaults: {
+ radius: 'none',
+ },
+})
+
+export type SkImageUcvProps = InferProps
diff --git a/packages/skiyee-uni-ui/src/types/common.ts b/packages/skiyee-uni-ui/src/types/common.ts
index 0ed8b3f..28639f6 100644
--- a/packages/skiyee-uni-ui/src/types/common.ts
+++ b/packages/skiyee-uni-ui/src/types/common.ts
@@ -15,3 +15,28 @@
* 用于表单组件的 v-model 绑定
*/
export type AcceptableModelValue = string | number | null
+
+/**
+ * 图片模式类型
+ * 对应 uni-app image 组件的 mode 属性
+ */
+export type ImageMode =
+ | 'scaleToFill' // 不保持纵横比缩放图片,使图片的宽高完全拉伸至填满 image 元素
+ | 'aspectFit' // 保持纵横比缩放图片,使图片的长边能完全显示出来
+ | 'aspectFill' // 保持纵横比缩放图片,只保证图片的短边能完全显示出来
+ | 'widthFix' // 宽度不变,高度自动变化,保持原图宽高比不变
+ | 'heightFix' // 高度不变,宽度自动变化,保持原图宽高比不变
+ | 'top' // 不缩放图片,只显示图片的顶部区域
+ | 'bottom' // 不缩放图片,只显示图片的底部区域
+ | 'center' // 不缩放图片,只显示图片的中间区域
+ | 'left' // 不缩放图片,只显示图片的左边区域
+ | 'right' // 不缩放图片,只显示图片的右边区域
+ | 'top left' // 不缩放图片,只显示图片的左上边区域
+ | 'top right' // 不缩放图片,只显示图片的右上边区域
+ | 'bottom left' // 不缩放图片,只显示图片的左下边区域
+ | 'bottom right' // 不缩放图片,只显示图片的右下边区域
+
+/**
+ * 圆角大小类型
+ */
+export type RadiusSize = 'small' | 'medium' | 'large' | 'full' | number | string
diff --git a/packages/skiyee-uni-ui/src/utils/format.ts b/packages/skiyee-uni-ui/src/utils/format.ts
index 3d815fb..f40fd1a 100644
--- a/packages/skiyee-uni-ui/src/utils/format.ts
+++ b/packages/skiyee-uni-ui/src/utils/format.ts
@@ -6,7 +6,7 @@ import { isNil } from './is'
*/
export function formatSize(size: string | number) {
const isNumeric = !Number.isNaN(Number(size))
- return isNumeric ? `${size}rpx` : size
+ return isNumeric ? `${size}rpx` : `${size}`
}
/**