
我们在上一篇文章之中,实现了在首页调用侧边栏的 最近发布 栏目,详细修改教程,大家可以参阅 安知鱼主题侧边栏最近发布的修改 这篇文章,我们今天来给侧边栏添加一个 随机发布 的栏目,在很多传统的博客中,这个栏目不多见,只是一些门户网站中常见。

代码借助了安知鱼主题默认的 最近发布 的 CSS 样式,所以有些内容与默认的 最近发布 板块类似,下面我们来看实现的过程。
1.添加主题设置
打开主题文件夹下面的 _config.yml 文件,搜索 # aside (侧边栏) ,在 aside: 里面添加如下设置
1 2 3 4 5 6
| # 新增:随机文章组件配置 card_random_post: enable: true # 是否开启随机文章组件 limit: 5 # 显示的随机文章数量 date_enable: true # 是否显示文章发布日期 date_format: "YYYY-MM-DD" # 日期格式
|
2.添加标题设置
打开根目录下面的 /themes/anzhiyu/languages 文件夹,在里面找到 default.yml 文件,打开之后找到如下代码
1 2 3 4 5 6 7 8 9
| aside: articles: 文章 tags: 标签 categories: 分类 card_announcement: 公告 card_categories: 分类 card_tags: 标签 card_archives: 归档 card_recent_post: 最近发布
|
代码之后还有很多行代码,主要是在
下面,添加如下代码
添加之后的效果
1 2 3 4 5 6 7 8 9 10 11
| aside: articles: 文章 tags: 标签 categories: 分类 card_announcement: 公告 card_categories: 分类 card_tags: 标签 card_archives: 归档 card_recent_post: 最近发布 card_random_post: 随机推荐 card_webinfo:
|
3.添加随机调用代码
打开 /themes/anzhiyu/layout/includes/widget 文件夹,在里面新建 card_random_post.pug 文件,之后复制下面的代码粘贴到文件中
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
| //- 侧边栏随机文章卡片(稳定版:逻辑清晰+刷新即变+样式统一) if theme.aside.card_random_post.enable && site.posts.length > 0 .card-widget.card-recent-post .item-headline
i.anzhiyufont.anzhiyu-icon-dice-d20 span= _p('aside.card_random_post') //- 1. 隐藏的完整文章数据源(彻底隐藏,不显示) #random-posts-data.random-posts-data - site.posts.each(function(article) { // 逐行声明变量,逻辑清晰,避免Pug解析报错 - var articleLink = url_for(article.link || article.path); - var articleTitle = article.title || _p('no_title'); - var articleCover = article.cover ? url_for(article.cover) : ''; - var noCoverClass = article.cover === false || !theme.cover.aside_enable ? 'no-cover' : ''; - var articleDate = date(article.date, config.date_format); - var articleUpdated = date(article.updated, config.date_format); - var articleDateXml = date_xml(article.date); - var articleUpdatedXml = date_xml(article.updated);
// 用多个data属性存储数据,绕开Pug解析JSON的坑 div( data-link=articleLink, data-title=articleTitle, data-cover=articleCover, data-no-cover=noCoverClass, data-date=articleDate, data-updated=articleUpdated, data-date-xml=articleDateXml, data-updated-xml=articleUpdatedXml ) - })
//- 2. 随机文章显示容器 #random-posts-display.aside-list
//- 3. 前端随机逻辑(ES5写法,稳定无兼容问题) script. // 页面加载完成后执行 window.onload = function() { // 读取主题配置参数 var showLimit = !{theme.aside.card_random_post.limit === 0 ? site.posts.length : theme.aside.card_random_post.limit || 5}; var sortType = !{JSON.stringify(theme.aside.card_random_post.sort || 'date')}; var errorImage = !{JSON.stringify(url_for(theme.error_img.post_page))}; var textUpdated = !{JSON.stringify(_p('post.updated') || '更新于')}; var textCreated = !{JSON.stringify(_p('post.created') || '创建于')};
// 步骤1:获取所有文章数据 var allPostNodes = document.querySelectorAll('#random-posts-data > div'); var allPosts = []; for (var i = 0; i < allPostNodes.length; i++) { var node = allPostNodes[i]; allPosts.push({ link: node.dataset.link, title: node.dataset.title, cover: node.dataset.cover, noCover: node.dataset.noCover, date: node.dataset.date, updated: node.dataset.updated, dateXml: node.dataset.dateXml, updatedXml: node.dataset.updatedXml }); }
// 步骤2:Fisher-Yates洗牌算法(经典随机,结果均匀) for (var j = allPosts.length - 1; j > 0; j--) { var randomIndex = Math.floor(Math.random() * (j + 1)); var temp = allPosts[j]; allPosts[j] = allPosts[randomIndex]; allPosts[randomIndex] = temp; }
// 步骤3:截取需要显示的数量 var randomPosts = allPosts.slice(0, showLimit);
// 步骤4:渲染到页面 var displayContainer = document.getElementById('random-posts-display'); var htmlContent = ''; for (var k = 0; k < randomPosts.length; k++) { var post = randomPosts[k]; // 拼接封面图HTML var coverHtml = ''; if (post.cover && post.noCover === '') { coverHtml = '<a class="thumbnail" href="' + post.link + '" title="' + post.title + '">' + '<img src="' + post.cover + '" onerror="this.onerror=null;this.src=\'' + errorImage + '\'" alt="' + post.title + '">' + '</a>'; }
// 拼接日期HTML var dateHtml = ''; if (sortType === 'updated') { dateHtml = '<time datetime="' + post.updatedXml + '" title="' + textUpdated + ' ' + post.updated + '">' + post.updated + '</time>'; } else { dateHtml = '<time datetime="' + post.dateXml + '" title="' + textCreated + ' ' + post.date + '">' + post.date + '</time>'; }
// 拼接单篇文章的完整HTML htmlContent += '<div class="aside-list-item ' + post.noCover + '">' + coverHtml + '<div class="content">' + '<a class="title" href="' + post.link + '" title="' + post.title + '">' + post.title + '</a>' + dateHtml + '</div>' + '</div>'; }
// 把拼接好的HTML插入显示容器 displayContainer.innerHTML = htmlContent; };
|
这段代码主要作用,就是随机生成文章,显示在页面中,通过 JS 调用,刷新页面重建数据。
然后打开同文件夹下的 index.pug 将 card_random_post.pug 文件引入到模板中,在这个文件夹中,找到如下代码
1 2 3 4 5
| else //- page !=partial('includes/widget/card_author', {}, {cache: true}) !=partial('includes/widget/card_announcement', {}, {cache: true}) !=partial('includes/widget/card_weixin', {}, {cache: true})
|
你如果修改过这个文件,应该清除把 card_random_post.pug 放到哪里,我把这个 card_random_post.pug 文件放在了
1
| !=partial('includes/widget/card_weixin', {}, {cache: true})
|
代码下面,我的代码如下
1 2 3 4 5 6 7
| else //- page !=partial('includes/widget/card_author', {}, {cache: true}) !=partial('includes/widget/card_weixin', {}, {cache: true}) !=partial('includes/widget/card_announcement', {}, {cache: true}) !=partial('includes/widget/card_recent_post', {}, {cache: true}) !=partial('includes/widget/card_random_post', {}, {cache: true})
|
到这里代码文件修改完成,我顺便调用了 最近发布 板块。
在这里顺便记录一下安知鱼主题的 iconfont 库的链接地址,因为需要修改这个板块的图标,所以查阅了一下
1
| https://www.iconfont.cn/collections/detail?cid=44481
|
使用起来会很方便的。
4.补充精简代码
补充的这份代码,没有 JS 调用,仅在 Hexo 编译时生成一次随机列表,刷新网页不会变化。
核心原因是 随机逻辑在服务端编译阶段执行 ,而且只是仅执行了一次,而非在浏览器端每次刷新时执行。分享给大家只是为了做一个标记
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
| //- 侧边栏随机文章卡片(沿用最新文章样式) if theme.aside.card_random_post.enable && site.posts.length > 0 .card-widget.card-recent-post .item-headline i.anzhiyufont.anzhiyu-icon-dice-d20 span= _p('aside.card_random_post') .aside-list //- 核心:Fisher-Yates 洗牌算法打乱文章列表 - // 将Hexo的posts集合转为普通数组 let postsArray = site.posts.toArray(); // 随机打乱数组(保证随机性均匀) for (let i = postsArray.length - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)); [postsArray[i], postsArray[j]] = [postsArray[j], postsArray[i]]; } // 读取配置的显示数量(和原组件逻辑一致) let postLimit = theme.aside.card_random_post.limit === 0 ? postsArray.length : theme.aside.card_random_post.limit || 5; // 截取指定数量的随机文章 let randomPosts = postsArray.slice(0, postLimit); //- 渲染随机文章列表(完全复用原有样式结构) - randomPosts.forEach(function(article){ - let link = article.link || article.path - let title = article.title || _p('no_title') // 复用封面图显示逻辑(是否显示封面、无封面样式) - let no_cover = article.cover === false || !theme.cover.aside_enable ? 'no-cover' : '' - let post_cover = article.cover .aside-list-item(class=no_cover) // 封面图区域 if post_cover && theme.cover.aside_enable a.thumbnail(href=url_for(link) title=title) img(src=url_for(post_cover) onerror=`this.onerror=null;this.src='${url_for(theme.error_img.post_page)}'` alt=title) // 标题和日期区域 .content a.title(href=url_for(link) title=title)= title // 日期显示逻辑(支持按创建时间/更新时间显示) if theme.aside.card_random_post.sort === 'updated' time(datetime=date_xml(article.updated) title=_p('post.updated') + ' ' + full_date(article.updated)) #[=date(article.updated, config.date_format)] else time(datetime=date_xml(article.date) title=_p('post.created') + ' ' + full_date(article.date)) #[=date(article.date, config.date_format)] - })
|
仅做记录,这份代码不如第一份代码调用数据灵活。
5.检查效果生成
最后 Hexo 三连(hexo cl && hexo g && hexo s)就可以看到文章中第二张图调用的效果。