让用户愿意等待的秘密:实时图片预览
你有没有经历过这样的场景?点击“上传头像”,选了一张照片,页面却毫无反应——没有提示,没有图像,只有一个静默的按钮。你开始怀疑:是没选上?网速慢?还是系统出错了?于是你犹豫要不要再点一次,甚至直接关掉页面。
而如果在你选择文件的瞬间,一张清晰的缩略图立刻出现在眼前,哪怕后端还在处理,你也会安心地等待下去。
不是用户没耐心,而是他们需要一点“确定性”来支撑等待的理由。
图片预览,正是那个微小却关键的信号:你的操作已被接收,一切正在按预期进行。
得到程序正在运行的信号之后用户才会有等待的欲望。
今天,我们就来亲手实现一个图片预览功能。 先思考:要让一张用户选中的本地图片显示在网页上,我们到底需要做些什么?
第一步:我们要显示图片,那肯定得有个 <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 有值时,图片就自动显示出来了!
完整逻辑串起来
把这些碎片拼在一起,整个流程就清晰了:
- 用户点击 input 选择图片;
-
@change触发updateImageData; - 通过
ref拿到 input,取出files[0]; - 用
FileReader读取为 Data URL; - 把结果存到响应式变量
imgPreview; - Vue 自动更新
<img :src="imgPreview">,图片就出来了。
这整个过程完全在前端完成,不需要上传到服务器,也不依赖任何第三方库——只用了浏览器原生 API 和 Vue 的响应式系统。
最后:完整实例
在view中实现图片预览的完整代码及效果
![]()