由于ParticleX主题没有内置的Links页面,而是把友链整合到了主页的Card里,我个人不是很喜欢,而且Card能写的友链太少了,于是决定自己写一个Links页
Particlex主题就是EJS写的,所以用EJS是首选
什么是EJS
EJS(Embedded JavaScript)是一个流行的 JavaScript 模板引擎,具有简单、灵活的模板语法,广泛应用于动态生成 HTML 内容
简单来说,EJS是能嵌入JS的HTML
所以语法也很简单,看看EJS官网就大概能知道了
如何在自己的网站使用EJS
由于前人给我们栽了树,搭好了框架,我们可以直接在themes\layout目录写EJS
对于HEXO其他主题的用户,你需要安装 Hexo 支持 EJS 模板引擎的插件
1
| npm install hexo-renderer-ejs --save
|
具体实现方法
(用Particlex实现,其他主题可以参考思路)
新建link页
添加EJS模板
1 2 3 4
| your-theme/ ├── layout/ │ ├── links.ejs # 新增:友链页面模板 │ └── layout.ejs
|
修改themes\particlex\_config.yml
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
| menu: Home: name: house theme: solid link: / About: name: id-card theme: solid link: /about Archives: name: box-archive theme: solid link: /archives Categories: name: bookmark theme: solid link: /categories Tags: name: tags theme: solid link: /tags Links: name: link theme: solid link: /links
|
修改layout.ejs使其能用links.ejs渲染links页
Highlight.js没有内置ejs语法高亮,只好用js的高亮
!! 但是本文除特殊说明外所有js代码块都应是ejs !!
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
| <!-- 这是Particlex主题的EJS,不同主题写法可能不一样,但是原理相同 --> <% let type = "post"; if (is_home()) type = "index"; if (is_post() || is_page()) type = "post"; if (is_category() || page.type === "categories") type = "categories"; if (is_tag() || page.type === "tags") type = "tags"; if (is_archive()) type = "archives"; if (is_current("links")) type = "links"; let title = page.title + " | " + config.title; if (is_home()) title = config.title; if (is_post() || is_page()) title = page.title + " | " + config.title; if (is_category()) title = "Categories: " + page.category + " | " + config.title; if (is_tag()) title = "Tags: " + page.tag + " | " + config.title; if (is_archive()) title = "Archives | " + config.title; if (is_current("links")) title = "Links | " + config.title; ... <%- partial("import", { type }) %> ... %> ...
|
完成之后在themes\particlex\layout\links.ejs随便写点东西就能看到页面正确渲染了:)
links.ejs内容示例,实现读取友链列表
我的想法是读取一个包含友链格式的yml文件,
(其实本来是想用json的,但是HEXO好像比较喜欢yml)
创建文件source\_data\links.yml,样例如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| Friends: Florance1: name: Florance1 url: https://Florance.top ava: https://Florance.top/images/avatar.jpg des: It's Florance! Florance2: name: Florance2 url: https://Florance.top ava: https://Florance.top/images/avatar.jpg des: It's Florance!!
Tools: Florance3: name: Florance3 url: https://Florance.top ava: https://Florance.top/images/avatar.jpg des: It's Florance? Florance4: name: Florance4 url: https://Florance.top ava: https://Florance.top/images/avatar.jpg des: It's Florance??
|
然后根据这个样例写links.ejs
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
| <div id="archives"> <div class="links-content">
<% const linkData = site.data.links || {}; %>
<% Object.keys(linkData).forEach(function(category) { %> // 分类标题 <h2 class="link-category-title"> <i class="fa fa-link"></i> // FontAwesome的图标 <%= category %> </h2>
<div class="link-navigation"> // 遍历每个条目 <% const items = linkData[category]; %> <% Object.keys(items).forEach(function(key) { %> <% const item = items[key]; %> <a href="<%= item.url %>" target="_blank" class="card"> <div class="card-header"> // 增加onerror处理,防止头像加载失败 <img src="<%= item.ava %>" alt="<%= item.name %>" onerror="this.src='/images/avatar.jpg'"> </div> <div class="card-body"> <h3 class="card-title"><%= item.name %></h3> <p class="card-desc" title="<%= item.des %>"><%= item.des %></p> </div> </a>
<% }); %> </div> <% }); %> </div> </div>
|
当然,css可是The Key!
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
| .link-category-title { font-size: 1.5em; margin: 30px 0 15px 0; border-bottom: 2px solid #eee; padding-bottom: 10px; } .link-category-title i { margin-right: 10px; }
.links-content { margin-top: 20px; margin-bottom: 40px; }
.link-navigation { display: flex; flex-wrap: wrap; justify-content: center; gap: 20px; margin: 0 auto; }
.card { width: 300px; max-width: 100%; background-color: var(--card-bg, #92ac9b); border-radius: 12px; box-shadow: 0 4px 10px rgba(255, 255, 255, 0.315); padding: 15px; transition: all 0.2s ease; text-decoration: none; color: inherit; display: flex; align-items: center; box-sizing: border-box; border: 1px solid rgba(255, 255, 255, 0.05); }
.card:hover { transform: translateY(-5px); box-shadow: 0 8px 20px rgba(0,0,0,0.12); }
.card-header { margin-right: 15px; flex-shrink: 0; display: flex; align-items: center; }
.card-header img { width: 64px; height: 64px; border-radius: 50%; object-fit: cover; border: 2px solid #eee; background: #fff; }
.card-body { flex: 1; overflow: hidden; min-width: 0; }
.card-title { font-size: 1.1em; font-weight: bold; margin: 0 0 5px 0; white-space: nowrap; text-overflow: ellipsis; overflow: hidden; color: var(--text-color, #466753); }
.card-desc { font-size: 0.85em; color: #5d6e62; margin: 0; line-height: 1.5; display: -webkit-box; }
|
什么?你想看具体效果?点击菜单的Links就好了 :)