普通视图

发现新文章,点击刷新页面。
昨天 — 2025年7月5日首页

别再只用 base64!HTML5 的 Blob 才是二进制处理的王者,面试常考

作者 然我
2025年7月5日 17:16

前端开发中,90%的人都不知道:掌握Blob对象处理二进制数据的能力,是突破技术瓶颈的关键!

你是不是还在只用 base64 处理图片?面试官问 “如何高效处理大文件上传” 时一脸懵?其实 HTML5 的 Blob 对象才是二进制处理的 “隐藏王者”—— 它能轻松搞定图片预览、大文件分片、PDF 生成等高级操作,也是前端面试的高频考点。

从一个面试题说起:为什么 base64 不适合大图片?🤦‍♀️

先看一个场景:前端需要预览用户上传的图片。很多人第一反应是转成 base64:

// 传统方式:图片转base64
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => {
  img.src = reader.result; // 类似 "data:image/png;base64,/9j/4AAQSkZJRg..."
};

但面试官追问:“如果用户上传 10MB 的图片,用 base64 有什么问题?”

答案藏在 base64 的原理里:base64 是把二进制数据转成字符串,会让数据体积增加 30% 。10MB 的图片转成 base64 后变成 13MB,不仅浪费带宽,还会让 JS 处理变慢(字符串操作比二进制操作低效)。

image.png

这时候,Blob 对象就要登场了 —— 它能直接操作二进制数据,处理大文件更高效,也是前端处理二进制的 “标准答案”。

Blob 是什么?二进制世界的 “万能容器”😍

Blob 的全称是Binary Large Object(二进制大对象) ,你可以把它理解成一个 “装二进制数据的文件袋”:

  • 里面可以装图片、视频、PDF 等任何二进制数据;
  • 有明确的 “文件类型”(比如image/png);
  • 支持切割、合并等操作,像 “拆快递盒” 一样灵活处理二进制。

对比 base64 和 Blob 的核心区别:

特性 base64 Blob
本质 字符串(二进制的文本编码) 二进制数据对象
体积 比原文件大 30% 和原文件体积相同
操作效率 低(字符串处理慢) 高(直接操作二进制)
适用场景 小图标、简单数据 大文件、复杂二进制处理

简单说:小数据用 base64 方便,大数据用 Blob 高效

实战:Base64图片转Blob全流程🤔

我们用一个 “图片处理” 案例,手把手教你用 Blob:把 base64 格式的图片转成 Blob 对象,再显示到页面上(这是面试常考的转换逻辑)

步骤 1:准备一个 base64 图片(模拟后端返回或本地存储的图片)

假设我们有一张 PNG 图片的 base64 编码(很长,这里简化表示):

const base64Str = "data:image/png;base64,UklGRiAHAABXRUJQVlA4IBQHAACwHACdASpQAFAAP...";

步骤 2:从 base64 中提取纯二进制字符串

base64 编码的格式是data:类型;base64,实际编码,第一步要去掉前缀,只保留后面的二进制编码部分:

// 去掉base64前缀("data:image/png;base64,")
const pureBase64 = base64Str.split(",")[1]; // 结果:"UklGRiAHAABXRUJQVlA4IBQHAACwHACd..."

步骤 3:用 atob () 解码 base64,得到二进制字符串

atob()是浏览器内置的解码函数,能把 base64 字符串转成二进制字符串(注意:这里的 “字符串” 是每个字符对应一个字节的二进制数据):

// 解码base64,得到二进制字符串
const binaryStr = atob(pureBase64);

打印出来将会是这样 image.png

步骤 4:把二进制字符串转成 Uint8Array(二进制数组)

二进制字符串不方便直接操作,需要转成TypedArray(类型化数组) —— 这里用Uint8Array(8 位无符号整数数组),每个元素代表一个字节的二进制数据:

// 创建一个和二进制字符串长度相同的Uint8Array
const uint8Array = new Uint8Array(binaryStr.length);

// 逐个字符转成对应的二进制数值(0-255)
for (let i = 0; i < binaryStr.length; i++) {
  uint8Array[i] = binaryStr.charCodeAt(i);
}

image.png

步骤 5:用 Uint8Array 创建 Blob 对象

有了二进制数组,就能创建 Blob 了,指定正确的 MIME 类型(比如image/png):

// 创建Blob对象(二进制数据+类型)
const blob = new Blob([uint8Array], { type: "image/png" });

image.png

步骤 6:用 URL.createObjectURL () 生成 Blob 的访问地址

