前言:
最近想着是能自己写一个博客的,不仅可以练练手,也可以提高一下自己的前端技术,参照了现在主流的框架,像Nextjs、Astro这两个是非常适合去开发这种静态博客的,因为这两种都是内置了对md文档的支持,我们只要专注页面就行了,后面还是选择了Astro框架来搭建博客,感觉Astro 还是很适合静态文档类的网站的,整个项目搭建也是很简单的,参照 Astro官网 就行,官网还有一个直接现成博客模板可以下载,直接在这个现成模板上开发也是可以的,搭建过程不讲述,整体框架可以参照下图,基本差不多都是这种结构,这里主要记录一下:在Astro中实现图片懒加载和分页的功能
图片懒加载实现
实现方法:
- 默认情况下,图片不会载入,而是将图片实际的
src路径存储在data-src属性中。 - 当用户滚动页面,并且图片接近视窗时,JavaScript 会动态地将
data-src的值赋给src属性,触发图片的加载。 - 加载后的图片可以从懒加载图片的数组中删除,这样就不会再次被检查或加载。
- 当所有懒加载的图片都被加载后,事件监听器可以被移除,以减少不必要的性能开销。
效果图:
具体代码:
// 图片懒加载功能
document.addEventListener("DOMContentLoaded", function () {
let lazyImages = [].slice.call(document.querySelectorAll("img.lazyload"));
let active = false;
const lazyLoad = function () {
if (active === false) {
active = true;
setTimeout(function () {
lazyImages.forEach(function (lazyImage) {
if (
lazyImage.getBoundingClientRect().top <= window.innerHeight &&
lazyImage.getBoundingClientRect().bottom >= 0 &&
getComputedStyle(lazyImage).display !== "none"
) {
lazyImage.src = lazyImage.dataset.src;
lazyImage.classList.remove("lazyload");
lazyImages = lazyImages.filter(function (image) {
return image !== lazyImage;
});
if (lazyImages.length === 0) {
document.removeEventListener("scroll", lazyLoad);
window.removeEventListener("resize", lazyLoad);
window.removeEventListener("orientationchange", lazyLoad);
}
}
});
active = false;
}, 200);
}
};
lazyLoad(); // 这里注意下,加载完成时要调用一次
document.addEventListener("scroll", lazyLoad);
window.addEventListener("resize", lazyLoad);
window.addEventListener("orientationchange", lazyLoad);
});
分页实现
1、获取分页数据:
使用Astro中getStaticPaths方法获取分页的数据,Astro 会生成常见的分页属性,包括上一页/下一页链接、总页数等。我们可以用 paginate() 函数根据数组值生成这些页面:[...page].astro
---
import { getCollection, type CollectionEntry } from "astro:content";
import Layout from "../layouts/layout.astro";
import _ from "lodash";
import HomePage from "../pages/home/index.astro";
import type { FrontMatter } from "@/types/posts";
/**
* 此函数基于分页生成所有博客文章的静态路径。
* 它首先从 "blog" 集合获取所有博客文章,
* 然后使用lodash的orderBy函数按日期降序排序文章列表。
* 最后,它通过paginate函数将这个列表分页,
* 每页显示10篇文章。
*
* @param {Object} params - 包含函数所需参数的对象。
* @param {Function} params.paginate - 用于分页文章列表的函数。
* @returns 分页的结果,它包含静态路径的列表等信息。
*/
export async function getStaticPaths({ paginate }) {
// 从 "blog" 集合中获取所有博客文章
const allBlogPosts = await getCollection("blog");
// 将所有文章按文章的date属性进行降序排序
const articleList = _.orderBy(
allBlogPosts,
// 使用文章的'date'属性作为排序依据
[(article) => new Date(article.data.date)],
// 指定为降序排序
["desc"]
);
// 使用传入的paginate函数对文章列表进行分页,设定每页10篇文章
return paginate(articleList, {
pageSize: 10, // 指定每页的文章数量为10
});
}
export interface Props {
page: {
data: CollectionEntry<"posts">[];
start: number;
end: number;
size: number;
total: number;
currentPage: number;
lastPage: number;
url: { current: string; next?: string; prev?: string };
};
}
// 所有分页数据都在 "page" 参数中传递
// 当你使用 paginate() 函数时,每个页面将通过 page 传递数据。page 有很多有用的属性,下面列出最为重要的:
// page.data - 数组,包含你传递给 paginate() 函数的页面数据片段
// page.url.next - 下一个页面的链接
// page.url.prev - 上一个页面的链接
const { page } = Astro.props;
// console.log(page,'page...')
const frontmatter: FrontMatter = {
title: "Nick Blog 首页",
description: "使用了Astro4搭建的一个个人博客",
author: "NickYang",
date: new Date(),
keywords: "Astro4.0 , 个人博客,快速的前端开发框架",
cover: "/images/bg/bg1.jpg",
};
---
<Layout header="home" frontmatter={frontmatter}>
<HomePage pagination={page} />
</Layout>
2、数据渲染:
我们将数据通过props传递到home组件中,然后就可以进行渲染了~
Astro代码:
---
import { Image, Picture } from "astro:assets";
import dayjs from "dayjs";
import _ from "lodash";
import "./index.css";
const { pagination } = Astro.props;
const currentPage = pagination?.currentPage || 0;
const totalPages = pagination?.lastPage || 0;
const url = pagination?.url;
const pageArray = Array.from({ length: totalPages }, (_, i) => i + 1);
const numRegex = /\d+/;
---
渲染数据:
实现分页:
<!-- 分页 -->
<nav id="pagination">
<div class="pagination">
<!-- 上一页 -->
{
url?.prev && (
<a class="extend next" rel="next" href={url?.current?.prev}>
<i class="fas fa-chevron-left fa-fw" />
</a>
)
}
{
totalPages > 1 &&
pageArray.map((page) => {
let targetUrl = url.current;
let currentUrl = url.current;
if (currentUrl == "/") {
currentUrl = "";
}
if (numRegex.test(currentUrl)) {
if (page == 1) {
targetUrl = currentUrl.replace(numRegex, "");
} else {
targetUrl = currentUrl.replace(numRegex, page.toString());
}
} else {
targetUrl = `${currentUrl}/${page}`;
}
return (
<a
class={`page-number ${currentPage == page && "current"}`}
href={targetUrl}
data-astro-prefetch
>
{page}
</a>
);
})
}
<!-- 下一页 -->
{
url?.next && (
<a class="extend next" rel="next" href={url.next} data-astro-prefetch>
<i class="fas fa-chevron-right fa-fw" />
</a>
)
}
</div>
</nav>
效果预览:
总结:
整个框架是基于最新的Astro4.0,现在目前只完成了首页页面和文章内容页面的显示,还有很多的功能都没有去实现,像个人页面、归档等页面,后期再慢慢完善哈~