一、input实现文件上传
【1】type属性
type='file' 表示文件域,用于文件上传
【2】accept属性
input框的accept属性值,它规定能够通过文件上传进行提交的文件类型 eg: accept="image/gif, image/jpeg"
【3】实例
<input type="file" name="file" accept="image/png,image/jpg,image/gif,image/JPEG" />
// 上面代码意思是:input元素类型为文件域; accept属性表示可上传提交的文件类型为 image/png,image/jpg,image/gif,image/JPEG
二、封装上传文件的工具函数
新建一个getFile.js文件,通过创建type为file类型的input框实现文件上传功能
export default function ({
accept = "", // input框的accept属性值,它规定能够通过文件上传进行提交的文件类型 eg: accept="image/gif, image/jpeg"
multiple = false, // 是否多个
exts = [], // 文件格式
maxSize = 0 // 文件大小
}) {
exts = exts.map(it => it.toLowerCase());
return new Promise((resolve, reject) => {
let input = document.createElement("input");
input.setAttribute("type", "file");
input.setAttribute("style", "position:absolute;left: -1000px;");
accept && input.setAttribute("accept", accept);
multiple && input.setAttribute("multiple", "multiple");
document.body.appendChild(input);
input.focus();
input.click();
input.addEventListener("change", function () {
let fileExts = Array.from(this.files)
.map(it => it.name.replace(/.*\.([^.]+)$/, "$1"))
.map(it => it.toLowerCase());
if (fileExts.some(it => !exts.includes(it))) {
reject(`只支持文件格式:${exts.join(",")}`);
}
if (maxSize > 0) {
if (Array.from(this.files).some(it => it.size / 1024 / 1024 > maxSize)) {
reject(`最大文件大小${maxSize}M`);
}
}
if (multiple) {
resolve(this.files);
} else {
resolve(this.files[0] || null);
}
input.parentElement.removeChild(input);
})
})
}
三、上传文件组件
新建一个imageSelector.vue文件,实现可复用的上传文件组件
<template>
<div @click="onClick" class="imageSelector" :class="className">
<img class="imageSelector-img" v-if="src" :src="src" />
<slot v-else />
</div>
</template>
<script>
import getFile from "@/libs/getFile";
export default {
props: {
value: {
type: String,
},
disabled: {
type: Boolean,
default: false,
},
},
data() {
return {
src: this.value,
imgFile: "",
};
},
watch: {
src(val) {
this.$emit("input", val);
this.$emit("getimgFile", this.imgFile);
},
value(val) {
this.src = val;
this.imgFile = "";
},
},
computed: {
className() {
return {
"imageSelector-disabled": this.disabled,
"imageSelector-noImg": !this.src,
};
},
},
methods: {
onClick() {
if (this.disabled) return;
this.getFile();
},
async getFile() {
try {
let image = await getFile({
accept: "image/jpeg,image/png",
exts: ["jpg", "png"],
maxSize: 10,
});
console.log(image);
if (image) {
this.imgFile = image;
this.src = await this.fileToBase64(image);
}
} catch (e) {
this.$Message.error(e);
}
},
fileToBase64(file) {
return new Promise((resolve, reject) => {
if (!file) reject(new Error("no file"));
let reader = new FileReader();
reader.addEventListener("load", () => {
resolve(reader.result);
});
reader.readAsDataURL(file);
});
},
},
};
</script>
<style scoped>
.imageSelector {
display: inline-block;
border: 1px solid #dcdee2;
border-radius: 4px;
overflow: hidden;
cursor: pointer;
}
.imageSelector-disabled {
cursor: default;
}
.imageSelector-noImg {
height: 50px;
width: 50px;
}
.imageSelector-img {
width: 100%;
height: 100%;
vertical-align: middle;
}
</style>
四、页面调用
【1】引入
import ImageSelector from "./imageSelector.vue";
export default {
components: { ImageSelector },
}
【2】使用
<ImageSelector
ref="photo"
class="photo"
@getimgFile="getimgFile" // 上传之后处理逻辑
v-model="params.file" // 双向绑定值
@click="uploadPhoto" // 上传之前处理逻辑
/>
【3】处理逻辑
methods: {
uploadPhoto() {
this.imgFile = [];
},
getimgFile(val) {
this.imgFile = [];
if (val) {
this.imgFile.push(val);
}
},
}
五、效果展示
文章每周持续更新,可以微信搜索「 前端大集锦 」第一时间阅读,回复【视频】【书籍】领取200G视频资料和30本PDF书籍资料