您的位置:首页技术文章
文章详情页

vue 实现上传组件

【字号: 日期:2022-09-29 10:03:44浏览:2作者:猪猪
目录1.介绍2.思路文件上传的两种实现方式3.生命周期4.代码草稿5.具体实现1.介绍

效果如下图

vue 实现上传组件

2.思路文件上传的两种实现方式

1.From形式

<form method='post' enctype='multipart/from-data' action='api/upload'> <input type='file name='file'> <button type='submit'>Submit</button></form>

form的method属性指定为 'post' 请求,通过HTML表单发送数据给服务器,并返回服务器的修改结果,在这种情况下Content-Type是通过在<form>元素中设置正确的enctype属性。

form的enctype属性规定在发送到服务器之前应该如何对表单数据进行编码。

application/x-www-form-urlencoded(默认值):表示在发送前编码所有字符,数据被编码成以'&'分隔的键值对,同时以'='分隔键和值,('name=seven&age=19')。不支持二进制数据。 multipart/form-data:支持二进制数据(上传文件时必须指定)

2.JavaScript异步请求形式

我们知道 FormData 接口提供了一种表示表单数据的键值对 key/value 的构造方式,并且可以轻松的将数据通过XMLHttpRequest.send()方法发送出去,本接口和此方法都相当简单直接。如果送出时的编码类型被设为 'multipart/form-data',它会使用和表单一样的格式。

var formdata = new FormData(); // 创建FormData对象formdata.append('name','laotie'); // 通过append()方法添加新的属性值... // 更多方法请点下面链接

FormData接口

3.生命周期

上传组件也有它的生命周期

beforeUpload --> uploading --> fileUploaded 或者 uploadedError

4.代码草稿

本例中采用js异步请求的方式开发上传组件

<input type='file' name='file' @change.prevent='handleFileChange'>// 创建一个file类型的input,用于触发文件上传,后面可以把input隐藏掉,自定义好看的样式// 自定义样式的时候可以用slot区分不同上传状态的样式(loading,success,defult)

