Skip to content

Commit

Permalink
feat(component): add upload component
Browse files Browse the repository at this point in the history
  • Loading branch information
‘xiuxiu-yang’ committed Feb 13, 2023
1 parent 68527d8 commit acc3970
Show file tree
Hide file tree
Showing 8 changed files with 253 additions and 6 deletions.
1 change: 1 addition & 0 deletions packages/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ export * from './src/message'
export * from './src/drawer'
export * from './src/checkbox'
export * from './src/icon'
export * from './src/upload'
74 changes: 74 additions & 0 deletions packages/components/src/upload/ajax.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
type XMLHttpFN = (ev: ProgressEvent<XMLHttpRequestEventTarget>) => void

export interface UploadRequestOptions {
action: string
method: string
file: File
data?: { [k: string]: string | Blob }
filename: string
withCredentials: boolean
onProgress?: XMLHttpFN
onSuccess: (res: any) => void
onError?: (
actions: string,
options: UploadRequestOptions,
xhr: XMLHttpRequest
) => void
}

const getResponce = (xhr: XMLHttpRequest) => {
const text = xhr.responseText || xhr.response

try {
return JSON.parse(text)
}
catch (error) {
return text
}
}

export const httpRequest = (options: UploadRequestOptions): XMLHttpRequest => {
if (typeof XMLHttpRequest === 'undefined')
throw new Error('XMLHttpRequest is undefined')
const {
action,
method,
file,
data,
filename,
withCredentials,
onProgress,
onSuccess,
onError,
} = options

const xhr = new XMLHttpRequest()

const formData = new FormData()

if (data) {
for (const key in data)
formData.append(key, data[key])
}

xhr.open(method, action, true)

xhr.addEventListener('progress', (ev) => {
onProgress && onProgress(ev)
})

xhr.addEventListener('error', () => {
onError && onError(action, options, xhr)
})

xhr.addEventListener('load', () => {
onSuccess && onSuccess(getResponce(xhr))
})

xhr.withCredentials = withCredentials

formData.append(filename, file, file.name)

xhr.send(formData)
return xhr
}
8 changes: 8 additions & 0 deletions packages/components/src/upload/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { withInstall } from '@lucky-design/common'
import Upload from './upload.vue'
import './style.scss'

export const LUpload = withInstall(Upload)

export * from './props'
export default LUpload
20 changes: 20 additions & 0 deletions packages/components/src/upload/props.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import type { MethodType } from './types'
import type { UploadRequestOptions } from './ajax'

export interface IUploadProps {
action: string
data?: { [k: string]: string | Blob }
method?: MethodType
name?: string
multiple?: boolean
withCredentials?: boolean
disabled?: boolean
beforeUpload?: (file: File) => Promise<any>
onProgress?: (et: ProgressEvent<XMLHttpRequestEventTarget>) => void
onSuccess?: (res: any) => void
onError?: (
actions: string,
options: UploadRequestOptions,
xhr: XMLHttpRequest
) => void
}
6 changes: 6 additions & 0 deletions packages/components/src/upload/style.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
.ld-upload {
@apply cursor-pointer flex-inline justify-center items-center;
.ld-upload_input {
@apply hidden;
}
}
8 changes: 8 additions & 0 deletions packages/components/src/upload/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export type MethodType =
| 'post'
| 'get'
| 'delete'
| 'head'
| 'option'
| 'patch'
| 'put'
129 changes: 129 additions & 0 deletions packages/components/src/upload/upload.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
<script setup lang="ts">
import { shallowReactive, shallowRef } from 'vue'
import { httpRequest } from './ajax'
import type { UploadRequestOptions } from './ajax'
const props = withDefaults(
defineProps<{
action: string
data?: { [k: string]: string | Blob }
method?: string
autoUpload?: boolean
name?: string
multiple?: boolean
accept?: string
withCredentials?: boolean
disabled?: boolean
beforeUpload?: (file: File) => Promise<any>
onProgress?: (et: ProgressEvent<XMLHttpRequestEventTarget>) => void
onSuccess?: (res: any) => void
onError?: (
actions: string,
options: UploadRequestOptions,
xhr: XMLHttpRequest
) => void
}>(),
{
method: 'post',
name: 'file',
autoUpload: true,
withCredentials: false,
disabled: false,
multiple: false,
},
)
const inCompleteFiles = shallowRef<File[]>([])
const completeFiles = shallowReactive<File[]>([])
const requests = shallowReactive<XMLHttpRequest[]>([])
const inputRef = shallowRef<HTMLInputElement>()
const upload = (file: File) => {
const {
action,
method,
data,
withCredentials,
name: filename,
beforeUpload,
onProgress,
onSuccess,
onError,
} = props
const options: UploadRequestOptions = {
action,
method,
data,
withCredentials,
file,
filename,
onProgress,
onError,
onSuccess: (res) => {
completeFiles.push(file)
inCompleteFiles.value = inCompleteFiles.value.filter(v => v !== file)
onSuccess && onSuccess(res)
},
}
if (beforeUpload) {
beforeUpload(file)
.then(() => {
const xhr = httpRequest(options)
requests.push(xhr)
})
.catch(() => {})
}
else {
const xhr = httpRequest(options)
requests.push(xhr)
}
}
const uploadFiles = (files: File[]) => {
if (!files.length)
return
for (const file of files) {
inCompleteFiles.value.push(file)
if (props.autoUpload)
upload(file)
}
}
const handleChange = (e: Event) => {
const files = (e.target as HTMLInputElement).files
if (!files)
return
uploadFiles(Array.from(files))
}
const handleClick = () => {
if (!props.disabled)
inputRef.value?.click()
}
const abort = () => {
for (const xhr of requests) xhr.abort()
}
defineExpose({
abort,
upload,
inCompleteFiles,
})
</script>

<template>
<div class="ld-upload" @click="handleClick">
<slot />
<input
ref="inputRef"
class="ld-upload_input"
:name="name"
:disabled="disabled"
:multiple="multiple"
type="file"
@change="handleChange"
@click.stop
>
</div>
</template>
13 changes: 7 additions & 6 deletions packages/lucky-design/src/components.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { LButton, LDrawer, LMessage, LTree } from '@lucky-design/components'

export const plugins = [
import {
LButton,
LTree,
LMessage,
LDrawer,
] as const
LMessage,
LTree,
LUpload,
} from '@lucky-design/components'

export const plugins = [LButton, LTree, LMessage, LDrawer, LUpload] as const

0 comments on commit acc3970

Please sign in to comment.