vue点击上传图片并实现图片预览功能,并实现多张图片放到一个数组中进行后端请求(使用原生input)

一、将 File 对象转成 BASE64 字符串 (FileReader)

html 复制代码
<template>
  <div>
    <!-- 用来显示封面的图片 -->
    <!-- <img src="@/assets/images/cover.jpg" alt="" class="cover-img" ref="imgRef" /> -->
    <img :src="previewImg" alt="" class="cover-img" ref="imgRef" />
    <br />
    <!-- 文件选择框,默认被隐藏 -->
    <input @change="coverImgChangeHandler" type="file"  accept="image/*" ref="iptFileRef" hidden/>
    <!-- 选择封面的按钮 -->
    <button type="text" @click="choosecoverImgHandler">+ 选择封面</button>
  </div>
</template>

<script>
// ◆导入默认图片, webpack 就会进行打包
import coverImg from '@/assets/images/cover.jpg'
export default {
  data () {
    return {
      // ◆把默认图片赋值给封面图片显示
      previewImg: coverImg
    }
  },
  methods: {
    // ◆点击选择封面,触发图片选择框的点击事件
    choosecoverImgHandler () {
      this.$refs.iptFileRef.click()
    },
    // ◆图片选择框的 change 事件触发
    coverImgChangeHandler (e) {
      console.log(e.target.files)
      // 1.获取用户选择的文件对象
      const files = e.target.files
      // 2.判断用户是否选择了文件对象
      if (files.length === 0) {
        // 2.1用户没有选择图片(使用默认图片)
        // 法1
        // this.$refs.imgRef.src = coverImg
        // 法2
        this.previewImg = coverImg
      } else {
        // 2.2用户选择了图片(使用选择的图片)
        // ◆将 File 对象 转成 BASE64 字符串 
        // 1.创建 FileReader 对象
        const fr = new FileReader()
        // 2.调用 readAsDataURL 函数,读取文件内容
        fr.readAsDataURL(files[0])
        // 3.监听 fr 的 onload 事件
        fr.onload = (e) => {
          // 通过 e.target.result 获取到读取的结果,值是 BASE64 格式的字符串
          // 法1
          // this.$refs.imgRef.src = e.target.result
          // 法2
          this.previewImg = e.target.result
        }
      }
    }
  }
}
</script>

<style lang="less" scoped>
// 设置图片封面的宽高
.cover-img {
  width: 400px;
  height: 280px;
  object-fit: cover;
}
</style>

二、将 File 对象转成 url

html 复制代码
<template>
  <div>
    <!-- 用来显示封面的图片 -->
    <img :src="previewImg" alt="" class="cover-img" ref="imgRef" />
    <br />
    <!-- 文件选择框,默认被隐藏 -->
    <input @change="coverImgChangeHandler" type="file"  accept="image/*" ref="iptFileRef" hidden/>
    <!-- 选择封面的按钮 -->
    <button type="text" @click="choosecoverImgHandler">+ 选择封面</button>
  </div>
</template>

<script>
// ◆导入默认图片, webpack 就会进行打包
import coverImg from '@/assets/images/cover.jpg'
export default {
  data () {
    return {
      // ◆把默认图片赋值给封面图片显示
      previewImg: coverImg
    }
  },
  methods: {
    // ◆点击选择封面,触发图片选择框的点击事件
    choosecoverImgHandler () {
      this.$refs.iptFileRef.click()
    },
    // ◆图片选择框的 change 事件触发
    coverImgChangeHandler (e) {
      console.log(e.target.files)
      // 1.获取用户选择的文件对象
      const files = e.target.files
      // 2.判断用户是否选择了文件对象
      if (files.length === 0) {
        // 2.1用户没有选择图片(使用默认图片)
        this.previewImg = coverImg
      } else {
        // 2.2用户选择了图片(使用选择的图片)
        // 将 File 对象转成 url
        this.previewImg = URL.createObjectURL(files[0])
      }
    }
  }
}
</script>

<style lang="less" scoped>
// 设置图片封面的宽高
.cover-img {
  width: 400px;
  height: 280px;
  object-fit: cover;
}
</style>

三、总结与思考

