magiccube-vue3
Version:
vue3-js版组件库
179 lines (171 loc) • 5.68 kB
JavaScript
/**
* TODO
* 基本功能已实现,遗留问题:
* 1 多个图片时,删除报错(*)
* 2 何时需要清空上传的value值
* 3 onProgress函数
* 4 less 文件,default.min.css 如何生成(*)
*/
import '../../style/upload.less'
import { computed, ref } from 'vue'
import $post from '../import/ajax'
const McUpload = {
name: 'McUpload',
props: {
// 必传
modelValue: [String, Array],
url: String, // 上传的文件地址
// 非必传
width: {
type: [String, Number],
default: 240
},
height: {
type: [String, Number],
default: 152
},
multi: {
type: Boolean,
default: false
},
headers: {
type: Object,
default: () => { }
},
params: {
type: Object,
default: () => { }
},
max: { // 最多展示几个
type: [Number, String],
default: 1
},
disabled: Boolean,
customResponse: Function,
},
emits: ['update:modelValue', 'preview', 'change'],
setup(props, { emit, slots }) {
const model = computed({
get() {
return props.modelValue && typeof props.modelValue === 'string' ? [props.modelValue] : (props.modelValue || [])
},
set(value) {
emit('update:modelValue', value)
}
})
/**
* TODO
* uploadInput.value.value = '' 可以清空上传的文件值
*/
const uploadInput = ref(null)
/**
* 预览图片
*/
const handleRemove = (url) => {
const ary = model.value
const i = ary.indexOf(url)
if (i > -1) ary.splice(i, 1)
model.value = ary
}
const handlePreview = (url) => emit('preview', url)
const getSize = (size) => {
if(!size) return ''
let _s = size
if(typeof size === 'number'){
_s = size.toString()
}
return _s.indexOf('%') > -1? _s : _s + 'px'
}
const previewNode = (url) => (
<div class="mc-upload-preview" style={{
width: getSize(props.width),
height: getSize(props.height) || getSize(props.width),
cursor: props.disabled? 'default' : 'pointer'
}} onClick={() => handlePreview(url)}>
<img src={url} />
{
props.disabled? '' : <div class="mc-upload-preview__close" onClick={() => handleRemove(url)}></div>
}
</div>
)
/**
* 上传图片
*/
const handleChange = (e) => {
if(props.disabled) return false
loading.value = true
const file = props.multi ? e.target.files : e.target.files[0]
const options = {
headers: props.headers,
action: props.url,
multi: props.multi,
file,
extraParams: props.params,
onSuccess: res => {
loading.value = false
// 自定义处理请求返回值(主要用于第三方上传后的处理)
if(props.customResponse){
props.customResponse(res)
return
}
if (res.code === 200) {
const url = res.data && res.data.url ? res.data.url : ''
handleSuccess({
url,
res,
file
})
} else {
throw new Error('上传失败')
}
},
onError: err => {
loading.value = false
throw new Error('上传失败')
}
}
$post(options)
}
const handleSuccess = ({ url, res, file }) => {
const max = Number(props.max)
model.value = max > 1 ? [...model.value, url] : url
emit('change', { url, res, file })
}
const loading = ref(false)
const actionNode = () => (
<div v-loading={loading.value}
class="mc-upload-action"
style={{
width: getSize(props.width),
height: getSize(props.height) || getSize(props.width)
}}>
{
slots.placeholder? slots.placeholder() : <span class="mc-upload-action__arrow"></span>
}
<input class="mc-upload-action__inner"
ref={uploadInput}
type="file"
accept="image/*"
onChange={handleChange}
disabled={props.disabled}
multiple={props.multi} />
</div>
)
return () => (
<div class="mc-upload">
<div class="mc-upload__wrap">
{
model.value?.length ? model.value.map(url => previewNode(url)) : ''
}
{
model.value.length < Number(props.max) ? actionNode() : ''
}
</div>
</div>
)
}
}
McUpload.install = (app) => {
app.component(McUpload.name, McUpload)
}
export { McUpload, McUpload as default }