Blob 对象不能直接当src用,需要通过URL.createObjectURL()生成一个临时 URL(类似blob:http://localhost/xxx),浏览器能直接识别这个 URL:

// 生成Blob的临时URL
const blobUrl = URL.createObjectURL(blob);

// 显示图片(和用base64的方式一样简单,但更高效)
const img = document.getElementById("myImage");
img.src = blobUrl;

// 注意:用完后要释放URL,避免内存泄漏
img.onload = () => {
  URL.revokeObjectURL(blobUrl);
};

image.png

image.png 运行代码后,图片正常显示,但背后用的是 Blob 而非 base64—— 处理大图片时,你会明显感觉到加载更快、页面更流畅。

面试必背:Blob 的核心 API 和注意事项

1. 核心 API

  • new Blob(blobParts, options):创建 Blob 对象,blobParts是二进制数据数组(如[uint8Array, "字符串", anotherBlob]),options指定type(MIME 类型);
  • URL.createObjectURL(blob):生成 Blob 的临时 URL;
  • URL.revokeObjectURL(url):释放临时 URL,避免内存泄漏;
  • blob.slice(start, end, contentType):切割 Blob,返回新的 Blob(类似字符串的slice)。

2. 注意事项

  • 内存管理URL.createObjectURL()会占用内存,不用时必须用revokeObjectURL释放;
  • 兼容性:Blob 是 HTML5 标准 API,所有现代浏览器都支持(IE10+),不用担心兼容性问题;
  • 与 File 的关系File对象是Blob的子类,所以File能使用所有 Blob 的方法(比如slice)—— 这也是为什么我们能直接切割用户上传的File对象。

最后建议:Blob作为HTML5的底层能力,单独使用不足以成为亮点。但当你能结合文件处理、性能优化、音视频等场景展示其价值时,它将成为你技术深度的完美证明。记住:

"掌握Blob,就掌握了现代Web应用处理二进制数据的钥匙!"

前端高手才知道的秘密:Blob 居然这么强大!

作者 小飞悟
2025年7月5日 16:43

🔍 一、什么是 Blob?

Blob(Binary Large Object)是 HTML5 提供的一个用于表示不可变的、原始二进制数据块的对象。

✨ 特点:

  • 不可变性:一旦创建,内容不能修改。
  • 可封装任意类型的数据:字符串、ArrayBuffer、TypedArray 等。
  • 支持 MIME 类型描述,方便浏览器识别用途。

💡 示例:

const blob = new Blob(['Hello World'], { type: 'text/plain' });

🧠 二、Base64 编码的前世今生

虽然名字听起来像是某种“64进制”,但实际上它是一种编码方式,不是数学意义上的“进制”。

📜 起源背景:

Base64 最早起源于电子邮件协议 MIME(Multipurpose Internet Mail Extensions),因为早期的电子邮件系统只能传输 ASCII 文本,不能直接传输二进制数据(如附件)。于是人们发明了 Base64 编码方法,把二进制数据转换成文本形式,从而安全地在网络上传输。

🧩 使用场景:

场景 说明
图片嵌入到 HTML/CSS 中 Data URI 方式减少请求
JSON 数据中传输二进制信息 如头像、加密数据等
WebSocket 发送二进制消息 避免使用 ArrayBuffer
二维码生成 将图像转为 Base64 存储

⚠️ 注意:Base64 并非压缩算法,它会将数据体积增加约 33%。


🔁 三、从 Base64 到 Blob 的全过程

1. Base64 字符串解码:atob()

JavaScript 提供了一个内置函数 atob(),可以将 Base64 字符串解码为原始的二进制字符串(ASCII 表示)。

const base64Data = 'SGVsbG8gd29ybGQh'; // "Hello world!"
const binaryString = atob(base64Data);

⚠️ 返回的是 ASCII 字符串,不是真正的字节数组。


2. 构建 Uint8Array(字节序列)

为了构造 Blob,我们需要一个真正的字节数组。我们可以用 charCodeAt() 将每个字符转为对应的 ASCII 数值(即 0~255 的整数)。

const byteArray = new Uint8Array(binaryString.length);

for (let i = 0; i < binaryString.length; i++) {
    byteArray[i] = binaryString.charCodeAt(i);
}

现在,byteArray 是一个代表原始图片二进制数据的数组。


3. 创建 Blob 对象

有了字节数组,就可以创建 Blob 对象了:

const blob = new Blob([byteArray], { type: 'image/png' });

这个 Blob 对象就代表了一张 PNG 图片的二进制内容。


4. 使用 URL.createObjectURL() 显示图片

为了让浏览器能够加载这个 Blob 对象,我们需要生成一个临时的 URL 地址:

const imageUrl = URL.createObjectURL(blob);
document.getElementById('blobImage').src = imageUrl;

这样,你就可以在网页中看到这张图片啦!


🛠️ 四、Blob 的核心功能与应用场景

功能 说明
分片上传 .slice(start, end) 方法可用于大文件切片上传
本地预览 Canvas.toBlob() 导出图像,配合 URL.createObjectURL 预览
文件下载 使用 a 标签 + createObjectURL 实现无刷新下载
缓存资源 Service Worker 中缓存 Blob 数据提升性能
处理用户上传 结合 FileReader 和 File API 操作用户文件

🧪 五、Blob 的高级玩法

1. 文件切片上传(分片上传)

const chunkSize = 1024 * 1024; // 1MB
const firstChunk = blob.slice(0, chunkSize);

2. Blob 转换为其他格式

  • FileReader.readAsText(blob) → 文本
  • FileReader.readAsDataURL(blob) → Base64
  • FileReader.readAsArrayBuffer(blob) → Array Buffer

3. Blob 下载为文件

const a = document.createElement('a');
a.href = URL.createObjectURL(blob);
a.download = 'example.png';
a.click();

🧩 六、相关知识点汇总

技术点 作用
Base64 将二进制数据编码为文本,便于传输
atob() 解码 Base64 字符串,还原为二进制字符串
charCodeAt() 获取字符的 ASCII 值(0~255)
Uint8Array 构建字节数组,表示原始二进制数据
Blob 封装二进制数据,作为文件对象使用
URL.createObjectURL() 生成临时地址,让浏览器加载 Blob 数据

🧾 七、完整代码回顾

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <title>Blob 实战</title>
</head>
<body>
  <img src="" id="blobImage" width="100" height="100" alt="Blob Image" />

  <script>
    const base64Data = 'UklGRiAHAABXRUJQVlA4IBQHAACwHACdASpQAFAAPok0lEelIyIhMziOYKARCWwAuzNaQpfW+apU37ZufB5rAHqW2z3mF/aX9o/ev9LP+j9KrqSOfp9mf+6WmE1P1yFc3gTlw8B8d/TebelHaI3mplPrZ+Aa0l5qDGv5N8Tt9vYhz3IH37wqm2al+FdcFQhDnObv2+WfpwIZ+K6eBPxKL2RP6hiC/K1ZynnvVYth9y+ozyf88Obh4TRYcv3nkkr43girwwJ54Gd0iKBPZFnZS+gd1vKqlfnPT5wAwzxJiSk+pkbtcOVP+QFb2uDqUhuhNiHJ8xPt6VfGBfUbTsUzYuKgAP4L9wrkT8KU4sqIHwM+ZeKDBpGq58k0aDirXeGc1Odhvfx+cpQaeas97zVTr2pOk5bZkI1lkF9jnc0j2+Ojm/H+uPmIhS7/BlxuYfgnUCMKVZJGf+iPM44vA0EwvXye0YkUUK...';

    const binaryString = atob(base64Data); // Base64 解码
    const byteArray = new Uint8Array(binaryString.length); // 创建 Uint8Array

    for (let i = 0; i < binaryString.length; i++) {
        byteArray[i] = binaryString.charCodeAt(i); // 填充字节数据
    }

    const blob = new Blob([byteArray], { type: 'image/png' }); // 创建 Blob
    const imageUrl = URL.createObjectURL(blob); // 生成 URL

    document.getElementById('blobImage').src = imageUrl; // 显示图片
  </script>
</body>
</html>

📚 八、扩展阅读建议


🧩 九、结语

Blob 是连接 JavaScript 世界与真实二进制世界的桥梁,是每一个想要突破瓶颈的前端开发者必须掌握的核心技能之一。 掌握了 Blob,你就拥有了操作二进制数据的能力,这在现代 Web 开发中是非常关键的一环。 下次当你看到一张图片在网页中加载出来,或者一个文件被顺利下载时,不妨想想:这一切的背后,都有 Blob 的身影。

昨天以前首页

深入解析WeUI Uploader组件源码:移动端上传组件实现

2025年7月4日 17:04

最近在研究WeUI的源码,发现Uploader组件的设计真的很有意思。我想分享一下对这个组件的深度解析。

为什么要学习WeUI Uploader?

说实话,uploader组件在大厂面试中出现频率真的很高。不仅仅是因为它功能重要,更是因为它背后蕴含的设计思想和编码技巧。通过研究高质量的源码,我们能学到:

  • 语义化标签的正确使用
  • BEM命名规范的实际应用
  • 弹性布局的巧妙运用
  • CSS预处理器的模块化思维
  • 移动端适配的细节处理

整体架构分析

让我们先看看HTML结构,这里的设计很有讲究:

<div class="weui-cells weui-cells_form">
  <div class="weui-cell weui-cell_uploader">
    <div class="weui-cell__bd">
      <div class="weui-uploader">
        <div class="weui-uploader__hd">
          <p class="weui-uploader__title">图片上传</p>
          <div class="weui-uploader__info">
            <span>0</span> / <span>2</span>
          </div>
        </div>
        <div class="weui-uploader__bd">
          <ul class="weui-uploader__files">
            <!-- 文件列表 -->
          </ul>
        </div>
      </div>
    </div>
  </div>
</div>

这个结构乍看复杂,但仔细分析会发现设计得很巧妙:

  • 最外层 .weui-cells 提供了统一的表单容器
  • 中间层 .weui-cell 作为单个表单项的包装
  • 内层 .weui-uploader 才是真正的上传组件

这种层级设计的好处是什么?复用性和一致性.weui-cells 不仅用于uploader,还能用于其他表单元素,保持了整个UI体系的一致性。

移动端适配的精妙细节

在CSS实现中,有几个细节特别值得关注:

1. 滚动优化

.page {
  overflow: scroll;
  -webkit-overflow-scrolling: touch;
}

这里的 -webkit-overflow-scrolling: touch 是个神奇的属性。它能让移动端的滚动更加顺滑,感知touch事件更敏感。虽然是webkit前缀的实验性属性,但在移动端(iOS和Android都基于webkit内核)使用效果很好。

2. 弹性布局的应用

.weui-uploader__hd {
  display: flex;
  align-items: center;
}
.weui-uploader__title {
  flex: 1;
}

这里用flex布局来处理标题和计数器的对齐,flex: 1 让标题占据剩余空间,计数器自然靠右对齐。简洁而优雅。

3. 伪元素的巧妙运用

.weui-cells::before {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  height: 1px;
  background-color: #86e98c;
  z-index: 2;
}

用伪元素画分割线,这比直接用border要灵活得多,可以精确控制线条的位置和样式。

Stylus预处理器的威力

项目中使用了Stylus作为CSS预处理器,这里有几个值得学习的技巧:

变量系统

$weui-bg-0 = #6ad8eb
$weui-bg-2 = #fff
$weui-fg-1 = #c177e6 
$weui-fg-2 = #888
$weui-fg-3 = #86e98c

这套变量命名很有规律:bg表示背景色,fg表示前景色,数字表示层级。这种命名方式让主题切换变得非常简单。

嵌套语法的优势

.weui-uploader
  .weui-uploader__hd
    display flex
    .weui-uploader__title
      flex 1
    .weui-uploader__info
      color $weui-fg-2

Stylus的嵌套语法让CSS结构更清晰,配合BEM命名规范,代码可读性大大提升。

float布局的考量

在文件列表的实现中,使用了float布局:

.weui-uploader__file {
  float: left;
  margin-right: 8px;
  margin-bottom: 8px;
  width: 96px;
  height: 96px;
}

可能有人会问:都2024年了,为什么不用grid或flex?

其实这里有几个考虑:

  1. 兼容性:float布局兼容性最好,特别是在一些老旧的webview中
  2. 性能:对于简单的网格布局,float的性能开销更小
  3. 灵活性:float布局在处理不等高元素时更加灵活

BEM命名规范的实践

整个组件严格遵循BEM命名规范:

  • Block(块).weui-uploader
  • Element(元素).weui-uploader__hd.weui-uploader__bd
  • Modifier(修饰符).weui-cell_uploader

这种命名方式的好处是:

  1. 语义明确,一眼就能看出元素的作用
  2. 避免样式冲突
  3. 便于维护和扩展

实际开发中的应用

在实际项目中,我们可以基于这个设计思路来优化自己的组件:

// 编译命令
// stylus -w common.styl -o common.css

这个编译命令告诉我们,项目采用了watch模式,修改styl文件后自动编译成CSS。这种开发方式大大提高了效率。

成果展示(换了颜色)

image.png

总结

通过分析WeUI Uploader组件的源码,我们学到了很多有价值的技巧:

  1. 分层设计思维:通过合理的层级结构提高复用性
  2. 移动端优化:关注细节,提升用户体验
  3. CSS预处理器:变量系统和嵌套语法的合理运用
  4. 命名规范:BEM规范让代码更易维护
  5. 技术选型:根据实际需求选择合适的布局方案

这些技巧不仅适用于组件开发,在日常的前端开发中都很有参考价值。希望这篇分析能帮助大家更好地理解移动端UI组件的设计思路。

最后想说的是,学习源码不是为了炫技,而是为了提升我们的代码质量和设计思维。每一个看似简单的组件背后,都蕴含着开发者的智慧和经验。

❌
❌