总结

  • 设置默认图片:将图片作为模块导入,定义变量接收,赋值给图片的 src
    • 其他方法:使用自定义指令设置默认图片、在模板中使用 v-if 等
  • 点击上传图片按钮,触发图片输入框的 click 事件
    • 隐藏图片输入框:hiddendisplay:none
  • 绑定图片输入框 的 change 事件,获取文件对象 e.target.files
  • 判断 e.target.fileslength
    • 长度为0:用户取消选择图片,传给后台的数据就是 null,把默认图片赋值给当前预览区
    • 长度为1:用户确认选择图片,把 e.target.files[0]传给后台
  • 用户选择了图片之后,预览图片的方法:
    • 将获取的文件对象转成 BASE64 字符串:小图片
    • 将获取的文件对象转成 url:大图片

思考

为什么 当用户选择了图片之后,我们不把 e.target.files[0] 直接赋值给预览图片的 srcpreviewImg,而传给后台就可以?

首先src 只支持 urlBASE64 字符串,而当后台需要的数据类型是 Blob 时,我们就可以直接把 e.target.files[0] 传给它,因为 File 就是 Blob 的子类,关系就像 ArrayObject 的关系一样。

进阶

一般进行身份认证时会上传身份证正反面,如果这时后端要求将两张身份证图片放到一个数组中进行请求应该如何做到呢?

首先,我们已经通过输入框 的 change 事件,获取到了文件对象 e.target.files``, e.target.files[0]为单个文件,将拿到的单个文件``push``到新的数组中,以下代码为``vue3``语法实现

javascript 复制代码
//显示图片(图片预览方法)
export const readUrl=(file,preImg)=>{
    const fr = new FileReader()
    fr.readAsDataURL(file)
    fr.onload = (e) => {
        preImg.value = e.target.result//preImg为预览图片的数据
    }
}
//此为input框的change事件,以此拿到单个文件
const coverImgChangeHandler= (e)=> {
    form.value.authFiles.push(e.target.files[0])
    readUrl(e.target.files[0],previewImg)
}
//提交认证按钮
const submitForm =async (formEl: FormInstance | undefined) => {
    if (!formEl) return
    await formEl.validate((valid, fields) => {
        if (valid) {
            let formData = new FormData();
            //此处为重点!!记得遍历后再append,直接append报错
            form.value.authFiles.forEach((file) =>{formData.append('authFiles',file)})
            // console.log(formData)
            axios.post('url',formData
            ).then((res) => {
                console.log(res)
            }).catch(err => {
                // console.log(err);
            })
        } else {
            // console.log('提交失败', fields)
        }
    })

}
相关推荐
Mintopia4 分钟前
⚙️ Next.js 缓存与队列:当数据与请求跳起“低延迟之舞”
前端·全栈·next.js
Shi_haoliu13 分钟前
Vue2 + Office Add-in关于用vue项目于加载项控制excel单元格内容(Demo版)
前端·javascript·vue.js·node.js·html·excel·office
计算机毕业设计木哥37 分钟前
计算机毕业设计选题推荐:基于SpringBoot和Vue的爱心公益网站
java·开发语言·vue.js·spring boot·后端·课程设计
IT_陈寒1 小时前
Redis 性能翻倍的 5 个隐藏技巧,99% 的开发者都不知道第3点!
前端·人工智能·后端
街尾杂货店&1 小时前
css word属性
前端·css
fruge3 小时前
2025前端工程化与性能优化实战指南:从构建到监控的全链路方案
前端·性能优化
aesthetician4 小时前
Node.js v25 重磅发布!革新与飞跃:深入探索 JavaScript 运行时的未来
javascript·node.js·vim
知识分享小能手7 小时前
uni-app 入门学习教程,从入门到精通,uni-app基础扩展 —— 详细知识点与案例(3)
vue.js·学习·ui·微信小程序·小程序·uni-app·编程
demi_meng8 小时前
reactNative 遇到的问题记录
javascript·react native·react.js
MC丶科8 小时前
【SpringBoot 快速上手实战系列】5 分钟用 Spring Boot 搭建一个用户管理系统(含前后端分离)!新手也能一次跑通!
java·vue.js·spring boot·后端