<template>
<view>
<ImagePicker v-model="imageList"></ImagePicker>
</view>
</template>
<script>
import ImagePicker from '@/components/common/image-picker.vue'
export default {
components: {
ImagePicker,
},
data() {
// 图片回显
imageList: [
{
name: 'uni-app.jpg',
url: 'https://bjetxgzv.cdn.bspapp.com/VKCEYUGU-dc-site/9a952c80-6080-11eb-a16f-5b3e54966275.png',
size: 1000,
}
]
}
...
}
</script>
image-picker 组件如下:
<template>
<view class="image-picker">
<uni-file-picker
v-model="imageValue"
:auto-upload="false"
:title="title"
:limit="limit"
:image-styles="imageStyles"
:file-mediatype="fileMediatype"
:mode="mode"
@select="select"
>
<view v-if="fileMediatype === 'image'" class="form-item-column-center">
<uni-icons type="image" size="30"></uni-icons>
<view :style="{ marginTop: '5px' }">上传照片</view>
<view>最多{{ limit }}张</view>
</view>
</uni-file-picker>
<view class="watermark-canvas">
<canvas
id="watermark-canvas"
:style="{ width: canvasWidth, height: canvasHeight }"
canvas-id="watermark-canvas"
/>
</view>
</view>
</template>
<script>
export default {
name: 'ImagePicker',
props: {
limit: {
type: Number,
default: 1,
},
title: {
type: String,
default: null,
},
mode: {
type: String,
default: 'grid',
},
fileMediatype: {
type: String,
default: 'image',
},
imageStyles: {
type: Object,
default: null,
},
watermark: {
type: Boolean,
default: true,
},
// #ifdef VUE3
modelValue: {
type: Array,
default() {
return []
},
},
// #endif
// #ifndef VUE3
value: {
type: Array,
default() {
return []
},
},
// #endif
},
emits: ['input', 'update:modelValue'],
data() {
return {
imageValue: [],
canvasWidth: '1080px',
canvasHeight: '2160px',
}
},
watch: {
imageValue(newVal) {
// #ifdef VUE3
this.$emit('update:modelValue', newVal)
// #endif
// #ifndef VUE3
this.$emit('input', newVal)
// #endif
},
// #ifndef VUE3
value: {
handler(newVal) {
this.imageValue = newVal
},
immediate: true,
},
// #endif
// #ifdef VUE3
modelValue: {
handler(newVal) {
this.imageValue = newVal
},
immediate: true,
},
// #endif
},
methods: {
checkImage(url) {
const checkNum = 5
let currentCheckNum = 1
return new Promise((resolve, reject) => {
process()
function process() {
uni.getImageInfo({
src: url,
success: function (image) {
resolve(image)
},
fail: function (err) {
if (checkNum <= currentCheckNum) {
uni.showToast({ title: '图片上传失败', icon: 'none' })
reject(err)
} else {
currentCheckNum++
const timer = setTimeout(() => {
clearTimeout(timer)
process()
}, 300)
}
},
})
}
})
},
async select(e) {
const { name, size, extname, uuid } = e.tempFiles[0]
let tempFilePath = e.tempFilePaths[0]
// 添加水印
if (this.watermark) {
tempFilePath = await this.addWatermark(tempFilePath)
}
// 上传图片
const url = await this.uploadFile(tempFilePath)
// 检测图片,确保图片存在
await this.checkImage(url)
this.imageValue = [
...this.imageValue,
{
name,
extname,
url,
size,
uuid,
},
]
},
async addWatermark(tempFilePath) {
return new Promise((resolve, reject) => {
uni.getImageInfo({
src: tempFilePath,
success: async (res) => {
// 设置画布高度和宽度
this.canvasWidth = `${res.width}px`
this.canvasHeight = `${res.height}px`
await this.sleep(200) // 某些平台 canvas 渲染慢,需要等待
const ctx = uni.createCanvasContext('watermark-canvas', this)
ctx.clearRect(0, 0, res.width, res.height)
ctx.beginPath()
ctx.drawImage(tempFilePath, 0, 0, res.width, res.height)
// 水印 字体大小,颜色,内容,位置
ctx.beginPath()
ctx.setFontSize(24)
ctx.setFillStyle('rgba(250,250,250,0.8)')
ctx.fillText('我是水印1', 60, res.height - 90)
ctx.fillText('我是水印2', 60, res.height - 60)
// 开始绘制 (canvas -> 临时文件路径)
ctx.draw(false, async () => {
await this.sleep(500) // 某些平台 canvas 渲染慢,需要等待
uni.canvasToTempFilePath(
{
canvasId: 'watermark-canvas',
destWidth: res.width,
destHeight: res.height,
fileType: 'jpg',
quality: 0.8,
success: (fileRes) => {
resolve(fileRes.tempFilePath)
},
fail: (err) => {
console.log('[Error draw]', err)
uni.showToast({ title: err.errMsg, icon: 'none' })
reject()
},
},
this,
)
})
},
fail: (err) => {
console.log('[Error getImageInfo]', err)
uni.showToast({ title: err.errMsg, icon: 'none' })
reject()
},
})
})
},
async uploadFile(path) {
const formData = {
'params.bizType': 'xxx',
'params.tags': 'xxx',
'meta.code': 'xxxx',
'meta.client': 'uniapp',
'meta.tag': 'xxx',
'meta.time': new Date().getTime(),
}
const res = await uni.uploadFile({
url: `${process.env.VUE_APP_BASE_URL}/file/upload`,
filePath: path,
name: 'params.files',
formData,
header: {
Authorization: uni.getStorageSync('accessToken'),
},
})
return JSON.parse(res[1].data).data.filePaths[0]
},
sleep(millisecond) {
return new Promise((resolve) => {
setTimeout(resolve, millisecond)
})
},
},
}
</script>
<style lang="scss">
.image-picker {
position: relative;
.form-item-column-center {
display: flex;
align-items: center;
justify-content: center;
flex: 1;
flex-direction: column;
}
.watermark-canvas {
position: absolute;
top: 5px;
left: 5px;
width: 1px;
height: 1px;
overflow: hidden;
}
}
</style>