1.首页大图内描述打字特效
如果是博主同款主题,在控制台->外观->网站公告 复制到首页大图内描述框内即可
<div id="chakhsu"></div> <script> var chakhsu = function (r) { function t() { return b[Math.floor(Math.random() * b.length)] } function e() { return String.fromCharCode(94 * Math.random() + 33) } function n(r) { for (var n = document.createDocumentFragment(), i = 0; r > i; i++) { var l = document.createElement("span"); l.textContent = e(), l.style.color = t(), n.appendChild(l) } return n } function i() { var t = o[c.skillI]; c.step ? c.step-- : (c.step = g, c.prefixP < l.length ? (c.prefixP >= 0 && (c.text += l[c.prefixP]), c.prefixP++) : "forward" === c.direction ? c.skillP < t.length ? (c.text += t[c.skillP], c.skillP++) : c.delay ? c.delay-- : (c.direction = "backward", c.delay = a) : c.skillP > 0 ? (c.text = c.text.slice(0, -1), c.skillP--) : (c.skillI = (c.skillI + 1) % o.length, c.direction = "forward")), r.textContent = c.text, r.appendChild(n(c.prefixP < l.length ? Math.min(s, s + c.prefixP) : Math.min(s, t.length - c.skillP))), setTimeout(i, d) } /*以下内容自定义修改*/ var l = "", o = ["当你凝视网页的时候,网页也在凝视着你!", ].map(function (r) { return r + "" }), a = 2, g = 1, s = 5, d = 75, b = ["rgb(110,64,170)", "rgb(150,61,179)", "rgb(191,60,175)", "rgb(228,65,157)", "rgb(254,75,131)", "rgb(255,94,99)", "rgb(255,120,71)", "rgb(251,150,51)", "rgb(226,183,47)", "rgb(198,214,60)", "rgb(175,240,91)", "rgb(127,246,88)", "rgb(82,246,103)", "rgb(48,239,130)", "rgb(29,223,163)", "rgb(26,199,194)", "rgb(35,171,216)", "rgb(54,140,225)", "rgb(76,110,219)", "rgb(96,84,200)"], c = {text: "", prefixP: -s, skillI: 0, skillP: 0, direction: "forward", delay: a, step: g}; i() }; chakhsu(document.getElementById('chakhsu')); </script> <div>
中间的 var l = "" 与文字是可根据需求修改的参数喔!
展示
2.炫彩鼠标特效
展示
此效果可以由HoerMouse插件实现
点此下载插件
将插件解压后的文件夹放入主题的/usr/plugins/目录,然后控制台启用插件并设置自己喜欢的特效就OK啦!
3.添加网站运行时间
引入 JS
将以下代码加入到 <head>
标签中。对于本主题,依次进入 控制台 - 外观 - 设置外观 - 主题自定义扩展
,加入到 自定义 HTML 元素拓展 - 标签: head 头部 (meta 元素后)
,也可直接加入到主题对应的 header.php
中的 </head>
标签前。开始时间和中文提示可自定义。
<script>
document.addEventListener('DOMContentLoaded', initLiveDay);
function initLiveDay() {
const birthTime = '2021/3/20 20:00:06';
const template = (A, B, C, D) => `本站已风雨无阻地运行了 ${A}d ${B}h ${C}m ${D}s.`;
/* 锚点开始 */
const container = footer.querySelector('.container');
const p = document.createElement('p');
container.insertBefore(p, container.firstElementChild);
/* 锚点结束*/
const msoad = 24 * 60 * 60 * 1000;
const warp = n => n > 9 ? n : '0' + n;
const toInt = n => warp(Math.floor(n));
setInterval(() => {
const lived = new Date() - new Date(birthTime);
const days = lived / msoad;
const intDays = toInt(days);
const hours = (days - intDays) * 24;
const intHours = toInt(hours);
const minutes = (hours - intHours) * 60;
const intMinutes = toInt(minutes);
const seconds = (minutes - intMinutes) * 60;
const intSeconds = toInt(seconds);
p.innerHTML = template(intDays, intHours, intMinutes, intSeconds);
}, 1000);
}
</script>
4.为Typecho评论框加入七彩打字动画
最终效果
使用步骤
对于 本主题,依次进入 控制台 - 外观 - 设置外观 - 主题自定义扩展,将以下代码加入到 自定义 HTML 元素拓展 - 在 body 标签结束前。其他主题,加入到主题对应的 footer.php 中 </body> 标签结束前。
<script>
(function webpackUniversalModuleDefinition(a,b){if(typeof exports==="object"&&typeof module==="object"){module.exports=b()}else{if(typeof define==="function"&&define.amd){define([],b)}else{if(typeof exports==="object"){exports["POWERMODE"]=b()}else{a["POWERMODE"]=b()}}}})(this,function(){return(function(a){var b={};function c(e){if(b[e]){return b[e].exports}var d=b[e]={exports:{},id:e,loaded:false};a[e].call(d.exports,d,d.exports,c);d.loaded=true;return d.exports}c.m=a;c.c=b;c.p="";return c(0)})([function(c,g,b){var d=document.createElement("canvas");d.width=window.innerWidth;d.height=window.innerHeight;d.style.cssText="position:fixed;top:0;left:0;pointer-events:none;z-index:999999";window.addEventListener("resize",function(){d.width=window.innerWidth;d.height=window.innerHeight});document.body.appendChild(d);var a=d.getContext("2d");var n=[];var j=0;var k=120;var f=k;var p=false;o.shake=true;function l(r,q){return Math.random()*(q-r)+r}function m(r){if(o.colorful){var q=l(0,360);return"hsla("+l(q-10,q+10)+", 100%, "+l(50,80)+"%, "+1+")"}else{return window.getComputedStyle(r).color}}function e(){var t=document.activeElement;var v;if(t.tagName==="TEXTAREA"||(t.tagName==="INPUT"&&t.getAttribute("type")==="text")){var u=b(1)(t,t.selectionStart);v=t.getBoundingClientRect();return{x:u.left+v.left,y:u.top+v.top,color:m(t)}}var s=window.getSelection();if(s.rangeCount){var q=s.getRangeAt(0);var r=q.startContainer;if(r.nodeType===document.TEXT_NODE){r=r.parentNode}v=q.getBoundingClientRect();return{x:v.left,y:v.top,color:m(r)}}return{x:0,y:0,color:"transparent"}}function h(q,s,r){return{x:q,y:s,alpha:1,color:r,velocity:{x:-1+Math.random()*2,y:-3.5+Math.random()*2}}}function o(){var t=e();var s=5+Math.round(Math.random()*10);while(s--){n[j]=h(t.x,t.y,t.color);j=(j+1)%500}f=k;if(!p){requestAnimationFrame(i)}if(o.shake){var r=1+2*Math.random();var q=r*(Math.random()>0.5?-1:1);var u=r*(Math.random()>0.5?-1:1);document.body.style.marginLeft=q+"px";document.body.style.marginTop=u+"px";setTimeout(function(){document.body.style.marginLeft="";document.body.style.marginTop=""},75)}}o.colorful=false;function i(){if(f>0){requestAnimationFrame(i);f--;p=true}else{p=false}a.clearRect(0,0,d.width,d.height);for(var q=0;q<n.length;++q){var r=n[q];if(r.alpha<=0.1){continue}r.velocity.y+=0.075;r.x+=r.velocity.x;r.y+=r.velocity.y;r.alpha*=0.96;a.globalAlpha=r.alpha;a.fillStyle=r.color;a.fillRect(Math.round(r.x-1.5),Math.round(r.y-1.5),3,3)}}requestAnimationFrame(i);c.exports=o},function(b,a){(function(){var d=["direction","boxSizing","width","height","overflowX","overflowY","borderTopWidth","borderRightWidth","borderBottomWidth","borderLeftWidth","borderStyle","paddingTop","paddingRight","paddingBottom","paddingLeft","fontStyle","fontVariant","fontWeight","fontStretch","fontSize","fontSizeAdjust","lineHeight","fontFamily","textAlign","textTransform","textIndent","textDecoration","letterSpacing","wordSpacing","tabSize","MozTabSize"];var e=window.mozInnerScreenX!=null;function c(k,l,o){var h=o&&o.debug||false;if(h){var i=document.querySelector("#input-textarea-caret-position-mirror-div");if(i){i.parentNode.removeChild(i)}}var f=document.createElement("div");f.id="input-textarea-caret-position-mirror-div";document.body.appendChild(f);var g=f.style;var j=window.getComputedStyle?getComputedStyle(k):k.currentStyle;g.whiteSpace="pre-wrap";if(k.nodeName!=="INPUT"){g.wordWrap="break-word"}g.position="absolute";if(!h){g.visibility="hidden"}d.forEach(function(p){g[p]=j[p]});if(e){if(k.scrollHeight>parseInt(j.height)){g.overflowY="scroll"}}else{g.overflow="hidden"}f.textContent=k.value.substring(0,l);if(k.nodeName==="INPUT"){f.textContent=f.textContent.replace(/\s/g,"\u00a0")}var n=document.createElement("span");n.textContent=k.value.substring(l)||".";f.appendChild(n);var m={top:n.offsetTop+parseInt(j["borderTopWidth"]),left:n.offsetLeft+parseInt(j["borderLeftWidth"])};if(h){n.style.backgroundColor="#aaa"}else{document.body.removeChild(f)}return m}if(typeof b!="undefined"&&typeof b.exports!="undefined"){b.exports=c}else{window.getCaretCoordinates=c}}())}])});
POWERMODE.colorful=true;POWERMODE.shake=false;document.body.addEventListener("input",POWERMODE);
</script>
5.为Typecho的Code Block添加Copy按钮
之前为了隐藏无意义内容写了 Typecho 简单实现点击复制,方式是创建隐藏内容的复制按钮。今天无意间看到某大佬的 JS 代码块复制按钮,发现也是我需要的,于是把它移植到了 Typecho 上,下面就介绍 Mirages 主题的使用步骤,其他主题改改选择器名称就行了。
引入 JS
将以下代码添加到主题 header.php 中的 </head> 标签前,或前往 控制台 - 设置外观 - 主题自定义扩展,将它添加到 自定义 HTML 元素拓展 - 标签: head 头部 (meta 元素后)。
<script>
// 在代码块右上角添加复制按钮
document.addEventListener('DOMContentLoaded', initCodeCopyButton);
function initCodeCopyButton() {
function initCSS(callback) {
const css = `
.btn-code-copy {
position: absolute;
line-height: .6em;
top: .2em;
right: .2em;
color: rgb(87, 87, 87);
}
.btn-code-copy:hover {
color: rgb(145, 145, 145);
cursor: pointer;
}
`;
const styleId = btoa('btn-code-copy').replace(/[=+\/]/g, '');
const head = document.getElementsByTagName('head')[0];
if (!head.querySelector('#' + styleId)) {
const style = document.createElement('style');
style.id = styleId;
if (style.styleSheet) {
style.styleSheet.cssText = css;
} else {
style.appendChild(document.createTextNode(css));
}
head.appendChild(style);
}
callback();
};
function copyTextContent(source) {
let result = false;
const target = document.createElement('pre');
target.style.opacity = '0';
target.textContent = source.textContent;
document.body.appendChild(target);
try {
const range = document.createRange();
range.selectNode(target);
window.getSelection().removeAllRanges();
window.getSelection().addRange(range);
document.execCommand('copy');
window.getSelection().removeAllRanges();
result = true;
} catch (e) { console.log('copy failed.'); }
document.body.removeChild(target);
return result;
};
function initButton(pre) {
const code = pre.querySelector('code');
if (code) {
const preParent = pre.parentElement;
const newPreParent = document.createElement('div');
newPreParent.style = 'position: relative';
preParent.insertBefore(newPreParent, pre);
const copyBtn = document.createElement('div');
copyBtn.innerHTML = 'copy';
copyBtn.className = 'btn-code-copy';
copyBtn.addEventListener('click', () => {
copyBtn.innerHTML = copyTextContent(code) ? 'success' : 'failure';
setTimeout(() => copyBtn.innerHTML = 'copy', 250);
});
newPreParent.appendChild(copyBtn);
newPreParent.appendChild(pre);
}
};
const pres = document.querySelectorAll('pre');
if (pres.length !== 0) {
initCSS(() => pres.forEach(pre => initButton(pre)));
}
};
</script>
如果你开启了 PJAX,则需单独加入回调函数。对于本主题,依次进入 控制台 - 外观 - 设置外观 - PJAX(BETA) - PJAX RELOAD,将 initCodeCopyButton(); 添加进入即可。
6.Typecho 简单实现点击复制
在文章中插入大量无意义内容一不美观,二不便复制,不如使用 js 创建隐藏内容的复制按钮吧。
引入 JS
依次进入 控制台 - 外观 - 设置外观 - 主题自定义扩展,将以下代码加入到 自定义 HTML 元素拓展 - 标签: head 头部 (meta 元素后),也可直接加入到主题对应的 header.php 中的 </head> 标签前。
<script>
// 创建隐藏内容的复制按钮
document.addEventListener('DOMContentLoaded', initCopyButton);
function initCopyButton() {
const util = {
newButton: function (cp) {
cp.style.display = '0';
let text = cp.getAttribute('text');
text = text[0] === '\n' ? text.slice(1) : text;
const button = document.createElement('a');
button.href = '#'
button.innerHTML = cp.getAttribute('name');
button.className = 'btn btn-primary';
button.onclick = () => {
const originName = button.innerHTML;
const actionResult = this.copy(text) ? '成功' : '失败';
button.innerHTML = '复制' + actionResult;
setTimeout(() => button.innerHTML = originName, 250);
return false;
};
cp.parentNode.insertBefore(button, cp);
},
copy: function (text) {
let result = false;
const target = document.createElement('pre');
target.style.opacity = '0';
target.textContent = text;
document.body.appendChild(target);
try {
const range = document.createRange();
range.selectNode(target);
window.getSelection().removeAllRanges();
window.getSelection().addRange(range);
document.execCommand('copy');
window.getSelection().removeAllRanges();
result = true;
} catch (e) {
console.log('copy failed.');
}
document.body.removeChild(target);
return result;
}
};
document.querySelectorAll('cp').forEach(cp => util.newButton(cp));
}
</script>
如果你开启了 PJAX,可能需要单独加入回调函数。对于本主题,依次进入 控制台 - 外观 - 设置外观 - PJAX(BETA) - PJAX RELOAD,将 initCopyButton(); 添加进入即可。
添加按钮
以 html 形式将以下内容写入文章中,即可创建复制按钮。
!!!
<cp name="复制静夜思" text="
静夜思
床前明月光,疑是地上霜。
举头望明月,低头思故乡。
"></cp>
!!!
7.主题相邻文章默认头图去重
代码逻辑在/path/to/typecho/usr/themes/Mirages/lib/Content.php文件的loadDefaultThumbnailForArticle 函数:
public static function loadDefaultThumbnailForArticle($cid) {
$defaultThumbs = self::exportThumbnails();
$length = count($defaultThumbs);
if ($length > 0) {
$index = abs(intval($cid)) % count($length);
$thumb = $defaultThumbs[$index];
} else {
$thumb = NULL;
}
return $thumb;
}
可以看到,作者根据文章 cid 对图片数量取余选取图片。尽管 cid 不同,运算后的结果也可能相同,这就可能导致上述问题。
简单起见,我直接让静态变量每次加 1,更改后的代码如下:
private static $defaultThumbs;
private static $defaultThumbsLength;
private static $nextThumbnailIndex;
public static function loadDefaultThumbnailForArticle($cid) {
if (self::$defaultThumbs == NULL) {
// 这些变量存活于当前页
self::$defaultThumbs = self::exportThumbnails();
self::$defaultThumbsLength = count(self::$defaultThumbs);
self::$nextThumbnailIndex = rand(0, abs(self::$defaultThumbsLength - 1));
}
if (self::$defaultThumbsLength > 0) {
$index = self::$nextThumbnailIndex++ % self::$defaultThumbsLength;
$thumb = self::$defaultThumbs[$index];
} else {
$thumb = NULL;
}
return $thumb;
}
文章默认图片的添加位置为 控制台 - 外观 - 设置外观 - 配图和图片管理 - 卡片式文章列表的默认背景图列表。现在刷新下主页,感觉稍微好了一点。
8.在文章中插入视频
引入 JS
对于 本主题,依次进入 控制台 - 外观 - 设置外观 - 主题自定义扩展,将代码加入到 自定义 HTML 元素拓展 - 标签: head 头部 (meta 元素后)。其他主题,加入到主题对应的 header.php 中的 </head> 标签前。
<script>
// DPlayer API
document.addEventListener('DOMContentLoaded', initDplayer);
function initDplayer() {
const common = {
loadResource: function (id, resource, type, callback) {
let loaded = document.head.querySelector('#' + id);
if (loaded) {
callback();
return;
}
const element = document.createElement(type);
element.onload = element.onreadystatechange = () => {
if (!loaded && (!element.readyState || /loaded|complete/.test(element.readyState))) {
element.onload = element.onreadystatechange = null;
loaded = true;
callback();
}
}
if (type === 'link') {
element.rel = 'stylesheet';
element.href = resource;
} else {
element.src = resource;
}
element.id = id;
document.getElementsByTagName('head')[0].appendChild(element);
},
loadResources: function (callback) {
const cdn = '//s0.pstatp.com/cdn/expire-1-M';
const resources = [
'/dplayer/1.25.0/DPlayer.min.css',
'/dplayer/1.25.0/DPlayer.min.js',
'/hls.js/0.12.4/hls.light.min.js',
'/flv.js/1.5.0/flv.min.js'
];
let unloadedResourceCount = resources.length;
resources.forEach(resource => {
this.loadResource(btoa(resource).replace(/[=+\/]/g, ''), cdn + resource,
({
'css': 'link',
'js': 'script'
})[resource.split('.').pop()],
() => --unloadedResourceCount ? null : callback()
);
});
},
createDplayers: function (sources, callback) {
for (let i = 0; i < sources.length; i++) {
const child = document.createElement('div');
const src = sources[i].getAttribute('src');
sources[i].parentNode.insertBefore(child, sources[i]);
sources[i].style.display = 'none';
const type = src.split('.').pop();
const option = { url: src };
type === 'flv' ? option.type = type : null;
const dplayer = new DPlayer({ container: child, preload: 'none', autoplay: false, screenshot: false, video: option });
}
if (typeof callback === 'function') callback();
}
};
const mirages = {
isMirages: function () { return window.Mirages || false },
fixVideoSize: function (length) {
let outerTimer = false;
const outerInterval = setInterval(() => {
if (outerTimer) return;
const videos = document.getElementsByTagName('video');
if (videos.length === length) {
const dplayerWraps = document.querySelectorAll('.dplayer-video-wrap');
for (let i = 0; i < length; i++) {
const videoContainers = dplayerWraps[i].querySelectorAll('.video-container.video-4-3');
if (videoContainers.length) {
videoContainers[0].style = 'position: initial;';
videoContainers[0].className = 'video-container video-16-9';
console.log('video-4-3 fixed.');
} else {
const videoContainer = document.createElement('div');
videoContainer.style = 'position: initial;';
videoContainer.className = 'video-container video-16-9';
videoContainer.appendChild(videos[i]);
dplayerWraps[i].appendChild(videoContainer);
console.log('video-16-9 inserted.');
const targetNode = videoContainer;
const config = { childList: true };
const callback = (mutationsList, observer) => {
const newVideoContainers = videoContainer.querySelectorAll(
'.video-container.video-4-3');
if (newVideoContainers.length) {
newVideoContainers[0].className = '';
console.log('auto inserted video-4-3 fixed.');
observer.disconnect();
}
};
const observer = new MutationObserver(callback);
observer.observe(targetNode, config);
setTimeout(() => observer.disconnect(), 1000 * 120);
}
}
outerTimer = true;
clearInterval(outerInterval);
}
}, 500);
}
};
const dps = document.getElementsByTagName('dp');
if (dps.length !== 0) {
common.loadResources(() => common.createDplayers(dps, () => {
// 修正 Mirages 视频比例错误
mirages.isMirages() ? mirages.fixVideoSize(dps.length) : null;
}));
}
};
</script>
如果你开启了 PJAX,可能需要单独加入回调函数。对于本主题,依次进入 控制台 - 外观 - 设置外观 - PJAX(BETA) - PJAX RELOAD,将 initDplayer(); 添加进入即可。
添加播放器
在文章所需位置以 html 形式插入代码,即可添加播放器,支持 m3u8、mp4,flv 和 mkv 格式,不过编码必须是 H.264 AAC。
!!!
<dp src="demo.mp4"></dp>
!!!
9.博客评论显示 UserAgent (UA)
本功能可替代 UserAgent 插件,更美观、简洁且好看
引入 CSS
将下面的样式表外链加入到 /usr/themes/Mirages/component/header.php 的 head 部分,当然也可通过主题设置界面添加。
<link rel="stylesheet" href="//code.bdstatic.com/npm/logicdn@1.0.0/logi.im/usr/themes/Mirages/usr/logi.css" />
引入 PHP
将以下代码加入到 /usr/themes/Mirages/function.php 末尾。
// 获取浏览器信息
function getBrowser($agent)
{
if (preg_match('/MSIE\s([^\s|;]+)/i', $agent, $regs)) {
$outputer = '<i class="ua-icon icon-ie"></i> Internet Explore';
} else if (preg_match('/FireFox\/([^\s]+)/i', $agent, $regs)) {
$str1 = explode('Firefox/', $regs[0]);
$FireFox_vern = explode('.', $str1[1]);
$outputer = '<i class="ua-icon icon-firefox"></i> FireFox';
} else if (preg_match('/Maxthon([\d]*)\/([^\s]+)/i', $agent, $regs)) {
$str1 = explode('Maxthon/', $agent);
$Maxthon_vern = explode('.', $str1[1]);
$outputer = '<i class="ua-icon icon-edge"></i> MicroSoft Edge';
} else if (preg_match('#360([a-zA-Z0-9.]+)#i', $agent, $regs)) {
$outputer = '<i class="ua-icon icon-360"></i> 360极速浏览器';
} else if (preg_match('/Edge([\d]*)\/([^\s]+)/i', $agent, $regs)) {
$str1 = explode('Edge/', $regs[0]);
$Edge_vern = explode('.', $str1[1]);
$outputer = '<i class="ua-icon icon-edge"></i> MicroSoft Edge';
} else if (preg_match('/UC/i', $agent)) {
$str1 = explode('rowser/', $agent);
$UCBrowser_vern = explode('.', $str1[1]);
$outputer = '<i class="ua-icon icon-uc"></i> UC浏览器';
} else if (preg_match('/QQ/i', $agent, $regs)||preg_match('/QQBrowser\/([^\s]+)/i', $agent, $regs)) {
$str1 = explode('rowser/', $agent);
$QQ_vern = explode('.', $str1[1]);
$outputer = '<i class= "ua-icon icon-qq"></i> QQ浏览器';
} else if (preg_match('/UBrowser/i', $agent, $regs)) {
$str1 = explode('rowser/', $agent);
$UCBrowser_vern = explode('.', $str1[1]);
$outputer = '<i class="ua-icon icon-uc"></i> UC浏览器';
} else if (preg_match('/Opera[\s|\/]([^\s]+)/i', $agent, $regs)) {
$outputer = '<i class= "ua-icon icon-opera"></i> Opera';
} else if (preg_match('/Chrome([\d]*)\/([^\s]+)/i', $agent, $regs)) {
$str1 = explode('Chrome/', $agent);
$chrome_vern = explode('.', $str1[1]);
$outputer = '<i class="ua-icon icon-chrome"></i> Google Chrome';
} else if (preg_match('/safari\/([^\s]+)/i', $agent, $regs)) {
$str1 = explode('Version/', $agent);
$safari_vern = explode('.', $str1[1]);
$outputer = '<i class="ua-icon icon-safari"></i> Safari';
} else{
$outputer = '<i class="ua-icon icon-chrome"></i> Google Chrome';
}
echo $outputer;
}
// 获取操作系统信息
function getOs($agent)
{
$os = false;
if (preg_match('/win/i', $agent)) {
if (preg_match('/nt 6.0/i', $agent)) {
$os = ' <i class= "ua-icon icon-win1"></i> Windows Vista / ';
} else if (preg_match('/nt 6.1/i', $agent)) {
$os = ' <i class= "ua-icon icon-win1"></i> Windows 7 / ';
} else if (preg_match('/nt 6.2/i', $agent)) {
$os = ' <i class="ua-icon icon-win2"></i> Windows 8 / ';
} else if(preg_match('/nt 6.3/i', $agent)) {
$os = ' <i class= "ua-icon icon-win2"></i> Windows 8.1 / ';
} else if(preg_match('/nt 5.1/i', $agent)) {
$os = ' <i class="ua-icon icon-win1"></i> Windows XP / ';
} else if (preg_match('/nt 10.0/i', $agent)) {
$os = ' <i class="ua-icon icon-win2"></i> Windows 10 / ';
} else{
$os = ' <i class="ua-icon icon-win2"></i> Windows X64 / ';
}
} else if (preg_match('/android/i', $agent)) {
if (preg_match('/android 9/i', $agent)) {
$os = ' <i class="ua-icon icon-android"></i> Android Pie / ';
}
else if (preg_match('/android 8/i', $agent)) {
$os = ' <i class="ua-icon icon-android"></i> Android Oreo / ';
}
else{
$os = ' <i class="ua-icon icon-android"></i> Android / ';
}
}
else if (preg_match('/ubuntu/i', $agent)) {
$os = ' <i class="ua-icon icon-ubuntu"></i> Ubuntu / ';
} else if (preg_match('/linux/i', $agent)) {
$os = ' <i class= "ua-icon icon-linux"></i> Linux / ';
} else if (preg_match('/iPhone/i', $agent)) {
$os = ' <i class="ua-icon icon-apple"></i> iPhone / ';
} else if (preg_match('/mac/i', $agent)) {
$os = ' <i class="ua-icon icon-mac"></i> MacOS / ';
}else if (preg_match('/fusion/i', $agent)) {
$os = ' <i class="ua-icon icon-android"></i> Android / ';
} else {
$os = ' <i class="ua-icon icon-linux"></i> Linux / ';
}
echo $os;
}
引入 HTML
将以下代码添加到 /usr/themes/Mirages/lib/comments.php 中 122 行所在的 div 中。
<span class="comment-ua">
<?php getOs($this->agent); ?>
<?php getBrowser($this->agent); ?>
</span>
10.SEO插件
Typecho-AMP-MIP
自动生成 Google AMP
和百度MIP
页面
生成 AMP / MIP 的站点地图,方便提交
后台批量提交 AMP/MIP 网址到百度,可选手动或自动
BaiduSubmit
生成适用于百度的站点地图,并显示搜索引擎请求情况
后台批量提交批量网址到百度,可选手动或自动
ShortLinks
把博客中的外部链接转换为网站内链,据说有利于搜索引擎收录
具体可以看下篇Typecho 开启外链转内链
11.Typecho 开启外链转内链
把博客中的外部链接转换为网站内链,据说有利于搜索引擎收录。
食用方法
下载地址
https://github.com/benzBrake/ShortLinks/releases
将下载解压好的文件夹放到 Plugins 目录(注意:文件夹名必须是ShortLinks)
启用插件
在插件设置中外链转内链和转换评论者链接都要开启 > 跳转页面开关开启(不开启则不显示跳转动画)> 跳转延时填 2 秒 ==> 保存设置。
修复冲突
实测插件与本主题冲突,需做如下修改,当然若链接可正常转换则无需操作。打开Typecho根目录/usr/plugins/ShortLinks/Plugin.php
,分别搜索如下内容并做相应修改,最后禁用再启用插件
。
冲突1
搜索
Typecho_Plugin::factory('Widget_Abstract_Contents')->contentEx
更改为
Typecho_Plugin::factory('Mirages_Plugin')->contentEx
冲突2
搜索
Typecho_Plugin::factory('Widget_Abstract_Contents')->excerptEx
更改为
Typecho_Plugin::factory('Mirages_Plugin')->excerptEx
修改模板
左岸大佬为项目提供了四套跳转模板,将喜欢的模板重命名为 go.html 即可食用,效果如下。
- 模板 go.html
- 模板一 go1.html
- 模板二 go2.html
- 模板三 go3.html
新页打开
插件设置里有新标签页打开文章外链
的选项,实测评论区并不可以,临时方法是打个 JS 补丁。将以下代码加入到<head>
标签中。对于本主题,依次进入控制台-外观-设置外观-主题自定义扩展
,将代码加入到自定义HTML元素拓展-标签:head 头部(meta 元素后)
,也可直接加入到主题对应的header.php
中的</head>
标签前。
<script>
// 评论区外链在新窗口打开
document.addEventListener('DOMContentLoaded', initOuterLinkInComment);
function initOuterLinkInComment() {
document.querySelectorAll('.comment-list a[href*="/go/"]').forEach(a => a.target = '_blank');
}
</script>
如果你开启了PJAX
,可能需要单独加入回调函数。对于本主题,依次进入控制台-外观-设置外观-PJAX(BETA)-PJAX RELOAD
,将initOuterLinkInComment();
添加进入即可。
12. Mirages 主题自定义公告样式
效果展示
使用步骤
将以下代码加入到<head>
标签中。对于本主题,依次进入控制台 - 外观 - 设置外观 - 主题自定义扩展
,将代码加入到自定义HTML元素拓展 - 标签: head 头部 (meta 元素后)
,也可直接加入到主题对应的header.php
中的</head>
标签前。
<script>
// 自定义公告显示
document.addEventListener('DOMContentLoaded', initNotice2);
document.head.append(document.createRange().createContextualFragment(
`<style>
.blog-notice {
display: none;
}
@media screen and (max-device-width: 767px) {
.el-notification.right {
margin: 0 auto;
left: 0;
right: 0 !important;
}
}
</style>`
).firstElementChild);
function initNotice2() {
const common = {
loadResource: function (id, resource, type) {
return new Promise(function (resolve, reject) {
let loaded = document.head.querySelector('#' + id);
if (loaded) {
resolve('success: ' + resource);
return;
}
const element = document.createElement(type);
element.onload = element.onreadystatechange = () => {
if (!loaded && (!element.readyState || /loaded|complete/.test(element.readyState))) {
element.onload = element.onreadystatechange = null;
loaded = true;
resolve('success: ' + resource);
}
}
element.onerror = function () {
reject(Error(resource + ' load error!'));
};
if (type === 'link') {
element.rel = 'stylesheet';
element.href = resource;
} else {
element.src = resource;
}
element.id = id;
document.getElementsByTagName('head')[0].appendChild(element);
});
},
loadResources: function () {
const initVue = this.initVue;
const loadResource = this.loadResource;
const host = '//s0.pstatp.com/cdn/expire-1-M/';
const resources = [
'vue/2.6.10/vue.min.js',
'element-ui/2.8.2/index.js',
'element-ui/2.8.2/theme-chalk/index.css'
];
const loadPromises = [];
resources.forEach(resource => {
loadPromises.push(loadResource(btoa(resource).replace(/[=+\/]/g, ''), host + resource,
({
'css': 'link',
'js': 'script'
})[resource.split('.').pop()]
));
});
Promise.all(loadPromises).then(
function () {
let flag = false;
const waitVue = setInterval(() => {
if (!flag && typeof Vue === 'function') {
flag = true;
initVue();
clearInterval(waitVue);
}
}, 100);
}
);
},
initVue: function () {
var blog = new Vue({
el: document.createElement('div'),
created() {
this.sayHello();
if (this.notice) {
this.showNotice();
}
window.alert = this.alert;
},
computed: {
notice: function () {
const blgNotice = document.querySelector('.blog-notice p');
if (blgNotice) {
const oldNotice = localStorage.getItem('BLOG-NOTICE');
const newNotice = blgNotice.innerText;
if (!oldNotice || oldNotice !== newNotice) {
return newNotice;
}
}
return ''
},
hello: function () {
var hours = (new Date()).getHours()
var t
if (hours < 5) {
t = '凌晨好,注意休息哦!'
} else if (hours >= 5 && hours < 8) {
t = '早上好,新的一天又是元气满满呢!'
} else if (hours >= 8 && hours < 12) {
t = '上午好!'
} else if (hours === 12) {
t = '中午好!'
} else if (hours > 12 && hours <= 18) {
t = '下午好!'
} else if (hours > 18 && hours <= 22) {
t = '晚上好!'
} else if (hours > 22 && hours < 24) {
t = '夜深了,注意休息哦!'
}
return t
}
},
methods: {
alert: function (message, title, type, duration, showClose, offset, onClose) {
if (duration !== 0) {
duration = 4500;
}
this.$notify({
message: message,
type: type || 'error',
title: title || '警告',
duration: duration,
showClose: showClose || false,
offset: offset || 0,
onClose: onClose
})
},
showNotice: function () {
setTimeout(() => {
const notice = this.notice;
this.alert(notice, '公告', 'info', 0, true, null, function () {
localStorage.setItem('BLOG-NOTICE', notice);
});
}, 1000);
},
sayHello: function () {
setTimeout(() => {
this.alert('欢迎来到 谭先生 的博客!', this.hello, 'success');
}, 1000);
}
},
})
}
};
common.loadResources();
}
</script>
13.Typecho主流音乐插件及YouduPlayer完全配置指南
主流的音频播放插件有APlayer和Youdu Player,前者支持直接填写网易云歌单、歌手 ID,还支持歌词显示,而后者一开始也内置了网易云 API,但随着猪场 API 改变便不再支持了。所以方便起见选择前者,但如果你喜欢后者的界面,也就是本博客使用的,可以接着往下看。
生成网易云歌单配置
无需多言,首先要安装该插件,具体看作者主页介绍。接着你可以将歌曲上传到 CDN 或网站,然后按作者指定格式编写插件配置。
不过,我已经编写了 Youdu Player 配置生成器,你可以使用它直接生成网易云歌单配置。具体操作为:在网易云新建歌单
,将想要展示的音乐加进去。接着选择分享
,将分享链接在PC
浏览器打开
,随后复制浏览器地址
,将其粘贴到配置生成器中点击生成
,随后点击复制
,最后将配置粘贴到插件后台
。
调整 Youdu Player 界面
插件默认风格可能与博客不符,不过它预留了自定义 CSS 接口。下面的我的 CSS 配置,主要调整了高度,进度条颜色,歌曲名称间隔以及长歌曲名不换行等。
/* 高度 */
#bgmpanel, span.bgmbuttom {
height: 72px;
}
/* 进度条颜色 */
#jindu {
background-color: red;
}
/* 歌名与作者间距 */
.artist {
float: initial !important;
margin-left: 5px;
}
/* Chrome 隐藏滚动条 */
.yd-lib::-webkit-scrollbar {
display: none !important;
}
.yd-lib {
/* 歌曲上下间距 */
margin: 5px 0;
/* 歌曲信息超出不换行 */
white-space: nowrap;
overflow-x: scroll;
/* 火狐隐藏滚动条 */
overflow: -moz-hidden-unscrollable;
scrollbar-width: none;
/* IE、EDGE 隐藏滚动条 */
-ms-overflow-style: none !important;
}
14.Mirages主题非侵入式友链随机教程
友链随机
,你可以刷新该页面查看效果。使用方法
将以下代码粘贴到友链页文章末尾
即可,其他主题,包括Wordpress
, 改一下CSS 选择器
应该也可以使用。
!!!
<script>
(() => {
const linkBox = document.querySelector('.link-box');
const links = linkBox.children;
let sequence = [...new Array(links.length).keys()];
for (let i = links.length - 1; i > 0; i--) {
const random = Math.floor(Math.random() * i);
[sequence[i], sequence[random]] = [sequence[random], sequence[i]];
}
let innerHTML = '';
sequence.forEach(value => innerHTML += links[value].outerHTML);
linkBox.innerHTML = innerHTML;
})();
</script>
!!!
15.代码颜色
一般情况下代码为灰底红字,而主题默认的不够鲜艳。只需在主题设置 - 高级选项 - 真 • 高级设置中填入codeColor = #f44242
。注意自定义主色调必须使用Hex Color
16.为 Typecho 评论添加邮件提醒
项目地址
食用步骤
下载插件
上传到typecho根目录/usr/plugins
,下载插件代码并将文件夹重命名为Comment2Mail
。
填写配置
依次进入控制台 -> 插件
,启用 Comment2Mail,随后进入插件设置填写邮箱后保存。需要注意的是,如果使用 QQ 邮箱,密码栏应填写授权码,而非 QQ 密码。
模板修改
默认模板比较简陋,分享一个reply.html
模板,效果如下,请自行 DIY。
<meta charset="utf-8">
<div style="position:relative;width:450px;height:auto;margin:0 auto;padding-bottom:5px;border:rgb(224, 221, 224) solid 1px;border-radius:10px">
<div style="background-image:url(https://cdn.tandongtao.com/usr/uploads/images/UTB8uTIaPSnEXKJk43Ubq6zLppXaW.jpg);width:100%;height:300px;background-size:cover;background-repeat:no-repeat;border-radius:10px 10px 0px 0px"></div>
<div style="width:40%;height:40px;background-color:rgb(231, 145, 145);margin-top:-20px;margin-left:20px;color:#fff;text-align:center;line-height:40px;border-radius:30px">
亲爱的:{author} !
</div>
<div style="line-height:180%;padding:0 15px 12px;width:90%;margin:auto;margin-bottom:0px;font-size:12px">
<div style="border-bottom:1px solid rgb(216, 213, 213);font-size:13px;margin:10px 0px;padding:10px 0px">
<span style="color:#12ADDB;font-weight:bold">> </span>
<span>您在</span>
<a style="text-decoration:none;color:#12ADDB;font-weight:bold;" href="{permalink}" target="_blank">《{title}》</a>
<span>的评论有了新回复呢!</span>
</div>
<div style="padding:0 10px 0 10px;margin-top:18px">
<p>您的评论:</p>
<p style="padding:10px 15px;margin:18px 0;border-radius:30px;background-color:rgb(255, 240, 240);">{text}</p>
<p><strong>{replyAuthor}</strong> 给您的回复:</p>
<p style="padding:10px 15px;margin:18px 0;border-radius:30px;background-color:rgb(240, 240, 255);">{replyText}</p>
</div>
</div>
<div
style="color:#8c8c8c;font-size:8px;width:93%;margin:auto;margin-top:-30px">
<p style="padding:20px;">萤火虫消失之后,那光的轨迹仍久久地印在我的脑际。那微弱浅淡的光点,仿佛迷失方向的魂灵,在漆黑厚重的夜幕中彷徨。——《挪威的森林》村上春树</p>
</div>
<a style="text-decoration:none;background-color:rgb(155, 151, 221);color:#FFF;width:40%;text-align:center;height:40px;line-height:40px;box-shadow:5px 5px 5px rgba(0,0,0,0.2);margin:-10px auto;display:block;border-radius:30px" href="{commentUrl}" target="_blank">查看完整回复內容</a>
<div style="color:#8c8c8c;font-size:8px;width:100%;text-align:center;margin-top:30px">
<p>本邮件为系统自动发送,请勿直接回复哦!</p>
</div>
<div style="color:#8c8c8c;font-size:8px;width:100%;text-align:center">
<p>Copyright © {blogName}. All Rights Reserved.</p>
</div>
</div>
17.Typecho 网站添加复制提醒
这边使用的是 layer 的 web 弹层组件,详情查看layer官网
食用方法
依次进入控制台 - 外观 - 设置外观 - 主题自定义扩展
,将以下代码加入到自定义 HTML 元素拓展 - 在 body 标签结束前
<!-- 引入layer.js,也可以替换成别的源 -->
<script src="https://cdn.staticfile.org/layer/3.1.1/layer.js"></script>
<!-- 复制提醒 -->
<script>document.body.oncopy = function() {layer.msg('复制成功,若要转载请务必保留原文链接!');};</script>
- 打开官网
- 点击下载
- 上传至服务器
18.浏览统计和热门文章调用插件TePostViews
TePostViews是一款简单的 typecho 热门文章调用插件,通过该插件可以显示每篇文章的阅读次数,以及调用阅读次数最多或者评论数最多的文章作为热门文章调用,用户可以自由选择调用依据和调用文章的数量,使用相当简单。
插件使用方法:
1、把下载的压缩包解压,上传 TePostViews 文件夹到 usr/plugins/ 目录;
2、进入网站后台 —— 控制台 —— 插件中启用 TePostViews 插件;
3、在主题的 post.php 文件添加阅读次数调用代码:
阅读:<?php $this->viewsNum();?>
4、在主题的 sidebar.php 文件(或其它文件)添加热门文章调用代码:
<?php TePostViews_Plugin::outputHotPosts() ?>
5、保存文件即可。
插件设置:
进入后台 —— 控制台 —— 插件页面,点击 TePostViews 插件后面的【设置】可以对插件的参数进行配置
需要注意的是【卸载设置】,如果选择删除数据,卸载插件可数据不可恢复!
19.Typecho防黑安全加固
删除安装文件
成功安装后删除install.php
文件、install/
文件夹。
修改后台地址
把admin
修改为黑客猜不到的名字,例如 pipixia,防止黑客穷举密码。
修改`admin`文件夹名称
修改admin
文件夹名称为你喜欢的名称,例如 pipixia
修改配置文件以适配修改后的`admin`路径
修改config.inc.php
修改为以下代码,我就当修改为pipixia了。
/** 后台路径(相对路径) */
define('__TYPECHO_ADMIN_DIR__', '/pipixia/');
好了。现在你可以访问你的域名/pipixia/ 了。这就是你的新的后台地址,原来的你的域名/admin/ 已经不能访问了。
屏蔽 usr、var 目录下 php 文件的访问
屏蔽usr
、var
目录下php
文件的访问可以阻止黑客访问到他上传的 php木马。
我们利用 Rewrite 伪静态机制来做。我这里以 Apache 服务器为例,大部分虚拟主机都是 Apache。LiteSpeed Web Server 也使用的是 Apache 的规则。
我们同时屏蔽 config.inc.php 和.htaccess 的访问。
屏蔽原理就是把要屏蔽的请求重定向到首页文件,首页文件会当成文章名来解析,没有同名文章就会返回 404 未找到。所以就算黑客上传了木马也只会得到 404 未找到的响应。
文件名:.htaccess
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php [E=PATH_INFO:$1]
RewriteRule (var|usr)(.+ph*)$ index.php [E=PATH_INFO:$1]
RewriteRule (config.inc.php|.htaccess)$ index.php [L,E=PATH_INFO:$1]
</IfModule>
新建.htaccess 文件添加以上内容,上传到你 typecho 博客的根目录就可以了。
经测试 Nginx 和 OpenResty 下可用。
if (!-e $request_filename) {
rewrite ^(.*)$ /index.php$1;
}
rewrite /(var|usr)(.+ph*)$ /index.php;
rewrite /(config.inc.php|.htaccess)$ /index.php last;
20.文章标签选择器
插件名为 tagshelper(Typecho 插件)
作用:在 Typecho 文章编辑页面右下方标签位置的下方,会显示出你的博客所有的标签(常用标签会显示在前面),点击任意标签即可为当前文章添加选中的标签。
具体操作如下图:
插件下载地址
21.网站内容的禁止复制和粘贴
1、使右键和复制失效
方法 1:
在网页中加入以下代码:
<script language="Javascript">
document.oncontextmenu=new Function("event.returnValue=false");
document.onselectstart=new Function("event.returnValue=false");
</script>
方法 2:
在 <body> 中加入以下代码:
<body oncontextmenu="return false" onselectstart="return false">
或
<body oncontextmenu="event.returnValue=false" onselectstart="event.returnValue=false">
实质上,方法 2 与方法 1 是一样的。
方法 3:
如果只限制复制,可以在 <body> 加入以下代码:
<body oncopy="alert('对不起,禁止复制!');return false;">
2、使菜单 "文件"-"另存为" 失效
如果只是禁止了右键和选择复制,别人还可以通过浏览器菜单中的 "文件"-"另存为" 拷贝文件。为了使拷贝失效,可以在 <body> 与 </body> 之间加入以下代码:
<noscript>
<iframe src="*.htm"></iframe>
</noscript>
这样,用户在另存网页时,就会出现 "无法保存 Web 页" 的错误。
————————————————————————————————————
另外,也可以使用 event.preventDefault () 方法来阻止 oncontextmenu () 还有 onselectstart ()
document.oncontextmenu=function(evt){
evt.preventDefault();
}
document.onselectstart=function(evt){
evt.preventDefault();
};
既然可以禁止,那么当然也可以启用它,将事件重新赋值即可,可以赋值为 null,或字符串、布尔值都行。如:
document.oncontextmenu="";
document.onselectstart=true;
或者 禁用 js:打开谷歌浏览器,选择 “设置” – 选择 “隐私设置” – 选项 “内容设置” – 选择 “JavaScript” – 选择 “不允许任何网站运行 JavaScript”,设置完成刷新即可。
22.关于Font Awesome图标的使用 加入动态效果
1.引入CSS
本主题在控制台——>设置外观——>主题自定义扩展——>自定义 HTML 元素拓展-标签: head 尾部 (head 标签结束前)
进行添加
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/font-awesome-animation@0.2.1/dist/font-awesome-animation.min.css">
2.修改图标以及动画效果
<i class="fa fa-heartbeat faa-flash animated " aria-hidden="true" style="color: rgba(255, 0, 0, 0.9)"></i>
图标样式可参考【这里】
动态样式可参考【这里】
测试效果可参考我的主页【演示界面】
速度优化
1.GZIP加速网站
找到你的Typecho的网站根目录中的index.php,添加如下代码
/* 开启gzip压缩 */
ob_start('ob_gzhandler');
添加的位置
<?php
/**
* Typecho Blog Platform
*
* @copyright Copyright (c) 2008 Typecho team (http://www.typecho.org)
* @license GNU General Public License 2.0
* @version $Id: index.php 1153 2009-07-02 10:53:22Z magike.net $
*/
/**开启gzip */
ob_start('ob_gzhandler');
/** 载入配置支持 */
if (!defined('__TYPECHO_ROOT_DIR__') && !@include_once 'config.inc.php') {
file_exists('./install.php') ? header('Location: install.php') : print('Missing Config File');
exit;
}
/** 初始化组件 */
Typecho_Widget::widget('Widget_Init');
/** 注册一个初始化插件 */
Typecho_Plugin::factory('index.php')->begin();
/** 开始路由分发 */
Typecho_Router::dispatch();
/** 注册一个结束插件 */
Typecho_Plugin::factory('index.php')->end();
2.Gravatar头像国内源
找到Typecho的安装目录中的config.inc.php
文件,添加一行代码更换为国内v2ex源
define('__TYPECHO_GRAVATAR_PREFIX__', 'https://cdn.v2ex.com/gravatar/');
更多镜像源
P.S 直接替换上边的地址就行了
http://gravatar.ihuan.me/avatar/
https://gravatar.proxy.ustclug.org/
https://cdn.v2ex.com/gravatar/
http://dn-qiniu-avatar.qbox.me/avatar
https://gravatar.loli.net/avatar/
3.网站预加载JS脚本instant.page
原理介绍及作用
插件名称为 instant.page,由国外大佬开发,基于 JS,作用是预加载网页。具体实现为鼠标悬停 65ms 后触发浏览器下载,宣称可让网站加载时间缩短到 1 分钟以内,并提高 1% 的转化率。效果咱不知道,使用倒是简单,往上怼就是了。
食用方法
一、使用官方提供的带有 Cloudflare 加速的脚本
建议服务器在国外的朋友使用。只要把这行代码添加到网站的 </body>标签之前即可。(一般都可以在后台直接添加)
<script src="//instant.page/1.2.2" type="module" integrity="sha384-2xV8M5griQmzyiY3CDqh1dn4z3llDVqZDqzjzcY+jCBCk/a5fXJmuZ/40JJAPeoU"></script>
二、自托管
建议服务器在国内的朋友使用。只需将下面这段 js 上传到自己服务器,然后在 </body>标签之前根据路径添加下面的代码即可。点击查看
<script src="`存放路径`/instantclick-1.2.2.js" type="module"></script>
赞一个,很实用!@(滑稽)
小胡同志,欢迎你的到来,要常来喔::quyin:1huaji::