封装评论组件 内置【Twikoo、Waline】✅
This commit is contained in:
parent
bf2bdf1720
commit
3bf613946c
@ -25,7 +25,7 @@
|
||||
- [x] LivePhoto
|
||||
- [x] LaTex 数学公式
|
||||
- [x] 赞赏功能
|
||||
- [x] Twikoo 评论
|
||||
- [x] 评论 - 内置【Twikoo、Waline】
|
||||
- [x] 本地搜索
|
||||
- [x] 标签
|
||||
- [x] 分类
|
||||
|
||||
@ -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",
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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 广告
|
||||
|
||||
@ -46,7 +46,7 @@ top: true
|
||||
- [x] LivePhoto
|
||||
- [x] LaTex数学公式
|
||||
- [x] 赞赏功能
|
||||
- [x] Twikoo 评论
|
||||
- [x] 评论 - 内置【Twikoo、Waline】
|
||||
- [x] 本地搜索
|
||||
- [x] 标签
|
||||
- [x] 分类
|
||||
|
||||
@ -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";
|
||||
<p>{frontmatter.desc}</p>
|
||||
</header>
|
||||
<main><slot /></main>
|
||||
{Twikoo.envId && frontmatter.comment != false && <Comment envId={Twikoo.envId} />}
|
||||
{checkComment() && frontmatter.comment != false && <Comment />}
|
||||
</section>
|
||||
<Aside />
|
||||
</section>
|
||||
|
||||
@ -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";
|
||||
</header>
|
||||
<main><slot /></main>
|
||||
<main class={`${frontmatter.type}-main main`}><section class="vh-space-loading"><span></span><span></span><span></span></section></main>
|
||||
{Twikoo.envId && frontmatter.comment != false && <Comment envId={Twikoo.envId} />}
|
||||
{checkComment() && frontmatter.comment != false && <Comment />}
|
||||
</section>
|
||||
<Aside />
|
||||
</section>
|
||||
|
||||
@ -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 && <GoogleAd className="vh-article-ad" slotID={GoogleAds.articleAD_Slot} />}
|
||||
</footer>
|
||||
{Twikoo.envId && <Comment envId={Twikoo.envId} />}
|
||||
{checkComment() && <Comment />}
|
||||
</article>
|
||||
<Aside />
|
||||
</section>
|
||||
|
||||
@ -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 = '<section class="vh-space-loading"><span></span><span></span><span></span></section>'
|
||||
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) })
|
||||
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 }
|
||||
@ -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) => `<article><a href="${i.link}" target="_blank" rel="noopener nofollow"><header><h2>${i.title}</h2></header><p>${i.content}</p><footer><span><img src="https://icon.bqb.cool/?url=${i.link.split('//')[1].split('/')[0]}" /><em>${i.auther}</em></span><time>${fmtDate(i.date, false)}前</time></footer></a></article>`).join('');
|
||||
// 图片懒加载
|
||||
vhLzImgInit();
|
||||
} catch {
|
||||
vh.Toast('获取数据失败')
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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) => `<article><header><img data-vh-lz-src="https://q1.qlogo.cn/g?b=qq&nk=1655466387&s=640" /><p class="info"><span>.𝙃𝙖𝙣</span><time>${fmtDate(i.date)}前</time></p></header><section class="main">${i.content}</section><footer>${i.tags.map((tag: any) => `<span>${tag}</span>`).join('')}</footer></article>`).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('获取数据失败')
|
||||
}
|
||||
|
||||
23
src/scripts/ViewImage.ts
Normal file
23
src/scripts/ViewImage.ts
Normal file
@ -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(","));
|
||||
}
|
||||
}
|
||||
@ -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" });
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user