整屏是一张被放大虚化的风景照,中央摆着一张方形主图,右侧竖着一列圆形缩略图,顶部是一个搜索框:“我想看的照片是 ___”。在框里输入关键词,右侧缩略图会即时筛选出匹配的照片;点任意一张,新主图从下方滑上来,旧主图同时向上移出,两张一进一出,背景则用交叉淡入淡出换成新照片的虚化版本。整个切换连贯到几乎察觉不到接缝。
它的巧妙之处在于把“背景”和“主图”用的是同一张照片:背景放大、虚化、压暗,主图清晰居中。这样每换一张,整个页面的色调就随之变化,成本却只有一次图片加载。
这套画廊的四个设计点
切换是双图并行而不是换 src。脚本会新建一张图插进容器,让新旧两张同时存在并各自播放动画,动画结束后再移除旧的。直接改地址会出现一帧空白或旧图闪现,这是这类切换最常见的瑕疵。
加了切换锁。一个布尔变量在动画期间挡住重复点击,避免用户连点导致多张图叠在一起、清理逻辑错乱。
搜索用了防抖。输入事件被包在防抖函数里,停止输入约三百毫秒后才真正执行筛选,连续打字不会触发多次重排。
筛选是本地的。每张照片带标题和一组关键词标签,命中任意一个即保留;没有命中时回退到显示全部,不会给用户一个空白页面。
三处实现细节
其一,动画靠加类名分两拍完成。新图插入后先在下一个时序里加上位移类,而不是同一时刻:源码里用了一个极短的定时器包住加类的动作。原因是元素刚插入 DOM 时还没有完成初始样式的计算,立刻改类名浏览器可能把两个状态合并,过渡就不会播放。这个“插入后隔一拍再改类”的技巧在纯 CSS 过渡里很常用。
其二,清理时按位置而不是按引用移除。动画结束后取容器里的第一张图删掉——因为新图是追加到末尾的,第一张必然是旧图。同时把新图身上的动画类去掉,让它回到静止态,等待下一次成为“旧图”。这套写法保证容器里永远只留一张图,不会随点击次数堆积。
其三,防抖函数是自己写的,只有八行:
clearTimeout(timer); timer = setTimeout(() => func.apply(this, args), timeout);
每次调用都取消上一次的定时器,重新计时。对于搜索这类“只关心最后一次输入”的场景,防抖比节流合适——节流会在打字途中就触发查询,结果闪来闪去。
拿到源码后能改什么
照片数据是脚本顶部的一个数组,每项包含标题、关键词标签、大图路径和缩略图路径。加照片就是加一条,缩略图建议单独准备小尺寸文件,右侧列表会因此加载得很快。关键词用空格分隔,可以给同一张图打多个标签,中英文都行。
若要接后台或图片接口,把筛选函数里的本地过滤换成一次网络请求,拿到结果后组装成同样结构的数组再调用渲染函数即可——渲染与切换逻辑完全不用动。
视觉方面:主图尺寸、缩略图直径与间距、背景的虚化与压暗程度都在样式表里各自一处。滑入的方向由位移动画决定,改成左右滑入只需把纵向位移换成横向。切换时长在样式的过渡与脚本的清理定时器两处,改的时候两边要保持一致,否则会看到旧图提前消失。
运行提示:页面依赖 jQuery(从 CDN 加载),离线环境请先下载到本地。图片位于同目录的子文件夹中,建议用本地服务器打开。字体从网络加载,加载失败会退回系统字体,不影响功能。建议使用近两年版本的 Chrome、Edge、Firefox 或 Safari。详细运行方法请参见压缩包内的帮助文档。
关于这套图片画廊的常见问题
照片很多时右侧列表会不会太长?
会。缩略图列是竖排的,数量多时需要给它加上滚动容器,或者改成分页显示。也可以把筛选做得更细,靠关键词把每次展示的数量控制在十张以内。
能加键盘上下键切换吗?
可以。监听方向键,找到当前选中项的相邻元素并触发一次点击即可,切换锁会自动防止按键过快导致的问题。
手机上怎么用?
主图与缩略图列在窄屏下建议改为上下排列,缩略图改成横向滚动条。切换动画本身在触摸设备上表现一致,不需要额外处理。
切换时背景闪了一下白色是怎么回事?
通常是大图还没加载完就开始了淡入。可以在插入新图后监听它的加载完成事件再启动动画,或者提前把下一张图预载进浏览器缓存。
它适合放在哪里
适合作品集、旅游目的地图库、房产与酒店的房型相册、菜品展示这类“同类照片较多且需要挑选”的页面。搜索框的存在让它比普通轮播更像一个可检索的图库,稍加改造接上后台就是一个轻量的图片管理前台。双图切换、切换锁与防抖筛选的完整写法都在源码里,代码量很小,下载后可查看。