属性名 | 属性说明 | 默认值 |
value | v-model 绑定的上传图片列表 | |
compressSwitch | 是否开启图片压缩 | false |
quality | 图片压缩质量【0-1】 | 0.1 |
threshold | 图片压缩阈值(图片大于等于该阈值才进行压缩) | 500KB |
maxCount | 图片上传数量限制 | 1 |
- <template>
- <div class="comp-ship">
- <compress-uploader v-model="fileList" :compressSwitch="true" :quality="0.5" :maxCount="3" />
- div>
- template>
-
- <script>
- import compressUploader from './components/compress-uploader'
- export default {
- name: 'CompShip',
- data () {
- return {
- fileList: [],
- }
- },
- components: {
- compressUploader
- }
- }
- script>
-
- <style lang="scss" scoped>
- style>
- <template>
- <van-uploader :fileList="fileList" :after-read="afterRead"
- multiple :max-count="maxCount" v-bind="$attrs" v-on="$listeners" />
- template>
-
- <script>
- export default {
- name: 'compress-uploader',
- props: {
- value: Array,
- quality: {
- type: Number,
- default: 0.1
- },
- compressSwitch: {
- type: Boolean,
- default: false
- },
- threshold: {
- type: Number,
- default: 500
- },
- maxCount: {
- type: Number,
- default: 1
- }
- },
- computed: {
- fileList: {
- get () {
- return this.value
- },
- set (n) {
- this.$emit('input', n)
- }
- }
- },
- methods: {
- afterRead (file, detail) {
- file.status = 'uploading'
- file.message = '上传中...'
- this.imgPreview(file, detail.index)
- return true
- },
- // 处理图片
- async imgPreview (myFile, index) {
- const file = myFile.file
- if (!file || !window.FileReader) { // 看支持不支持FileReader
- return
- }
- const size = file.size / 1024
- console.log(`图片大小 ===> ${size}kb`)
- console.log('图片压缩:', this.compressSwitch ? '开' : '关')
- console.log('图片压缩阈值:', this.threshold + 'kb')
- console.log('图片压缩降帧值:', this.quality)
- if (/^image/.test(file.type) && size >= this.threshold && this.compressSwitch) {
- const img = new Image()
- img.src = await this.getBase64(file) // 将图片将转成base64格式
- img.onload = () => {
- const data = this.compress(img, file.name, file.type)
- console.log(`压缩后 ===> ${data.fileData.size / 1024}kb`)
- this.fileList[index] = {
- content: data.base64Data,
- file: data.fileData
- }
- myFile.status = 'done'
- }
- } else {
- myFile.status = 'done'
- }
- },
- // 压缩图片
- compress (img, name, type) {
- const canvas = document.createElement('canvas')
- const ctx = canvas.getContext('2d')
- // 瓦片canvas
- const tCanvas = document.createElement('canvas')
- const tctx = tCanvas.getContext('2d')
- let width = img.width
- let height = img.height
- // 如果图片大于四百万像素,计算压缩比并将大小压至400万以下
- let ratio
- if ((ratio = (width * height) / 4000000) > 1) {
- ratio = Math.sqrt(ratio)
- width /= ratio
- height /= ratio
- } else {
- ratio = 1
- }
- canvas.width = width
- canvas.height = height
- // 铺底色
- ctx.fillStyle = '#fff'
- ctx.fillRect(0, 0, canvas.width, canvas.height)
- // 如果图片像素大于100万则使用瓦片绘制
- let count
- if ((count = (width * height) / 1000000) > 1) {
- count = ~~(Math.sqrt(count) + 1) // 计算要分成多少块瓦片
- // 计算每块瓦片的宽和高
- const nw = ~~(width / count)
- const nh = ~~(height / count)
- tCanvas.width = nw
- tCanvas.height = nh
- for (let i = 0; i < count; i++) {
- for (let j = 0; j < count; j++) {
- tctx.drawImage(img, i * nw * ratio, j * nh * ratio, nw * ratio, nh * ratio, 0, 0, nw, nh)
- ctx.drawImage(tCanvas, i * nw, j * nh, nw, nh)
- }
- }
- } else {
- ctx.drawImage(img, 0, 0, width, height)
- }
- // 进行压缩
- const ndata = canvas.toDataURL('image/jpeg', this.quality)
- tCanvas.width = tCanvas.height = canvas.width = canvas.height = 0
- return { base64Data: ndata, fileData: this.dataURLtoFile(ndata, name, type) }
- },
- // 获取图片base64格式
- getBase64 (data) {
- return new Promise((resolve, reject) => {
- const fileReader = new FileReader()
- fileReader.onload = (e) => {
- resolve(e.target.result)
- }
- fileReader.readAsDataURL(data)
- fileReader.onerror = () => {
- reject(new Error('文件流异常'))
- }
- })
- },
- // 将base64转换为文件
- dataURLtoFile (dataurl, name, type) {
- name = name || '图片'
- type = type || 'jpg'
- const arr = dataurl.split(',')
- const bstr = atob(arr[1])
- let n = bstr.length
- const u8arr = new Uint8Array(n)
- while (n--) {
- u8arr[n] = bstr.charCodeAt(n)
- }
- return new File([u8arr], name, {
- type: type
- })
- }
- }
- }
- script>