From 3bf613946c601f2c3395c35e3ba8b6ed993a3898 Mon Sep 17 00:00:00 2001
From: Han <1655466387@qq.com>
Date: Tue, 25 Mar 2025 17:27:12 +0800
Subject: [PATCH] =?UTF-8?q?=20=E5=B0=81=E8=A3=85=E8=AF=84=E8=AE=BA?=
=?UTF-8?q?=E7=BB=84=E4=BB=B6=20=E5=86=85=E7=BD=AE=E3=80=90Twikoo=E3=80=81?=
=?UTF-8?q?Waline=E3=80=91=E2=9C=85?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
README.md | 2 +-
package.json | 7 +-
src/components/ArticleCard/ArticleCard.less | 1 +
src/components/Comment/Comment.less | 104 ++++++++++++++++++
src/config.ts | 15 ++-
.../blog/Astro主题优雅的vhAstro-Theme.md | 2 +-
src/layouts/PageLayout/PageLayout.astro | 5 +-
src/layouts/ToolLayout/ToolLayout.astro | 5 +-
src/pages/article/[...article].astro | 5 +-
src/scripts/Comment.ts | 47 +++++---
src/scripts/Friends.ts | 4 +
src/scripts/Init.ts | 12 +-
src/scripts/Talking.ts | 7 --
src/scripts/ViewImage.ts | 23 ++++
src/scripts/vhLazyImg.ts | 8 +-
src/styles/ArticleBase.less | 11 +-
16 files changed, 215 insertions(+), 43 deletions(-)
create mode 100644 src/scripts/ViewImage.ts
diff --git a/README.md b/README.md
index fa55151..ba2db47 100644
--- a/README.md
+++ b/README.md
@@ -25,7 +25,7 @@
- [x] LivePhoto
- [x] LaTex 数学公式
- [x] 赞赏功能
-- [x] Twikoo 评论
+- [x] 评论 - 内置【Twikoo、Waline】
- [x] 本地搜索
- [x] 标签
- [x] 分类
diff --git a/package.json b/package.json
index 51b77d1..87bcbe0 100644
--- a/package.json
+++ b/package.json
@@ -7,7 +7,9 @@
"build": "astro build",
"preview": "astro preview",
"astro": "astro",
- "newpost": "node ./script/newpost.js"
+ "newpost": "node ./script/newpost.js",
+ "offdev": "astro preferences disable devToolbar",
+ "ondev": "astro preferences enable devToolbar"
},
"dependencies": {
"@astrojs/mdx": "^4.2.1",
@@ -15,7 +17,7 @@
"@astrojs/sitemap": "^3.3.0",
"@swup/astro": "^1.5.0",
"aplayer": "^1.10.1",
- "astro": "^5.5.3",
+ "astro": "^5.5.4",
"overlayscrollbars": "^2.11.1",
"vanilla-lazyload": "^19.1.3",
"vh-plugin": "^1.2.2"
@@ -24,6 +26,7 @@
"@playform/compress": "^0.1.7",
"@types/dplayer": "^1.25.5",
"@types/nprogress": "^0.2.3",
+ "@waline/client": "^3.5.6",
"cheerio": "^1.0.0",
"dayjs": "^1.11.13",
"less": "^4.2.2",
diff --git a/src/components/ArticleCard/ArticleCard.less b/src/components/ArticleCard/ArticleCard.less
index f7b0f56..d206c21 100644
--- a/src/components/ArticleCard/ArticleCard.less
+++ b/src/components/ArticleCard/ArticleCard.less
@@ -6,6 +6,7 @@ section.article-list {
grid-template-columns: repeat(3, 1fr);
gap: 1.6rem;
width: 100%;
+ min-width: 0;
height: max-content;
overflow: hidden;
diff --git a/src/components/Comment/Comment.less b/src/components/Comment/Comment.less
index bf3dc8b..37b7d1c 100644
--- a/src/components/Comment/Comment.less
+++ b/src/components/Comment/Comment.less
@@ -319,4 +319,108 @@
}
}
}
+
+ div[data-waline] {
+ // 头像尺寸和圆角
+ --waline-avatar-size: 2.56rem;
+ --waline-avatar-radius: 0.58rem;
+ font-size: var(--vh-size-h2);
+
+ .wl-cards {
+ &>.wl-card-item {
+ padding-left: 0;
+
+ .wl-card {
+ padding-bottom: 0;
+
+ &>.wl-head {
+ .wl-nick {
+ color: var(--vh-black-100);
+ font-size: var(--vh-size-h2);
+ line-height: 1.18;
+
+ &::after {
+ position: absolute;
+ content: "";
+ right: 0;
+ left: auto;
+ bottom: 0;
+ width: 0;
+ height: 1px;
+ background-color: var(--vh-black-88);
+ transition: all 0.28s;
+ }
+
+ &:hover {
+ &::after {
+ left: 0;
+ right: auto;
+ width: 100%;
+ }
+ }
+ }
+ }
+
+ // &>.wl-meta {}
+
+ &>.wl-content {
+ padding: 0;
+
+ p {
+ padding: 0.18rem 0;
+ color: var(--vh-black-100);
+ font-size: var(--vh-size-span);
+ line-height: 1.75rem;
+ }
+
+ &>p {
+ &:nth-of-type(1) {
+ padding: 0;
+ }
+
+ a {
+ color: var(--vh-black-100);
+ font-size: 0.76rem;
+ font-weight: 700;
+ }
+ }
+ }
+
+ &>.wl-quote {
+ border-left: solid 0.25rem var(--vh-main-color-38);
+ }
+ }
+
+ // item 中 wl-card 虚线间距
+ &>.wl-card {
+ padding-bottom: 1.25rem;
+ border-bottom-color: var(--vh-black-16);
+ }
+ }
+ }
+
+ // 图片
+ img {
+ &:not(.wl-user-avatar, .wl-reaction-list img) {
+ max-height: 66px;
+ object-fit: contain;
+ cursor: zoom-in;
+ cursor: -moz-zoom-in;
+ cursor: -webkit-zoom-in;
+ }
+
+ &.tk-owo-emotion {
+ max-height: 28px;
+ cursor: default;
+ }
+ }
+
+ a {
+ color: var(--vh-black-100);
+ }
+
+ code {
+ font-size: 0.68rem;
+ }
+ }
}
\ No newline at end of file
diff --git a/src/config.ts b/src/config.ts
index 738f988..dc076d8 100644
--- a/src/config.ts
+++ b/src/config.ts
@@ -40,8 +40,19 @@ export default {
],
// 博客音乐组件解析接口
vhMusicApi: 'https://music.zhheo.com/meting-api/',
- // 评论组件 Twikoo
- Twikoo: { envId: '' },
+ // 评论组件(只允许同时开启一个)
+ Comment: {
+ // Twikoo 评论
+ Twikoo: {
+ enable: false,
+ envId: ''
+ },
+ // Waline 评论
+ Waline: {
+ enable: false,
+ serverURL: ''
+ }
+ },
// Han Analytics 统计(https://github.com/uxiaohan/HanAnalytics)
HanAnalytics: { enable: true, server: 'https://analytics.vvhan.com', siteId: 'Hello-HanHexoBlog' },
// Google 广告
diff --git a/src/content/blog/Astro主题优雅的vhAstro-Theme.md b/src/content/blog/Astro主题优雅的vhAstro-Theme.md
index 2cf13c8..89cff4e 100644
--- a/src/content/blog/Astro主题优雅的vhAstro-Theme.md
+++ b/src/content/blog/Astro主题优雅的vhAstro-Theme.md
@@ -46,7 +46,7 @@ top: true
- [x] LivePhoto
- [x] LaTex数学公式
- [x] 赞赏功能
-- [x] Twikoo 评论
+- [x] 评论 - 内置【Twikoo、Waline】
- [x] 本地搜索
- [x] 标签
- [x] 分类
diff --git a/src/layouts/PageLayout/PageLayout.astro b/src/layouts/PageLayout/PageLayout.astro
index b16d975..fefe0f4 100644
--- a/src/layouts/PageLayout/PageLayout.astro
+++ b/src/layouts/PageLayout/PageLayout.astro
@@ -2,12 +2,13 @@
const { frontmatter } = Astro.props;
// 页面 Info
import SITE_CONFIG from "@/config";
-const { Description, Twikoo, Title } = SITE_CONFIG;
+const { Description, Title } = SITE_CONFIG;
// Aside组件
import Aside from "@/components/Aside/Aside.astro";
// 公共 Layout
import Layout from "@/layouts/Layout/Layout.astro";
// 评论组件
+import { checkComment } from "@/scripts/Comment";
import Comment from "@/components/Comment/Comment.astro";
// 关于样式
import "@/styles/About.less";
@@ -23,7 +24,7 @@ import "@/styles/ArticleBase.less";
{frontmatter.desc}
- {Twikoo.envId && frontmatter.comment != false && }
+ {checkComment() && frontmatter.comment != false && }
diff --git a/src/layouts/ToolLayout/ToolLayout.astro b/src/layouts/ToolLayout/ToolLayout.astro
index 2e7d651..521cb4a 100644
--- a/src/layouts/ToolLayout/ToolLayout.astro
+++ b/src/layouts/ToolLayout/ToolLayout.astro
@@ -2,12 +2,13 @@
const { frontmatter } = Astro.props;
// 页面 Info
import SITE_CONFIG from "@/config";
-const { Description, Twikoo, Title } = SITE_CONFIG;
+const { Description, Title } = SITE_CONFIG;
// Aside组件
import Aside from "@/components/Aside/Aside.astro";
// 公共 Layout
import Layout from "@/layouts/Layout/Layout.astro";
// 评论组件
+import { checkComment } from "@/scripts/Comment";
import Comment from "@/components/Comment/Comment.astro";
// ToolLayout 布局样式
import "./ToolLayout.less";
@@ -24,7 +25,7 @@ import "@/styles/ArticleBase.less";
- {Twikoo.envId && frontmatter.comment != false && }
+ {checkComment() && frontmatter.comment != false && }
diff --git a/src/pages/article/[...article].astro b/src/pages/article/[...article].astro
index 5af86e3..e4837c6 100644
--- a/src/pages/article/[...article].astro
+++ b/src/pages/article/[...article].astro
@@ -14,7 +14,7 @@ import getCover from "@/utils/getCover";
const ARTICLE_COVER: string = await getCover(post.data.cover);
// 页面 Info
import SITE_CONFIG from "@/config";
-const { Site, Title, Author, Twikoo, GoogleAds } = SITE_CONFIG;
+const { Site, Title, Author, GoogleAds } = SITE_CONFIG;
// 处理文章内容
const description = getDescription(post);
const { Content, remarkPluginFrontmatter } = await render(post);
@@ -29,6 +29,7 @@ import Copyright from "@/components/Copyright/Copyright.astro";
// Reward 组件
import Reward from "@/components/Reward/Reward.astro";
// 评论组件
+import { checkComment } from "@/scripts/Comment";
import Comment from "@/components/Comment/Comment.astro";
// Google 广告组件
import GoogleAd from "@/components/GoogleAd/GoogleAd.astro";
@@ -70,7 +71,7 @@ import "@/styles/ArticleBase.less";
{GoogleAds.ad_Client && GoogleAds.articleAD_Slot && }
- {Twikoo.envId && }
+ {checkComment() && }
diff --git a/src/scripts/Comment.ts b/src/scripts/Comment.ts
index c0e1ee6..44a5210 100644
--- a/src/scripts/Comment.ts
+++ b/src/scripts/Comment.ts
@@ -1,22 +1,37 @@
import SITE_INFO from "@/config";
-// 图片灯箱
-import "@public/assets/js/view-image.min.js";
-declare const ViewImage: any;
import { LoadScript } from "@/utils/index";
declare const twikoo: any;
-// 处理评论区数据
-const formateComment = () => {
- // 图片灯箱
- ViewImage && ViewImage.init(".vh-container>article.vh-article-main img.vh-article-img, main.talking-main>article>.main img, .vh-comment>.twikoo>.tk-comments img:not(.tk-avatar-img,.tk-owo-emotion,.OwO-item img)");
- // 处理 URL
- document.querySelectorAll('.vh-comment a[href="#"]').forEach(link => link.removeAttribute('href'));
-}
-// 初始化评论插件
-export default async () => {
- const commentDOM = '.vh-comment>section'
- if (!document.querySelector(commentDOM) || !SITE_INFO.Twikoo.envId) return formateComment();
+// Twikoo 评论
+const TwikooFn = async (commentDOM: string) => {
document.querySelector(commentDOM)!.innerHTML = ''
await LoadScript("https://registry.npmmirror.com/twikoo/1.6.41/files/dist/twikoo.all.min.js");
- twikoo.init({ envId: SITE_INFO.Twikoo.envId, el: commentDOM, onCommentLoaded: () => setTimeout(formateComment) })
-}
\ No newline at end of file
+ twikoo.init({ envId: SITE_INFO.Comment.Twikoo.envId, el: commentDOM, onCommentLoaded: () => setTimeout(() => document.querySelectorAll('.vh-comment a[href="#"]').forEach(link => link.removeAttribute('href'))) })
+}
+
+// Waline 评论
+const WalineFn = async (commentDOM: string, walineInit: any) => {
+ import('@waline/client/waline.css');
+ import('@waline/client/waline-meta.css');
+ const { init } = await import('@waline/client');
+ walineInit = init({ el: commentDOM, serverURL: SITE_INFO.Comment.Waline.serverURL });
+}
+
+// 检查是否开启评论
+const checkComment = () => {
+ const CommentARR: any = Object.keys(SITE_INFO.Comment);
+ const CommentItem = CommentARR.find((i: keyof typeof SITE_INFO.Comment) => SITE_INFO.Comment[i].enable);
+ return CommentItem;
+}
+
+// 初始化评论插件
+const commentInit = async (key: string, walineInit: any) => {
+ // 评论列表
+ const CommentList: any = { TwikooFn, WalineFn };
+ // 评论 DOM
+ const commentDOM = '.vh-comment>section'
+ // 初始化评论
+ CommentList[`${key}Fn`](commentDOM, walineInit);
+}
+
+export { checkComment, commentInit }
\ No newline at end of file
diff --git a/src/scripts/Friends.ts b/src/scripts/Friends.ts
index 925a1b3..c1d00de 100644
--- a/src/scripts/Friends.ts
+++ b/src/scripts/Friends.ts
@@ -2,6 +2,8 @@
import vh from 'vh-plugin'
import { fmtDate } from '@/utils/index'
import { $GET } from '@/utils/index'
+// 图片懒加载
+import vhLzImgInit from "@/scripts/vhLazyImg";
const FriendsInit = async (data: any) => {
const friendsDOM = document.querySelector('.vh-container>.vh-tools-main>main.friends-main')
@@ -12,6 +14,8 @@ const FriendsInit = async (data: any) => {
res = await $GET(api);
}
friendsDOM.innerHTML = res.map((i: any) => `${i.content}
`).join('');
+ // 图片懒加载
+ vhLzImgInit();
} catch {
vh.Toast('获取数据失败')
}
diff --git a/src/scripts/Init.ts b/src/scripts/Init.ts
index 4b22a25..e4ec7c8 100644
--- a/src/scripts/Init.ts
+++ b/src/scripts/Init.ts
@@ -13,6 +13,8 @@ import BackTopInitFn from "@/scripts/BackTop";
import { searchFn, vhSearchInit } from "@/scripts/Search";
// 图片懒加载
import vhLzImgInit from "@/scripts/vhLazyImg";
+// 图片灯箱
+import ViewImage from "@/scripts/ViewImage";
// 顶部导航 Current 状态
import initLinkCurrent from "@/scripts/Header";
// 底部网站运行时间
@@ -24,7 +26,7 @@ import initFriends from "@/scripts/Friends";
// 动态说说初始化
import initTalking from "@/scripts/Talking";
// 文章评论初始化
-import initComment from "@/scripts/Comment";
+import { checkComment, commentInit } from "@/scripts/Comment";
// 移动端侧边栏初始化
import initMobileSidebar from "@/scripts/MobileSidebar";
// Google 广告
@@ -39,6 +41,7 @@ import SmoothScroll from "@/scripts/Smoothscroll";
// 页面初始化 Only
const videoList: any[] = [];
const MusicList: any[] = [];
+let commentLIst: any = { walineInit: null };
const indexInit = async (only: boolean = true) => {
// 预加载搜索数据
only && searchFn("");
@@ -57,9 +60,11 @@ const indexInit = async (only: boolean = true) => {
// 初始化文章代码块
codeInit();
// 文章评论初始化
- initComment();
+ checkComment() && commentInit(checkComment(), commentLIst)
// 图片懒加载初始化
vhLzImgInit();
+ // 图片灯箱
+ only && ViewImage();
// 友情链接初始化
initLinks();
// 朋友圈 RSS 初始化
@@ -85,6 +90,9 @@ export default () => {
inRouter(() => indexInit(false));
// 离开当前页面时触发
outRouter(() => {
+ // 销毁评论
+ commentLIst.walineInit && commentLIst.walineInit.destroy();
+ commentLIst.walineInit = null;
// 销毁播放器
videoList.forEach((i: any) => i.destroy());
videoList.length = 0;
diff --git a/src/scripts/Talking.ts b/src/scripts/Talking.ts
index 61ddfe3..596e3ee 100644
--- a/src/scripts/Talking.ts
+++ b/src/scripts/Talking.ts
@@ -4,10 +4,6 @@ import { fmtDate } from '@/utils/index'
import { $GET } from '@/utils/index'
// 图片懒加载
import vhLzImgInit from "@/scripts/vhLazyImg";
-// 灯箱JS初始化======
-import "@public/assets/js/view-image.min.js";
-declare const ViewImage: any;
-// 灯箱JS初始化======
const TalkingInit = async (data: any) => {
const talkingDOM = document.querySelector('.vh-container>.vh-tools-main>main.talking-main')
@@ -20,9 +16,6 @@ const TalkingInit = async (data: any) => {
talkingDOM.innerHTML = res.map((i: any) => `![]()
.𝙃𝙖𝙣
`).join('');
// 图片懒加载
vhLzImgInit();
- // 灯箱JS初始化======
- setTimeout(() => (ViewImage && ViewImage.init("main.talking-main>article>.main img, .vh-comment>.twikoo>.tk-comments img:not(.tk-avatar-img,.tk-owo-emotion,.OwO-item img)")));
- // 灯箱JS初始化======
} catch {
vh.Toast('获取数据失败')
}
diff --git a/src/scripts/ViewImage.ts b/src/scripts/ViewImage.ts
new file mode 100644
index 0000000..003aa55
--- /dev/null
+++ b/src/scripts/ViewImage.ts
@@ -0,0 +1,23 @@
+
+import { LoadScript } from "@/utils/index";
+// 图片灯箱
+declare const ViewImage: any;
+const ViewImgList: string[] = [
+ // 文章内图片
+ ".vh-container>article.vh-article-main img.vh-article-img",
+ // 动态页面图片
+ "main.talking-main>article>.main img",
+ // Twikoo 评论区图片
+ ".vh-comment>.twikoo>.tk-comments img:not(.tk-avatar-img,.tk-owo-emotion,.OwO-item img)",
+ // Waline 评论区图片
+ ".vh-comment div[data-waline] img:not(.wl-user-avatar,.wl-avatar img,.wl-reaction-list img)"
+];
+// 初始化
+export default async () => {
+ try {
+ ViewImage.init(ViewImgList.join(","));
+ } catch (error) {
+ await LoadScript("/assets/js/view-image.min.js");
+ ViewImage.init(ViewImgList.join(","));
+ }
+}
diff --git a/src/scripts/vhLazyImg.ts b/src/scripts/vhLazyImg.ts
index b110d66..b6d13d1 100644
--- a/src/scripts/vhLazyImg.ts
+++ b/src/scripts/vhLazyImg.ts
@@ -2,6 +2,7 @@
import LazyLoad from "vanilla-lazyload";
// 初始化图片懒加载
+let lazyLoadStatus: any = null;
export default () => {
document.querySelectorAll("main>.vh-container img:not(.view-image-container)").forEach((i: any) => {
// 是否包含data-vh-lz-src
@@ -10,9 +11,6 @@ export default () => {
i.setAttribute("src", '/assets/images/lazy-loading.webp');
}
});
- new LazyLoad({
- elements_selector: "img:not(.view-image-container)",
- threshold: 0,
- data_src: "vh-lz-src"
- });
+ if (lazyLoadStatus) return lazyLoadStatus.update();
+ lazyLoadStatus = new LazyLoad({ elements_selector: "img:not(.view-image-container)", threshold: 0, data_src: "vh-lz-src" });
}
\ No newline at end of file
diff --git a/src/styles/ArticleBase.less b/src/styles/ArticleBase.less
index 62a7643..39f0106 100644
--- a/src/styles/ArticleBase.less
+++ b/src/styles/ArticleBase.less
@@ -131,6 +131,15 @@
a {
color: #49B1F5;
+ transition: all .16s;
+
+ &:hover {
+ color: #1b99ee;
+ }
+
+ span {
+ color: currentColor;
+ }
}
th {
@@ -165,7 +174,7 @@
}
&:hover {
- background-color: #f2f2f2;
+ background-color: #f2f2f266;
}
}