魔改教程 魔改 hexo Hexo 魔改 - 给文章添加看法 Pupper 2023-09-18 2024-10-30 教程已作废,请勿使用; 教程已作废,请勿使用; 教程已作废,请勿使用;
效果展示
注意:
本应用需要自备 MySQL
数据库, 数据库表结构可以使用 script.sql
文件快速创建; 最新的 css、js 请在 index.html
中提取; 如果需要使用其他数据库, 请自行修改源码; 一、前端配置 1.1 数据配置 在主题配置文件(_config.anzhiyu.yaml
)添加以下内容
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 view: enable: true title: "就现在,表明你的态度!" images: - src: "https://jsd.cdn.zzko.cn/npm/sticker-heo/Sticker-100/鼓掌.png" text: "鼓励" - src: "https://jsd.cdn.zzko.cn/npm/sticker-heo/Sticker-100/菜狗.png" text: "菜狗" - src: "https://jsd.cdn.zzko.cn/npm/sticker-heo/Sticker-100/正确.png" text: "正确" - src: "https://jsd.cdn.zzko.cn/npm/sticker-heo/Sticker-100/错误.png" text: "错误" - src: "https://jsd.cdn.zzko.cn/npm/sticker-heo/Sticker-100/思考.png" text: "思考" - src: "https://jsd.cdn.zzko.cn/npm/sticker-heo/Sticker-100/睡觉.png" text: "无聊"
1.2 页面配置 1.2.1 创建 view 在 themes/anzhiyu/layout/includes/post/
文件夹中创建 view.pug
文件,在文件中添加以下内容
1 2 3 4 5 6 7 8 9 10 11 12 if theme.view.enable !== false .wl-reaction hr .wl-reaction-title= theme.view.title ul.wl-reaction-list each image in theme.view.images li.wl-reaction-item .wl-reaction-img img(src=image.src, alt=image.text) .wl-reaction-votes 0 .wl-reaction-text= image.text
1.2.2 添加页面 在 themes/anzhiyu/layout/post.pug
中添加以下内容
1 2 3 4 5 6 7 8 9 10 11 ...... else - let data_type_update = theme.post_meta.post.date_type === 'updated' - let date_type = data_type_update ? 'updated' : 'date' time(itemprop="dateCreated datePublished" datetime=date_xml(page[date_type]) title=date_title + ' ' + full_date(page[date_type]))=date(page[date_type], config.date_format) !=page.content + include includes/post/view.pug include includes/post/post-copyright.pug ......
1.2.3 添加 js 和 css 在合适的地方添加 css 和 js, (我是单独创建一个文件,然后在配置文件中导入)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 function updateVotes (data ) { const liElements = document .querySelectorAll ('.wl-reaction-item' ); liElements.forEach ((li, index ) => { const voteElement = li.querySelector ('.wl-reaction-votes' ); if (voteElement) { voteElement.classList .remove ('my-view' ); const viewKey = 'view' + (index + 1 ); if (data.hasOwnProperty (viewKey)) { voteElement.textContent = data[viewKey]; } if (data.hasOwnProperty ('my_view' ) && Number (data.my_view ) === (index + 1 )) { voteElement.classList .add ('my-view' ); } } }); } function sendPostRequest (address, ip, view ) { const data = { address : address, ip : ip, view : view }; const clickedLi = document .querySelector ('.wl-reaction-item.clicked' ); const voteElement = clickedLi.querySelector ('.wl-reaction-votes' ); voteElement.classList .add ('view_loading' ); fetch ('https://hexo-view.pupper.cn/insert/' , { method : 'POST' , headers : { 'Content-Type' : 'application/json' }, body : JSON .stringify (data) }) .then (response => response.json ()) .then (data => { updateVotes (data); voteElement.classList .remove ('view_loading' ); }) .catch (error => { console .error ('Error:' , error); voteElement.classList .remove ('view_loading' ); }); } function sendGetRequest (address, ip ) { var voteElements = document .querySelectorAll ('.wl-reaction-votes' ); voteElements.forEach (element => { element.classList .add ('view_loading' ); }); fetch ('https://hexo-view.pupper.cn/read/?address=' + encodeURIComponent (address) + '&ip=' + encodeURIComponent (ip)) .then (response => response.json ()) .then (data => { updateVotes (data); }) .catch (error => { console .error ('Error:' , error); }) .finally (() => { voteElements.forEach (element => { element.classList .remove ('view_loading' ); }); }); } const address = window .location .href ;let ip = '' ;function setIP ( ) { return fetch ('https://api.ipify.org?format=json' ) .then (response => response.json ()) .then (data => { ip = data.ip ; }) .catch (error => { console .error ('获取 IP 地址失败:' , error); ip = '127.4.0.4' ; }); } setIP ().then (() => { console .log (ip); }); const liElements = document .querySelectorAll ('.wl-reaction-item' );liElements.forEach ((li, index ) => { li.addEventListener ('click' , () => { const view = 'view' + (index + 1 ); console .log (address, ip, view); const clickedLi = document .querySelector ('.wl-reaction-item.clicked' ); if (clickedLi) { clickedLi.classList .remove ('clicked' ); } li.classList .add ('clicked' ); sendPostRequest (address, ip, view); }); }); window .addEventListener ('DOMContentLoaded' , () => { sendGetRequest (address, ip); });
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 .wl-reaction { overflow : auto hidden; margin-bottom : 1.75em ; text-align : center; } [data-waline] * { box-sizing : content-box; line-height : 1.75 ; } .wl-reaction-title { margin : 25px auto; font-weight : bold; font-size : 25px ; } [data-waline] .wl-reaction-list { margin-inline-start : 0 ; } [data-waline] ol ,[data-waline] ul { margin-inline-start : 1.25em ; padding : 0 ; } .wl-reaction-list { display : flex; flex-direction : row; gap : 30px ; justify-content : center; margin : 0 ; padding : 8px ; list-style-type : none; } .wl-reaction-item { display : flex; flex-direction : column; align-items : center; cursor : pointer; } .wl-reaction-img { position : relative; width : 60px ; height : 60px ; } .wl-reaction-text { font-size : .875em ; } .wl-reaction img { width : 100% ; height : 100% ; transition : all 250ms ease-in-out; } [data-waline] img { max-width : 100% ; max-height : 400px ; border : none; } .wl-reaction-votes { position : absolute; top : -9px ; inset-inline-end: -9px ; min-width : 1.5em ; padding : 2px ; border : 1px solid var (--anzhiyu-theme-op-deep); border-radius : 1em ; background : #fff ; color : var (--anzhiyu-theme-op-deep); font-weight : 700 ; font-size : .75em ; line-height : 1 ; } .wl-reaction-item :hover img ,.wl-reaction-item .active img { transform : scale (1.5 ); } .view_loading { border : 2px solid #f3f3f3 ; border-top : 2px solid #555 ; border-radius : 50% ; width : 20px ; height : 20px ; display : inline-block; animation : spin 2s linear infinite; } @keyframes spin {0% { transform : rotate (0deg ); }100% { transform : rotate (360deg ); }} .my-view { border : 1px solid var (--anzhiyu-theme-op-deep); border-radius : 1em ; background : var (--anzhiyu-theme-op-deep); color : #fff ; }
二、后端配置
在 vercel 中创建项目
2.2 数据库配置 自备 MySQL 数据库 自备 MySQL 数据库 自备 MySQL 数据库
数据库表配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";SET time_zone = "+00:00";; ; ; ; CREATE TABLE IF NOT EXISTS `hv_article` ( `id` int (11 ) NOT NULL , `address` text ) ENGINE= InnoDB DEFAULT CHARSET= utf8mb4; CREATE TABLE IF NOT EXISTS `hv_user` ( `ip` varchar (60 ) NOT NULL , `id` int (11 ) NOT NULL , `view1` int (11 ) NOT NULL DEFAULT '0' , `view2` int (11 ) NOT NULL DEFAULT '0' , `view3` int (11 ) NOT NULL DEFAULT '0' , `view4` int (11 ) NOT NULL DEFAULT '0' , `view5` int (11 ) NOT NULL DEFAULT '0' , `view6` int (11 ) NOT NULL DEFAULT '0' , `view7` int (11 ) NOT NULL DEFAULT '0' , `view8` int (11 ) NOT NULL DEFAULT '0' , `view9` int (11 ) NOT NULL DEFAULT '0' ) ENGINE= InnoDB DEFAULT CHARSET= utf8mb4; ALTER TABLE `hv_article` ADD PRIMARY KEY (`id`); ALTER TABLE `hv_article` MODIFY `id` int (11 ) NOT NULL AUTO_INCREMENT; ; ; ;
2.3 配置环境变量 在项目的 setting --> Environment Variables
中创建 VIEW_SQL_DB, VIEW_SQL_PASSWORD, VIEW_SQL_HOST, VIEW_SQL_USER
四个连接数据库的变量
三、over ~