yj-imgpond
Version:
Image uploading one-stop solution.
449 lines (330 loc) • 14.4 kB
Markdown
<h1 align="center">ImgPond</h1>
<p align="center">
图片上传一站式解决方案。
</p>
<p align="center">
<a href="https://bundlephobia.com/package/yj-imgpond"><img alt="minzipped size" src="https://img.shields.io/bundlephobia/minzip/yj-imgpond"></a>
</p>
<br>
## 特性
- 数据双向绑定 `v-model`,支持任意绑定值类型
- 数据源
- 用户选择本地文件 (File)
- 编程式提供数据源 (File/Blob/Base64/URL/[object URL](https://developer.mozilla.org/en-US/docs/Web/API/File_API/Using_files_from_web_applications#example_using_object_urls_to_display_images))
- 编辑图片
- 自由裁剪
- 锁定比例裁剪 (支持设置具体的值及其公差,也支持设置一个范围)
- 翻转、缩放、无级角度旋转
- 输出品质调节
- 限制图片
- 数量上限、下限
- 体积上限、下限
- 格式筛选
- 自定义校验
- 拖拉拽排序
- 预览图片
- 局部注册并传参,或全局注册并传参
<br>
## 安装
```shell
npm i yj-imgpond
```
### 外置依赖
- vue@2
- element-ui
- pic-viewer
### 局部注册
```vue
<template>
<ImgPond
v-model="value"
v-bind="{
/* 局部配置 */
}"
/>
</template>
<script>
import PicViewer from 'pic-viewer'
import ImgPond from 'yj-imgpond'
export default {
components: { PicViewer, ImgPond }
}
</script>
```
### 全局注册
```ts
import PicViewer from 'pic-viewer'
import ImgPond from 'yj-imgpond'
Vue.use(PicViewer, {
// 全局配置
})
Vue.use(ImgPond, {
// 全局配置
})
```
### CDN + ESM
> ⚠ 暂不支持 (ElementUI 未提供 ESM 导出)
### CDN + UMD
```html
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css" />
</head>
<body>
<div id="app">
<img-pond v-model="value"></img-pond>
</div>
<script src="https://unpkg.com/vue@2"></script>
<script src="https://unpkg.com/element-ui/lib/index.js"></script>
<script src="https://unpkg.com/pic-viewer@0.10"></script>
<script src="https://unpkg.com/yj-imgpond@0.12"></script>
<script>
Vue.use(PicViewer)
Vue.use(ImgPond)
new Vue({
data() {
return {
value: undefined
}
}
}).$mount('#app')
</script>
</body>
</html>
```
<br>
## 属性
| 名称 | 说明 | 类型 | 默认值 |
| -------------------- | ------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- | ----------- |
| value / v-model | 绑定值 | any | |
| arrayed | 绑定值是否为数组类型,默认自动 | boolean | |
| srcAt | 图片链接的位置 | string / symbol / (value: any) => any | |
| upload | 调用接口上传图片,返回图片链接 | (output: File \| Blob) => Promise<string \| object> \| string \| object \| void | |
| count | 数量限制 | number / [number?, number?] | |
| size | 体积限制(MB) | number / [number?, number?] | |
| accept | [原生 input 的 accept](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/accept) | string | `'image/*'` |
| validator | 自定义数据源校验器 | (source: File \| Blob \| string) => boolean | |
| disabled | 禁用状态 | boolean | `false` |
| editable | 是否开启编辑功能 | boolean | `true` |
| aspectRatio | 锁定裁剪比例 | string / [string?, string?] | |
| aspectRatioTolerance | 锁定裁剪比例的公差 | number | `0` |
| isCompress | 超出宽度是否自动压缩 | boolean | true |
| compressMaxWidth | 自动压缩宽度 | number | 1280 |
| compressorParams | 压缩图片参数(同compressorjs参数) | number | {convertTypes: [], convertSize: Infinity} |
| cropperMode | 图片裁剪模式 | number | 0 |
### arrayed
如果数量上限和图片数量均不超过 1,则处于单选状态,否则为多选
默认情况下,在单选时输出的绑定值形如:item,多选时输出的绑定值形如:[item,item]
item 具体是什么格式?
未配置 srcAt 时,会提取图片链接作为 item,配置了则不会
如果将 arrayed 设置为 `true` 则强制输出数组类型,无论单选还是多选
如果将 arrayed 设置为 `false` 则强制输出非数组类型,如果此时图片数量为多个,则会执行 `JSON.stringify`
### srcAt
用于定位 value 和 upload 返回值中的图片链接,适用于绑定值非图片链接本身的情况
- 支持属性名,如 `'url'`
- 支持属性路径,如 `'data[0].url'`
- 支持 symbol 类型的属性名
- 支持 Function,如 `value => value.url`
### upload
开启编辑功能时,会在编辑完成后调用,未开启编辑功能时,会在选择图片后调用
未配置或函数返回值为空时,绑定值将输出二进制文件
参数为编辑产物:
用户选择本地文件、编程式提供 File 类型的数据源时,编辑产物的类型为 File
编程式提供非 File 类型的数据源且编辑了图片时,编辑产物的类型为 Blob
未开启编辑功能或未编辑时,编辑产物即输入值
编程式提供 string 类型的数据源且未编辑时,不需要上传,该方法不会被调用
返回值类型为 Promise\<object\> 或 object 时需要配置 srcAt
### count
- `10`:限制数量上限不高于 10 张
- `[1]`:限制数量下限不低于 1 张
- `[1, 10]`:限制数量下限不低于 1 张,且上限不高于 10 张
### size
- `10`:限制体积上限不高于 10 MB
- `[1]`:限制体积下限不低于 1 MB
- `[1, 10]`:限制体积下限不低于 1 MB,且上限不高于 10 MB
### aspectRatio
- `1/1`:限制宽高比为 1 比 1
- `['1/1']`:限制宽高比下限不低于 1 比 1
- `['1/1', '2/1']`:限制宽高比下限不低于 1 比 1,且上限不高于 2 比 1
### accept
通过文件对话框选择图片时,优先展示指定类型的文件
> ⚠ 用户仍可以选择其它类型,文件类型校验应使用 validator
语法:
- 文件扩展名,不区分大小写,如 `'.jpg.jpeg.png'`
- [MIME type](http://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types),如 `'image/jpeg,image/png'`
### cropperMode
- 0: 没有限制
- 1: 限制裁剪框不超过图片容器的范围。
- 2: 限制最片容器尺寸以在裁剪容器中展示。 如果图片容器和裁剪容器的比例不同,则图片容器以 cover 模式填充(图片容器保持原有比例,最长边和裁剪容器大小一致,短边等比缩放,可能会有部分区域不可见)。
- 3: 限制图片容器尺寸以在裁剪器中展示。 如果图片容器和裁剪容器的比例不同,则图片容器以 contain 模式填充(图片容器保持原有比例,最短边和裁剪容器大小一直,长边等比缩放,可能会有留白)。
<br>
## 插槽
同 `el-upload`
<br>
## 事件
| 名称 | 说明 | 回调参数 |
| ---------- | ------------------------------------------------------- | ---------------- |
| size-error | 选中图片的体积不符合要求时触发 | 图片体积(Byte) |
| ... | `el-upload` 的事件(Function 类型的属性,去掉 on 前缀) | |
```html
<ImgPond @remove="onRemove" @beforeUpload="onBeforeUpload" />
```
<br>
## 方法
| 名称 | 说明 | 参数 |
| ---------- | ------------------ | ------------------------------------------------------------------------ |
| openEditor | 打开图片编辑对话框 | (source: File \| Blob \| string \| File[] \| Blob[] \| string[]) => void |
参数为输入的数据源,支持的数据类型有:
- File
- Blob
- Base64
- URL:需要跨域支持
- object URL:需要在当前 `document` 创建
如果没有编辑图片,则输出值类型不变 (与输入值一致)
如果编辑了图片,输入类型为 File 时,输出类型也为 File,其它情况均输出 Blob 类型
<br>
## 编程式提供数据源
```vue
<!-- 示例: 输入图片链接进行编辑 -->
<!-- 如果需要附加图片名称,可以先转换为 File 类型再输入 -->
<template>
<ImgPond v-show="false" ref="imgPondRef" :upload="upload" />
<el-button @click="openEditor"> 编辑图片 </el-button>
</template>
<script setup>
const imgPondRef = ref()
async function urlToFile(url, fileName) {
const blob = await (await fetch(url)).blob()
return new File([blob], fileName, { type: blob.type })
}
function openEditor() {
const file = urlToFile('https://picsum.photos/100', '100x100.jpg')
imgPondRef.value.openEditor(file)
}
function upload(file) {
return POST.upload(import.meta.env.VITE_APP_UPLOAD_API, {
file
}).then((res) => res.data.data)
}
</script>
```
<br>
## 校验文件扩展名
```vue
<template>
<ImgPond :accept="accept" :validator="validator" />
</template>
<script setup>
const accept = '.jpg,.jpeg,.png'
const extension = accept.split(',')
function validator(source) {
let valid = true
if (source instanceof File) {
valid = extension.includes(source.name.replace(/.+\./, '.').toLowerCase())
if (!valid) {
alert(`"${source.name}" 的格式不在可支持范围: ${accept}`)
}
}
return valid
}
</script>
```
<br>
## 上传状态
```vue
<template>
<ImgPond ref="imgPondRef" />
</template>
<script setup>
const imgPondRef = ref()
console.log(imgPondRef.value.uploading)
</script>
```
<br>
## 自定义上传时机
1. 不配置 upload,绑定值得到二进制文件
2. 将 srcAt 配置为 `'url'`,使图片能够正常预览
3. 在适当时机自行上传
<br>
## 自定义 trigger
```vue
<template>
<ImgPond class="custom-trigger" list-type="text" mb="8px">
<el-button>自定义 trigger</el-button>
</ImgPond>
</template>
<style lang="scss" scoped>
.custom-trigger {
:deep(.pic-viewer),
:deep(.el-upload-list),
:deep(.el-upload__tip),
:deep(.el-upload__text) {
display: none;
}
}
</style>
```
<br>
## 自定义 tip
```vue
<ImgPond aspectRatio="375/120" :size="10" :count="1">
<template #tip="{ aspectRatio, size, count, accept }">
<div>{{ count }}</div>
<div>{{ size }}</div>
<div>{{ aspectRatio }}</div>
<div>{{ accept }}</div>
</template>
</ImgPond>
```
<br>
## 嵌套在表格中
以宽高 `50px` 为例,修改为如下样式:
```scss
:deep(.pic-viewer li) {
margin: 0 !important; // 如果允许多张,则去掉这行
img {
height: 50px !important;
}
}
:deep(.el-upload-list__item) {
width: 50px;
height: 50px;
margin: 0; // 如果允许多张,则去掉这行
& > .el-upload-list__item-status-label {
width: 34px;
height: 18px;
& > i {
margin-top: 0;
}
}
.el-upload-list__item-actions {
line-height: 50px;
font-size: 16px;
& > span + span {
margin-left: 4px;
}
}
}
:deep(.el-upload) {
width: 50px;
height: 50px;
line-height: 50px;
margin: 0;
& > .el-icon-plus {
font-size: initial;
}
& > .el-upload__text {
display: none;
}
}
```
<br>
## 升级日志
### v0.12.10
feat: 实现自动压缩功能,当图片宽度超过 compressMaxWidth 时进行压缩
### v0.12.10
feat: 增加文件建议大小和溢出提示配置,文件大小溢出时自动压缩,如果压缩后仍然大于预期大小,将提示用户自行处理
### v0.12.9
feat: 支持配置图片压缩功能,实时显示裁剪后的图片大小