好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

解读vant的Uploader上传问题

vant的Uploader上传

vant的uploader组件的交互是点击上传之后才会触发一系列回调函数,如果想要实现点击uploader的时候先出现弹框提示,选择了确定之后才进行文件上传这该怎么做到呢?

大致是,给uploader组件外面包裹一层元素,然后给组件设为禁用模式,当外层的元素状态改变时,就改变组件的disabled值,再使用vant提供的chooseFile通过 ref 可以获取到 Uploader 实例并调用实例的方法重新调起文件选择。

主要的步骤如下

首先,我们可以在uploader组件外面包裹一层div

?? ?<span
? ? ? @click="handleClick"
? ? ? v-if="isconfirm"
? ? ? class="message"
? ? ></span>
? ? <van-uploader
? ? ? v-model="fileList"
? ? ? :after-read="afterRead"
? ? ? :disabled="isconfirm"
? ? ? ref="uploadImg"
? ? />

然后在data以及methods中进行定义

data() {
? ? return {
? ? ? fileList: [],
? ? ? isconfirm: true
?};
? methods: {
? ? handleClick() {
? ? ? this.$dialog
? ? ? ? .confirm({
? ? ? ? ? message: "test,test,test"
? ? ? ? })
? ? ? ? .then(() => {
? ? ? ? ? this.isconfirm = false;
? ? ? ? ? this.$refs.uploadImg.chooseFile();
? ? ? ? })
? ? ? ? .catch(() => {
? ? ? ? ? this.isconfirm = true;
? ? ? ? });
? ? },
? }

看到这里要注意chooseFile这个方法支持的版本是v2.5.6以上的,如果出现了没有效果的话,先检查一下自己安装的版本是否是符合要求的。

检查之后,版本也符合要求,但是this.$refs.uploadImg.chooseFile()就是没有效果,这是怎么一回事呢?

原来跟浏览器执行机制event loop有关,每当执行到choosefile的时候,组件仍为禁用模式,无法调起,其实isconfirm状态还没有进行改变,所以调起文件选择看不见效果,可以使用一个setTimeout或者是vue中的this.$nextTick()进行解决。

setTimeout(() => {
? ? this.$refs.uploadImg.chooseFile();
?}, 0);
?
this.$nextTick(() => {
??? ?this.$refs.uploadImg.chooseFile();
});

vant文件上传Uploader图片压缩

为什么要对图片进行压缩?

随着科技的发展,手机像素越来越好,拍摄的图片也越来越清晰。图片越清晰,体积也就越大。当移动端上传大图时就会发生卡顿,请求超时的情况。

当图片过大时,图片预览也会非常慢,所以需要在图片上传时对图片进行压缩。

vant中文件上传组件Uploader并不支持图片压缩,因为业务场景中有多个地方需要上传图片时对图片进行压缩,所以我基于Uploader封装了一个新的组件。

Uploader组件封装

此组件封装 基于vant文件上传Uploader

API

属性名 属性说明 默认值

quality

压缩质量【0-1】 0.5

compressSwitch

是否开启压缩 false

threshold

达到此大小开始压缩【500k】 500

Vant 文件上传Uploader属性请参照 vant官网

模板部分

<template>
? ? <van-uploader :fileList="$attrs.value" :before-read="beforeReadFn" v-bind="$attrs" v-on="$listeners"/>
</template>

Javascript部分

export default {
? name: 'van-small-upload',
? props: {
? ? quality:{
? ? ? type:Number,
? ? ? default:0.1
? ? },
? ? compressSwitch:{
? ? ? type:Boolean,
? ? ? default:false
? ? },
? ? threshold:{
? ? ? type:Number,
? ? ? default:500
? ? },
? ? beforeRead:{
? ? ? type: Function,
? ? ? default:()=>true
? ? }
? },
? data() {
? ? return {
?
? ? }
? },
? methods: {
? ? // 处理图片
? ? imgPreview(file,index) {
? ? ? console.log('处理图片Fn...');
? ? ? let self = this
? ? ? // 看支持不支持FileReader
? ? ? if (!file || !window.FileReader) return;
? ? ? const size = file.size/1024
? ? ? console.log(`图片大小 ===> ${file.size/1024}k`);
? ? ? console.log('图片压缩:',this.compressSwitch?'开':'关');
? ? ? console.log('图片压缩阈值:',this.threshold+'k');
? ? ? console.log('图片压缩降帧值:',this.quality);
? ? ? if (/^image/.test(file.type) && size >= this.threshold && this.compressSwitch) {
? ? ? ? // 创建一个reader
? ? ? ? let reader = new FileReader()
? ? ? ? // 将图片2将转成 base64 格式
? ? ? ? reader.readAsDataURL(file)
? ? ? ? // 读取成功后的回调
? ? ? ? reader.onloadend = function() {
? ? ? ? ? let result = this.result
? ? ? ? ? let img = new Image()
? ? ? ? ? img.src = result
? ? ? ? ? img.onload = function() {
? ? ? ? ? ? // 压缩
? ? ? ? ? ? let data = self.compress(img,file.name,file.type)
? ? ? ? ? ? console.log(`压缩后 ===>${data.fileData.size/1024}k`);
? ? ? ? ? ? self.$attrs.value[index].content = data.base64Data
? ? ? ? ? ? self.$attrs.value[index].file = data.fileData
? ? ? ? ? }
? ? ? ? }
? ? ? }
? ? },
? ? // 压缩图片
? ? compress(img, name, type) {
? ? ? let canvas = document.createElement('canvas')
? ? ? let ctx = canvas.getContext('2d')
? ? ? //瓦片canvas
? ? ? let tCanvas = document.createElement('canvas')
? ? ? let tctx = tCanvas.getContext('2d')
? ? ? // let initSize = img.src.length;
? ? ? let width = img.width
? ? ? let height = img.height
? ? ? //如果图片大于四百万像素,计算压缩比并将大小压至400万以下
? ? ? let ratio
? ? ? if ((ratio = (width * height) / 4000000) > 1) {
? ? ? ? // console.log("大于400万像素");
? ? ? ? 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) {
? ? ? ? // console.log("超过100W像素");
? ? ? ? count = ~~(Math.sqrt(count) + 1) //计算要分成多少块瓦片
? ? ? ? // ? ? ?计算每块瓦片的宽和高
? ? ? ? let nw = ~~(width / count)
? ? ? ? let 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)
? ? ? }
? ? ? //进行压缩?
? ? ? let 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转换为文件
? ? dataURLtoFile(dataurl,name,type) {
? ? ? name = name ? name : '图片'
? ? ? type = type ? type : 'jpg'
? ? ? var arr = dataurl.split(','),
? ? ? ? bstr = atob(arr[1]),
? ? ? ? n = bstr.length,
? ? ? ? u8arr = new Uint8Array(n)
? ? ? while (n--) {
? ? ? ? u8arr[n] = bstr.charCodeAt(n)
? ? ? }
? ? ? return new File([u8arr], name, {
? ? ? ? type: type
? ? ? })
? ? },
? ? beforeReadFn(file,detail){
? ? ? const {index} = detail
? ? ? this.imgPreview(file,index)
? ? ? return this.beforeRead(...arguments);
? ? }
? },
? mounted(){
? ??
? }
};

使用示例

<SmUpload v-model="fileList" :before-read="beforeRead" :compressSwitch="true" :quality="0.5"/>

以上为个人经验,希望能给大家一个参考,也希望大家多多支持。 

查看更多关于解读vant的Uploader上传问题的详细内容...

  阅读:69次