const handleFileChange = (e:Event)=>{ const target = e.target as HTMLInputElement const files = Array.from(target.files)// 注意这里取得的是一个类数组 if(files){ // 取得文件 const uploadedFile = files[0]if(!validateFormat) return // ...这里只是提供一种思路,具体校验不再讲述 // 在这里做一些上传文件前的校验,比如文件格式,大小等, // 不符合要求的话就不在继续发送请求const formData = new FormData() formData.append(uploadedFile.name,uploadedFile)axios.post(’/upload’,formData,{ headers:{ // 注意设置编码类型’Content-Type’: ’multipart/form-data’ } }).then(res=>{ console.log(’上传成功’) }).catch(error =>{ // 文件上传失败 }).finally(()=>{ // 文件上传完成,无论成功还是失败 // 这里可以清除一下input.value }) }}5.具体实现

// Upload.vue<template> <div class='upload-container'> <div @click.prevent='triggerUpload' v-bind='$attrs'> <slot name='loading' v-if='fileStatus===’loading’'><button class='btn btn-primary'>上传中</button> </slot> <slot name='uploaded' v-else-if='fileStatus===’success’' :uploadedData='fileData'><button class='btn btn-primary'>上传成功</button> </slot> <slot v-else name='default'><button class='btn btn-primary'>点击上传</button> </slot> </div> <input type='file' name='file' ref='uploadInput' @change='hanldeInput'/> </div></template><script lang='ts'>import { defineComponent, ref, PropType, watch } from ’vue’import axios from ’axios’type UploadStatus = ’ready’ | ’loading’ | ’success’ | ’error’type FunctionProps = (file:File) => booleanexport default defineComponent({ name: ’Upload’, inheritAttrs: false, props: { // 上传的url action: { type: String, required: true }, // 上传之前的校验,是一个返回布尔值的函数 beforeUpload: { type: Function as PropType<FunctionProps> }, // 上传好的数据,用来判断状态或做初始化展示 uploadedData: { type: Object } }, emits: [’file-uploaded-success’, ’file-uploaded-error’], setup(props, ctx) { const uploadInput = ref<null | HTMLInputElement>(null) const fileStatus = ref<UploadStatus>(props.uploadedData ? ’success’ : ’ready’) const fileData = ref(props.uploadedData) watch(() => props.uploadedData, (val) => { if (val) {fileStatus.value = ’success’fileData.value = val } }) const triggerUpload = () => { if (uploadInput.value) {uploadInput.value.click() } } const hanldeInput = (e:Event) => { const target = e.target as HTMLInputElement const files = target.files console.log(target) if (files) {const uploadFile = Array.from(files)const validateFormat = props.beforeUpload ? props.beforeUpload(uploadFile[0]) : trueif (!validateFormat) returnfileStatus.value = ’loading’const formData = new FormData()formData.append(’file’, uploadFile[0])axios.post(props.action, formData, { headers: { ’Content-Type’: ’multipart/form-data’ }}).then(res => { console.log(’文件上传成功’, res) fileStatus.value = ’success’ fileData.value = res.data ctx.emit(’file-uploaded-success’, res.data)}).catch(error => { console.log(’文件上传失败’, error) fileStatus.value = ’error’ ctx.emit(’file-uploaded-error’, error)}).finally(() => { console.log(’文件上传完成’) if (uploadInput.value) { uploadInput.value.value = ’’ }}) } } return { uploadInput, triggerUpload, hanldeInput, fileStatus, fileData } }})</script>

使用示例:

<template> <div class='create-post-page'> <upload action='/upload' :beforeUpload='beforeUpload' :uploadedData='uploadedData' @file-uploaded-success='hanldeUploadSuccess' > <template #uploaded='slotProps'><div class='uploaded-area'> <img :src='https://www.haobala.com/bcjs/slotProps.uploadedData.data.url'/> <h3>点击重新上传</h3></div> </template> <template #default> <h2>点击上传头图</h2> </template> <template #loading> <div class='d-flex'> <div role='status'> <span class='sr-only'></span> </div> </div> </template> </upload> </div></template><script lang='ts'>import { defineComponent, ref, onMounted } from ’vue’import Upload from ’../components/Upload.vue’import createMessage from ’../components/createMessage’export default defineComponent({ name: ’CreatePost’, components: { Upload }, setup() { const uploadedData = ref() //创建一个响应式数据 let imageId = ’’ onMounted(() => { .... // 这里有逻辑省略了,取到初始化数据image if (image) {uploadedData.value = { data: image } } }) // 上传前校验,返回布尔值 const beforeUpload = (file:File) => { const res = beforeUploadCheck(file, {format: [’image/jpeg’, ’image/png’],size: 1 }) const { error, passed } = res if (error === ’format’) {createMessage(’上传图片只能是JPG/PNG格式!’, ’error’) } if (error === ’size’) {createMessage(’上传图片大小不能超过1MB’, ’error’) } return passed } // 上传成功后拿到imageId就可以进行后续处理,创建表单啥的 const hanldeUploadSuccess = (res:ResponeseProps<ImageProps>) => { createMessage(`上传图片ID ${res.data._id}`, ’success’) if (res.data._id) {imageId = res.data._id } } return { beforeUpload, hanldeUploadSuccess, uploadedData } }})</script><style>.create-post-page{ padding:0 20px 20px;}.create-post-page .upload-box{ height:200px; cursor: pointer; overflow: hidden;}.create-post-page .upload-box img{ width: 100%; height: 100%; object-fit: cover;}.uploaded-area{ position: relative;}.uploaded-area:hover h3{ display: block;}.uploaded-area h3{ display: none; position: absolute; color: #999; text-align: center; width: 100%; top:50%}</style>

以上就是vue 实现上传组件的详细内容,更多关于vue 上传组件的资料请关注好吧啦网其它相关文章!

标签: Vue
相关文章: