UNPKG

yj-imgpond

Version:

Image uploading one-stop solution.

449 lines (330 loc) 14.4 kB
<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 <!DOCTYPE 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: 支持配置图片压缩功能,实时显示裁剪后的图片大小