当前位置: 首页 > java >正文

头像预览和上传

        在写一个项目的时候,遇到了头像修改这个功能的需求,在最开始的学习中发现可以通过type为file的input文件读取图片,然后将其转换为DataUrl格式,最终作为Ima元素的src即可在页面上展示图片。但到后面开始写交互的时候发现DataUrl格式的图片数据太长了,发送请求不是请求头太大就是数据库塞不下,然后开始学习后面的multipart/form-data这种数据传输方式(虽然没用,但学了doge^-^)

前端开发中的 DataUrl:原理、应用与实践

        一、DataUrl 是什么

        DataUrl,即数据 URL,是一种将数据直接嵌入 URL 的方式,其目的是将一些小的数据,直接嵌入到网页中,从而避免额外的网络请求。它的格式遵循特定的规范,基本格式如下:

data:[<mediatype>][;base64],<data>

        其中,mediatype是数据的 MIME 类型,例如image/png表示 PNG 图片,text/plain表示纯文本等;base64是一个可选的参数,当数据需要进行 Base64 编码时使用,一般图片等二进制数据会采用 Base64 编码;最后的<data>部分就是实际的数据内容。

举个简单的例子,一个表示绿色像素点的 DataUrl 如下:

 

data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7

        在这个 DataUrl 中,image/gif表明数据是 GIF 图片类型,base64表示后面的数据经过了 Base64 编码,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7就是编码后的图片数据。

        二、DataUrl 的原理

          DataUrl 的实现原理基于浏览器对 URL 协议的支持和解析。当浏览器遇到一个 DataUrl 时,它会按照上述格式规则对其进行解析,提取出 MIME 类型和数据部分。如果数据是经过 Base64 编码的,浏览器会自动对其进行解码,然后根据 MIME 类型来处理数据。

        以图片为例,当一个 HTML 页面中使用 DataUrl 作为img标签的src属性值时,浏览器解析到该 DataUrl 后,会解码数据并将其渲染为图片,整个过程不需要发起额外的网络请求去获取图片资源。这种方式对于一些小的、不经常变化的资源来说,能够有效减少网络请求次数,提升页面的加载速度。

        三、常见使用场景

(一)小图标嵌入

        在网页设计中,常常会用到一些小图标,如按钮图标、导航图标等。将这些小图标转换为 DataUrl,然后直接嵌入到 CSS 或 HTML 中,可以避免为每个小图标单独发起网络请求。例如,在 CSS 中设置背景图片:

 

.icon {

background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUA...);

}

        这样,当页面加载时,图标会随着 CSS 样式的解析一起呈现,无需额外请求,提高了页面渲染效率。

(二)内联样式和脚本

对于一些简单的 CSS 样式或 JavaScript 脚本,也可以使用 DataUrl 的形式嵌入到 HTML 中。比如,在 HTML 的style标签中嵌入一段 Base64 编码后的 CSS 样式:

 
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><style>body {background: url(data:text/css;base64,LmltZyB7cGFkZGluZzogMTAwcHggMTAwcHg7fQ==);}</style><title>DataUrl示例</title></head><body><!-- 页面内容 --></body></html>

        虽然这种方式在实际项目中不常大规模使用,但在某些特定场景下,如生成动态页面且样式内容较小时,能简化资源管理。

        四、优缺点分析

(一)优点

  1. 减少网络请求:正如前面提到的,将小资源转换为 DataUrl 嵌入页面,避免了额外的 HTTP 请求,对于页面加载速度有显著提升,尤其是在网络环境较差的情况下效果更明显。
  1. 便于资源管理:将资源直接嵌入代码中,不需要单独管理资源文件,在一些小型项目或特定场景下,能简化项目结构和开发流程。
  1. 动态生成资源:可以根据运行时的数据动态生成 DataUrl,实现一些灵活的功能,如根据用户输入生成特定的图片或下载文件。

(二)缺点

  1. 增大文件体积:Base64 编码会使数据体积增加约 1/3 左右,对于较大的资源,转换为 DataUrl 后会使 HTML 或 CSS 文件体积大幅增大,反而影响加载速度,这同时也意味着其不太适合作为请求的数据发送。
  1. 缓存问题:由于 DataUrl 直接嵌入在代码中,浏览器无法像对独立资源文件那样进行有效的缓存管理。如果 DataUrl 中的数据经常变化,会导致每次页面加载都需要重新处理这部分数据。
  1. 可读性和可维护性差:大量的 Base64 编码数据嵌入代码中,会使代码变得冗长且难以阅读和维护,不利于项目的长期迭代和团队协作。

