介绍:从零开始写一个hexo主题的步骤

前言

写作目的:
作为一名前端学习者,想试一下自己写一个Hexo主题
在这里我将记录自己的学习过程以及遇到的问题和解决方式
好像我最初搭建这个博客平台的目的就不是写博客,而是为了做一个自己的、好看的网站,但是在网上看了一圈,大部分博客网站都是运用各种现有的主题制作的,感觉没有很大的学习价值,于是我决定,自己也学着写一个主题

目录结构

thems目录下新建一个theme-name(你的主题名字)文件夹,一个主题主要有以下结构:

.
├── _config.yml  #主题的配置文件
├── languages    #语言文件夹
├── layout       #布局文件夹,用来存放主题的模板文件
├── scripts      #脚本文件夹
└── source       #资源文件夹,除了模板外的Asset,例如CSS、JS文件等

结构模板

大部分博客网站由:顶部导航栏、中间内容区域以及底部信息展示区域三大部分组成。因此我们在这里先设置我们网站的头部以及底部样式。
layout目录下新建_partial目录,添加head.ejsheader.ejs以及fonter.ejs文件

layout/_partial/head.ejs代码:
<head>
  <meta http-equiv="content-type" content="text/html; charset=utf-8">
  <meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" name="viewport">
  <title>标题</title>
</head>
layout/_partial/header.ejs代码:
<header>我是导航栏</header>
<footer>我是底部信息</footer>

layout中创建layout.ejslayout.ejs文件是通用的布局文件模板,我们在后面新增的ejs文件都会继承layout.ejs,并将其内容填充到body中。

layout/layout.ejs代码:
<!DOCTYPE html>
<html>
  <%- partial('_partial/head') %>
  <body>
    <div class="container">
      <%- partial('_partial/header') %>
      <%- body %>
      <%- partial('_partial/footer') %>
    </div>
  </body>
</html> 

首页

首页是我们网站加载完毕后的第一个页面
layout中创建index.ejs文件,index.ejs将会继承layout.ejs布局模板生成HTML文件。

layout/index.ejs代码:
<h1>Hello World</h1>

将这些文件全部添加完后我们的网站将会是这样

编写导航栏和底部信息

编写layout/_partial/head.ejs信息
<head>    
  <meta http-equiv="content-type" content="text/html; charset=utf-8">    
  <meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" name="viewport">    
  <title>
    <%= config.title %>
  </title>
</head>

使用了config全局变量,该变量包含的是站点配置(即站点根目录下_config.yml中的配置)。
除此之外还有theme变量,该变量是主题配置(即主题目录下_config.yml中的配置)。
其他配置参照Hexo文档

编写导航栏部分,layout/_partial/header.ejs
<header class="header">
  <div class="title">
    <a href="<%= url_for() %>" class="logo">
      <%= config.title %>
    </a>
  </div>
  <nav class="navbar">
    <ul class="menu">
      <% for (name in theme.menu) { %>
        <li class="menu-item">
          <a href="<%- url_for(theme.menu[name]) %>" class="menu-item-link"><%= name %></a>
        </li>
      <% } %> 
    </ul>
  </nav>
</header>

