依稀记得刚使用hexo的时候, 大部分的照片墙解决方案还是调用Instagram的接口
毕竟这是个很方便上传和管理照片的平台
如今墙一天比一天高, 这方案也基本不灵了
现在博客用上了对象存储作为图片库, 照片墙实现起来也可以有另一套办法了
先整理一下思路, 大概是以下几个步骤
- 上传图片到对象存储仓库, 这个可以写个脚本跑一遍就可以了
但是考虑到页面加载这些图片时候的性能问题
计划是把100张图作为一组, 每组一个目录, 这个目录当中除了这100张图片, 还有一个json文件, 是该组的文件列表
为动态加载提供方便 - 创建自定义页面, 这个hexo本身就支持, 直接在里面写html代码即可
但是由于hexo本身对于md文件的渲染策略, 每一行都会加上<br>
在普通文章里面没什么, 在这个纯html页面就会影响DOM结构, 修改hexo的渲染策略会影响所有页面
所以要注意这个md文件正文不能有换行 - 照片墙页面的布局, 这个准备采用瀑布流的模式, 跟已被关闭的Google plus
(深切缅怀🕯)一样的布局结构 - 分页加载以及滚动加载的一些实现
上传图片
根据这次的需要改造一下图片上传的js脚本
跟之前的差不多, 不过这次引入一个images库
这个库有一些对图片进行操作的API, 准备用它来获取到图片的宽高, 也写入到json文件里面
1 | const argv = { |
其中需要对文件名进行替换修改, 改为在该分组内的正确目录
执行完成后, 对象存储仓库的photo-wall目录下就已经有若干个数字命名的子目录了
每个子目录里面都有至多100张图片和一个json文件
比如第一组中json文件的内容为
1 | { |
创建自定义页面
在source目录下创建photo_wall
目录, 其中创建index.md
文件
1 | --- |
这里写个pageid是为了方便在js当中区分自定义页面
从而执行chunk的动态加载, 避免影响其他页面的加载速度
瀑布流布局
得益于浏览器对多列布局的良好实现, css写起来还是非常简单的
1 | #photo-wall { |
指定列宽, 不指定列数, 根据容器的大小自动适配
虽然指定了列宽, 但是列宽也不是固定的, 这个值相当于是个可允许范围内的最小值 ( 多于1列的情况下 )
比如上面的css当中指定列宽240px, 列间距20px ( 这个值是固定的 )
如果外部容器的宽度600px, 假如排3列, 那么每一列的宽度就是 ( 600 - 20 * 2 ) / 3 ≈ 186.67 < 240
所以无法容纳3列
假如排2列, 那么每一列的宽度是 ( 600 - 20 ) / 2 = 290 > 240
实际就会显示为2列, 每一列的宽度是290px, 列间距20px
换句话说, 就是剩余的宽度会平均分布到各列
滚动加载
有一些第三方库实现了滚动加载, 但是尝试过之后发现无法与现有的整体布局很好地结合
于是决定自己实现一下
photo-wall.js
1 | import axios from 'axios' |
有几点需要注意
- 滚动事件需要使用函数防抖方式, 防止滚动事件频繁触发导致的性能问题
- 对已存在的滚动事件回调函数要注意保留和调用, 避免直接覆盖
- 记录当前分页加载所在的位置, 并在当前分组到达末尾的时候切换到下一个分组
- 当不存在下一个分组时, ajax获取下一个分组的json文件会返回404, 要在catch当中处理没有更多图片的交互逻辑
- 判断是否滚动到容器底部要添加不同浏览器的兼容
- 之前记录下的图片宽高用于指定div在页面中的实际高度, 避免加载过程中频繁打乱整体布局
( 因为图片还未加载完成的时候浏览器也不知道这个图片的实际尺寸 ) 主要目标就是不使用jQuery
动态引入photo-wall.js文件
利用webpack的分块动态引入的功能
1 | if(window.themeConfig.pageid === 'PhotoWall') { |
注释中的webpackChunkName
是webpack可以读取的分块打包声明
该引入会被单独打包为一个chunk