diff --git a/conf/artalk.example.simple.yml b/conf/artalk.example.simple.yml index 43e77420..56bac286 100644 --- a/conf/artalk.example.simple.yml +++ b/conf/artalk.example.simple.yml @@ -171,6 +171,7 @@ frontend: content: 300 children: 400 scrollable: false + imgLazyLoad: false reqTimeout: 15000 versionCheck: true pluginURLs: [] diff --git a/conf/artalk.example.yml b/conf/artalk.example.yml index 903fa73a..86cdfb02 100644 --- a/conf/artalk.example.yml +++ b/conf/artalk.example.yml @@ -338,6 +338,8 @@ frontend: children: 400 # Scrollable (scrollable height limit area) scrollable: false + # Image lazy load [false, "native", "data-src"] + imgLazyLoad: false # Request timeout (unit: ms) reqTimeout: 15000 # Version check diff --git a/conf/artalk.example.zh-CN.yml b/conf/artalk.example.zh-CN.yml index 5ef287e2..5ebf44a0 100644 --- a/conf/artalk.example.zh-CN.yml +++ b/conf/artalk.example.zh-CN.yml @@ -343,6 +343,8 @@ frontend: children: 400 # 滚动限高 (允许限高区域滚动) scrollable: false + # 图片懒加载 [false, "native", "data-src"] + imgLazyLoad: false # 请求超时 (单位:毫秒) reqTimeout: 15000 # 版本检测 diff --git a/docs/docs/.vitepress/config.ts b/docs/docs/.vitepress/config.ts index 329372e7..d283eba0 100644 --- a/docs/docs/.vitepress/config.ts +++ b/docs/docs/.vitepress/config.ts @@ -117,6 +117,7 @@ export default defineConfig({ { text: '浏览量统计', link: '/guide/frontend/pv.md' }, { text: 'Latex', link: '/guide/frontend/latex.md' }, { text: '图片灯箱', link: '/guide/frontend/lightbox.md' }, + { text: '图片懒加载', link: '/guide/frontend/img-lazy-load.md' }, { text: 'IP 属地', link: '/guide/frontend/ip-region.md' }, { text: '精简版本', link: '/guide/frontend/artalk-lite.md' }, { text: '置入博客', link: '/guide/frontend/import-blog.md' }, diff --git a/docs/docs/guide/backend/config.md b/docs/docs/guide/backend/config.md index 0fdb0f20..f1000f77 100644 --- a/docs/docs/guide/backend/config.md +++ b/docs/docs/guide/backend/config.md @@ -177,7 +177,7 @@ Artalk.init({ site: 'Artalk 官网' }) 这样,你就无需在侧边栏的[控制中心](../frontend/sidebar.md#控制中心)手动创建站点。 -## 前端配置 `frontend` +## 界面配置 `frontend` 增加 `frontend` 字段内容可以在后端控制前端的配置,详情可参考:[在后端控制前端](/guide/backend/fe-control)。 diff --git a/docs/docs/guide/frontend/config.md b/docs/docs/guide/frontend/config.md index 8708e74a..44d419b3 100644 --- a/docs/docs/guide/frontend/config.md +++ b/docs/docs/guide/frontend/config.md @@ -314,6 +314,17 @@ Artalk.init({ }) ``` +### imgLazyLoad + +**图片懒加载** + +- 类型:`"native"|"data-src"|Boolean` +- 默认值:`false` + +为评论中的图片启用懒加载功能。 + +详情参考:[图片懒加载](./img-lazy-load.md) + ### preview **编辑器实时预览功能** diff --git a/docs/docs/guide/frontend/img-lazy-load.md b/docs/docs/guide/frontend/img-lazy-load.md new file mode 100644 index 00000000..c6164673 --- /dev/null +++ b/docs/docs/guide/frontend/img-lazy-load.md @@ -0,0 +1,53 @@ +# 图片懒加载 + +Artalk 支持为评论中的图片添加懒加载功能,以减少页面加载时间。该功能默认禁用,可在控制中心「设置 - 界面配置」找到「图片懒加载」配置项 (frontend.imgLazyLoad): + +| 配置值 | 说明 | +| --- | --- | +| `native` | 使用浏览器原生的图片懒加载 | +| `data-src` | 使用懒加载库实现图片懒加载 | +| `false` | 禁用图片懒加载 | + +## 浏览器原生 + +当图片懒加载设置为 `native` 时,Artalk 将使用浏览器原生的图片懒加载功能,即为图片标签添加 `loading="lazy"` 属性。例如: + +```html + +``` + +这不需要额外引入库和编写代码,是最简单的方式,但部分浏览器可能不支持该属性,或者实现的懒加载策略不同,详情参考:[MDN - 懒加载](https://developer.mozilla.org/zh-CN/docs/Web/Performance/Lazy_loading)。 + +## 懒加载库 + +使用该方式能确保在不同的浏览器下有一致的表现,并且能定制更多功能,如图片加载动画等。一个博客主题可能自带懒加载库,借助其附带的库,让 Artalk 也同时支持懒加载。 + +当图片懒加载设置为 `data-src` 时,Artalk 将为图片标签添加 `class="lazyload"` 和 `data-src` 属性。例如: + +```html + +``` + +这时,你需要引入一个额外的图片懒加载库:[vanilla-lazyload](https://github.com/verlok/vanilla-lazyload);在页面的 `
` 中添加以下代码: + +```html + +``` + +编写代码,在 Artalk 初始化之前,添加事件监听:当评论列表发生更新后,调用图片懒加载库的 `update` 方法: + +```js +// 初始化图片懒加载库 +const lazyLoadInstance = new LazyLoad({ + elements_selector: '.lazyload', + threshold: 0, +}) + +// 监听 Artalk 事件 +Artalk.use((ctx) => { + ctx.on('list-loaded', () => lazyLoadInstance.update()) +}) + +// 初始化 Artalk +const artalk = Artalk.init({ /* ... */ }) +``` diff --git a/ui/artalk/src/comment/height-limit.ts b/ui/artalk/src/comment/height-limit.ts index 1ccdea14..22fb0178 100644 --- a/ui/artalk/src/comment/height-limit.ts +++ b/ui/artalk/src/comment/height-limit.ts @@ -2,8 +2,8 @@ import * as Utils from '../lib/utils' import $t from '../i18n' export interface IHeightLimitConf { - /** Post expand btn click */ - postExpandBtnClick?: (e: MouseEvent) => void + /** After expand btn click */ + afterExpandBtnClick?: () => void /** Allow Scroll */ scrollable?: boolean } @@ -27,23 +27,27 @@ export function check(conf: IHeightLimitConf, rules: THeightLimitRuleSet) { if (!el) return // set max height to limit the height - if (imgCheck) el.style.maxHeight = `${max + 1}px` // allow 2px more for next detecting + if (imgCheck) el.style.maxHeight = `${max + 1}px` // allow 1px more for next detecting + + let lock = false + const _check = () => { + if (lock) return + if (Utils.getHeight(el) <= max) return // if not exceed the limit, do nothing + + const afterExpandBtnClick = () => { + lock = true // add lock to prevent collapse again after expand when image lazy loaded + conf.afterExpandBtnClick?.() + } - const _apply = () => { - const postBtnClick = conf.postExpandBtnClick !conf.scrollable - ? applyHeightLimit({ el, max, postBtnClick }) + ? applyHeightLimit({ el, max, afterExpandBtnClick }) : applyScrollableHeightLimit({ el, max }) } - // checking - const _check = () => { - if (Utils.getHeight(el) > max) _apply() // 是否超过高度 - } - - _check() // check immediately + // check immediately + _check() - // image check + // check images after loaded if (imgCheck) { // check again when image loaded el.querySelectorAll