mand-mobile/components/image-reader/index.vue

199 lines
4.2 KiB
Vue

<template>
<div class="md-image-reader">
<input
class="md-image-reader-file"
type="file"
:key="inputTmpKey"
:name="name"
:accept="mimeType"
:capture="isCameraOnly"
:multiple="isMultiple"
@change="$_onFileChange"/>
</div>
</template>
<script>
import createImageReader from './image-reader'
import {dataURItoBlob} from './image-dataurl'
import {functionToUrl, randomId} from '../_util'
const ERROR = {
'100': 'browser does not support',
'101': 'picture size is beyond the preset',
'102': 'picture read failure',
'103': 'the number of pictures exceeds the limit',
}
export default {
name: 'md-image-reader',
props: {
name: {
type: String,
default() {
return randomId('image-reader')
},
},
size: {
type: [String, Number],
default: 0,
},
mime: {
type: Array,
default() {
/* istanbul ignore next */
return []
},
},
isCameraOnly: {
type: Boolean,
default: false,
},
isMultiple: {
type: Boolean,
default: false,
},
amount: {
type: Number,
default: 0,
},
},
data() {
return {
inputTmpKey: Date.now(), // trigger of refreshing input file
}
},
computed: {
mimeType() {
/* istanbul ignore else */
if (this.mime.length) {
let mimeStr = ''
this.mime.forEach(type => {
mimeStr += `image/${type},`
})
return mimeStr.substring(0, mimeStr.length - 1)
} else {
return 'image/*'
}
},
},
methods: {
// MARK: private methods
$_emitter(event, data) {
this.$emit(event, this.name, data)
},
$_openWebWorker(fn) {
/* istanbul ignore next */
return new Worker(functionToUrl(fn))
},
$_closeWebWorker(worker) {
/* istanbul ignore next */
worker.terminate()
},
$_readFile(fileElement) {
const size = +this.size * 1000
const files = fileElement.files
let worker
let count = 0
/* istanbul ignore if */
if (window.Worker) {
worker = this.$_openWebWorker(createImageReader)
// worker send
worker.postMessage({
files,
size: size,
isWebWorker: true,
})
// worker response
worker.onmessage = evt => {
this.$_onReaderComplete(evt.data)
count++
// shut down worker after all files have been read
if (count === files.length) {
this.$_closeWebWorker(worker)
}
}
} else {
// generate imageReader
const imageReader = createImageReader(window)
imageReader({
files,
size: size,
isWebWorker: false,
complete: this.$_onReaderComplete,
})
}
},
$_cleaeFile() {
this.inputTmpKey = Date.now()
},
// MARK: events handler
$_onFileChange(event) {
/* istanbul ignore next */
const fileElement = event.target
/* istanbul ignore next */
if (fileElement.files && fileElement.files.length) {
this.$_emitter('select', {
files: Array.prototype.slice.call(fileElement.files),
})
// error 超出每次上传最大张数
if (this.amount && fileElement.files.length > this.amount) {
this.$_emitter('error', {
code: '103',
msg: ERROR['103'],
})
this.$_cleaeFile()
return
}
this.$_readFile(fileElement)
}
},
$_onReaderComplete({errorCode, dataUrl, file}) {
if (errorCode) {
this.$_emitter('error', {
code: errorCode,
msg: ERROR[errorCode],
})
return
}
this.$_emitter('complete', {
blob: dataURItoBlob(dataUrl),
dataUrl: dataUrl,
file,
})
this.$_cleaeFile()
},
},
}
</script>
<style lang="stylus">
.md-image-reader
position absolute
width 100%
height 100%
z-index 100
left 0
top 0
-webkit-tap-highlight-color rgba(0,0,0,0)
.md-image-reader-file
position absolute
width 100%
height 100%
opacity 0
left 0
top 0
-webkit-tap-highlight-color rgba(0,0,0,0)
</style>