由于我准备把侧边栏时钟功能移除掉了，但是之前魔改的代码还是想留着，所以有了本文，爱折腾，有兴趣的可以尝试一下！效果预览魔改步骤1.新建 card_clock.pug，添加如下内容if theme.aside.card_clock.enable style. .clock_frame { background: var(--Jay-main); display: flex; justify-content: center; align-content: center; box-shadow: var(--Jay-shadow-border); background: var(--Jay-card-bg); border: var(--style-border); border-radius: 12px; transition: .3s; position: relative; overflow: hidden; margin-top: 1rem; } .clock { width: 256px; height: 256px; border-radius: 50%; background-color: #fff; position: relative; overflow: hidden; } .clock::after { content: ""; width: calc(256px - 80px); height: calc(256px - 80px); background-color: inherit; border-radius: 50%; display: block; position: absolute; top: 0; right: 0; bottom: 0; left: 0; margin: auto; } .clock .marker { height: calc(100% - 25px); width: 3.2px; background-color: rgb(52 73 94 / 40%); position: absolute; top: 0; right: 0; bottom: 0; left: 0; margin: auto; } .clock .marker:nth-of-type(3n + 1) { background: rgb(52 73 94); } .clock .marker:nth-of-type(2) { transform: rotate(30deg); } .clock .marker:nth-of-type(3) { transform: rotate(60deg); } .clock .marker:nth-of-type(4) { transform: rotate(90deg); } .clock .marker:nth-of-type(5) { transform: rotate(120deg); } .clock .marker:nth-of-type(6) { transform: rotate(150deg); } .clock .hand { transform-origin: center bottom; position: absolute; z-index: 3; bottom: 50%; left: 50%; width: 5.12px; transition: transform 1s linear; } .clock .hand.second { height: 85.3333333333px; width: 1.3837837838px; left: calc(50% - 1.5px); border-radius: 1.5px; background-color: #ec231e; box-shadow: 4px 6px 0 0 rgba(0, 0, 0, 0.15); transform: rotate(40deg); z-index: 9; } .clock .hand.second::before, .clock .hand.second::after { content: ""; background-color: inherit; position: absolute; border-radius: 50%; left: 50%; } .clock .hand.second::before { width: 12.8px; height: 12.8px; bottom: 0; transform: translate(-50%, 50%); box-shadow: 2px 2px 2px 0 rgba(0, 0, 0, 0.15); } .clock .hand.second::after { width: 7.1111111111px; height: 7.1111111111px; top: 17.0666666667px; transform: translate(-50%, 0); box-shadow: 4px 6px 2px 0 rgba(0, 0, 0, 0.15); } .clock .hand.minute { height: 85.3333333333px; left: calc(50% - 3px); border-radius: 3px; background-color: rgb(52 73 94); } .clock .hand.hour { height: 64px; left: calc(50% - 3px); border-radius: 3px; background-color: rgb(52 73 94); } @media screen and (max-width: 768px) { .clock_frame { display: none; } } @-webkit-keyframes rotateArms { from { transform: rotate(0); } to { transform: rotate(360deg); } } @keyframes rotateArms { from { transform: rotate(0); } to { transform: rotate(360deg); } } .cat_block.clock_frame .clock .marker .marker .marker .marker .marker .marker .hand.second .hand.minute .hand.hour script. let secondPlus = 0; function getTime() { let date = new Date(), seconds = date.getSeconds() * 6, minutes = date.getMinutes() * 6, hours = (date.getHours() % 12) * 30 + minutes / 15; if (seconds == 0) { secondPlus += 360; } document.querySelector(".hand.second").style.transform = "rotate( " + (seconds + secondPlus) + "deg)"; document.querySelector(".hand.minute").style.transform = "rotate( " + minutes + "deg)"; document.querySelector(".hand.hour").style.transform = "rotate( " + hours + "deg)"; } setInterval(function() { getTime(); }, 1000); 2.在 theme\layout\includes\widget\index.pug 中的侧边栏引入//- 时钟 !=partial('includes/widget/card_clock', {}, {cache: true})3.主题配置文件 _config.mxblog.yml 添加开关aside: card_clock: enable: true # 时钟至此，你的侧边栏将多了一个时钟，快去试试吧！
这篇文章与其说是分享，不如直接说是我部署过程的记录，虽然文中写到的东西在其他博客都能找到，但是我仍然还是记录下我使用到的部署流程，方便我以后换服务器，或是其他特殊原因，需要重新部署时查阅前言昨天心血来潮，把服务器又折腾了一番，之前采用Nginx + Docker方式部署，所有映射及转发都采用手动配置，当然这些对于我来说并没什么难度，而现在采用baota + Nginx + Docker方式部署，目前使用的是静态博客，以及fcircle + twikoo部署都更为便捷，下面分享内容主要以文字为主，可能不会截图，这部分部署相信大家都会安装由于我的服务器并不是纯净系统，所以不能直接安装宝塔，当然网络上也有人说可以通过 docker 安装 centos 方式来安装，但是我没试，而采用粗暴方式，重装系统（记得备份），我这里选择宝塔专享版的镜像直接安装安装完后，发现这个专享版什么也不带，需要自己安装Apache、Nginx，当然php也不能少部署部署 hexo源代码拉到服务器，然后hexo g编译，宝塔配置目录绑定即可，eg：/www/wwwroot/hexo_blog/public部署 fcircle 鱼塘之前部署在vercle上，总感觉不太稳定，现改为私有部署，我这里采用 docker 部署，官网部署docker安装 Docker CE 之前需要删除 Docker 旧版本yum remove docker docker-common docker-selinux docker-engine安装 Docker 所需的软件包yum install -y yum-utils device-mapper-persistent-data lvm2设置 docker yum 源yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo安装 DOCKER CEyum install docker-ce yum list docker-ce --showduplicates | sort -r #要安装特定版本的Docker CE，请列出repo中的可用版本启动 Dockersystemctl start docker systemctl status docker安装gityum install -y git宝塔中自带python，在软件商店直接安装即可，我这里采用服务器安装模式安装依赖yum -y install zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-devel tk-devel gdbm-devel db4-devel libpcap-devel xz-devel libffi-devel yum vim gcc安装 pythonwget https://www.python.org/ftp/python/3.8.8/Python-3.8.8.tgz tar -zxf Python-3.8.8.tgz && cd Python-3.8.8 ./configure --prefix=/usr/local/python3 make && make install建立软连接ln -s /usr/local/python3/bin/python3.8 /usr/bin/python3 ln -s /usr/local/python3/bin/pip3.8 /usr/bin/pip3验证(出现版本号即安装成功)python3 --version安装 yamlpip3 install pyyaml停止运行找到进程号，杀掉即可ps auxkill 掉 PID 即可，也可通过fcircle项目中python3 deploy.py脚本一键取消运行部署后端克隆仓库git clone https://github.com/Rock-Candy-Tea/hexo-circle-of-friends拉取镜像docker pull yyyzyyyz/fcircle:latest运行部署脚本 进入hexo-circle-of-friends根目录，运行一下脚本，选择docker -> 部署即可python3 deploy.py尝试访问：curl 127.0.0.1:8000/all，有数据即为部署成功，再使用域名反向代理即可部署前端官网、heo、akilar、安知鱼部署 twikoo官网拉取镜像docker pull imaegoo/twikoo运行容器docker run --name twikoo -e TWIKOO_THROTTLE=1000 -p 8080:8080 -v /root/twikoo/data:/app/data -d imaegoo/twikoo部署卜算子搭建docker + docker-compose环境；宝塔添加静态页面，绑定域名busuanzi.lovelu.top，别忘记添加解析；进入/www/wwwroot/busuanzi.lovelu.top下，新建docker-compose.yaml，内容如下；version: "2" services: redis: image: "redis:alpine" volumes: - /root/busuanzi/redis:/data bsz: image: "xcsoft/busuanzi:latest" ports: - "8999:8080" volumes: - /root/busuanzi:/app/expose links: - redis depends_on: - redis environment: LOG_ENABLE: true API_SERVER: http:\/\/127.0.0.1:8999\/api端口根据自己需要，因为我 8080 占用，所以改用 8999，记得添加解析，以及防火墙配置其中你需要修改API_SERVER为你的地址，例如你的网址为busuanzi.lovelu.top，那么就需要填写https://busuanzi.lovelu.top/api修改完成后，执行docker-compose up -d 4. 宝塔设置反代将http://127.0.0.1:8999进行代理即可另外有个坑，记录一下这个的 id 名为：busuanzi_page_pv我的原来是：busuanzi_value_page_pv如果你的也是busuanzi_value_site_pv，需要更改一下。butterfly 主题可以到themes/butterfly/layout/includes/header/post-info.pug文件中修改部署百度统计网站域名根目录，新建info.php，内容如下<?php // 设置允许所有来源的请求 header("Access-Control-Allow-Origin: *"); // 设置API密钥和网站ID $apiKey = ''; $secretKey = ''; $siteId = ''; $code = ''; // 通过授权码获取Access Token函数 function getAccessToken($apiKey, $secretKey, $code) { $url = "https://openapi.baidu.com/oauth/2.0/token"; $params = array( 'grant_type' => 'authorization_code', 'code' => $code, 'client_id' => $apiKey, 'client_secret' => $secretKey, 'redirect_uri' => 'oob', ); $query = http_build_query($params); $response = file_get_contents($url . '?' . $query); if ($response === false) { die('Error fetching access token.'); } $data = json_decode($response, true); return $data; } // 刷新Access Token函数 function refreshAccessToken($apiKey, $secretKey, $refreshToken) { $url = "https://openapi.baidu.com/oauth/2.0/token"; $params = array( 'grant_type' => 'refresh_token', 'refresh_token' => $refreshToken, 'client_id' => $apiKey, 'client_secret' => $secretKey, ); $query = http_build_query($params); $response = file_get_contents($url . '?' . $query); if ($response === false) { die('Error refreshing access token.'); } $data = json_decode($response, true); return $data; } // 持久化存储令牌 function saveTokens($accessToken, $refreshToken) { file_put_contents('tokens.json', json_encode(array( 'access_token' => $accessToken, 'refresh_token' => $refreshToken, ))); } // 从文件中加载令牌 function loadTokens() { if (!file_exists('tokens.json')) { return null; } return json_decode(file_get_contents('tokens.json'), true); } // 检查并刷新令牌 function checkAndRefreshTokens($apiKey, $secretKey) { $tokens = loadTokens(); if ($tokens === null) { global $code; $tokens = getAccessToken($apiKey, $secretKey, $code); saveTokens($tokens['access_token'], $tokens['refresh_token']); } else { $tokens = refreshAccessToken($apiKey, $secretKey, $tokens['refresh_token']); saveTokens($tokens['access_token'], $tokens['refresh_token']); } return $tokens; } // 定义获取数据的函数 function getData($startDate, $endDate, $metrics, $accessToken, $siteId) { $url = "https://openapi.baidu.com/rest/2.0/tongji/report/getData"; $params = array( 'access_token' => $accessToken, 'site_id' => $siteId, 'method' => 'overview/getTimeTrendRpt', 'start_date' => $startDate, 'end_date' => $endDate, 'metrics' => $metrics, ); $query = http_build_query($params); $fullUrl = $url . '?' . $query; $response = file_get_contents($fullUrl); if ($response === false) { die('Error fetching data.'); } return json_decode($response, true); } // 定义缓存文件路径 $cacheFile = 'data_cache.json'; $cacheTime = 60; // 缓存时间，单位：秒 // 获取Access Token并刷新令牌 $tokens = checkAndRefreshTokens($apiKey, $secretKey); $accessToken = $tokens['access_token']; // 检查缓存文件是否存在且未过期 if (file_exists($cacheFile) && (time() - filemtime($cacheFile) < $cacheTime)) { $data = json_decode(file_get_contents($cacheFile), true); } else { // 准备数据 $data = array( 'today_uv' => null, 'today_pv' => null, 'yesterday_uv' => null, 'yesterday_pv' => null, 'last_month_pv' => null, 'last_year_pv' => null, ); // 获取最近31天的数据 $startDate = date('Ymd', strtotime('-31 days')); $endDate = date('Ymd'); $monthData = getData($startDate, $endDate, 'pv_count,visitor_count', $accessToken, $siteId); // 处理并提取最近31天的数据 $last31DaysPV = 0; if (isset($monthData['result']['items'][1])) { $dataPoints = $monthData['result']['items'][1]; foreach ($dataPoints as $point) { // $last31DaysPV += $point[0]; $last31DaysPV += intval($point[0]); } } // 获取一整年的数据 $startDate = date('Ymd', strtotime('-1 year')); $endDate = date('Ymd'); $yearData = getData($startDate, $endDate, 'pv_count,visitor_count', $accessToken, $siteId); // 处理并提取所需数据 if (isset($yearData['result']['items'][1])) { $dataPoints = $yearData['result']['items'][1]; $today = date('Y/m/d'); $yesterday = date('Y/m/d', strtotime('-1 day')); $lastMonth = date('Y/m/d', strtotime('-30 days')); foreach ($yearData['result']['items'][0] as $index => $date) { if ($date[0] == $today) { $data['today_uv'] = $dataPoints[$index][1]; $data['today_pv'] = $dataPoints[$index][0]; } elseif ($date[0] == $yesterday) { $data['yesterday_uv'] = $dataPoints[$index][1]; $data['yesterday_pv'] = $dataPoints[$index][0]; } elseif ($date[0] == $lastMonth) { $data['last_month_pv'] = $dataPoints[$index][0]; } } $data['last_year_pv'] = array_sum(array_column($dataPoints, 0)); } // 添加最近31天的PV总和 $data['last_month_pv'] = $last31DaysPV; // 保存数据到缓存文件 file_put_contents($cacheFile, json_encode($data)); } // 返回JSON数据 header('Content-Type: application/json'); echo json_encode($data); ?>再来说说页头几个参数怎么获取获取apiKey和secretKey，数据导出服务获取code，将其中{CLIENT_ID}替换为你的apiKeyhttp://openapi.baidu.com/oauth/2.0/authorize?response_type=code&client_id={CLIENT_ID}&redirect_uri=oob&scope=basic&display=popup获取siteId，siteid为你的网站id，查看百度统计报告的url中会显示siteid以上信息修改完后，立即访问一次，防止过期防止泄露token宝塔站点中添加访问限制名称：禁止访问tokens 后缀：tokens.json 目录：baidutongji然后尝试访问一次tokens.json，如果访问失败了就大功告成。一套部署下来，服务器内存占用还是比较客观，下面再去部署一个图床吧参考：Heo、Akilar、安知鱼以上我的部署就完成了，剩下就是配置反向代理以及 SSL 了
博客页脚之前使用的是友联朋友圈部署随机获取的，前段时间突然发现无法访问了，重启才恢复正常，所以想将这部分独立出来，不再依赖友联朋友圈，废话不多说，开整介绍两种魔改方案，一种是通过json方式来读取，另一种是通过hexo内置过滤器来实现通过json方式实现此方式就是需要手动创建json，每次添加友联补充进json文件即可【新建】butterfly/source/frendlink.json[{ "class_name": "推荐", "class_desc": "参与本站开发、提供设计灵感、捐助本站的优秀博主，综合排序", "class_mode": "MxBlog", "link_list": [ { "name": "满心", "link": "https://zhoutian.com" }, { "name": "Jayhrn", "link": "https://blog.jayhrn.com" } ] }, { "class_name": "资源", "class_desc": "寻找资源不迷路", "class_mode": "MxBlog", "link_list": [ { "name": "steven安", "link": "https://chenjunan.top/" }, { "name": "MacApp分享", "link": "https://macapp.org.cn/" }, { "name": "精品MAC", "link": "https://pomac.cc/" } ] } ]js中添加如下var mx = { addFriendLinksInFooter: function () { var fetchUrl = "/mx/friendlink.json"; fetch(fetchUrl) .then((res) => res.json()) .then((json) => { var result = []; var prevIndex = -1; for (const item of json) { const links = item.link_list; for (let i = 0; i < Math.min(links.length, 1); i++) { let index = Math.floor(Math.random() * links.length); while (index === prevIndex && links.length > 1) { index = Math.floor(Math.random() * links.length); } prevIndex = index; result.push({ name: links[index].name, link: links[index].link, }); links.splice(index, 1); } } //删除result中最后一个元素 result.pop(); var htmlText = ""; for (let i = 0; i < result.length; ++i) { var item = result[i]; htmlText += `${item.name}`; } htmlText += `更多`; document.getElementById("friend-links-in-footer").innerHTML = htmlText; }); } }【修改】butterfly/layout/includes/additional-js.pug//- 初步进入需要加载的函数 .js-pjax script. mx.addFriendLinksInFooter()该方法，每天添加友联后，在json文件对应类别中添加即可方案二（推荐）此方式较为简单，无需json文件，直接读取，此方案来源于jayhrn【新建】butterfly/scripts/helpers/random.jshexo.extend.filter.register('after_render:html', function (data) { const flinks = [] hexo.locals.get('data').link.map(function (list) { list.link_list.map(function (flink) { flinks.push(flink) }) }) data += ` ` return data })jsaddFriendLinksInFooter: function() { let randomFriendLinks = getRandomFlink(3) let htmlText = ''; for (let i = 0; i < randomFriendLinks.length; ++i) { let item = randomFriendLinks[i] htmlText += `${item.name}`; } htmlText += `更多` document.getElementById("friend-links-in-footer").innerHTML = htmlText; }【修改】butterfly/layout/includes/additional-js.pug//- 初步进入需要加载的函数 .js-pjax script. mx.addFriendLinksInFooter()该方法较为简单，推荐使用
网站打开速度，一直是博主所关心的问题，那么除了优化系统本身、CDN等方式，还可以采用 gulp 来压缩资源，从而提升效率Gulp是什么Gulp 是一个基于 Node.js 的自动化构建工具，通过编写 JavaScript 脚本来定义任务，从而实现自动化构建。简单易用：Gulp 的 API 简单易用，不需要很多配置就能够快速上手。插件系统：Gulp 的插件系统丰富，几乎可以处理各种开发任务，包括文件压缩、合并、图片压缩、CSS 预处理器等。自动化构建：Gulp 可以自动监视文件变化，并自动执行相应的任务，大大提高了开发效率。流式处理：Gulp 使用流式处理，可以大大降低内存使用，提高构建速度。易于扩展：Gulp 使用 Node.js 开发，开发者可以自行编写插件来扩展其功能。综上所述，Gulp 是一个功能强大、易于使用和扩展的自动化构建工具，可以大大提高前端开发的效率。资源压缩静态资源：指在 Web 应用程序中，不需要动态生成内容的资源，例如 HTML、CSS、JavaScript、图片、字体等等。这些资源的特点是不会随着请求而发生变化，通常存储在服务器的文件系统中，并通过 HTTP 协议向客户端传输对于多媒体文件，很多资源都可以被压缩。尽管压缩多少会有一些失真（有损压缩），但只要失真程度不影响用户体验，我们也不必计较这些损失。最常见的压缩方式包括但不限于：使用webp格式、降低图片分辨率等。字体文件对于英文网站不会有特别严重的负担，但是中文字符数量非常庞大，如果把所有字符都囊括进来，一个字体文件动辄4MB，甚至有些能够超过20MB。因此，对字体文件进行压缩也是必要的。压缩字体文件有两种方案：从字体文件中提取出常用的文字或仅保留我们需要用到的文字。第二种方案的压缩率通常更高，同时也更安全，不会出现有些生僻字我们用到了却给删掉了的情况。但是，第二种方案每当更新网站内容时，就要生成新的字体文件，这就需要考虑客户端缓存的影响。教程下面我们使用 gulp 来压缩静态资源。注：我并没有通过gulp压缩多媒体资源，多媒体资源我是通过netlify插件，如果你需要压缩多媒体资源，可以自行去网上查找相应的插件。根目录执行，安装gulpnpm install --global gulp-cli npm install gulp --save安装插件，按需安装# 压缩HTML npm install gulp-htmlclean --save-dev npm install gulp-html-minifier-terser --save-dev # 压缩CSS npm install gulp-cssnano --save-dev # 压缩JS npm install gulp-terser --save-dev # 压缩TTF npm install gulp-fontmin --save-dev新建gulpfile.jsconst gulp = require("gulp") //用到的各个插件 const htmlMin = require('gulp-html-minifier-terser') const htmlClean = require('gulp-htmlclean') const terser = require('gulp-terser') const cssnano = require('gulp-cssnano') const fontmin = require('gulp-fontmin') // 压缩js gulp.task('minify-js', () => gulp.src(['./public/**/*.js', '!./public/**/*.min.js']) .pipe(terser({})) .pipe(gulp.dest('./public')) ) //压缩css gulp.task('minify-css', () => gulp.src(['./public/**/*.css']) .pipe(cssnano({ mergeIdents: false, reduceIdents: false, discardUnused: false, zIndex: false })).pipe(gulp.dest('./public')) ) //压缩html gulp.task('minify-html', () => gulp.src('./public/**/*.html') .pipe(htmlClean()) .pipe(htmlMin({ removeComments: true, //清除html注释 collapseWhitespace: true, //压缩html collapseInlineTagWhitespace: true, collapseBooleanAttributes: true, noNewlinesBeforeTagClose: false, removeAttributeQuotes: true, removeRedundantAttributes: true, //省略布尔属性的值，例如： ==> removeEmptyAttributes: true, //删除所有空格作属性值，例如： ==> removeScriptTypeAttributes: true, //删除 的type="text/javascript" removeStyleLinkTypeAttributes: true, //删除 和 的 type="text/css" minifyJS: true, //压缩页面 JS minifyCSS: true, //压缩页面 CSS minifyURLs: true //压缩页面URL })) .pipe(gulp.dest('./public')) ) //压缩字体 function minifyFont(text, cb) { gulp .src('./public/fonts/*.ttf') //原字体所在目录 .pipe(fontmin({ text: text })) .pipe(gulp.dest('./public/fontsdest/')) //压缩后的输出目录 .on('end', cb); } gulp.task('minify-ttf', (cb) => { var buffers = []; gulp .src(['./public/**/*.html']) //HTML文件所在目录请根据自身情况修改 .on('data', function (file) { buffers.push(file.contents); }) .on('end', function () { var text = Buffer.concat(buffers).toString('utf-8'); minifyFont(text, cb); }); }); //压缩 gulp.task("zip", gulp.parallel('minify-js', 'minify-css', 'minify-html', 'minify-ttf'))如果有不需要压缩的资源，直接删除或注释对应压缩代码即可。现在，只要我们在执行 hexo g 后执行 gulp zip 即可压缩我们想要压缩的资源了。下面是优化后的效果文件压缩前(KB)压缩后(KB)减少(KB)manxin.css358150208main.js271413注意使用gulp压缩TTF字体文件的方法。对于中文网站来说，由于中文字符数量庞大，如果把所有字符都囊括进字体文件中，一个字体文件很容易就会动辄4MB甚至超过20MB。因此，对字体文件进行压缩也是必要的。压缩字体文件主要有两种方案：第一种：从字体文件中提取出常用的文字或仅保留需要用到的文字。第二种：方案的压缩率通常更高，同时也更安全，因为不会出现删掉了实际需要的生僻字的情况。不过，第二种方案每当更新网站内容时，就要生成新的字体文件，这就需要考虑客户端缓存的影响。整合css我们可以通过将CSS整合进一个文件中来提高空间的利用率（原理自行百度"小文件多为什么占用空间大"）同时也能提高插件的压缩率（因为插件压缩的时候只会分析正在压缩的文件，不会分析多个CSS之间的关系）。整合CSS有两个方案，一种是手动整合，一种是修改源代码。尽量使用第二种方案，这里我只给出butterfly主题对应的方案，其它主题的读者可以自行摸索或者干脆用第一种方案。修改[butterfly]\source\css\index.styl// search if hexo-config('algolia_search.enable') @import '_search/index' @import '_search/algolia' if hexo-config('local_search') && hexo-config('local_search.enable') @import '_search/index' @import '_search/local-search' + @import '_custom/*.styl' + @import '_custom/*.css'然后在与该文件同级目录中新建文件夹_custom，接下来，我们把我们自己编写的CSS/styl文件全部放到这里就能直接整合进index.css中了。本地缓存另一个简单有效的方案就是配置网站的本地缓存，将网站的一部分静态资源缓存在客户端上。这样客户端在访问网站时，就可以减少一部分网络请求，以此优化用户体验，同时还能减轻服务器负担。我使用的ServiceWorker进行本地缓存，有兴趣的小伙伴可以看这篇博文：解剖SW原理暨博主SW实现
深色模式下，总感觉背景有点单调，也考虑过添加背景图，还是太花了，看到安知鱼的深色模式，感觉这就是我想要的效果，果断整上效果预览魔改步骤主题中添加配置项(butterfly.yml)# 深色模式粒子效果 darkCanvas: enable: true引入 js(additional-js.pug)//- 黑色模式粒子效果canvas if theme.universe.enable canvas(id="universe") script(async src="/mx/js/dark.js")dark.js文件function dark() { window.requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame; var n, e, i, h, t = 0.05, s = document.getElementById("universe"), o = !0, a = "180,184,240", r = "226,225,142", d = "226,225,224", c = []; function f() { (n = window.innerWidth), (e = window.innerHeight), (i = 0.216 * n), s.setAttribute("width", n), s.setAttribute("height", e); } function u() { h.clearRect(0, 0, n, e); for (var t = c.length, i = 0; i < t; i++) { var s = c[i]; s.move(), s.fadeIn(), s.fadeOut(), s.draw(); } } function y() { (this.reset = function () { (this.giant = m(3)), (this.comet = !this.giant && !o && m(10)), (this.x = l(0, n - 10)), (this.y = l(0, e)), (this.r = l(1.1, 2.6)), (this.dx = l(t, 6 * t) + (this.comet + 1 - 1) * t * l(50, 120) + 2 * t), (this.dy = -l(t, 6 * t) - (this.comet + 1 - 1) * t * l(50, 120)), (this.fadingOut = null), (this.fadingIn = !0), (this.opacity = 0), (this.opacityTresh = l(0.2, 1 - 0.4 * (this.comet + 1 - 1))), (this.do = l(5e-4, 0.002) + 0.001 * (this.comet + 1 - 1)); }), (this.fadeIn = function () { this.fadingIn && ((this.fadingIn = !(this.opacity > this.opacityTresh)), (this.opacity += this.do)); }), (this.fadeOut = function () { this.fadingOut && ((this.fadingOut = !(this.opacity < 0)), (this.opacity -= this.do / 2), (this.x > n || this.y < 0) && ((this.fadingOut = !1), this.reset())); }), (this.draw = function () { if ((h.beginPath(), this.giant)) (h.fillStyle = "rgba(" + a + "," + this.opacity + ")"), h.arc(this.x, this.y, 2, 0, 2 * Math.PI, !1); else if (this.comet) { (h.fillStyle = "rgba(" + d + "," + this.opacity + ")"), h.arc(this.x, this.y, 1.5, 0, 2 * Math.PI, !1); for (var t = 0; t < 30; t++) (h.fillStyle = "rgba(" + d + "," + (this.opacity - (this.opacity / 20) * t) + ")"), h.rect( this.x - (this.dx / 4) * t, this.y - (this.dy / 4) * t - 2, 2, 2 ), h.fill(); } else (h.fillStyle = "rgba(" + r + "," + this.opacity + ")"), h.rect(this.x, this.y, this.r, this.r); h.closePath(), h.fill(); }), (this.move = function () { (this.x += this.dx), (this.y += this.dy), !1 === this.fadingOut && this.reset(), (this.x > n - n / 4 || this.y < 0) && (this.fadingOut = !0); }), setTimeout(function () { o = !1; }, 50); } function m(t) { return Math.floor(1e3 * Math.random()) + 1 < 10 * t; } function l(t, i) { return Math.random() * (i - t) + t; } f(), window.addEventListener("resize", f, !1), (function () { h = s.getContext("2d"); for (var t = 0; t < i; t++) (c[t] = new y()), c[t].reset(); u(); })(), (function t() { document.getElementsByTagName("html")[0].getAttribute("data-theme") == "dark" && u(), window.requestAnimationFrame(t); })(); } dark();css文件[data-theme="dark"] #universe { display: block; position: fixed; margin: 0; padding: 0; border: 0; outline: 0; left: 0; top: 0; width: 100%; height: 100%; pointer-events: none; z-index: 1; } canvas#universe { display: none; }
前言由于Heo主题元素的版面和流畅度都不错，很多人都想拥有，也包括满心，但是Heo没有开放主题的计划，所以想拥有该主题只能自己动手了，在此之前我对hexo使用的技术并不熟悉，但奈何实在喜欢这个主题，那么只能靠自己，所以大概花费了半年多的时间把，才有了现在的满心记，目前乃至以后仍然会跟随Heo更新，当然也不是所有元素都照搬，满心觉得不错的，而且不影响效率的，以及不依赖第三方组件条件下，满心会酌情考虑将其加入满心记当中关于满心记源码满心记源码为满心一步步魔改至此，其中花费的精力可想而知，再加上我也尊重原创，所以并未开源主题的打算，不过针对有些非常喜欢heo主题的朋友来说，可以选择使用hexo-theme-solitude这款主题，这款是目前与Heo相似度较高的主题，可以试试演示地址该主题目前也在持续更新，我也在此项目中，不过主要修复一些显示问题，并未实际参与功能开发
针对不同博客，改动略有不同，本文仅供参考，我这里把fps开关放到了中控台修改 themes/butterfly/layout/includes/header/nav.pug#page-name-mask #page-name a#page-name-text(onclick= 'btf.scrollToDest(0,500)')=navTitleName #menus !=partial('includes/header/menu_item', {}, {cache: true}) #nav-left #fps-group #fps span.fpsText=_p('FPS')修改 themes/butterfly/layout/includes/console.pugif theme.console.keyboard.enable .console-btn-item#consoleKeyboard(onclick='manxin.keyboardToggle()', title='快捷键开关') a.keyboard-switch i.fas.fa-keyboard .console-btn-item#consoleCommentBarrage(onclick='manxin.switchCommentBarrage()', title='热评开关') a.commentBarrage i.fa-solid.fa-message .console-btn-item#consoleFPS(onclick='manxin.FPSToggle()', title='帧率显示开关') a.FPS-switch i.fas.fa-gauge新建 themes/butterfly/source/manxin/fps.js（引入js略）let Jay_showFPS = !1; "true" === localStorage.getItem("showFPS") ? ((Jay_showFPS = !0), document.querySelector("#fps-group").classList.add("show"), document.querySelector("#consoleFPS").classList.add("on")) : ((Jay_showFPS = !1), document.querySelector("#fps-group").classList.remove("show"), document.querySelector("#consoleFPS").classList.remove("on")); var showFPS = (function() { let e, t, o, n, a, i = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function(e) { window.setTimeout(e, 1e3 / 60); }; (e = 0), (t = Date.now()), (n = function() { (o = Date.now() - t), (e += 1), o >= 1e3 && ((t += o), a(e), (e = 0)), i(n); }), (a = function(e) { $("#fps").html(e); }), n(); })(); var manxin = { FPSToggle: function() { Jay_showFPS ? ((Jay_showFPS = !1), document.querySelector("#fps-group").classList.remove("show"), document.querySelector("#consoleFPS").classList.remove("on"), localStorage.setItem("showFPS", "false")) : ((Jay_showFPS = !0), document.querySelector("#fps-group").classList.add("show"), document.querySelector("#consoleFPS").classList.add("on"), localStorage.setItem("showFPS", "true")); }, };新建 themes/butterfly/source/manxin/fps.css（引入css略）/* FPS */ #fps-group.show { opacity: 1; } .nav-fixed #fps-group, .not-top-img #fps-group { color: var(--Jay-fontcolor); } #fps-group { opacity: 0; display: flex; flex-direction: column; margin-left: 16px; color: var(--Jay-white); } #fps { z-index: 10000; font-size: 12px; font-weight: 700; transition: all 0.3s ease 0s; line-height: 1; } #fps-group .fpsText { font-size: 12px; line-height: 1; opacity: 0.6; } /* FPS */
修改 themes/butterfly/layout/includes/header/index.pug 大概第 38 行左右if top_img !== false if is_post() include ./post-info.pug section.main-hero-waves-area.waves-area svg.waves-svg(xmlns='http://www.w3.org/2000/svg', xlink='http://www.w3.org/1999/xlink', viewBox='0 24 150 28', preserveAspectRatio='none', shape-rendering='auto') defs path#gentle-wave(d='M -160 44 c 30 0 58 -18 88 -18 s 58 18 88 18 s 58 -18 88 -18 s 58 18 88 18 v 44 h -352 Z') g.parallax use(href='#gentle-wave', x='48', y='0') use(href='#gentle-wave', x='48', y='3') use(href='#gentle-wave', x='48', y='5') use(href='#gentle-wave', x='48', y='7') #post-top-cover img#post-top-bg(class='nolazyload' src=bg_img) else if is_home() #site-info h1#site-title=site_title if theme.subtitle.enable为了方便复制，提供一份需要修改的部分:section.main-hero-waves-area.waves-area svg.waves-svg(xmlns='http://www.w3.org/2000/svg', xlink='http://www.w3.org/1999/xlink', viewBox='0 24 150 28', preserveAspectRatio='none', shape-rendering='auto') defs path#gentle-wave(d='M -160 44 c 30 0 58 -18 88 -18 s 58 18 88 18 s 58 -18 88 -18 s 58 18 88 18 v 44 h -352 Z') g.parallax use(href='#gentle-wave', x='48', y='0') use(href='#gentle-wave', x='48', y='3') use(href='#gentle-wave', x='48', y='5') use(href='#gentle-wave', x='48', y='7')然后在_config.butterfly.yml的 [inject.head] 或者自定义 css 中 引入以下 css, 不会的同学参考Hexo 博客添加自定义 css 和 js 文件/* 波浪css */ .main-hero-waves-area { width: 100%; position: absolute; left: 0; bottom: -11px; z-index: 5; } .waves-area .waves-svg { width: 100%; height: 5rem; } /* Animation */ .parallax > use { animation: move-forever 25s cubic-bezier(0.55, 0.5, 0.45, 0.5) infinite; } .parallax > use:nth-child(1) { animation-delay: -2s; animation-duration: 7s; fill: #f7f9febd; } .parallax > use:nth-child(2) { animation-delay: -3s; animation-duration: 10s; fill: #f7f9fe82; } .parallax > use:nth-child(3) { animation-delay: -4s; animation-duration: 13s; fill: #f7f9fe36; } .parallax > use:nth-child(4) { animation-delay: -5s; animation-duration: 20s; fill: #f7f9fe; } /* 黑色模式背景 */ [data-theme="dark"] .parallax > use:nth-child(1) { animation-delay: -2s; animation-duration: 7s; fill: #18171dc8; } [data-theme="dark"] .parallax > use:nth-child(2) { animation-delay: -3s; animation-duration: 10s; fill: #18171d80; } [data-theme="dark"] .parallax > use:nth-child(3) { animation-delay: -4s; animation-duration: 13s; fill: #18171d3e; } [data-theme="dark"] .parallax > use:nth-child(4) { animation-delay: -5s; animation-duration: 20s; fill: #18171d; } @keyframes move-forever { 0% { transform: translate3d(-90px, 0, 0); } 100% { transform: translate3d(85px, 0, 0); } } /*Shrinking for mobile*/ @media (max-width: 768px) { .waves-area .waves-svg { height: 40px; min-height: 40px; } }总结大功告成，需要注意的是 css 中fill属性可以控制波浪颜色，最好使其中一个颜色与背景颜色一致，否则会显的有点奇怪
twikoo邮件通知自带模板，不忍直视，还是决定调整一下，自己写了一个简约模板，同时借鉴了Akilar、Heo邮件模板，并做了一些微调，统一放出来，方便切换使用方案一(简约模板)预览效果代码 Dear ${PARENT_NICK} 来自 ${NICK} 的回复 您在 ${SITE_NAME} 上发表的评论： ${PARENT_COMMENT} ${NICK} 给您回复啦： ${COMMENT} 欢迎再次光临${SITE_NAME}！ 点击去原文查看>> © 2022 lovelu.top 方案二(基于Akilar的模板)作者Akilar效果预览MAIL_TEMPLATE代码 <div style="position: relative;overflow: visible;height: 1500px;width: 500px;margin: 0px auto;transition: all 1s ease-in-out .3s;padding-top:200px;" ${PARENT_NICK}，见信安： 您在${SITE_NAME}上发表的评论: ${PARENT_COMMENT} 收到了来自${NICK}的回复： ${COMMENT} ${SITE_NAME}｜请您签收~ 自动书记人偶竭诚为您服务！ ©2023${SITE_NAME} MAIL_TEMPLATE_ADMIN代码 来自${NICK}的留言: ${COMMENT} ${SITE_NAME}｜请您过目~ 自动书记人偶竭诚为您服务！ ©2020${SITE_NAME} 方案三(基于heo模板)作者Heo在原作者基础上，进行了微调，并添加了头像呼吸效果，在电脑QQ邮箱无效，手机邮箱可正常预览效果预览MAIL_TEMPLATE代码 嘿！你在 ${SITE_NAME} 博客中收到一条新回复。 你之前的评论 在 ${SITE_NAME} 博客中收到来自 ${NICK} 的回复 ${PARENT_NICK} ${PARENT_COMMENT} ${NICK} ${COMMENT} 查看详情 此邮件由评论服务自动发出，直接回复无效。 前往博客 MAIL_TEMPLATE_ADMIN 嘿！你在 ${SITE_NAME} 博客中收到一条消息。 ${NICK} ${COMMENT} 查看详情 此邮件由评论服务自动发出，直接回复无效。 前往博客 如何使用在Twikoo后台进入邮件通知，将以上html代码，复制到MAIL_TEMPLATE和MAIL_TEMPLATE_ADMIN中，保存即可Twikoo邮件自定义字段Twikoo文档不提供邮件模板的参数含义，方便魔改，这里附上。参数释义${SITE_URL}网站地址${SITE_NAME}网站名${PARENT_NICK}被回复人昵称${PARENT_COMMENT}被回复人的评论内容${NICK}回复人昵称${COMMENT}回复人评论内容${POST_URL}文章链接${IMG}回复人头像${PARENT_IMG}被回复人头像${MAIL}回复人邮件${IP}回复人 IP 地址参考：Twikoo评论回复邮件模板：Acrylic Mail 粉
对于这个功能个人感觉也是非常香，不过我后来参照heo方式，改为腾讯云API方式获取RGB了，目前把通过rgbaster和腾讯API方式都分享出来对于提取主题色，看过生成封面图片主色来作为文章封面顶图的文章，无意中看到了一篇帖子是关于这个的，于是便根据这个，加上Heo的教程，便解决了这个问题。[新建]themes/butterfly/source/js/rgbaster.min.js!function(n){"use strict";var t=function(){return document.createElement("canvas").getContext("2d")},e=function(n,e){var a=new Image,o=n.src||n;"data:"!==o.substring(0,5)&&(a.crossOrigin="Anonymous"),a.onload=function(){var n=t("2d");n.drawImage(a,0,0);var o=n.getImageData(0,0,a.width,a.height);e&&e(o.data)},a.src=o},a=function(n){return["rgb(",n,")"].join("")},o=function(n){return n.map(function(n){return a(n.name)})},r=5,i=10,c={};c.colors=function(n,t){t=t||{};var c=t.exclude||[],u=t.paletteSize||i;e(n,function(e){for(var i=n.width*n.height||e.length,m={},s="",d=[],f={dominant:{name:"",count:0},palette:Array.apply(null,new Array(u)).map(Boolean).map(function(){return{name:"0,0,0",count:0}})},l=0;i>l;){if(d[0]=e[l],d[1]=e[l+1],d[2]=e[l+2],s=d.join(","),m[s]=s in m?m[s]+1:1,-1===c.indexOf(a(s))){var g=m[s];g>f.dominant.count?(f.dominant.name=s,f.dominant.count=g):f.palette.some(function(n){return g>n.count?(n.name=s,n.count=g,!0):void 0})}l+=4*r}if(t.success){var p=o(f.palette);t.success({dominant:a(f.dominant.name),secondary:p[0],palette:p})}})},n.RGBaster=n.RGBaster||c}(window);引入jsinject: head: bottom: 使用对于使用，就是调用这个js，然后根据提取出来的图片设置博客的主题色就可以了，但是由于图片提取出来的颜色可能会太浅等原因，需要特殊处理下。对于里面的addRule设置变量颜色需要自行去修改。引入如下自定义js，你可以选择新建一个自定义的js文件，也可以在自己原本的自定义文件中使用。对于引入的文件需要保证在引入上述文件之后引入。// 封面纯色 function coverColor() { var path = document.getElementById("post-cover")?.src; if (path !== undefined) { RGBaster.colors(path, { paletteSize: 30, exclude: ["rgb(255,255,255)", "rgb(0,0,0)", "rgb(254,254,254)"], success: function (t) { if (t.dominant != 'rgb(66,90,239)') { const c = t.dominant.match(/\d+/g); var value = `rgb(${c[0]},${c[1]},${c[2]})`; if (getContrastYIQ(colorHex(value)) == "light") { value = LightenDarkenColor(colorHex(value), -40) } document.styleSheets[0].addRule(':root', '--Jay-main:' + value + '!important'); document.styleSheets[0].addRule(':root', '--Jay-main-op:' + value + '23!important'); document.styleSheets[0].addRule(':root', '--Jay-main-op-deep:' + value + 'dd!important'); document.styleSheets[0].addRule(':root', '--Jay-main-none:' + value + '00!important'); Jay.initThemeColor() document.getElementById("coverdiv").classList.add("loaded"); } } }); } else { document.styleSheets[0].addRule(':root', '--Jay-main: var(--Jay-theme)!important'); document.styleSheets[0].addRule(':root', '--Jay-main-op: var(--Jay-theme-op)!important'); document.styleSheets[0].addRule(':root', '--Jay-main-op-deep:var(--Jay-theme-op-deep)!important'); document.styleSheets[0].addRule(':root', '--Jay-main-none: var(--Jay-theme-none)!important'); Jay.initThemeColor() } } // RGB颜色转化为16进制颜色 function colorHex(str) { var reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/; var that = str; if (/^(rgb|RGB)/.test(that)) { var aColor = that.replace(/(?:\(|\)|rgb|RGB)*/g, "").split(","); var strHex = "#"; for (var i = 0; i < aColor.length; i++) { var hex = Number(aColor[i]).toString(16); if (hex === "0") { hex += hex; } strHex += hex; } if (strHex.length !== 7) { strHex = that; } return strHex; } else if (reg.test(that)) { var aNum = that.replace(/#/, "").split(""); if (aNum.length === 6) { return that; } else if (aNum.length === 3) { var numHex = "#"; for (var i = 0; i < aNum.length; i += 1) { numHex += (aNum[i] + aNum[i]); } return numHex; } } else { return that; } } // 16进制颜色转化为RGB颜色 function colorRgb(str) { var reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/; var sColor = str.toLowerCase(); if (sColor && reg.test(sColor)) { if (sColor.length === 4) { var sColorNew = "#"; for (var i = 1; i < 4; i += 1) { sColorNew += sColor.slice(i, i + 1).concat(sColor.slice(i, i + 1)); } sColor = sColorNew; } // 处理六位的颜色值 var sColorChange = []; for (var i = 1; i < 7; i += 2) { sColorChange.push(parseInt("0x" + sColor.slice(i, i + 2))); } return "rgb(" + sColorChange.join(",") + ")"; } else { return sColor; } } // 变暗变亮主方法 function LightenDarkenColor(col, amt) { var usePound = false; if (col[0] == "#") { col = col.slice(1); usePound = true; } var num = parseInt(col, 16); var r = (num >> 16) + amt; if (r > 255) r = 255; else if (r < 0) r = 0; var b = ((num >> 8) & 0x00FF) + amt; if (b > 255) b = 255; else if (b < 0) b = 0; var g = (num & 0x0000FF) + amt; if (g > 255) g = 255; else if (g < 0) g = 0; return (usePound ? "#" : "") + String("000000" + (g | (b << 8) | (r << 16)).toString(16)).slice(-6); } // 判断是否为亮色 function getContrastYIQ(hexcolor) { var colorrgb = colorRgb(hexcolor); var colors = colorrgb.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/); var red = colors[1]; var green = colors[2]; var blue = colors[3]; var brightness; brightness = (red * 299) + (green * 587) + (blue * 114); brightness = brightness / 255000; if (brightness >= 0.5) { return "light"; } else { return "dark"; } } coverColor()由于我使用的是腾讯云COS，正好也提供了这个API，果断使用上，当然像七牛云也有，实现方式大同小异function coverColor () { var path = document.getElementById("post-cover") ?.src; // console.log(path); if (path !== undefined) { var httpRequest = new XMLHttpRequest(); //第一步：建立所需的对象 httpRequest.open('GET', path + '?imageAve', true); //第二步：打开连接 将请求参数写在url中 ps:"./Ptest.php?name=test&nameone=testone" httpRequest.send(); //第三步：发送请求 将请求参数写在URL中 /** * 获取数据后的处理程序 */ httpRequest.onreadystatechange = function () { if (httpRequest.readyState == 4 && httpRequest.status == 200) { var json = httpRequest.responseText; //获取到json字符串，还需解析 var obj = eval('(' + json + ')'); var value = obj.RGB; value = "#" + value.slice(2) // console.log(value); if (getContrastYIQ(value) == "light") { value = LightenDarkenColor(colorHex(value), -50) } document.styleSheets[0].addRule(':root', '--Jay-main:' + value + '!important'); document.styleSheets[0].addRule(':root', '--Jay-main-op:' + value + '23!important'); document.styleSheets[0].addRule(':root', '--Jay-main-op-deep:' + value + 'dd!important'); document.styleSheets[0].addRule(':root', '--Jay-main-none:' + value + '00!important'); Jay.initThemeColor() document.getElementById("coverdiv").classList.add("loaded"); } }; } else { document.styleSheets[0].addRule(':root', '--Jay-main: var(--Jay-theme)!important'); document.styleSheets[0].addRule(':root', '--Jay-main-op: var(--Jay-theme-op)!important'); document.styleSheets[0].addRule(':root', '--Jay-main-op-deep:var(--Jay-theme-op-deep)!important'); document.styleSheets[0].addRule(':root', '--Jay-main-none: var(--Jay-theme-none)!important'); Jay.initThemeColor() } } // RGB颜色转化为16进制颜色 function colorHex (str) { var reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/; var that = str; if (/^(rgb|RGB)/.test(that)) { var aColor = that.replace(/(?:\(|\)|rgb|RGB)*/g, "").split(","); var strHex = "#"; for (var i = 0; i < aColor.length; i++) { var hex = Number(aColor[i]).toString(16); if (hex === "0") { hex += hex; } strHex += hex; } if (strHex.length !== 7) { strHex = that; } return strHex; } else if (reg.test(that)) { var aNum = that.replace(/#/, "").split(""); if (aNum.length === 6) { return that; } else if (aNum.length === 3) { var numHex = "#"; for (var i = 0; i < aNum.length; i += 1) { numHex += (aNum[i] + aNum[i]); } return numHex; } } else { return that; } } // 16进制颜色转化为RGB颜色 function colorRgb (str) { var reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/; var sColor = str.toLowerCase(); if (sColor && reg.test(sColor)) { if (sColor.length === 4) { var sColorNew = "#"; for (var i = 1; i < 4; i += 1) { sColorNew += sColor.slice(i, i + 1).concat(sColor.slice(i, i + 1)); } sColor = sColorNew; } // 处理六位的颜色值 var sColorChange = []; for (var i = 1; i < 7; i += 2) { sColorChange.push(parseInt("0x" + sColor.slice(i, i + 2))); } return "rgb(" + sColorChange.join(",") + ")"; } else { return sColor; } } // 变暗变亮主方法 function LightenDarkenColor (col, amt) { var usePound = false; if (col[0] == "#") { col = col.slice(1); usePound = true; } var num = parseInt(col, 16); var r = (num >> 16) + amt; if (r > 255) r = 255; else if (r < 0) r = 0; var b = ((num >> 8) & 0x00FF) + amt; if (b > 255) b = 255; else if (b < 0) b = 0; var g = (num & 0x0000FF) + amt; if (g > 255) g = 255; else if (g < 0) g = 0; return (usePound ? "#" : "") + String("000000" + (g | (b << 8) | (r << 16)).toString(16)).slice(-6); } // 判断是否为亮色 function getContrastYIQ (hexcolor) { var colorrgb = colorRgb(hexcolor); var colors = colorrgb.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/); var red = colors[1]; var green = colors[2]; var blue = colors[3]; var brightness; brightness = (red * 299) + (green * 587) + (blue * 114); brightness = brightness / 255000; if (brightness >= 0.5) { return "light"; } else { return "dark"; } } coverColor()由于此代码是根据本人博客结构实现的，不一定在您的博客上可以生效，如果有什么问题，相信您可以自行调试成功解决。参考：JayHrn、Heo