在这里我们使用<% for (name in theme.menu) { %>遍历我们在_config.yml中设置的menu信息

<footer>
  <p>
    Theme is 
    <a href="/" target="_blank">
      Theme-name
    </a> 
    by 
    <a href="<%= config.url %>" target="_blank">
      <%= config.author %>
    </a>
  </p>    
  <p>
    Powered by 
    <a href="https://hexo.io/" target="_blank" rel="nofollow">
      hexo
    </a> 
    &copy; <%- date(Date.now(), 'YYYY') %>
  </p>
</footer>

注意这里的Theme-name需要更换为你的主题名字

到这里我们就得到了一个包含导航栏和底部信息的简单页面
img

文章列表

接下来完善首页,使其能显示文章列表。
这里我们要用到page变量的posts属性拿到文章的数据集合。

编辑index.ejs文件
<section class="posts">
  <% page.posts.each(function (post) { %>
    <article class="post">
      <div class="post-title">
        <a class="post-title-link" href="<%- url_for(post.path) %>">
          <%= post.title %>
        </a>
      </div>
      <div class="post-content">
        <%- post.content %>
      </div>
      <div class="post-meta">
        <span class="post-time">
          <%- date(post.date, "YYYY-MM-DD") %>
        </span>
      </div>
    </article>
  <% }) %>
</section>

由于首页显示文章内容时使用的是post.content,即文章的全部内容,有时候我们并不想再首页显示全部内容,这时我们可以将post.content改成post.excerpt
post.excerpt表示文章的摘录部分。我们在文章中添加一个<!--more-->标记,之后,post.excerpt将会截取标记之前的内容。

添加样式

到这里,我们的框架以及大致内容显示已经完成了,但是由于没有设置样式,现在我们的网站还很丑。于是终于到了最激动人心的一刻了!我们开始添加css样式文件来美化我们的页面。
我们只需要将样式文件放到css文件夹中。Hexo在生成文件时会将source中的文件赋值到生产的public文件夹中,并将styl文件编译成css文件。
source文件夹中新建css文件夹,在 css 文件夹中创建 style.styl,编写一些基础的样式,并把所有样式 import到这个文件。所以最终编译之后只会有 style.css 一个文件。创建_partial/header.styl_partial/index.styl 存放页面导航以及文章的样式,并且在 style.stylimport 这两个文件。

style.stylimport

接下来我们只需要编辑样式文件,自由发挥即可。
示例:

_partial/header.styl
.header {
  margin-top: 30px;
}
_partial/index.styl
//代码
style.styl
@import "_partial/header";
@import "_partial/index";

最后我们需要将样式文件添加到页面中,这里使用了辅助函数css()

编辑layout/_partial/head.ejs
<head>    
  <meta http-equiv="content-type" content="text/html; charset=utf-8">    
  <meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" name="viewport">    
  <title>
    <%= config.title %>
  </title>
  <!-- 添加这一行即可 -->
  <%- css('css/style.styl') %>
</head>

添加文章详情页

新建post.ejs

<article class="post">
  <div class="post-title">
    <h2 class="title">
      <%= page.title %>
    </h2>
  </div>
  <div class="post-meta">
    <span class="post-time">
      <%- date(page.date, "YYYY-MM-DD") %>
    </span>
  </div>
  <div class="post-content">
    <%- page.content %>
  </div>
</article>

添加归档页

新建archive.ejs

<section class="archive">
  <ul class="post-archive">
    <% page.posts.each(function (post) { %>
    <li class="post-item">
      <span class="post-date">
        <%= date(post.date, "YYYY-MM-DD") %>
      </span>
      <a class="post-title" href="<%- url_for(post.path) %>">
        <%= post.title %>
      </a>
    </li>
    <% }) %>
  </ul>
</section>

添加分类页

新建自定义页面模板page.ejs

<% if (is_current(theme.menu.categories)) { %>
  <%- partial('_partial/category') %>
<% } else if (is_current(theme.menu.tags)) { %>
  <%- partial('_partial/tag') %>
<% } else { %>
  <%- partial('_partial/custom') %>
<% } %>

新建_partial/category.ejs

<section class="archive">
  <ul class="post-archive">
    <% site.categories.each(function (category) { %>
      <span>
        <%= category.name %>
      </span>
      <% category.posts.forEach(function(post) { %>
      <li class="post-item">
        <span class="post-date">
          <%= date(post.date, "YYYY-MM-DD") %>
        </span>
        <a class="post-title" href="<%- url_for(post.path) %>">
          <%= post.title %>
        </a>
      </li>
      <% }) %>
    <% }) %>
  </ul>
</section>

添加标签页

新建_partial/tag.ejs

<section class="archive">
  <ul class="post-archive">
    <% site.tags.each(function (tag) { %>
      <span>
        <%= tag.name %>
      </span>
      <% tag.posts.forEach(function(post) { %>
        <li class="post-item">
          <span class="post-date">
            <%= date(post.date, "YYYY-MM-DD") %>
          </span>
          <a class="post-title" href="<%- url_for(post.path) %>">
            <%= post.title %>
          </a>
        </li>
      <% }) %>
    <% }) %>
  </ul>
</section>

添加自定义页面

新建_partial/custom.ejs

<article class="post">
  <div class="post-title">
    <h2 class="title">
      <%= page.title %>
    </h2>
  </div>
  <div class="post-meta">
    <span class="post-time">
      <%- date(page.date, "YYYY-MM-DD") %>
    </span>
  </div>
  <div class="post-content">
    <%- page.content %>
  </div>
</article>

关于代码高亮

不知道是之前误操作还是怎么的,我发现我的博客内容页中代码高亮失效了。在网上百度了一翻,总算是解决了。
一般情况下hexo提供两种高亮方式,highlight.jsprism.js,这里我选择的是prism.js

下载prism

前去官网https://prismjs.com/download.html选择喜欢的主题以及需要的语言,点击下面的两个按钮即可下载prism.js以及prism.css两个文件
点击预览并选择主题

选择自己需要的语言

选择自己需要的插件

引入

下载得到css和js文件后分别放到主题的source/jssource/css目录下
header.ejs中引入这两个文件

<%- css('css/prism')  %> 
<%- js('js/prism.js') %>

更改默认配置

# _config.yml
highlight:
  enable: true ##enable表示是否启用
  auto_detect: false
  line_number: true
  tab_replace: ''
  wrap: true
  hljs: false
prismjs:
  enable: false
  preprocess: true
  line_number: true
  tab_replace: ''

以上为Hexo的默认配置,highlight默认开启,因此我们需要将highlight关闭,开启prismjs

# _config.yml
highlight:
  enable: false
  # line_number: true
  # auto_detect: false
  # tab_replace: ''
  # wrap: true
  # hljs: false
prismjs:
  enable: true
  preprocess: true
  line_number: true
  tab_replace: ''

更改后
这时我们再运行hexo cleanhexo ghexo s重启项目即可看到代码高亮成功

参考文章:
https://blog.csdn.net/smileyan9/article/details/124333810
https://www.w3cschool.cn/hexodocument/hexodocument-6m483cn4.html

部署时遇到的坑

关于链接

在本地运行时,我的<a></a>链接默认都是在当前窗口打开,但是部署到github上后,它们就变成了在新窗口打开链接
因此需要手动给每个a标签设置target="_self

关于图标

增加一些图标让你的网站更好看趴~
这里我选择的是Font Awesome
注册账户并登录,在你的head.ejs文件中加上

<script src="https://kit.fontawesome.com/487be84f99.js" crossorigin="anonymous"></script>

这样就可以选择你喜欢的图标然后使用啦
示例

<!-- .ejs文件 -->
<i class="fa-solid fa-angle-down"></i>