You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

152 lines
3.2 KiB
Vue

6 months ago
<template>
<view class="ch-image-uploader">
<ch-flex class="img-list" justify="center" items="center" @click.native="handleSelect">
<block v-for="item in imageList" key="item.name">
<view class="img-item" data-type="img">
<uni-icons type="clear" class="del-btn" size="50" v-if="showClose" data-type="delete" @click="delImg(item.name)"></uni-icons>
<image :src="item.path" mode="aspectFit"></image>
</view>
</block>
<view class="select-btn" data-type="btn" v-if="showBtn">
<uni-icons type="plusempty" data-type="add" size="70"/>
</view>
</ch-flex>
</view>
</template>
<script setup name="ch-image-uploader">
import { ref, defineProps, reactive, toRefs, watchEffect, watch, computed, defineEmits, defineExpose } from 'vue';
const emit = defineEmits(['update:modelValue'])
defineExpose({
upload
})
const props = defineProps({
limit: {
type: Number,
default: 8
},
extList: {
type: Array,
default: () => ['png', 'jepg', 'jpg']
},
sourceType: {
type: Array,
default: () => ['album', 'camera']
},
showClose: {
type: Boolean,
default: true
},
url: {
type: String,
default: ''
},
modelValue: {
type: Array,
default: () => []
}
})
const data = reactive({
imageList: []
})
const { imageList } = toRefs(data);
const showBtn = computed(() => {
return (props.limit <= 1 && imageList.value.length <= 0)
|| (props.limit > 1 && imageList.value.length <= props.limit - 1)
})
watchEffect(() => {
imageList.value = props.modelValue;
})
function handleSelect (e) {
const type = e.target.dataset.type || false;
if (!type || (type === 'img' && props.limit > 1)) return;
if (type === 'delete') {
delImg();
return;
}
uni.chooseImage({
count: props.limit,
extension: props.extList,
sourceType: props.sourceType,
success: (res) => {
if (props.limit > 1) {
const newImageList = filterImage(res.tempFiles)
imageList.value = [...imageList.value, ...newImageList]
} else {
imageList.value = res.tempFiles
}
emit('update:modelValue', imageList.value)
},
fail: (res) => {
uni.showToast({
icon: 'error',
title: '选择失败'
})
}
})
}
// 上传
function upload () {
const files = formatImageFiles(imageList.value);
console.log(files)
return new Promise((resolve, reject) => {
uni.uploadFile({
url: props.url,
files,
name: 'task-image',
success: (uploadFileRes) => {
uni.showToast({
title: '上传成功'
})
resolve(uploadFileRes)
},
fail: (error) => {
uni.showToast({
icon: 'fail',
title: '上传失败'
})
reject(error)
console.log('上传失败', error)
}
})
})
}
function delImg (delName) {
imageList.value = imageList.value.filter(item => item.name !== delName)
}
// 格式化image列表
function formatImageFiles (fileList) {
return imageList.value.map(item => {
return {
name: item.name,
size: item.size,
uri: item.path,
file: item
}
})
}
// 过滤重复的图片
function filterImage (images) {
return images.filter(item => {
const result = imageList.value.find(img => img.name === item.name );
return !result;
})
}
</script>
<style lang="scss" scoped>
@import './ch-image-uploader.scss';
</style>