Skip to content

Commit

Permalink
feat(uploader): support resolve-type (#1194)
Browse files Browse the repository at this point in the history
  • Loading branch information
chouchouji authored Sep 27, 2023
1 parent 3bf3f1f commit a8fbb35
Show file tree
Hide file tree
Showing 7 changed files with 170 additions and 26 deletions.
11 changes: 11 additions & 0 deletions packages/varlet-shared/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -194,3 +194,14 @@ export const inViewport = (element: HTMLElement) => {

return xInViewport && yInViewport
}

export const toDataURL = (file: File): Promise<string> =>
new Promise((resolve) => {
const fileReader = new FileReader()

fileReader.onload = () => {
resolve(fileReader.result as string)
}

fileReader.readAsDataURL(file)
})
36 changes: 13 additions & 23 deletions packages/varlet-ui/src/uploader/Uploader.vue
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,8 @@ import ImagePreview from '../image-preview'
import Ripple from '../ripple'
import Hover from '../hover'
import { defineComponent, nextTick, reactive, computed, watch, ref } from 'vue'
import { props, type VarFile, type ValidateTrigger } from './props'
import { isNumber, toNumber, isString, normalizeToArray } from '@varlet/shared'
import { props, type VarFile, type UploaderValidateTrigger } from './props'
import { isNumber, toNumber, isString, normalizeToArray, toDataURL } from '@varlet/shared'
import { isHTMLSupportImage, isHTMLSupportVideo } from '../utils/shared'
import { call, useValidation, createNamespace, formatElevation } from '../utils/components'
import { useForm } from '../form/provide'
Expand Down Expand Up @@ -217,27 +217,17 @@ export default defineComponent({
return Array.from<File>(fileList as ArrayLike<File>)
}
function resolver(varFile: VarFile): Promise<VarFile> {
return new Promise((resolve) => {
// For performance, only file reader processing is performed on images
if (!varFile.file!.type.startsWith('image')) {
resolve(varFile)
return
}
const fileReader = new FileReader()
fileReader.onload = () => {
const base64 = fileReader.result as string
varFile.cover = base64
varFile.url = base64
resolve(varFile)
}
async function resolver(varFile: VarFile): Promise<VarFile> {
if (
props.resolveType === 'data-url' ||
(varFile.file!.type.startsWith('image') && props.resolveType === 'default')
) {
const dataURL = await toDataURL(varFile.file!)
varFile.cover = dataURL
varFile.url = dataURL
}
fileReader.readAsDataURL(varFile.file as File)
})
return varFile
}
function getResolvers(varFiles: VarFile[]) {
Expand Down Expand Up @@ -370,7 +360,7 @@ export default defineComponent({
ImagePreview.close()
}
function validateWithTrigger(trigger: ValidateTrigger) {
function validateWithTrigger(trigger: UploaderValidateTrigger) {
nextTick(() => {
const { validateTrigger, rules, modelValue } = props
vt(validateTrigger, trigger, rules, modelValue, varFileUtils)
Expand Down
134 changes: 133 additions & 1 deletion packages/varlet-ui/src/uploader/__tests__/index.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ test('test uploader preview', async () => {
},
})

await wrapper.vm.handleChange(createEvent('cat.jpg', 'image/jpg'))
await wrapper.vm.handleChange(createEvent('cat.png', 'image/png'))
await delay(16)
await wrapper.find('.var-uploader__file').trigger('click')
await delay(100)
Expand Down Expand Up @@ -365,3 +365,135 @@ test('test uploader extra slot', async () => {

wrapper.unmount()
})

test('test uploader resolve-type as default when file type is image', async () => {
const { mockRestore } = mockFileReader('data:image/png;base64,')
const { mockRestore: mockRestoreStubs } = mockStubs()
const onUpdateModelValue = vi.fn((value) => wrapper.setProps({ modelValue: value }))

const wrapper = mount(VarUploader, {
props: {
modelValue: [],
resolveType: 'default',
'onUpdate:modelValue': onUpdateModelValue,
},
})

await wrapper.vm.handleChange(createEvent('cat.png', 'image/png'))
await delay(100)
expect(wrapper.vm.files[0].cover.includes('data:image/png;base64,')).toBe(true)

mockRestoreStubs()
wrapper.unmount()
mockRestore()
})

test('test uploader resolve-type as default when file type is not image', async () => {
const { mockRestore } = mockFileReader('data:')
const { mockRestore: mockRestoreStubs } = mockStubs()
const onUpdateModelValue = vi.fn((value) => wrapper.setProps({ modelValue: value }))

const wrapper = mount(VarUploader, {
props: {
modelValue: [],
resolveType: 'default',
'onUpdate:modelValue': onUpdateModelValue,
},
})

await wrapper.vm.handleChange(createEvent('data.json', 'application/json'))
await delay(100)
expect(wrapper.vm.files[0].cover.includes('data:')).toBe(false)

mockRestoreStubs()
wrapper.unmount()
mockRestore()
})

test('test uploader resolve-type as file when file type is image', async () => {
const { mockRestore } = mockFileReader('data:image/png;base64,')
const { mockRestore: mockRestoreStubs } = mockStubs()
const onUpdateModelValue = vi.fn((value) => wrapper.setProps({ modelValue: value }))

const wrapper = mount(VarUploader, {
props: {
modelValue: [],
resolveType: 'file',
'onUpdate:modelValue': onUpdateModelValue,
},
})

await wrapper.vm.handleChange(createEvent('cat.png', 'image/png'))
await delay(100)
expect(wrapper.vm.files[0].cover).toBe('')

mockRestoreStubs()
wrapper.unmount()
mockRestore()
})

test('test uploader resolve-type as file when file type is not image', async () => {
const { mockRestore } = mockFileReader('data:')
const { mockRestore: mockRestoreStubs } = mockStubs()
const onUpdateModelValue = vi.fn((value) => wrapper.setProps({ modelValue: value }))

const wrapper = mount(VarUploader, {
props: {
modelValue: [],
resolveType: 'file',
'onUpdate:modelValue': onUpdateModelValue,
},
})

await wrapper.vm.handleChange(createEvent('data.json', 'application/json'))
await delay(100)
expect(wrapper.vm.files[0].cover).toBe('')

mockRestoreStubs()
wrapper.unmount()
mockRestore()
})

test('test uploader resolve-type as data-url when file type is image', async () => {
const { mockRestore } = mockFileReader('data:image/png;base64,')
const { mockRestore: mockRestoreStubs } = mockStubs()
const onUpdateModelValue = vi.fn((value) => wrapper.setProps({ modelValue: value }))

const wrapper = mount(VarUploader, {
props: {
modelValue: [],
resolveType: 'data-url',
'onUpdate:modelValue': onUpdateModelValue,
},
})

await wrapper.vm.handleChange(createEvent('cat.png', 'image/png'))
await delay(100)
expect(wrapper.vm.files[0].cover.includes('data:image/png;base64,')).toBe(true)

mockRestoreStubs()
wrapper.unmount()
mockRestore()
})

test('test uploader resolve-type as data-url when file type is not image', async () => {
const { mockRestore } = mockFileReader('data:')
const { mockRestore: mockRestoreStubs } = mockStubs()
const onUpdateModelValue = vi.fn((value) => wrapper.setProps({ modelValue: value }))

const wrapper = mount(VarUploader, {
props: {
modelValue: [],
resolveType: 'data-url',
'onUpdate:modelValue': onUpdateModelValue,
},
})

await wrapper.vm.handleChange(createEvent('data.json', 'application/json'))
await delay(100)
expect(wrapper.vm.files[0].cover.includes('data:')).toBe(true)

mockRestoreStubs()
wrapper.unmount()
mockRestore()
})
1 change: 1 addition & 0 deletions packages/varlet-ui/src/uploader/docs/en-US.md
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,7 @@ const files = ref([
| `previewed` | Whether to allow preview | _boolean_ | `true` |
| `ripple` | Whether to open ripple | _boolean_ | `true` |
| `hide-list` | Whether to hide the file list | _boolean_ | `false` |
| `resolve-type` | The file read result type, Can be set to `default` `file` `data-url` (`default`, the image type contains base64 and File object, other types contain only File object. `file`, which contains only File object. `data-url`, which contains base64 and File object) | _string_ | `default` |
| `validate-trigger` | Timing to trigger validation, The optional value is `onChange` `onRemove` | _ValidateTriggers[]_ | `['onChange', 'onRemove']` |
| `rules` | The validation rules,Returns `true` to indicate that the validation passed,The remaining values are converted to text as user prompts | _Array<(v: VarFile, u: VarFileUtils) => any>_ | `-` |

Expand Down
1 change: 1 addition & 0 deletions packages/varlet-ui/src/uploader/docs/zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,7 @@ const files = ref([
| `previewed` | 是否允许预览 | _boolean_ | `true` |
| `ripple` | 是否开启水波纹 | _boolean_ | `true` |
| `hide-list` | 是否隐藏文件列表 | _boolean_ | `false` |
| `resolve-type` | 文件读取结果类型,可选值为 `default` `file` `data-url``default`,图像包含 base64 编码和 File 对象,其他类型仅包含 File 对象。`file`,仅包含 File 对象。`data-url`,包含 base64 编码和 File 对象) | _string_ | `default` |
| `validate-trigger` | 触发验证的时机, 可选值为 `onChange` `onRemove` | _ValidateTriggers[]_ | `['onChange', 'onRemove']` |
| `rules` | 验证规则,返回 `true` 表示验证通过,其余的值则转换为文本作为用户提示 | _Array<(v: VarFile, u: VarFileUtils) => any>_ | `-` |

Expand Down
10 changes: 8 additions & 2 deletions packages/varlet-ui/src/uploader/props.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ export interface VarFile {
state?: 'loading' | 'success' | 'error'
}

export type ValidateTrigger = 'onChange' | 'onRemove'
export type UploaderResolveType = 'default' | 'file' | 'data-url'

export type UploaderValidateTrigger = 'onChange' | 'onRemove'

export const props = {
modelValue: {
Expand All @@ -34,6 +36,10 @@ export const props = {
type: [Boolean, Number, String],
default: true,
},
resolveType: {
type: String as PropType<UploaderResolveType>,
default: 'default',
},
removable: {
type: Boolean,
default: true,
Expand All @@ -49,7 +55,7 @@ export const props = {
default: true,
},
validateTrigger: {
type: Array as PropType<Array<ValidateTrigger>>,
type: Array as PropType<Array<UploaderValidateTrigger>>,
default: () => ['onChange', 'onRemove'],
},
rules: Array as PropType<Array<(v: VarFile) => any>>,
Expand Down
3 changes: 3 additions & 0 deletions packages/varlet-ui/types/uploader.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ export type VarFileFit = 'fill' | 'contain' | 'cover' | 'none' | 'scale-down'

export type VarFileState = 'loading' | 'success' | 'error'

export type VarFileResolveType = 'default' | 'file' | 'data-url'

export interface VarFile {
file?: File
name?: string
Expand Down Expand Up @@ -41,6 +43,7 @@ export interface UploaderProps extends BasicAttributes {
previewed?: boolean
hideList?: boolean
ripple?: boolean
resolveType?: VarFileResolveType
validateTrigger?: Array<UploaderValidateTrigger>
rules?: Array<(v: VarFile[], u: UploaderVarFileUtils) => any>
onBeforeFilter?: ListenerProp<(files: VarFile[]) => Promise<VarFile[]> | VarFile[]>
Expand Down

0 comments on commit a8fbb35

Please sign in to comment.