普通视图

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

让用户愿意等待的秘密:实时图片预览

作者 烟袅破辰
2025年12月21日 16:58

你有没有经历过这样的场景?点击“上传头像”,选了一张照片,页面却毫无反应——没有提示,没有图像,只有一个静默的按钮。你开始怀疑:是没选上?网速慢?还是系统出错了?于是你犹豫要不要再点一次,甚至直接关掉页面。
而如果在你选择文件的瞬间,一张清晰的缩略图立刻出现在眼前,哪怕后端还在处理,你也会安心地等待下去。
不是用户没耐心,而是他们需要一点“确定性”来支撑等待的理由。
图片预览,正是那个微小却关键的信号:你的操作已被接收,一切正在按预期进行。

得到程序正在运行的信号之后用户才会有等待的欲望。

今天,我们就来亲手实现一个图片预览功能。 先思考:要让一张用户选中的本地图片显示在网页上,我们到底需要做些什么?


第一步:我们要显示图片,那肯定得有个 <img> 标签吧?

没错。想在页面上看到图片,最直接的方式就是用 <img :src="xxx" />。但问题来了:用户刚从电脑里选了一张照片,这张照片还在他本地硬盘上,还没传到服务器,也没有公开 URL。那 src 该填什么?

这时候你可能会想:“能不能把这张本地文件直接塞进 src?”
答案是:不能直接塞 File 对象,但——我们可以把它“变成”一个 URL。


第二步:用户选了图,我们怎么拿到它?

通常我们会用 <input type="file" accept="image/*"> 让用户选择图片。在 Vue 中,为了能“拿到”这个 input 元素本身(而不仅仅是它的值),我们会用到 ref

<input 
  type="file" 
  ref="uploadImage" 
  accept="image/*"
  @change="updateImageData"
/>

这里,ref="uploadImage" 就像给这个 input 贴了个标签。之后在 script 里,我们就能通过 uploadImage.value 拿到它的真实 DOM 引用。

于是,在 updateImageData 函数里,我们可以这样取到用户选中的文件:

const input = uploadImage.value;
const file = input.files[0]; // 用户选的第一张图

注意:不是 input.file,而是 input.files —— 这是一个常见的笔误,也是很多初学者卡住的地方。


第三步:有了 File 对象,怎么变成 <img> 能识别的 src

现在我们手里有一个 File 对象,但它不能直接赋给 img.src。我们需要把它转成一种浏览器能直接渲染的格式。

这时候,FileReader 就登场了。

const reader = new FileReader();
reader.readAsDataURL(file);

readAsDataURL 会把文件内容读取为一个 Data URL,格式类似:

data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA...

这串字符串可以直接作为 <img>src!是不是很巧妙?

那什么时候能拿到这个结果呢?FileReader 是异步的,所以我们监听它的 onloadend 事件:

reader.onloadend = (e) => {
  imgPreview.value = e.target.result; // 这就是 Data URL
}

而我们的模板中早已准备好了一个 <img>

<img :src="imgPreview" alt="" v-if="imgPreview" />

imgPreview 有值时,图片就自动显示出来了!


完整逻辑串起来

把这些碎片拼在一起,整个流程就清晰了:

  1. 用户点击 input 选择图片;
  2. @change 触发 updateImageData
  3. 通过 ref 拿到 input,取出 files[0]
  4. FileReader 读取为 Data URL;
  5. 把结果存到响应式变量 imgPreview
  6. Vue 自动更新 <img :src="imgPreview">,图片就出来了。

这整个过程完全在前端完成,不需要上传到服务器,也不依赖任何第三方库——只用了浏览器原生 API 和 Vue 的响应式系统。


最后:完整实例

在view中实现图片预览的完整代码及效果

❌
❌