优化一下博客的性能
This commit is contained in:
1 parent
15421ff0ac
commit
427b17d7a0
24 files changed
+2045
-148
No files matched your search
@@ -1,10 +1,17 @@
|
||||
{{ $src := .Destination }}
|
||||
{{ $alt := .Text }}
|
||||
{{ $width := "" }}
|
||||
{{ $height := "" }}
|
||||
{{ $srcset := "" }}
|
||||
|
||||
{{- if not (strings.HasPrefix $src "http") -}}
|
||||
{{- $img := .Page.Resources.GetMatch $src -}}
|
||||
{{- if $img -}}
|
||||
{{- $src = $img.RelPermalink -}}
|
||||
{{- $width = printf "%d" $img.Width -}}
|
||||
{{- $height = printf "%d" $img.Height -}}
|
||||
{{- else -}}
|
||||
{{- $src = $src | relURL -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
<img src="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" data-lazy-src="{{ $src }}" alt="{{ .Text }}" class="lazyload" uk-scrollspy="cls: uk-animation-fade; delay: 200">
|
||||
<img src="{{ $src }}" alt="{{ $alt }}" class="lazyload lazy-loaded" loading="lazy" decoding="async"{{ with $width }} width="{{ . }}"{{ end }}{{ with $height }} height="{{ . }}"{{ end }}>
|
||||
@@ -6,7 +6,7 @@
|
||||
{{ range $paginator.Pages }}
|
||||
<div class="post">
|
||||
<div class="time">{{ .Date.Format "January 2, 2006" }}</div>
|
||||
<a href="{{ .Permalink }}">{{ .Title }}</a>
|
||||
<a href="{{ .RelPermalink }}">{{ .Title }}</a>
|
||||
</div>
|
||||
{{ end }}
|
||||
</div>
|
||||
|
||||
@@ -90,6 +90,5 @@
|
||||
{{ end }}
|
||||
<!-- 评论区内容结束 -->
|
||||
</div>
|
||||
<script async src="/js/bsz.js"></script>
|
||||
</div>
|
||||
{{ end }}
|
||||
@@ -41,7 +41,7 @@
|
||||
{{ range $paginator.Pages }}
|
||||
<div class="post">
|
||||
<div class="time">{{ .Date.Format "January 2, 2006" }}</div>
|
||||
<a href="{{ .Permalink }}">{{ .Title }}</a>
|
||||
<a href="{{ .RelPermalink }}">{{ .Title }}</a>
|
||||
|
||||
<!-- 计算每篇文章的发布时间与当前时间的差值 -->
|
||||
{{ $publishDate := .Date }}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{{ define "main" }}
|
||||
<div id="pjax-container">
|
||||
<div id="pjax-container" data-needs-echarts="true">
|
||||
<div class="post-content" itemprop="articleBody" uk-scrollspy="target: > *; cls: uk-animation-slide-bottom-small; delay: 100">
|
||||
{{ .Content }}
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
|
||||
<li data-date="{{ $year }}{{ printf "%02d" $month }}{{ .Date.Day }}">
|
||||
<span class="articles_date_time">{{ .Date.Format "01/02" }}</span>
|
||||
<a class="a-archives" href="{{ .Permalink }}">{{ .Title }}</a>
|
||||
<a class="a-archives" href="{{ .RelPermalink }}">{{ .Title }}</a>
|
||||
</li>
|
||||
{{ end }}
|
||||
|
||||
|
||||
@@ -337,6 +337,15 @@
|
||||
allPosts: [],
|
||||
currentIndex: 0,
|
||||
BATCH_SIZE: 10,
|
||||
CACHE_KEY: 'friend-circle-v1',
|
||||
CACHE_OPTIONS: {
|
||||
version: 2,
|
||||
softTtl: 5 * 60 * 1000,
|
||||
hardTtl: 60 * 60 * 1000,
|
||||
validate: function(data) {
|
||||
return !!data && Array.isArray(data.posts);
|
||||
}
|
||||
},
|
||||
|
||||
timeAgo: function (dateStr) {
|
||||
const date = new Date(dateStr);
|
||||
@@ -403,6 +412,74 @@
|
||||
});
|
||||
},
|
||||
|
||||
renderEmpty: function () {
|
||||
const container = document.getElementById("friend-circle-container");
|
||||
if (!container) return;
|
||||
container.innerHTML = '<div class="empty" style="grid-column: 1/-1; text-align:center; padding:20px;">暂无动态</div>';
|
||||
},
|
||||
|
||||
renderError: function () {
|
||||
const container = document.getElementById("friend-circle-container");
|
||||
if (!container) return;
|
||||
container.innerHTML = '<div class="error" style="grid-column: 1/-1; text-align:center; padding:20px; color:#d9534f;">加载失败,请稍后刷新重试</div>';
|
||||
},
|
||||
|
||||
applyData: function (data) {
|
||||
const container = document.getElementById("friend-circle-container");
|
||||
if (!container) return;
|
||||
|
||||
if (!data.posts || data.posts.length === 0) {
|
||||
this.renderEmpty();
|
||||
return;
|
||||
}
|
||||
|
||||
window.FriendCircle.allPosts = data.posts;
|
||||
window.fcUpdateTime = new Date(data.updated).toLocaleString();
|
||||
window.FriendCircle.currentIndex = 0;
|
||||
container.innerHTML = "";
|
||||
window.FriendCircle.loadMore();
|
||||
},
|
||||
|
||||
fetchData: function () {
|
||||
if (window.BrowserCache && typeof window.BrowserCache.log === 'function') {
|
||||
window.BrowserCache.log('[FriendCircleCache][fetch]', {
|
||||
key: window.BrowserCache ? window.BrowserCache.buildKey(window.FriendCircle.CACHE_KEY) : window.FriendCircle.CACHE_KEY,
|
||||
softTtl: window.BrowserCache ? window.BrowserCache.formatDuration(window.FriendCircle.CACHE_OPTIONS.softTtl) : window.FriendCircle.CACHE_OPTIONS.softTtl,
|
||||
hardTtl: window.BrowserCache ? window.BrowserCache.formatDuration(window.FriendCircle.CACHE_OPTIONS.hardTtl) : window.FriendCircle.CACHE_OPTIONS.hardTtl
|
||||
});
|
||||
}
|
||||
return fetch("https://rssapi.usj.cc/api/articles?limit=50")
|
||||
.then(function(res) {
|
||||
if (!res.ok) throw new Error("Network response was not ok");
|
||||
return res.json();
|
||||
})
|
||||
.then(function(apiData) {
|
||||
const posts = (apiData.articles || []).map(function(a) {
|
||||
return {
|
||||
title: a.title || '',
|
||||
link: a.link || '',
|
||||
date: a.pubDate || '',
|
||||
author: a.feedName || a.author || '',
|
||||
avatar: a.favicon || '',
|
||||
blogUrl: a.siteUrl || '',
|
||||
image: null,
|
||||
description: ''
|
||||
};
|
||||
});
|
||||
|
||||
const data = {
|
||||
posts: posts,
|
||||
updated: apiData.timestamp || new Date().toISOString()
|
||||
};
|
||||
|
||||
if (window.BrowserCache) {
|
||||
window.BrowserCache.write(window.FriendCircle.CACHE_KEY, window.FriendCircle.CACHE_OPTIONS, data);
|
||||
}
|
||||
|
||||
return data;
|
||||
});
|
||||
},
|
||||
|
||||
initTooltip: function() {
|
||||
if (this.tooltipInitialized) return;
|
||||
this.tooltipInitialized = true;
|
||||
@@ -476,42 +553,35 @@
|
||||
if (this.isFetching) return;
|
||||
this.isFetching = true;
|
||||
|
||||
// 从 RSS API 拉取按时间排序的文章
|
||||
fetch("https://rssapi.usj.cc/api/articles?limit=50&t=" + new Date().getTime())
|
||||
.then(function(res) {
|
||||
if (!res.ok) throw new Error("Network response was not ok");
|
||||
return res.json();
|
||||
})
|
||||
.then(function(apiData) {
|
||||
// 将 API 格式转换为友圈格式
|
||||
const posts = (apiData.articles || []).map(function(a) {
|
||||
return {
|
||||
title: a.title || '',
|
||||
link: a.link || '',
|
||||
date: a.pubDate || '',
|
||||
author: a.feedName || a.author || '',
|
||||
avatar: a.favicon || '',
|
||||
blogUrl: a.siteUrl || '',
|
||||
image: null,
|
||||
description: ''
|
||||
};
|
||||
const cached = window.BrowserCache && window.BrowserCache.read(this.CACHE_KEY, this.CACHE_OPTIONS);
|
||||
if (cached) {
|
||||
if (window.BrowserCache && typeof window.BrowserCache.log === 'function') {
|
||||
window.BrowserCache.log('[FriendCircleCache][render]', {
|
||||
key: cached.key,
|
||||
age: cached.ageText,
|
||||
isFresh: cached.isFresh,
|
||||
softTtl: cached.softTtlText,
|
||||
hardTtl: cached.hardTtlText
|
||||
});
|
||||
const data = { posts: posts, updated: apiData.timestamp || new Date().toISOString() };
|
||||
}
|
||||
this.applyData(cached.data);
|
||||
if (cached.isFresh) {
|
||||
this.isFetching = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!data.posts || data.posts.length === 0) {
|
||||
container.innerHTML = '<div class="empty" style="grid-column: 1/-1; text-align:center; padding:20px;">暂无动态</div>';
|
||||
return;
|
||||
}
|
||||
|
||||
window.FriendCircle.allPosts = data.posts;
|
||||
window.fcUpdateTime = new Date(data.updated).toLocaleString();
|
||||
window.FriendCircle.currentIndex = 0;
|
||||
container.innerHTML = "";
|
||||
window.FriendCircle.loadMore();
|
||||
this.fetchData()
|
||||
.then(function(data) {
|
||||
window.FriendCircle.applyData(data);
|
||||
})
|
||||
.catch(function(err) {
|
||||
console.error("Friend Circle Error:", err);
|
||||
container.innerHTML = '<div class="error" style="grid-column: 1/-1; text-align:center; padding:20px; color:#d9534f;">加载失败,请稍后刷新重试</div>';
|
||||
if (window.BrowserCache && window.BrowserCache.isDebug && window.BrowserCache.isDebug()) {
|
||||
console.error("Friend Circle Error:", err);
|
||||
}
|
||||
if (!cached) {
|
||||
window.FriendCircle.renderError();
|
||||
}
|
||||
})
|
||||
.finally(function() {
|
||||
window.FriendCircle.isFetching = false;
|
||||
@@ -519,12 +589,18 @@
|
||||
}
|
||||
};
|
||||
|
||||
if (document.readyState === "loading") {
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
function initFriendCirclePage() {
|
||||
if (window.FriendCircle && typeof window.FriendCircle.init === 'function') {
|
||||
window.FriendCircle.init();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener('pjax:complete', initFriendCirclePage);
|
||||
|
||||
if (document.readyState === "loading") {
|
||||
document.addEventListener("DOMContentLoaded", initFriendCirclePage);
|
||||
} else {
|
||||
window.FriendCircle.init();
|
||||
initFriendCirclePage();
|
||||
}
|
||||
</script>
|
||||
</div>
|
||||
|
||||
@@ -78,18 +78,96 @@
|
||||
var list = document.getElementById('links-list');
|
||||
if (!list) return;
|
||||
|
||||
fetch('https://rssapi.usj.cc/api/links?t=' + new Date().getTime())
|
||||
.then(function(res) { return res.json(); })
|
||||
.then(function(data) {
|
||||
var links = data.links || [];
|
||||
if (links.length === 0) return;
|
||||
var html = '';
|
||||
links.forEach(function(l) {
|
||||
html += '<li><a href="' + l.url + '" class="url-name" target="_blank">' + l.name + '</a><span style="margin-left: 13px;">' + (l.description || '') + '</span></li>';
|
||||
var CACHE_KEY = 'friend-links-v1';
|
||||
var CACHE_OPTIONS = {
|
||||
version: 2,
|
||||
softTtl: 6 * 60 * 60 * 1000,
|
||||
hardTtl: 24 * 60 * 60 * 1000,
|
||||
validate: function(data) {
|
||||
return !!data && Array.isArray(data.links);
|
||||
}
|
||||
};
|
||||
|
||||
function escapeHtml(value) {
|
||||
return String(value || '')
|
||||
.replace(/&/g, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/'/g, ''');
|
||||
}
|
||||
|
||||
function renderState(message, className) {
|
||||
list.innerHTML = '<li class="' + className + '">' + escapeHtml(message) + '</li>';
|
||||
}
|
||||
|
||||
function renderLinks(links) {
|
||||
if (!Array.isArray(links) || links.length === 0) {
|
||||
renderState('暂无友链数据', 'links-empty');
|
||||
return;
|
||||
}
|
||||
|
||||
var html = '';
|
||||
links.forEach(function(l) {
|
||||
html += '<li><a href="' + escapeHtml(l.url) + '" class="url-name" target="_blank" rel="noopener noreferrer">' + escapeHtml(l.name) + '</a><span style="margin-left: 13px;">' + escapeHtml(l.description || '') + '</span></li>';
|
||||
});
|
||||
list.innerHTML = html;
|
||||
}
|
||||
|
||||
function logCache(event, payload) {
|
||||
if (window.BrowserCache && typeof window.BrowserCache.log === 'function') {
|
||||
window.BrowserCache.log('[LinksCache][' + event + ']', payload);
|
||||
}
|
||||
}
|
||||
|
||||
function fetchLinks() {
|
||||
logCache('fetch', {
|
||||
key: window.BrowserCache ? window.BrowserCache.buildKey(CACHE_KEY) : CACHE_KEY,
|
||||
softTtl: window.BrowserCache ? window.BrowserCache.formatDuration(CACHE_OPTIONS.softTtl) : CACHE_OPTIONS.softTtl,
|
||||
hardTtl: window.BrowserCache ? window.BrowserCache.formatDuration(CACHE_OPTIONS.hardTtl) : CACHE_OPTIONS.hardTtl
|
||||
});
|
||||
return fetch('https://rssapi.usj.cc/api/links')
|
||||
.then(function(res) {
|
||||
if (!res.ok) throw new Error('Failed to fetch links');
|
||||
return res.json();
|
||||
})
|
||||
.then(function(data) {
|
||||
var links = Array.isArray(data.links) ? data.links : [];
|
||||
var payload = { links: links };
|
||||
window.BrowserCache.write(CACHE_KEY, CACHE_OPTIONS, payload);
|
||||
return payload;
|
||||
});
|
||||
list.innerHTML = html;
|
||||
}
|
||||
|
||||
var cached = window.BrowserCache && window.BrowserCache.read(CACHE_KEY, CACHE_OPTIONS);
|
||||
if (cached) {
|
||||
logCache('render', {
|
||||
key: cached.key,
|
||||
age: cached.ageText,
|
||||
isFresh: cached.isFresh,
|
||||
softTtl: cached.softTtlText,
|
||||
hardTtl: cached.hardTtlText
|
||||
});
|
||||
renderLinks(cached.data.links);
|
||||
if (cached.isFresh) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
renderState('友链加载中...', 'links-loading');
|
||||
}
|
||||
|
||||
fetchLinks()
|
||||
.then(function(payload) {
|
||||
renderLinks(payload.links);
|
||||
})
|
||||
.catch(function() {});
|
||||
.catch(function(err) {
|
||||
if (window.BrowserCache && window.BrowserCache.isDebug && window.BrowserCache.isDebug()) {
|
||||
console.error('Links Error:', err);
|
||||
}
|
||||
if (!cached) {
|
||||
renderState('友链加载失败,请稍后刷新重试', 'links-error');
|
||||
}
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
</div>
|
||||
|
||||
@@ -52,19 +52,20 @@
|
||||
{{ $uikit := resources.Get "js/libs/uikit.min.js" }}
|
||||
{{ $easylazyload := resources.Get "js/modules/lazyload.js" }}
|
||||
{{ $viewimage := resources.Get "js/libs/view-image.min.js" }}
|
||||
{{ $artalk := resources.Get "js/libs/Artalk.js" }}
|
||||
{{ $barrage := resources.Get "js/modules/barrage.js" }}
|
||||
{{ $main := resources.Get "js/main.js" }}
|
||||
{{ $mypjax := resources.Get "js/modules/mypjax.js" }}
|
||||
{{ $nprogress := resources.Get "js/libs/nprogress.js" }}
|
||||
{{ $message := resources.Get "js/libs/message.min.js" }}
|
||||
{{ $echarts := resources.Get "js/libs/echarts.min.js" }}
|
||||
{{ $tiaozhuan := resources.Get "js/modules/tiaozhuan.js" }}
|
||||
{{ $reward := resources.Get "js/modules/reward.js" }}
|
||||
{{ $echarts := resources.Get "js/libs/echarts.min.js" }}
|
||||
{{ $artalk := resources.Get "js/libs/Artalk.js" }}
|
||||
|
||||
{{/* Modules */}}
|
||||
{{ $utils := resources.Get "js/modules/utils.js" }}
|
||||
{{ $loader := resources.Get "js/modules/loader.js" }}
|
||||
{{ $cache := resources.Get "js/modules/cache.js" }}
|
||||
{{ $search := resources.Get "js/modules/search.js" }}
|
||||
{{ $floatingTools := resources.Get "js/modules/floating-tools.js" }}
|
||||
{{ $paragraphComments := resources.Get "js/modules/paragraph-comments.js" }}
|
||||
@@ -72,9 +73,9 @@
|
||||
{{ $artalkModule := resources.Get "js/modules/artalk.js" }}
|
||||
{{ $pjaxLib := resources.Get "js/libs/pjax.js" }}
|
||||
|
||||
{{ $scripts := slice $iconfont $lightgallery $uikit $easylazyload $viewimage $artalk $barrage $utils $loader $search $floatingTools $paragraphComments $infiniteScroll $artalkModule $nprogress $pjaxLib $main $mypjax $message $echarts $tiaozhuan $reward | resources.Concat "js/bundle.js" | resources.Minify | resources.Fingerprint }}
|
||||
{{ $scripts := slice $iconfont $lightgallery $uikit $easylazyload $viewimage $barrage $utils $loader $cache $search $floatingTools $paragraphComments $infiniteScroll $artalkModule $nprogress $pjaxLib $main $mypjax $message $tiaozhuan $reward $echarts $artalk | resources.Concat "js/bundle.js" | resources.Minify | resources.Fingerprint }}
|
||||
|
||||
<script src="{{ $scripts.RelPermalink }}"></script>
|
||||
<script defer src="{{ $scripts.RelPermalink }}"></script>
|
||||
<script>
|
||||
// Global configuration from Hugo
|
||||
window.enableInfiniteScroll = {{ .Site.Params.infiniteScroll.enable | default false }};
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||
<title>{{ .Title }}</title>
|
||||
<!-- SEO & Meta Tags -->
|
||||
<meta name="description" content="{{ if .IsHome }}{{ .Site.Params.description }}{{ else }}{{ .Description | default .Summary | plainify | truncate 160 }}{{ end }}" />
|
||||
<link rel="canonical" href="{{ .Permalink }}" />
|
||||
<link rel="canonical" href="{{ .RelPermalink | absURL }}" />
|
||||
|
||||
{{- $keywords := slice "大学" "教程" "blog" "优世界" "优设计" "博客" "大学生博客" "生活" "文案" -}}
|
||||
{{- if .Params.tags -}}
|
||||
@@ -72,6 +71,7 @@
|
||||
</script>
|
||||
<!-- Preload Fonts -->
|
||||
<link rel="preload" href="{{ "font/zql-v2.woff2" | relURL }}" as="font" type="font/woff2" crossorigin>
|
||||
<link rel="preload" href="{{ "font/remixicon.woff2" | relURL }}" as="font" type="font/woff2" crossorigin>
|
||||
|
||||
<!-- Site Configuration -->
|
||||
<script>
|
||||
@@ -98,12 +98,14 @@
|
||||
{{ $remixicon := resources.Get "css/libs/remixicon.css" }}
|
||||
{{ $uikit := resources.Get "css/libs/uikit.min.css" }}
|
||||
{{ $nprogress := resources.Get "css/libs/nprogress.min.css" }}
|
||||
{{ $artalk := resources.Get "css/libs/Artalk.css" }}
|
||||
{{ $message := resources.Get "css/libs/message.min.css" }}
|
||||
{{ $main := resources.Get "css/main.css" }}
|
||||
|
||||
{{ $style := slice $normalize $remixicon $uikit $nprogress $artalk $message $main | resources.Concat "css/style.css" | resources.Minify | resources.Fingerprint }}
|
||||
{{ $style := slice $normalize $remixicon $uikit $nprogress $message $main | resources.Concat "css/style.css" | resources.Minify | resources.Fingerprint }}
|
||||
{{ $artalk := resources.Get "css/libs/Artalk.css" | resources.Minify | resources.Fingerprint }}
|
||||
|
||||
<link rel="stylesheet" href="{{ $style.RelPermalink }}">
|
||||
<link rel="stylesheet" href="{{ $artalk.RelPermalink }}">
|
||||
|
||||
{{- if and .Site.Params.style.enableBackgroundImage .Site.Params.style.backgroundImageUrl -}}
|
||||
<style>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<div class="header">
|
||||
<div class="header-top">
|
||||
<div class="header-avatar load-memos-editor" id="theme-toggle-avatar">
|
||||
<img src="{{ .Site.Params.author.avatar }}" class="blog-img" width="80" height="80" alt="{{ .Site.Title }}" />
|
||||
<img src="{{ .Site.Params.author.avatar }}" class="blog-img" width="80" height="80" alt="{{ .Site.Title }}" decoding="async" fetchpriority="high" />
|
||||
<div class="avatar-theme-tip">
|
||||
点击头像切换昼夜
|
||||
</div>
|
||||
|
||||
Reference in new issue
Block a user