下文所有短代码在实际使用中都需要是双括号
24.08.27
搭建
按照 塔塔老师的教程 搭建了博客!
换主题
然后在主题里翻看了半天选定了 stack,刚好塔塔老师有一个 魔改版!用上了!
研究 favicon 的第一天,失败。
24.08.29
留言
照着 官方文档 顺利地装上了 waline 的留言功能!
然后在 vercel 配置了 DISABLE_USERANGENT value 为 true,最后自定义偷懒也用了塔塔老师 分享的!
文章内插入播放器
在大家的友链之间穿梭看见了爱海老师超级可爱的博客以及超级炫酷的播放器惊呼这个我也要!
照着爱海的装修日志:■■Loading:《hugo装修日志05》■■,虽然暗黑模式下歌名的颜色有点问题但是文章中插入的姑且成功装上了!
在 layouts\partials\head.html:
<!-- require APlayer -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/aplayer/dist/APlayer.min.css">
<script src="https://cdn.jsdelivr.net/npm/aplayer/dist/APlayer.min.js"></script>
<!-- require MetingJS -->
<script src="https://cdn.jsdelivr.net/npm/meting@2/dist/Meting.min.js"></script>
使用:
<meting-js
server="netease"
theme="#232c34"
type="song"
id="2088204761">
</meting-js>
但是全局播放器一直报错,看不懂,遂摆。
24.08.30
全局播放器
毫无基础地问了一系列白痴问题,被 chatgpt 一边鼓励一边极有耐心地教会了!
不用人机验证的话绝对是完美的老师!!!
(怀疑报错是找来的 ncm to mp3 转换器导致的,总之在舍弃了原定六首歌的歌单只保留了非 ncm 的一首后问题完全解决。这么一讲好像 chatgpt 也没有起到什么作用。)
于是有全局播放器了!
目前歌单:
i wasnt allowed to watch whose line as a kid but i think its pretty good now
Chores
Something Good
To All Of You
24.08.31
favicon
毫无头绪地连续失败三天 history 里充斥了我的尝试我无助地在烤鱼哀嚎。
被爱海老师搭救,毫无希望地再次尝试并神秘地功了!!
这是!就和 puzzle 解不出就去 puzzle 群哀嚎一句就能获得群 buff 然后灵光一闪一样!
这是!友邻 buff!!
24.10.02
bilibili 视频插入
塔塔老师魔改的 stack 里其实原本就自带这个,但是没用明白?
总之插入之后视频变得太小小一个,根本看不清内容。
换成了在 ■■Loading:《hugo装修日志07》■■ 里看到的代码,非常成功!
在 \layouts\shortcodes\bilibili.html 中:
<div align=center class="aspect-ratio">
<iframe
src="//player.bilibili.com/player.html?bvid={{.Get 0 }}&page={{ if .Get 1 }}{{.Get 1}}{{ else }}1{{end}}&autoplay=0&as_wide=1&danmaku=0"
scrolling="no"
frameborder="no"
framespacing="0"
allowfullscreen="true"
>
</iframe>
</div>
<style>
.aspect-ratio {
position: relative;
width: 100%;
height: 0;
padding-bottom: 75%;
}
.aspect-ratio iframe {
position: absolute;
width: 100%;
height: 100%;
left: 0;
top: 0;
}
</style>
使用:
{< bilibili BV1cW421K776 >}
24.10.19
更换字体
作为全角半角符号小警察看这个全角引号不顺眼很久了!
今天终于做中学换了个字体解决了这个问题嘻嘻!
换成了塔塔老师在小雪 | 天黑得早,适合看点家长里短 中提到的 京華老宋体。
解决了引号问题!
然后就在正在写这段的时候突然想着检查一下,一看果然没有解决! (特地在中文网字计划的网站预览过引号,没有问题才捣鼓着换了,所以一开始很自信不会再异常了(x
哈哈 是 Hugo 的问题呢错怪字体了。
(Hexo 也有一样的问题。)
解决方式是在 config.yaml 里改成这样:
markup:
goldmark:
renderer:
unsafe: true
extensions:
typographer: false
参考:
字体就先接着用京华老宋体了。
修改了 aplayer 的 css!
虽然经历了很多波折,但是也顺带把 aplayer 的样式也改了!
现在能在 darkmode 下完美显示了!
24.10.20
quote 短代码的样式
变化就是加上了 <i></i>(x
<blockquote class="quote{{ range .Params }} {{ . }}{{ end }}">
{{- $content := .Inner | markdownify -}}
{{- if not (strings.HasPrefix $content "<p>") }}
{{ printf `<p><i>%s</i></p>` $content | safeHTML }}
{{- else }}
{{- $content }}
{{- end -}}
</blockquote>
作品卡片
作品卡片用的是爱海老师在 ■■Loading:《hugo装修日志05》■■ 中的代码,修改了一下 css。 非常非常酷功能!!
cloudflare 图床、域名服务器
捣鼓途中惊觉会需要很多图片,就想着把图床也搭好这样后续插入图片方便一点!
然后自定义域名只能绑定 cloudflare 托管的,又顺带把域名服务器迁移到了 cloudflare,解决了没办法稳定地直连的问题。
24.12.29
文本黑幕\高斯模糊
这两个的代码都可以在 Hugo|在Stack主题上可行的短代码们 这篇文章里找到。
文本黑幕:
.shady {
color:#000;
font-weight: bold;
box-shadow: 0px -20px 0px rgba(0,0,0,1) inset;
transition: all 0.3s ease;
}
.shady:hover{
font-weight: bold;
color:#FFF;
box-shadow: 0px -20px 0px rgba(0,0,0,1) inset;
}
.swiper-container {
max-width: 450px;
max-height: 750px;
margin: 2em auto;
}
.swiper-slide {
text-align: center;
font-size: 18px;
background-color: #fff;
/* Center slide text vertically */
display: flex;
justify-content: center;
align-items: center;
img {
margin: 0 !important;
}
}
文本高斯模糊:
.blur {
color: transparent;
text-shadow:0px 0px 8px var(--card-text-color-main)
}
.blur:hover {
color: transparent;
text-shadow:0px 0px 0px var(--card-text-color-main)
}
协议
改成了“UNAUTHORIZED COPYING AND REPLICATION ARE PROHIBITED”
YouTube 视频插入
YouTube 视频插入虽然早在我写 CHRONICLE 03 的时候就装上了但还是写在这里。
在 layout/shortcodes/youtube.html:
{{- $pc := .Page.Site.Config.Privacy.YouTube -}}
{{- if not $pc.Disable -}}
{{- $ytHost := cond $pc.PrivacyEnhanced "www.youtube-nocookie.com" "www.youtube.com" -}}
{{- $id := .Get "id" | default (.Get 0) -}}
<div class="video-wrapper">
<iframe loading="lazy"
src="https://{{ $ytHost }}/embed/{{ $id }}{{ with .Get "autoplay" }}{{ if eq . "true" }}?autoplay=1{{ end }}{{ end }}"
allowfullscreen
title="YouTube Video"
>
</iframe>
</div>
{{ end -}}
使用示例:
{< youtube "视频 ID" >}
25.11.23
标签块样式
其实 241229 那天就在搞这个,但是一直报错。
今天写大 repo 实在想用这个就又捣鼓了。终于用上了!
依然是这篇:Hugo|在Stack主题上可行的短代码们
但是结合了这个乱修改了一通没想到莫名其妙成功了。
在 layout/shortcodes/notice.html:
{{/* Available notice types: warning, info, note, tip */}}
{{- $noticeType := .Get 0 | default "note" -}}
{{/* Workaround markdownify inconsistency for single/multiple paragraphs */}}
{{- $raw := (markdownify .Inner | chomp) -}}
{{- $block := findRE "(?is)^<(?:address|article|aside|blockquote|canvas|dd|div|dl|dt|fieldset|figcaption|figure|footer|form|h(?:1|2|3|4|5|6)|header|hgroup|hr|li|main|nav|noscript|ol|output|p|pre|section|table|tfoot|ul|video)\\b" $raw 1 -}}
{{ $icon := (replace (index $.Site.Data.SVG $noticeType) "icon" "icon notice-icon") }}
<div class="notice {{ $noticeType }}" {{ if len .Params | eq 2 }} id="{{ .Get 1 }}" {{ end }}>
<div class="notice-title">{{ $icon | safeHTML }}</div>
{{- if or $block (not $raw) }}{{ $raw }}{{ else }}<p>{{ $raw }}</p>{{ end -}}
</div>
在 assets/scss/cutom.scss:
.notice {
position:relative;
padding: 1em 1em 1em 2.5em;
margin-bottom: 1em;
border-radius: 4px;
p:last-child {
margin-bottom: 0;
}
.notice-title {
position: absolute;
left: 0.8em;
.notice-icon {
width: 1.2em;
height: 1.2em;
}
}
&.notice-warning {
background: hsla(0, 65%, 65%, 0.15);
border-left: 5px solid hsl(0, 65%, 65%);
.notice-title {
color: hsl(0, 65%, 65%);
}
}
&.notice-info {
background: hsla(30, 80%, 70%, 0.15);
border-left: 5px solid hsl(30, 80%, 70%);
.notice-title {
color: hsl(30, 80%, 70%);
}
}
&.notice-note {
background: hsla(200, 65%, 65%, 0.15);
border-left: 5px solid hsl(200, 65%, 65%);
.notice-title {
color: hsl(200, 65%, 65%);
}
}
&.notice-tip {
background: hsla(140, 65%, 65%, 0.15);
border-left: 5px solid hsl(140, 65%, 65%);
.notice-title {
color: hsl(140, 65%, 65%);
}
}
}
[data-theme="dark"] .notice {
&.notice-warning {
background: hsla(0, 25%, 35%, 0.15);
border-left: 5px solid hsl(0, 25%, 35%);
.notice-title {
color: rgba(224, 108, 108, 0.5);
}
}
&.notice-info {
background: hsla(30, 25%, 35%, 0.15);
border-left: 5px solid hsl(30, 25%, 35%);
.notice-title {
color: rgba(240, 178, 117, 0.5);
}
}
&.notice-note {
background: hsla(200, 25%, 35%, 0.15);
border-left: 5px solid hsl(200, 25%, 35%);
.notice-title {
color: rgba(108, 185, 224, 0.5);
}
}
&.notice-tip {
background: hsla(140, 25%, 35%, 0.15);
border-left: 5px solid hsl(140, 25%, 35%);
.notice-title {
color: rgba(108, 224, 147, 0.5);
}
}
}
在 data/SVG.toml:
# Notice Icon
notice-warning = '<svg xmlns="http://www.w3.org/2000/svg" class="icon" viewBox="0 0 576 512" fill="hsl(0, 65%, 65%)"><path d="M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zM124 296c-6.6.0-12-5.4-12-12v-56c0-6.6 5.4-12 12-12h264c6.6.0 12 5.4 12 12v56c0 6.6-5.4 12-12 12H124z"/></svg>'
notice-info = '<svg xmlns="http://www.w3.org/2000/svg" class="icon" viewBox="0 0 512 512" fill="hsl(30, 80%, 70%)"><path d="M256 8a248 248 0 100 496 248 248 0 000-496zm0 110a42 42 0 110 84 42 42 0 010-84zm56 254c0 7-5 12-12 12h-88c-7 0-12-5-12-12v-24c0-7 5-12 12-12h12v-64h-12c-7 0-12-5-12-12v-24c0-7 5-12 12-12h64c7 0 12 5 12 12v100h12c7 0 12 5 12 12v24z"/></svg>'
notice-note = '<svg xmlns="http://www.w3.org/2000/svg" class="icon" viewBox="0 0 512 512" fill="hsl(200, 65%, 65%)"><path d="M504 256a248 248 0 11-496 0 248 248 0 01496 0zm-248 50a46 46 0 100 92 46 46 0 000-92zm-44-165l8 136c0 6 5 11 12 11h48c7 0 12-5 12-11l8-136c0-7-5-13-12-13h-64c-7 0-12 6-12 13z"/></svg>'
notice-tip = '<svg xmlns="http://www.w3.org/2000/svg" class="icon" viewBox="0 0 512 512" fill="hsl(140, 65%, 65%)"><path d="M504 256a248 248 0 11-496 0 248 248 0 01496 0zM227 387l184-184c7-6 7-16 0-22l-22-23c-7-6-17-6-23 0L216 308l-70-70c-6-6-16-6-23 0l-22 23c-7 6-7 16 0 22l104 104c6 7 16 7 22 0z"/></svg>'
26.02.02
CHRONICLE 序号
按年份加入了 S0x。
不太算装修日志但是也写在这里!
26.02.09
misskey 贴文插入短代码
在 layout/shortcodes/misskey.html:
{{- $host := .Get "host" | default (.Get 0) | default "stelpolva.moe" -}}
{{- $id := .Get "id" | default (.Get 1) -}}
{{- $random := delimit (shuffle (seq 1 9)) "" | truncate 6 "" -}}
<iframe
src="https://{{ $host }}/embed/notes/{{ $id }}"
data-misskey-embed-id="v1_{{ $random }}"
loading="lazy"
referrerpolicy="strict-origin-when-cross-origin"
style="border: none; width: 100%; max-width: 500px; height: 300px; color-scheme: light dark;"
></iframe>
<script defer src="https://{{ $host }}/embed.js"></script>
使用示例:
{< misskey id="帖子 ID" >}
不是星屑站的话需要另外 host="实例" 写明,或者把上面的 default "stelpolva.moe" 替换成你自己所在的实例。
26.04.15
图片轮播
在 layout/shortcodes/imgloop.html:
{{ if .Site.Params.enableimgloop }}
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/Swiper/3.4.2/css/swiper.min.css">
<!-- Swiper -->
<div class="swiper-container">
<div class="swiper-wrapper">
{{$itItems := split (.Get 0) ","}}
{{range $itItems }}
<div class="swiper-slide">
<img src="{{.}}" alt="">
</div>
{{end}}
</div>
<!-- Add Pagination -->
<div class="swiper-pagination"></div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Swiper/3.4.2/js/swiper.min.js"></script>
<!-- Initialize Swiper -->
<script>
var swiper = new Swiper('.swiper-container', {
pagination: '.swiper-pagination',
paginationClickable: true,
//自动调节高度
autoHeight: true,
//键盘左右方向键控制
keyboardControl : true,
//鼠标滑轮控制
mousewheelControl : true,
//自动切换
//autoplay : 5000,
//懒加载
lazyLoading : true,
lazyLoadingInPrevNext : true,
//无限循环
loop : true,
});
</script>
{{ end }}
然后在 assets/scss/cutom.scss:
.swiper-container {
max-width: 450px;
max-height: 750px;
margin: 2em auto;
}
.swiper-slide {
text-align: center;
font-size: 18px;
background-color: #fff;
/* Center slide text vertically */
display: flex;
justify-content: center;
align-items: center;
img {
margin: 0 !important;
}
}
这里我额外限制了高度,然后按 15.5:9 改了宽度。主要是太爱放大图了,在电脑上看起来观感很不好......
最后去 config.yaml 里 params 下加入 enableimgloop: true 就好了。
edit:
为了能让图片轮播也顺利用上灯箱,把 layout/shortcodes/imgloop.html 修改成了 一旦开始装修就会没完没了02中的代码:
{{ if .Site.Params.enableimgloop }}
<div class="swiper-container">
<div class="swiper-wrapper">
{{$itItems := split (.Get 0) ","}}
{{range $itItems }}
<div class="swiper-slide">
<img src="{{.}}" alt="" data-fancybox>
</div>
{{end}}
</div>
<!-- Add Pagination -->
<div class="swiper-pagination"></div>
</div>
<script>
// 动态加载 CSS 文件
function loadCSS(url) {
var link = document.createElement("link");
link.rel = "stylesheet";
link.href = url;
document.head.appendChild(link);
}
// 动态加载 JS 文件
function loadJS(url, callback) {
var script = document.createElement("script");
script.src = url;
script.onload = callback;
document.body.appendChild(script);
}
// 封装 Swiper 初始化逻辑
function initializeSwiper() {
// 加载 Swiper 的 CSS
loadCSS("https://cdnjs.cloudflare.com/ajax/libs/Swiper/3.4.2/css/swiper.min.css");
// 加载 Swiper JS 并在加载完成后初始化
loadJS("https://cdnjs.cloudflare.com/ajax/libs/Swiper/3.4.2/js/swiper.min.js", function() {
var swiper = new Swiper('.swiper-container', {
pagination: '.swiper-pagination',
paginationClickable: true,
autoHeight: true,
keyboardControl: true,
mousewheelControl: true,
lazyLoading: true,
lazyLoadingInPrevNext: true,
loop: true,
});
swiper.on('init', function () {
var slides = document.querySelectorAll('.swiper-slide');
slides.forEach(function (slide) {
var images = slide.querySelectorAll('.img-zoomable');
images.forEach(function (image) {
mediumZoom(image, {
margin: 32,
background: '#00000054',
scrollOffset: 128,
});
});
});
});
});
}
// 页面初次加载时调用
document.addEventListener('DOMContentLoaded', function () {
initializeSwiper();
});
// PJAX 加载完成后调用
document.addEventListener('pjax:complete', function () {
initializeSwiper();
});
</script>
{{ end }}
FancyBox 灯箱
参考:
- 一旦开始装修就会没完没了02
跟着这个步骤做,灯箱效果放大后的图片会大到不能接受的程度...... - Hugo 使用 Fancybox 实现图片灯箱/放大功能
这个倒是完全成功了,但是放弃不了给轮播也实现上的想法,继续折腾。
没想到最后是改了图片轮播的插件成功的...姑且先这样吧。
总之我目前的办法是:
先在 footer.html 或 head.html 中加入:
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/jquery.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fancyapps/[email protected]/dist/fancybox.css">
<script src="https://cdn.jsdelivr.net/npm/@fancyapps/[email protected]/dist/fancybox.umd.js"></script>
然后在 render-image.html 里加入:
<div class="post-img-view">
<a data-fancybox="gallery" href="{{ .Destination | safeURL }}">
<img src="{{ .Destination | safeURL }}" alt="{{ .Text }}" {{ with .Title}} title="{{ . }}"{{ end }} />
</a>
</div>
26.04.16
修改配色
这个就没什么好写的,直接在 assets/scss/variables.scss 里修改就好了。
26.04.17
系列文章
这个抄起来很简单!
layouts\shortcodes\seriesbox.html:
{{ $series := index .Page.Params.series 0 }}
{{ $open := true }}
{{ $uid := substr (md5 $series) 0 8 }}
{{ if .IsNamedParams }}
{{ with .Get "open" }}
{{ $open = eq (lower .) "true" }}
{{ end }}
{{ else if ge (len .Params) 1 }}
{{ $arg := .Get 0 }}
{{ $open = eq (lower $arg) "true" }}
{{ end }}
{{ if $series }}
{{ $pages := where site.RegularPages "Params.series" "intersect" (slice $series) }}
{{ $pages = where $pages ".Params.series_order" "!=" nil }}
{{ $pages = sort $pages "Params.series_order" }}
{{ if gt (len $pages) 1 }}
<details id="series-{{ $uid }}" class="series-box" {{ if $open }}open{{ end }}>
<summary class="series-title" style="cursor: pointer; font-weight: bold; margin-bottom: 10px;">
本文属于 <strong>{{ $series }}</strong> 系列
</summary>
<div class="series-list-container">
<ol class="series-list">
{{ range $pages }}
<li>
<a href="{{ .RelPermalink }}" class="{{ if eq $.Page.Permalink .Permalink }}active{{ end }}">
{{ printf "§ %d. %s" .Params.series_order .Title }}
</a>
</li>
{{ end }}
</ol>
</div>
</details>
<script>
(function() {
const container = document.querySelector('#series-{{ $uid }} .series-list');
const activeLink = container ? container.querySelector('.active') : null;
if (!container) return;
const maskBoth = 'linear-gradient(to bottom, transparent 0%, black 1.5rem, black calc(100% - 1.5rem), transparent 100%)';
const maskTop = 'linear-gradient(to bottom, transparent 0%, black 1.5rem, black 100%)';
const maskBottom = 'linear-gradient(to bottom, black 0%, black calc(100% - 1.5rem), transparent 100%)';
const maskNone = 'none';
const updateMask = () => {
const { scrollTop, scrollHeight, clientHeight } = container;
const isTop = scrollTop <= 1;
const isBottom = Math.abs(scrollHeight - clientHeight - scrollTop) <= 1;
const isNoScroll = scrollHeight <= clientHeight;
let currentMask;
if (isNoScroll) {
currentMask = maskNone;
} else if (isTop) {
currentMask = maskBottom;
} else if (isBottom) {
currentMask = maskTop;
} else {
currentMask = maskBoth;
}
container.style.setProperty('--active-mask', currentMask);
};
container.addEventListener('scroll', updateMask);
requestAnimationFrame(() => {
if (activeLink) {
activeLink.scrollIntoView({
block: 'center',
inline: 'nearest'
});
}
setTimeout(updateMask, 50);
});
})();
</script>
{{ end }}
{{ end }}
custom.scss:
.series-box {
border-radius: 0.5rem;
// padding: 1rem;
margin: 2rem 0;
}
.series-box summary,
.series-box .series-title {
font-weight: 600;
// margin-bottom: 0.75rem;
cursor: pointer;
}
.series-box ol.series-list {
padding-left: 1.25rem;
// margin: 0.5rem 0 0 0;
}
.series-box li {
margin: 0.25rem 0;
list-style: none;
}
.series-box a {
color: var(--link-color);
text-decoration: none;
box-shadow: none;
}
.series-box a.active {
font-weight: bold;
color: var(--highlight);
}
.series-list-container {
position: relative;
max-height: 12rem;
overflow: hidden;
}
.series-list {
max-height: 9rem;
overflow-y: auto;
margin: 0;
padding: 0 10px 0 20px;
scroll-behavior: smooth;
scrollbar-width: none;
-ms-overflow-style: none;
--mask-top: linear-gradient(to bottom, transparent 0%, black 1.5rem);
--mask-bottom: linear-gradient(to top, transparent 0%, black 1.5rem);
-webkit-mask-image: var(--active-mask, linear-gradient(to bottom, transparent, black 1.5rem, black calc(100% - 1.5rem), transparent));
mask-image: var(--active-mask, linear-gradient(to bottom, transparent, black 1.5rem, black calc(100% - 1.5rem), transparent));
}
.series-list::-webkit-scrollbar {
display: none;
}
使用的时候在文章 FrontMatter 上写上:
series:
- Series
series_order: 1
再在文章内容中写上:
{< seriesbox >}
26.04.19
Waline 迁移
LeanCloud 要停止服务了所以紧急迁移一下。
照着 官方的 TiDB 文档 弄了半天一直报错,干脆重新在 vercel 创建了一个新的 project。
总之现在 官方的快速部署文档 也不是 LeanCloud 了,就照着从零折腾了一下。
代码块 Copy 按钮
在 static/js/codecopy.js:
var codeblocks = document.getElementsByTagName("pre")
//循环每个pre代码块,并添加 复制代码
for (var i = 0; i < codeblocks.length; i++) {
//显示 复制代码 按钮
currentCode = codeblocks[i]
currentCode.style = "position: relative;"
var copy = document.createElement("div")
copy.style = "position: absolute;right: 4px;\
top: 4px;background-color: white;padding: 2px 8px;\
margin: 8px;border-radius: 4px;cursor: pointer;\
z-index: 9999;\
box-shadow: 0 2px 4px rgba(0,0,0,0.05), 0 2px 4px rgba(0,0,0,0.05);"
copy.innerHTML = "Copy"
currentCode.appendChild(copy)
//让所有 "复制"按钮 全部隐藏
copy.style.visibility = "hidden"
}
for (var i = 0; i < codeblocks.length; i++) {
!function (i) {
//鼠标移到代码块,就显示按钮
codeblocks[i].onmouseover = function () {
codeblocks[i].childNodes[1].style.visibility = "visible"
}
//执行 复制代码 功能
function copyArticle(event) {
const range = document.createRange();
//范围是 code,不包括刚才创建的div
range.selectNode(codeblocks[i].childNodes[0]);
const selection = window.getSelection();
if (selection.rangeCount > 0) selection.removeAllRanges();
selection.addRange(range);
document.execCommand('copy');
codeblocks[i].childNodes[1].innerHTML = "Copied!"
setTimeout(function () {
codeblocks[i].childNodes[1].innerHTML = "ReCopy"
}, 1000);
//清除选择区
if (selection.rangeCount > 0) selection.removeAllRanges(); 0
}
codeblocks[i].childNodes[1].addEventListener('click', copyArticle, false);
}(i);
!function (i) {
//鼠标从代码块移开 则不显示复制代码按钮
codeblocks[i].onmouseout = function () {
codeblocks[i].childNodes[1].style.visibility = "hidden"
}
}(i);
}
然后在 footer.html 或者 head.html 中引用:
<script src="/js/codecopy.js"></script>
鼠标点击烟花特效
依然是在这一篇 ■■Loading:《hugo装修日志02》■■:
在 static/js/firework.js:
class Circle {
constructor({ origin, speed, color, angle, context }) {
this.origin = origin
this.position = { ...this.origin }
this.color = color
this.speed = speed
this.angle = angle
this.context = context
this.renderCount = 0
}
draw() {
this.context.fillStyle = this.color
this.context.beginPath()
this.context.arc(this.position.x, this.position.y, 2, 0, Math.PI * 2)
this.context.fill()
}
move() {
this.position.x = (Math.sin(this.angle) * this.speed) + this.position.x
this.position.y = (Math.cos(this.angle) * this.speed) + this.position.y + (this.renderCount * 0.3)
this.renderCount++
}
}
class Boom {
constructor ({ origin, context, circleCount = 10, area }) {
this.origin = origin
this.context = context
this.circleCount = circleCount
this.area = area
this.stop = false
this.circles = []
}
randomArray(range) {
const length = range.length
const randomIndex = Math.floor(length * Math.random())
return range[randomIndex]
}
randomColor() {
const range = ['8', '9', 'A', 'B', 'C', 'D', 'E', 'F']
return '#' + this.randomArray(range) + this.randomArray(range) + this.randomArray(range) + this.randomArray(range) + this.randomArray(range) + this.randomArray(range)
}
randomRange(start, end) {
return (end - start) * Math.random() + start
}
init() {
for(let i = 0; i < this.circleCount; i++) {
const circle = new Circle({
context: this.context,
origin: this.origin,
color: this.randomColor(),
angle: this.randomRange(Math.PI - 1, Math.PI + 1),
speed: this.randomRange(1, 6)
})
this.circles.push(circle)
}
}
move() {
this.circles.forEach((circle, index) => {
if (circle.position.x > this.area.width || circle.position.y > this.area.height) {
return this.circles.splice(index, 1)
}
circle.move()
})
if (this.circles.length == 0) {
this.stop = true
}
}
draw() {
this.circles.forEach(circle => circle.draw())
}
}
class CursorSpecialEffects {
constructor() {
this.computerCanvas = document.createElement('canvas')
this.renderCanvas = document.createElement('canvas')
this.computerContext = this.computerCanvas.getContext('2d')
this.renderContext = this.renderCanvas.getContext('2d')
this.globalWidth = window.innerWidth
this.globalHeight = window.innerHeight
this.booms = []
this.running = false
}
handleMouseDown(e) {
const boom = new Boom({
origin: { x: e.clientX, y: e.clientY },
context: this.computerContext,
area: {
width: this.globalWidth,
height: this.globalHeight
}
})
boom.init()
this.booms.push(boom)
this.running || this.run()
}
handlePageHide() {
this.booms = []
this.running = false
}
init() {
const style = this.renderCanvas.style
style.position = 'fixed'
style.top = style.left = 0
style.zIndex = '999999999999999999999999999999999999999999'
style.pointerEvents = 'none'
style.width = this.renderCanvas.width = this.computerCanvas.width = this.globalWidth
style.height = this.renderCanvas.height = this.computerCanvas.height = this.globalHeight
document.body.append(this.renderCanvas)
window.addEventListener('mousedown', this.handleMouseDown.bind(this))
window.addEventListener('pagehide', this.handlePageHide.bind(this))
}
run() {
this.running = true
if (this.booms.length == 0) {
return this.running = false
}
requestAnimationFrame(this.run.bind(this))
this.computerContext.clearRect(0, 0, this.globalWidth, this.globalHeight)
this.renderContext.clearRect(0, 0, this.globalWidth, this.globalHeight)
this.booms.forEach((boom, index) => {
if (boom.stop) {
return this.booms.splice(index, 1)
}
boom.move()
boom.draw()
})
this.renderContext.drawImage(this.computerCanvas, 0, 0, this.globalWidth, this.globalHeight)
}
}
const cursorSpecialEffects = new CursorSpecialEffects()
cursorSpecialEffects.init()
然后在 footer.html 或者 head.html 中引用:
<script src="/js/firework.js"></script>
自定义鼠标指针样式
还是爱海老师的 ■■Loading:《hugo装修日志02》■■:
先找好想用的鼠标样式,然后把 .cur 文件转成 .png。
custom.scss 中:
body{
cursor:url(文件地址), default; /* 默认鼠标指针样式 */
}
a:hover{
cursor:url(文件地址), pointer; /* 链接鼠标指针样式 */
}
以此类推。
26.04.20
页脚游动小鱼
找了很多,目前抄的是 底部小鱼特效:
在 static/js/fish.js:
var RENDERER = {
POINT_INTERVAL : 5,
FISH_COUNT : 3,
MAX_INTERVAL_COUNT : 50,
INIT_HEIGHT_RATE : 0.5,
THRESHOLD : 50,
init : function(){
this.setParameters();
this.reconstructMethods();
this.setup();
this.bindEvent();
this.render();
},
setParameters : function(){
this.$window = $(window);
this.$container = $('#jsi-flying-fish-container');
this.$canvas = $('<canvas />');
this.context = this.$canvas.appendTo(this.$container).get(0).getContext('2d');
this.points = [];
this.fishes = [];
this.watchIds = [];
},
createSurfacePoints : function(){
var count = Math.round(this.width / this.POINT_INTERVAL);
this.pointInterval = this.width / (count - 1);
this.points.push(new SURFACE_POINT(this, 0));
for(var i = 1; i < count; i++){
var point = new SURFACE_POINT(this, i * this.pointInterval),
previous = this.points[i - 1];
point.setPreviousPoint(previous);
previous.setNextPoint(point);
this.points.push(point);
}
},
reconstructMethods : function(){
this.watchWindowSize = this.watchWindowSize.bind(this);
this.jdugeToStopResize = this.jdugeToStopResize.bind(this);
this.startEpicenter = this.startEpicenter.bind(this);
this.moveEpicenter = this.moveEpicenter.bind(this);
this.reverseVertical = this.reverseVertical.bind(this);
this.render = this.render.bind(this);
},
setup : function(){
this.points.length = 0;
this.fishes.length = 0;
this.watchIds.length = 0;
this.intervalCount = this.MAX_INTERVAL_COUNT;
this.width = this.$container.width();
this.height = this.$container.height();
this.fishCount = this.FISH_COUNT * this.width / 500 * this.height / 500;
this.$canvas.attr({width : this.width, height : this.height});
this.reverse = false;
this.fishes.push(new FISH(this));
this.createSurfacePoints();
},
watchWindowSize : function(){
this.clearTimer();
this.tmpWidth = this.$window.width();
this.tmpHeight = this.$window.height();
this.watchIds.push(setTimeout(this.jdugeToStopResize, this.WATCH_INTERVAL));
},
clearTimer : function(){
while(this.watchIds.length > 0){
clearTimeout(this.watchIds.pop());
}
},
jdugeToStopResize : function(){
var width = this.$window.width(),
height = this.$window.height(),
stopped = (width == this.tmpWidth && height == this.tmpHeight);
this.tmpWidth = width;
this.tmpHeight = height;
if(stopped){
this.setup();
}
},
bindEvent : function(){
this.$window.on('resize', this.watchWindowSize);
this.$container.on('mouseenter', this.startEpicenter);
this.$container.on('mousemove', this.moveEpicenter);
this.$container.on('click', this.reverseVertical);
},
getAxis : function(event){
var offset = this.$container.offset();
return {
x : event.clientX - offset.left + this.$window.scrollLeft(),
y : event.clientY - offset.top + this.$window.scrollTop()
};
},
startEpicenter : function(event){
this.axis = this.getAxis(event);
},
moveEpicenter : function(event){
var axis = this.getAxis(event);
if(!this.axis){
this.axis = axis;
}
this.generateEpicenter(axis.x, axis.y, axis.y - this.axis.y);
this.axis = axis;
},
generateEpicenter : function(x, y, velocity){
if(y < this.height / 2 - this.THRESHOLD || y > this.height / 2 + this.THRESHOLD){
return;
}
var index = Math.round(x / this.pointInterval);
if(index < 0 || index >= this.points.length){
return;
}
this.points[index].interfere(y, velocity);
},
reverseVertical : function(){
this.reverse = !this.reverse;
for(var i = 0, count = this.fishes.length; i < count; i++){
this.fishes[i].reverseVertical();
}
},
controlStatus : function(){
for(var i = 0, count = this.points.length; i < count; i++){
this.points[i].updateSelf();
}
for(var i = 0, count = this.points.length; i < count; i++){
this.points[i].updateNeighbors();
}
if(this.fishes.length < this.fishCount){
if(--this.intervalCount == 0){
this.intervalCount = this.MAX_INTERVAL_COUNT;
this.fishes.push(new FISH(this));
}
}
},
render : function(){
requestAnimationFrame(this.render);
this.controlStatus();
this.context.clearRect(0, 0, this.width, this.height);
this.context.fillStyle = 'hsl(0, 0%, 95%)';
for(var i = 0, count = this.fishes.length; i < count; i++){
this.fishes[i].render(this.context);
}
this.context.save();
this.context.globalCompositeOperation = 'xor';
this.context.beginPath();
this.context.moveTo(0, this.reverse ? 0 : this.height);
for(var i = 0, count = this.points.length; i < count; i++){
this.points[i].render(this.context);
}
this.context.lineTo(this.width, this.reverse ? 0 : this.height);
this.context.closePath();
this.context.fill();
this.context.restore();
}
};
var SURFACE_POINT = function(renderer, x){
this.renderer = renderer;
this.x = x;
this.init();
};
SURFACE_POINT.prototype = {
SPRING_CONSTANT : 0.03,
SPRING_FRICTION : 0.9,
WAVE_SPREAD : 0.3,
ACCELARATION_RATE : 0.01,
init : function(){
this.initHeight = this.renderer.height * this.renderer.INIT_HEIGHT_RATE;
this.height = this.initHeight;
this.fy = 0;
this.force = {previous : 0, next : 0};
},
setPreviousPoint : function(previous){
this.previous = previous;
},
setNextPoint : function(next){
this.next = next;
},
interfere : function(y, velocity){
this.fy = this.renderer.height * this.ACCELARATION_RATE * ((this.renderer.height - this.height - y) >= 0 ? -1 : 1) * Math.abs(velocity);
},
updateSelf : function(){
this.fy += this.SPRING_CONSTANT * (this.initHeight - this.height);
this.fy *= this.SPRING_FRICTION;
this.height += this.fy;
},
updateNeighbors : function(){
if(this.previous){
this.force.previous = this.WAVE_SPREAD * (this.height - this.previous.height);
}
if(this.next){
this.force.next = this.WAVE_SPREAD * (this.height - this.next.height);
}
},
render : function(context){
if(this.previous){
this.previous.height += this.force.previous;
this.previous.fy += this.force.previous;
}
if(this.next){
this.next.height += this.force.next;
this.next.fy += this.force.next;
}
context.lineTo(this.x, this.renderer.height - this.height);
}
};
var FISH = function(renderer){
this.renderer = renderer;
this.init();
};
FISH.prototype = {
GRAVITY : 0.4,
init : function(){
this.direction = Math.random() < 0.5;
this.x = this.direction ? (this.renderer.width + this.renderer.THRESHOLD) : -this.renderer.THRESHOLD;
this.previousY = this.y;
this.vx = this.getRandomValue(4, 10) * (this.direction ? -1 : 1);
if(this.renderer.reverse){
this.y = this.getRandomValue(this.renderer.height * 1 / 10, this.renderer.height * 4 / 10);
this.vy = this.getRandomValue(2, 5);
this.ay = this.getRandomValue(0.05, 0.2);
}else{
this.y = this.getRandomValue(this.renderer.height * 6 / 10, this.renderer.height * 9 / 10);
this.vy = this.getRandomValue(-5, -2);
this.ay = this.getRandomValue(-0.2, -0.05);
}
this.isOut = false;
this.theta = 0;
this.phi = 0;
},
getRandomValue : function(min, max){
return min + (max - min) * Math.random();
},
reverseVertical : function(){
this.isOut = !this.isOut;
this.ay *= -1;
},
controlStatus : function(context){
this.previousY = this.y;
this.x += this.vx;
this.y += this.vy;
this.vy += this.ay;
if(this.renderer.reverse){
if(this.y > this.renderer.height * this.renderer.INIT_HEIGHT_RATE){
this.vy -= this.GRAVITY;
this.isOut = true;
}else{
if(this.isOut){
this.ay = this.getRandomValue(0.05, 0.2);
}
this.isOut = false;
}
}else{
if(this.y < this.renderer.height * this.renderer.INIT_HEIGHT_RATE){
this.vy += this.GRAVITY;
this.isOut = true;
}else{
if(this.isOut){
this.ay = this.getRandomValue(-0.2, -0.05);
}
this.isOut = false;
}
}
if(!this.isOut){
this.theta += Math.PI / 20;
this.theta %= Math.PI * 2;
this.phi += Math.PI / 30;
this.phi %= Math.PI * 2;
}
this.renderer.generateEpicenter(this.x + (this.direction ? -1 : 1) * this.renderer.THRESHOLD, this.y, this.y - this.previousY);
if(this.vx > 0 && this.x > this.renderer.width + this.renderer.THRESHOLD || this.vx < 0 && this.x < -this.renderer.THRESHOLD){
this.init();
}
},
render : function(context){
context.save();
context.translate(this.x, this.y);
context.rotate(Math.PI + Math.atan2(this.vy, this.vx));
context.scale(1, this.direction ? 1 : -1);
context.beginPath();
context.moveTo(-30, 0);
context.bezierCurveTo(-20, 15, 15, 10, 40, 0);
context.bezierCurveTo(15, -10, -20, -15, -30, 0);
context.fill();
context.save();
context.translate(40, 0);
context.scale(0.9 + 0.2 * Math.sin(this.theta), 1);
context.beginPath();
context.moveTo(0, 0);
context.quadraticCurveTo(5, 10, 20, 8);
context.quadraticCurveTo(12, 5, 10, 0);
context.quadraticCurveTo(12, -5, 20, -8);
context.quadraticCurveTo(5, -10, 0, 0);
context.fill();
context.restore();
context.save();
context.translate(-3, 0);
context.rotate((Math.PI / 3 + Math.PI / 10 * Math.sin(this.phi)) * (this.renderer.reverse ? -1 : 1));
context.beginPath();
if(this.renderer.reverse){
context.moveTo(5, 0);
context.bezierCurveTo(10, 10, 10, 30, 0, 40);
context.bezierCurveTo(-12, 25, -8, 10, 0, 0);
}else{
context.moveTo(-5, 0);
context.bezierCurveTo(-10, -10, -10, -30, 0, -40);
context.bezierCurveTo(12, -25, 8, -10, 0, 0);
}
context.closePath();
context.fill();
context.restore();
context.restore();
this.controlStatus(context);
}
};
$(function(){
RENDERER.init();
});
然后 custom.scss 中:
.container {
width: 100%;
height: 200px;
position: fixed;
z-index: -1;
bottom: 0;
left: 0;
}
最后再在 footer.html 里引用:
<div id="jsi-flying-fish-container" class="container"></div>
<script src="/js/fish.js"></script>
但看了下鱼应该是和页脚的版权信息重叠的...先这样放着吧。