五、FileReader 对象与 DataUrl

        FileReader是 JavaScript 中用于异步读取文件内容的对象,常与DataUrl结合使用,实现将本地文件转换为DataUrl,从而在前端进行处理和展示。

(一)基本用法

FileReader对象有几个重要的方法和事件:

  • readAsDataURL(file):读取指定的文件,并将文件内容以 DataUrl 的形式返回。
  • onload事件:当文件读取成功完成时触发,在该事件回调函数中可以获取到转换后的 DataUrl。
  • onerror事件:当文件读取发生错误时触发。

        以下是一个简单示例,演示如何使用FileReader将用户选择的图片文件转换为 DataUrl 并展示在页面上:

 
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>FileReader与DataUrl示例</title></head><body><input type="file" id="fileInput"><img id="previewImage" src="" alt="图片预览"><script>const fileInput = document.getElementById('fileInput');const previewImage = document.getElementById('previewImage');fileInput.addEventListener('change', function (e) {const file = e.target.files[0];if (file) {const reader = new FileReader();reader.onload = function (event) {const dataUrl = event.target.result;previewImage.src = dataUrl;};reader.onerror = function (error) {console.log('文件读取错误: ', error);};reader.readAsDataURL(file);}});</script></body></html>

        在上述代码中,当用户选择一个图片文件后,通过FileReader的readAsDataURL方法将文件读取为 DataUrl,读取成功后在onload事件中,将得到的 DataUrl 设置为img标签的src属性,从而实现图片的预览功能。

(二)实际应用场景拓展

        在实际项目中,FileReader与DataUrl结合可以应用于更多场景。例如,在图片上传功能中,在将图片发送到服务器之前,可以先使用FileReader将图片转换为 DataUrl 进行本地预览,确认无误后再上传,提升用户体验。还可以在一些表单提交场景中,将用户上传的文件转换为 DataUrl 格式,与其他表单数据一起以 JSON 格式发送到服务器,简化数据传输和处理流程。

六、multipart/form-data

(一)原理

        multipart/form-data是一种在 HTTP 协议中用于发送表单数据的编码方式,特别是在需要上传文件的场景中广泛应用。它将表单数据分割成多个部分,每个部分都有自己的头部信息,描述了数据的类型、名称等信息,各部分之间使用特定的边界字符串进行分隔。服务器接收到数据后,根据边界字符串解析出各个部分的数据,并进行相应的处理 。

例如,当用户在网页上提交一个包含文件和文本字段的表单时,浏览器会按照multipart/form-data的格式将数据封装成类似以下的结构发送给服务器:

 

--boundary

Content-Disposition: form-data; name="username"

JohnDoe

--boundary

Content-Disposition: form-data; name="userfile"; filename="example.txt"

Content-Type: text/plain

这是文件的内容

--boundary--

其中,boundary是自定义的边界字符串,用于区分不同的数据部分。

(二)使用场景

  1. 文件上传:最常见的应用场景就是文件上传,无论是单个文件还是多个文件上传,multipart/form-data都能很好地处理文件数据与其他表单数据(如文件名、文件描述等文本字段)的混合传输。
  1. 表单提交含二进制数据:当表单中除了普通文本数据,还包含图片、音频、视频等二进制数据时,multipart/form-data是理想的选择,能确保各类数据准确无误地发送到服务器。

(三)与 DataUrl、FileReader 的对比

  1. 数据传输方式
    • DataUrl:将数据直接嵌入 URL 中,适用于小数据的内联展示或简单的数据导出,数据会随着 HTML、CSS 等页面代码一起传输。
    • FileReader:主要用于在前端将本地文件读取为特定格式(如 DataUrl),方便在前端进行数据处理和展示,本身不涉及数据向服务器的传输。
    • multipart/form-data:专门用于在 HTTP 请求中将表单数据(包括文件和普通数据)发送到服务器,是一种数据传输协议。
  1. 适用场景
    • DataUrl:适合小图标嵌入、内联样式脚本、小型数据导出等场景。
    • FileReader:常用于需要在前端对本地文件进行处理,如预览图片等场景。
    • multipart/form-data:主要用于文件上传以及包含二进制数据的表单提交。
  1. 优缺点
    • DataUrl:优点是减少网络请求、便于资源管理;缺点是增大文件体积、缓存困难、可读性差。
    • FileReader:优点是方便前端处理本地文件;缺点是仅适用于前端操作,不涉及数据传输到服务器。
    • multipart/form-data:优点是能高效传输复杂表单数据,支持文件上传;缺点是数据格式相对复杂,解析处理需要一定开销。

