之前看大家都增加了页码跳转功能,觉得很实用,就抄了过来,顺带把页码的样式整个优化了一下。以前的页码样式一直是 Butterfly 默认的,当时文章少,页码就一个,所以也没觉得不适,但如果后面页数多了,肯定会导致手机端显示错位的问题。就像这样:

旧款页码

所以重新设计一个页码样式是很有必要的。

首先看一下别人的优秀设计。第一个是 @张洪 的博客,洪哥不愧是设计大佬,交互动画和细节处理都是我友链的博客里做的最好的。下图为电脑端的页码样式,该有的功能基本上都有,“上一页”、“下一页”和页码跳转这三个按钮单独设计了优美的交互动画。页码跳转基本结构是一个输入框加一个确认按钮,洪哥将确认按钮覆盖在输入框上方,巧妙的将它们整合成了一个模块,只有当光标移动到模块上方时,输入框才会展开,这样设计既美观又节省了空间。另外,页码跳转功能的逻辑设计考虑的很周全,只支持输入有效范围内的整数,对于超出范围的数会强制转换为最大值,而对于自然数以外的其它字符,则无法输入。输入完页码后,可以通过确认按钮完成跳转,也可以通过回车键完成跳转。

HEO的页码样式(电脑端)

至于手机端的适配,洪哥选择的方案是舍去低频的部件,只保留高频的“上一页”和“下一页”按钮,避免了手机端显示过于臃肿的现象,使得整体效果更加美观。

HEO的页码样式(手机端)

第二个是 @轻笑 的博客,他的手机端和电脑端样式基本一样,都支持页码跳转,因为取消了“上一页”和“下一页”按钮,且缩小了按钮尺寸,所以也不会出现错位的现象,不失为一种好方案。在页码跳转的逻辑功能方面,只支持通过点击跳转按钮完成跳转,不支持回车键跳转,另外对于超出有效范围的页码也没有进行强制转换(实际逻辑上是强制跳转到最后一页,只是前端显示没有做限制)。

轻笑的页码样式

最后看的是 @Leonus 的博客,他的整体样式跟洪哥差不多,逻辑功能也一样,但砍掉了“上一页”、“下一页”和页码跳转三个按钮的交互动画,砍掉了页码跳转的确认按钮,只保留了回车键跳转,这样整体看起来简洁很多,也更契合他的主题。移动端的适配也是采取的跟洪哥一样的方案,只保留“上一页”和“下一页”按钮。

Leonus的页码样式

综合考虑下来决定采用 Leonus 的方案,毕竟我的博客主题也是跟他的更契合。

新版本页码样式(电脑端)

电脑端的样式跟 Leonus 的一样,但手机端我还是希望保留页码跳转等功能,所以我在 Leonus 结构的基础上稍微做了下调整,在仅增加一个按钮的情况下,使其既保留了页码跳转的功能,又保留了当前页码显示功能。另外,不仅主页文章列表,分类页、标签页和归档页等页面也做了同样的适配。

新版本页码样式(手机端)

首先通过order属性将页码输入框移至中间显示,然后通过 js 读取当前页码使其通过页码输入框的placeholder显示出来,这样,就使其同时具备了页码显示和页码跳转的功能。

代码实现

首先 pagination.pug 部分,将页面跳转模块应用到全部,大概在第32行的位置。

1
2
3
4
5
6
7
8
else
nav#pagination
.pagination
if is_home()
- options.format = 'page/%d/#content-inner'
//- 如果是一图流,可以把#content-inner删了
!=paginator(options)
input.toPageInput(placeholder="Go" oninput="value=value.replace(/[^0-9]/g,'')" maxlength="3")

在逻辑代码部分,由于洪哥他们仅支持主页文章列表的页码跳转,并没有对分类页、标签页和归档页的页码做适配,所以这里对原 js 代码做了改进。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
var ctrl = {
toPageJump() {
let e = document.querySelector("#pagination input.toPageInput");
function k(v) {
var p = window.location.pathname, // 获取当前网页相对路径
i = [],
c = -1;
while ((c = p.indexOf('/', c + 1)) !== -1) i.push(c) // i是所有/的索引
var l = i.length
if (l == 1 || p.substring(1, i[l-2]) == "page") return ["/#content-inner", `/page/${v}/#content-inner`]
else if (l >= 4 && p.substring(i[l-3]+1, i[l-2]) == "page") {
var j = p.substring(0, i[l-3]+1)
return [`${j}`, `${j}page/${v}/`]
} else return [`${p}`, `${p}page/${v}/`]
}
e && (e.addEventListener("input", () => {
let t = document.querySelectorAll(".page-number")
, n = t[t.length - 1].innerHTML;
Number(e.value) > n && (e.value = n),
Number(e.value) < 1 && (e.value = "")
}),
e.addEventListener("keyup", t => {
"Enter" == t.key && "" != e.value && "0" != e.value && pjax.loadUrl("1" == e.value ? k(e.value)[0] : k(e.value)[1])
})
)
},

getCurrentPage() {
if (window.innerWidth <= 768 && (document.querySelector("#body-wrap.page.home") || document.getElementById("tag") || document.getElementById("category") || document.getElementById("archive"))) {
var c = document.querySelector(".pagination .page-number.current").innerHTML;
if (c) {
var t = document.querySelector(".pagination .toPageInput");
if (t) {
t.placeholder = "第 " + c + " 页";
}
}
}
}
}

常用的window.location属性:

1
2
3
4
5
6
7
8
console.log(window.location.href);      // 获取完整的 URL 地址
console.log(window.location.protocol); // 获取协议部分(如 "http:" 或 "https:")
console.log(window.location.host); // 获取主机部分(包括域名和端口号)
console.log(window.location.hostname); // 获取主机名部分(不包括端口号)
console.log(window.location.port); // 获取端口号部分
console.log(window.location.pathname); // 获取路径部分
console.log(window.location.search); // 获取查询字符串部分
console.log(window.location.hash); // 获取 URL 锚点部分