(四)示例

以下是一个使用multipart/form-data进行文件上传的 HTML 表单示例:

 
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>multipart/form-data示例</title></head><body><form action="upload.php" method="post" enctype="multipart/form-data"><label for="username">用户名:</label><input type="text" id="username" name="username" required><br><label for="userfile">选择文件:</label><input type="file" id="userfile" name="userfile" required><br><input type="submit" value="上传"></form></body></html>

        在上述代码中,通过设置表单的enctype="multipart/form-data"属性,指定了使用multipart/form-data编码方式发送表单数据。服务器端(如upload.php)可以根据这种编码格式解析接收到的数据,提取出用户名和上传的文件。

        七、multipart/form-data在js里面的使用:Form-data

(一)原理

    FormData是HTML5新增的一个接口,用于创建和操作表单数据。它提供了一种简单的方式来收集表单元素的数据,并将其格式化为multipart/form-dataapplication/x-www-form-urlencoded格式,以便通过AJAX请求发送到服务器。

    FormData对象的核心原理是模拟HTML表单的提交过程,将表单中的各个字段(包括文本字段、文件字段等)收集起来,并按照一定的格式组织成键值对。这些键值对可以包含普通文本数据,也可以包含文件对象,然后可以通过XMLHttpRequest或Fetch API发送到服务器。

(二)常用方法与属性

  1. 构造函数

    • new FormData():创建一个空的FormData对象。
    • new FormData(form):从一个HTML表单元素中收集数据,创建FormData对象。
  2. 方法

    • append(name, value):向FormData中添加一个字段,字段名为name,值为value
    • append(name, file, filename):向FormData中添加一个文件字段,file是一个File对象,filename是可选的文件名。
    • delete(name):从FormData中删除所有字段名为name的字段。
    • get(name):获取FormData中第一个字段名为name的字段的值。
    • getAll(name):获取FormData中所有字段名为name的字段的值,返回一个数组。
    • has(name):检查FormData中是否存在字段名为name的字段。
    • set(name, value):设置FormData中字段名为name的字段的值,如果该字段不存在则添加。
    • set(name, file, filename):设置FormData中字段名为name的文件字段的值。
    • entries():返回一个迭代器,用于遍历FormData中的所有键值对。
    • keys():返回一个迭代器,用于遍历FormData中的所有字段名。
    • values():返回一个迭代器,用于遍历FormData中的所有字段值。

(三)应用场景

  1. AJAX表单提交:通过FormData可以方便地将表单数据通过AJAX请求发送到服务器,而不需要手动序列化表单数据。
  2. 文件上传FormData可以轻松处理文件上传,将文件对象添加到FormData中,然后通过AJAX请求发送到服务器。
  3. 动态表单数据处理:在一些需要动态添加或修改表单数据的场景中,FormData提供了灵活的API来操作表单数据。

(四)与其他技术的对比

  1. 与传统表单提交对比

    • 传统表单提交:表单数据会直接提交到服务器,页面会刷新。
    • FormData+AJAX:可以在不刷新页面的情况下异步提交表单数据,提升用户体验。
  2. 与手动序列化表单数据对比

    • 手动序列化:需要自己编写代码将表单数据转换为字符串格式,处理文件上传时比较复杂。
    • FormData:自动处理表单数据的格式,包括文件上传,简化了开发过程。
  3. 与DataUrl对比

    • DataUrl:适合将小数据嵌入到URL中,用于内联展示或简单数据导出。
    • FormData:适合处理复杂的表单数据,尤其是包含文件的表单数据,并将其发送到服务器。

(五)示例

以下是几个使用FormData的示例:

1. 从HTML表单创建FormData并提交

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><title>FormData示例1</title><!-- 引入jQuery --><script src="https://cdn.tailwindcss.com"></script>
</head><body><form id="myForm"><input type="text" name="username" value="John"><input type="email" name="email" value="john@example.com"><input type="file" name="avatar"><button type="button" id="submitBtn">提交</button></form><script>const form = document.getElementById('myForm');const submitBtn = document.getElementById('submitBtn');submitBtn.addEventListener('click', function() {const formData = new FormData(form);$.ajax({url: '/submit',type: 'POST',data: formData,processData: false,  // 不处理数据contentType: false,  // 不设置内容类型success: function(response) {console.log(response);},error: function(error) {console.error('Error:', error);}});});</script>
</body></html>
2. 动态创建FormData并添加数据
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><title>FormData示例2</title><!-- 引入jQuery --><script src="https://cdn.tailwindcss.com"></script>
</head><body><input type="text" id="username" value="Alice"><input type="file" id="fileInput"><button type="button" id="submitBtn">提交</button><script>const usernameInput = document.getElementById('username');const fileInput = document.getElementById('fileInput');const submitBtn = document.getElementById('submitBtn');submitBtn.addEventListener('click', function() {const formData = new FormData();// 添加文本字段formData.append('username', usernameInput.value);// 添加文件字段if (fileInput.files.length > 0) {formData.append('file', fileInput.files[0]);}// 添加额外的数据formData.append('timestamp', new Date().toISOString());$.ajax({url: '/upload',type: 'POST',data: formData,processData: false,  // 不处理数据contentType: false,  // 不设置内容类型success: function(response) {console.log(response);},error: function(error) {console.error('Error:', error);}});});</script>
</body></html>
3. 结合FileReader和FormData实现图片预览和上传

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><title>FormData示例3</title><!-- 引入jQuery --><script src="https://cdn.tailwindcss.com"></script>
</head><body><input type="file" id="imageInput" accept="image/*"><img id="preview" src="" alt="图片预览" style="max-width: 300px;"><button type="button" id="uploadBtn">上传图片</button><script>const imageInput = document.getElementById('imageInput');const preview = document.getElementById('preview');const uploadBtn = document.getElementById('uploadBtn');let selectedFile = null;imageInput.addEventListener('change', function() {if (this.files.length > 0) {selectedFile = this.files[0];// 使用FileReader预览图片const reader = new FileReader();reader.onload = function(e) {preview.src = e.target.result;};reader.readAsDataURL(selectedFile);}});uploadBtn.addEventListener('click', function() {if (!selectedFile) {alert('请先选择图片');return;}const formData = new FormData();formData.append('image', selectedFile);$.ajax({url: '/upload-image',type: 'POST',data: formData,processData: false,  // 不处理数据contentType: false,  // 不设置内容类型success: function(response) {console.log('上传成功:', response);alert('图片上传成功');},error: function(error) {console.error('上传失败:', error);alert('图片上传失败');}});});</script>
</body></html>


头像的修改的话把修改img的src步骤放到请求成功的回调函数里面

        最后本周感悟(也是本月doge//_\\),这段时间做那个新闻资讯类的项目收获很多,但缺点也暴露了出来,代码格式问题不是很大,但复用部分做的不咋滴,这点要改善一下。下一个学习计划已经发下来了,node.js的学习我一定会加倍努力的\*—*/

http://www.xdnf.cn/news/10600.html

相关文章:

  • 第一章:计算机系统概论
  • Y1——链式前向星
  • 在 Linux 服务器上无需 sudo 权限解压/打包 .7z 的方法(实用命令)
  • 21-CS61B-lab6:java文件操作以及持久化一见
  • BiliNote简介
  • 第100期 DL,多输入多输出通道
  • 学习STC51单片机25(芯片为STC89C52RCRC)
  • edg浏览器打开后默认是360界面
  • 某电子计数跳绳的一次修复经历
  • abandon便签:一个免费好用审美在线的桌面便签应用
  • python打卡day43
  • 【Python序列化】TypeError: Object of type xxx is not JSON serializable问题的解决方案
  • 分词算法BBPE详解和Qwen的应用
  • day 40 python打卡
  • Spring框架学习day6--事务管理
  • 【ISAQB大纲解读】信息隐藏指的是什么
  • 基于Qt的app开发的过渡期
  • PH热榜 | 2025-06-01
  • Flex弹性布局
  • langGraph多Agent
  • 【C语言入门级教学】冒泡排序和指针数组
  • ShardingSphere 分片策略深度解析
  • 导入典籍数据
  • 《仿盒马》app开发技术分享-- 购物车业务逻辑完善(端云一体)
  • java 多线程
  • 基于贝叶斯优化神经网络的光伏功率预测综述
  • Java JVM 内存模型详解
  • LeetCode 付费题157. 用 Read4 读取 N 个字符解题思路
  • deep forest安装及使用教程
  • 强大的PDF编辑工具,操作方便 ,长久使用