搭建基於Hexo+Butterfly主題的個人博客站


前言

Hexo是基於NodeJS構建簡潔高效的博客框架。使用 Markdown 編寫文章內容,幾秒內即可利用靚麗的主題生成靜態網頁。支持豐富的主題與插件,主題用於頁面展示效果,插件用於實現博客的特殊功能 如:文章及內容搜索、圖片懶加載、一鍵遠程部署等。

 

Butterfly是Hexo的主題之一,也是本文將要進行集成的主題。官方網站也是該主題的演示頁面,其教程更加詳細,本文為入門級教學,使用該主題不需要對hexo框架有過多了解,遵循butterfly的寫作規范開發即可。

安裝

安裝Hexo之前需要先安裝nodejs(建議版本12.13.0)。沒安裝nodejs請自行查詢安裝方法,本文將不對nodejs做說明。

全局安裝Hexo命令腳本

hexo全局命令用於 初始化Hexo項目、生成靜態頁面、一鍵遠程部署、本地運行Web頁面調試等。

$ npm install -g hexo-cli

 

創建Hexo項目

開發工具推薦使用VsCode,喜歡用別的工具也可以。

1. 創建工程目錄

 在本地任意文件夾下創建一個空目錄 如下

2. 初始化目錄結構

使用vscode打開該目錄,然后在控制台執行以下命令 (控制台快捷鍵 Ctrl + ~)

$ hexo init

上面命令執行完畢,等待目錄結構構建完成即可

3. 目錄介紹

下面為 hexo init 命令生成的目錄結構

需要關心的幾個文件夾及目錄如下

  • sourece 源碼數據目錄,一般存放博客markdown源文件數據和資源數據,這個目錄下的數據才會被打包編譯。
    • sources/_posts 目錄存放博客源文件(md)
    • 后期我們主題需要的頁面也會在source目錄下創建。
  • themes 主題存放目錄,主題的引入共兩種方式,一種源碼方式引入,一種npm方式,這個目錄下存放的為源碼方式引入的主題。
  • _config.yml 核心配置文件,此文件可配置博客標題、輸出目錄結構、訪問路徑規則、主題的引用配置以及一鍵發布的相關信息配置。
    • 該文件中的配置不固定,取決於使用的插件,如果使用圖片懶加載或本地內容搜索功能也都需要在該文件里配置信息。
    • 一般主題配置會獨立出一個單獨的yml文件,如_config.landscape.yml文件就是主題相關配置文件。

4. 啟動默認主題項目

執行如下命令,會在本地啟動一個web服務來訪問靜態博客站。暫時不對主題做任何更改,先看下默認界面

$ hexo server

出現如下字樣表示啟動完畢 訪問 http://localhost:4000/ 

默認主題的Hexo項目

  • 如上幾步操作就運行了一個hexo的博客項目。還是挺簡單的,下面我們進行butterfly主題配置使用(一般都不使用默認主題,默認主題不美觀且沒有定制化的東西)。

Butterfly主題配置

1. 使用npm方式安裝主題

執行如下命令進行主題依賴的安裝, npm可能安裝緩慢,如果你知道怎么使用yarn 可以使用yarn安裝它

卸載默認主題

$ npm uninstall hexo-theme-landscape

安裝主題

$ npm install hexo-theme-butterfly --save

安裝依賴插件

$ npm install hexo-renderer-pug hexo-renderer-stylus --save

2. 修改必要配置

修改主題引用

修改_config.yml 中 theme 值改為 butterfly

主題配置文件

修改 _config.landscape.yml 名稱為 _config.butterfly.yml ,將下面內容復制進_config.butterfly.yml中

查看代碼
# Main menu navigation (導航目錄)
# see https://butterfly.js.org/posts/4aa8abbe/#導航菜單
# --------------------------------------

menu:
  # Home: / || fas fa-home
  # Archives: /archives/ || fas fa-archive
  # Tags: /tags/ || fas fa-tags
  # Categories: /categories/ || fas fa-folder-open
  # List||fas fa-list:
  #   Music: /music/ || fas fa-music
  #   Movie: /movies/ || fas fa-video
  # Link: /link/ || fas fa-link
  # About: /about/ || fas fa-heart

# Code Blocks (代碼相關)
# --------------------------------------

highlight_theme: light #  darker / pale night / light / ocean / mac / mac light / false
highlight_copy: true # copy button
highlight_lang: true # show the code language
highlight_shrink: false # true: shrink the code blocks / false: expand the code blocks | none: expand code blocks and hide the button
highlight_height_limit: false # unit: px
code_word_wrap: false

# copy settings
# copyright: Add the copyright information after copied content (複製的內容後面加上版權信息)
copy:
  enable: true
  copyright:
    enable: false
    limit_count: 50

# social settings (社交圖標設置)
# formal:
#   icon: link || the description
social:
  # fab fa-github: https://github.com/xxxxx || Github
  # fas fa-envelope: mailto:xxxxxx@gmail.com || Email

# search (搜索)
# --------------------------------------

# Algolia search
algolia_search:
  enable: false
  hits:
    per_page: 6

# Local search
local_search:
  enable: false

# Math (數學)
# --------------------------------------
# About the per_page
# if you set it to true, it will load mathjax/katex script in each page (true 表示每一頁都加載js)
# if you set it to false, it will load mathjax/katex script according to your setting (add the 'mathjax: true' in page's front-matter)
# (false 需要時加載,須在使用的 Markdown Front-matter 加上 mathjax: true)

# MathJax
mathjax:
  enable: false
  per_page: false

# KaTeX
katex:
  enable: false
  per_page: false
  hide_scrollbar: true

# Image (圖片設置)
# --------------------------------------

# Favicon(網站圖標)
favicon: /img/favicon.png

# Avatar (頭像)
avatar:
  img: https://i.loli.net/2021/02/24/5O1day2nriDzjSu.png
  effect: false

# Disable all banner image
disable_top_img: false

# The banner image of home page
index_img:

# If the banner of page not setting, it will show the top_img
default_top_img:

# The banner image of archive page
archive_img:

# If the banner of tag page not setting, it will show the top_img
# note: tag page, not tags page (子標籤頁面的 top_img)
tag_img:

# The banner image of tag page
# format:
#  - tag name: xxxxx
tag_per_img:

# If the banner of category page not setting, it will show the top_img
# note: category page, not categories page (子分類頁面的 top_img)
category_img:

# The banner image of category page
# format:
#  - category name: xxxxx
category_per_img:

cover:
  # display the cover or not (是否顯示文章封面)
  index_enable: true
  aside_enable: true
  archives_enable: true
  # the position of cover in home page (封面顯示的位置)
  # left/right/both
  position: both
  # When cover is not set, the default cover is displayed (當沒有設置cover時,默認的封面顯示)
  default_cover:
    # - https://i.loli.net/2020/05/01/gkihqEjXxJ5UZ1C.jpg

# Replace Broken Images (替換無法顯示的圖片)
error_img:
  flink: /img/friend_404.gif
  post_page: /img/404.jpg

# A simple 404 page
error_404:
  enable: false
  subtitle: 'Page Not Found'
  background: https://i.loli.net/2020/05/19/aKOcLiyPl2JQdFD.png

post_meta:
  page: # Home Page
    date_type: created # created or updated or both 主頁文章日期是創建日或者更新日或都顯示
    date_format: date # date/relative 顯示日期還是相對日期
    categories: true # true or false 主頁是否顯示分類
    tags: false # true or false 主頁是否顯示標籤
    label: true # true or false 顯示描述性文字
  post:
    date_type: both # created or updated or both 文章頁日期是創建日或者更新日或都顯示
    date_format: date # date/relative 顯示日期還是相對日期
    categories: true # true or false 文章頁是否顯示分類
    tags: true # true or false 文章頁是否顯示標籤
    label: true # true or false 顯示描述性文字

# wordcount (字數統計)
wordcount:
  enable: false
  post_wordcount: true
  min2read: true
  total_wordcount: true

# Display the article introduction on homepage
# 1: description
# 2: both (if the description exists, it will show description, or show the auto_excerpt)
# 3: auto_excerpt (default)
# false: do not show the article introduction
index_post_content:
  method: 3
  length: 500 # if you set method to 2 or 3, the length need to config

# anchor
# when you scroll in post, the URL will update according to header id.
anchor: false

# Post
# --------------------------------------

# toc (目錄)
toc:
  post: true
  page: false
  number: true
  expand: false
  style_simple: false # for post

post_copyright:
  enable: true
  decode: false
  license: CC BY-NC-SA 4.0
  license_url: https://creativecommons.org/licenses/by-nc-sa/4.0/

# Sponsor/reward
reward:
  enable: false
  QR_code:
    # - img: /img/wechat.jpg
    #   link:
    #   text: wechat
    # - img: /img/alipay.jpg
    #   link:
    #   text: alipay

# Post edit
# Easily browse and edit blog source code online.
post_edit:
  enable: false
  # url: https://github.com/user-name/repo-name/edit/branch-name/subdirectory-name/
  # For example: https://github.com/jerryc127/butterfly.js.org/edit/main/source/
  url:

# Related Articles
related_post:
  enable: true
  limit: 6 # Number of posts displayed
  date_type: created # or created or updated 文章日期顯示創建日或者更新日

# figcaption (圖片描述文字)
photofigcaption: false

# post_pagination (分頁)
# value: 1 || 2 || false
# 1: The 'next post' will link to old post
# 2: The 'next post' will link to new post
# false: disable pagination
post_pagination: 1

# Displays outdated notice for a post (文章過期提醒)
noticeOutdate:
  enable: false
  style: flat # style: simple/flat
  limit_day: 500 # When will it be shown
  position: top # position: top/bottom
  message_prev: It has been
  message_next: days since the last update, the content of the article may be outdated.

# Share System (分享功能)
# --------------------------------------

# AddThis
# https://www.addthis.com/
addThis:
  enable: false
  pubid:

# Share.js
# https://github.com/overtrue/share.js
sharejs:
  enable: true
  sites: facebook,twitter,wechat,weibo,qq

# AddToAny
# https://www.addtoany.com/
addtoany:
  enable: false
  item: facebook,twitter,wechat,sina_weibo,facebook_messenger,email,copy_link

# Comments System
# --------------------------------------

comments:
  # Up to two comments system, the first will be shown as default
  # Choose: Disqus/Disqusjs/Livere/Gitalk/Valine/Waline/Utterances/Facebook Comments/Twikoo/Giscus
  use: # Valine,Disqus
  text: true # Display the comment name next to the button
  # lazyload: The comment system will be load when comment element enters the browser's viewport.
  # If you set it to true, the comment count will be invalid
  lazyload: false
  count: false # Display comment count in post's top_img
  card_post_count: false # Display comment count in Home Page

# disqus
# https://disqus.com/
disqus:
  shortname:
  apikey: # For newest comments widget

# Alternative Disqus - Render comments with Disqus API
# DisqusJS 評論系統,可以實現在網路審查地區載入 Disqus 評論列表,兼容原版
# https://github.com/SukkaW/DisqusJS
disqusjs:
  shortname:
  apikey:
  option:

# livere (來必力)
# https://www.livere.com/
livere:
  uid:

# gitalk
# https://github.com/gitalk/gitalk
gitalk:
  client_id:
  client_secret:
  repo:
  owner:
  admin:
  option:

# valine
# https://valine.js.org
valine:
  appId: # leancloud application app id
  appKey: # leancloud application app key
  avatar: monsterid # gravatar style https://valine.js.org/#/avatar
  serverURLs: # This configuration is suitable for domestic custom domain name users, overseas version will be automatically detected (no need to manually fill in)
  bg: # valine background
  visitor: false
  option:

# waline - A simple comment system with backend support fork from Valine
# https://waline.js.org/
waline:
  serverURL: # Waline server address url
  bg: # waline background
  visitor: false
  option:

# utterances
# https://utteranc.es/
utterances:
  repo:
  # Issue Mapping: pathname/url/title/og:title
  issue_term: pathname
  # Theme: github-light/github-dark/github-dark-orange/icy-dark/dark-blue/photon-dark
  light_theme: github-light
  dark_theme: photon-dark

# Facebook Comments Plugin
# https://developers.facebook.com/docs/plugins/comments/
facebook_comments:
  app_id:
  user_id: # optional
  pageSize: 10 # The number of comments to show
  order_by: social # social/time/reverse_time
  lang: en_US # Language en_US/zh_CN/zh_TW and so on

# Twikoo
# https://github.com/imaegoo/twikoo
twikoo:
  envId:
  region:
  visitor: false
  option:

# Giscus
# https://giscus.app/
giscus:
  repo:
  repo_id:
  category_id:
  theme:
    light: light
    dark: dark
  option:

# Chat Services
# --------------------------------------

# Chat Button [recommend]
# It will create a button in the bottom right corner of website, and hide the origin button
chat_btn: false

# The origin chat button is displayed when scrolling up, and the button is hidden when scrolling down
chat_hide_show: false

# chatra
# https://chatra.io/
chatra:
  enable: false
  id:

# tidio
# https://www.tidio.com/
tidio:
  enable: false
  public_key:

# daovoice
# http://daovoice.io/
daovoice:
  enable: false
  app_id:

# gitter
# https://gitter.im/
gitter:
  enable: false
  room:

# crisp
# https://crisp.chat/en/
crisp:
  enable: false
  website_id:

# Footer Settings
# --------------------------------------
footer:
  owner:
    enable: true
    since: 2020
  custom_text:
  copyright: true # Copyright of theme and framework

# Analysis
# --------------------------------------

# Baidu Analytics
# https://tongji.baidu.com/web/welcome/login
baidu_analytics:

# Google Analytics
# https://analytics.google.com/analytics/web/
google_analytics:

# CNZZ Analytics
# https://www.umeng.com/
cnzz_analytics:

# Cloudflare Analytics
# https://www.cloudflare.com/zh-tw/web-analytics/
cloudflare_analytics:

# Microsoft Clarity
# https://clarity.microsoft.com/
microsoft_clarity:

# Advertisement
# --------------------------------------

# Google Adsense (谷歌廣告)
google_adsense:
  enable: false
  auto_ads: true
  js: https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js
  client:
  enable_page_level_ads: true

# Insert ads manually (手動插入廣告)
# ad:
#   index:
#   aside:
#   post:

# Verification (站長驗證)
# --------------------------------------

site_verification:
  # - name: google-site-verification
  #   content: xxxxxx
  # - name: baidu-site-verification
  #   content: xxxxxxx

# Beautify/Effect (美化/效果)
# --------------------------------------

# Theme color for customize
# Notice: color value must in double quotes like "#000" or may cause error!

# theme_color:
#   enable: true
#   main: "#49B1F5"
#   paginator: "#00c4b6"
#   button_hover: "#FF7242"
#   text_selection: "#00c4b6"
#   link_color: "#99a9bf"
#   meta_color: "#858585"
#   hr_color: "#A4D8FA"
#   code_foreground: "#F47466"
#   code_background: "rgba(27, 31, 35, .05)"
#   toc_color: "#00c4b6"
#   blockquote_padding_color: "#49b1f5"
#   blockquote_background_color: "#49b1f5"
#   scrollbar_color: "#49b1f5"

# The top_img settings of home page
# default: top img - full screen, site info - middle (默認top_img全屏,site_info在中間)
# The position of site info, eg: 300px/300em/300rem/10% (主頁標題距離頂部距離)
index_site_info_top:
# The height of top_img, eg: 300px/300em/300rem (主頁top_img高度)
index_top_img_height:

# The user interface setting of category and tag page (category和tag頁的UI設置)
# index - same as Homepage UI (index 值代表 UI將與首頁的UI一樣)
# default - same as archives UI 默認跟archives頁面UI一樣
category_ui: # 留空或 index
tag_ui: # 留空或 index

# Website Background (設置網站背景)
# can set it to color or image (可設置圖片 或者 顔色)
# The formal of image: url(http://xxxxxx.com/xxx.jpg)
background:

# Footer Background
footer_bg: false

# the position of bottom right button/default unit: px (右下角按鈕距離底部的距離/默認單位為px)
rightside-bottom:

# Enter transitions (開啓網頁進入效果)
enter_transitions: true

# Background effects (背景特效)
# --------------------------------------

# canvas_ribbon (靜止彩帶背景)
# See: https://github.com/hustcc/ribbon.js
canvas_ribbon:
  enable: false
  size: 150
  alpha: 0.6
  zIndex: -1
  click_to_change: false
  mobile: false

# Fluttering Ribbon (動態彩帶)
canvas_fluttering_ribbon:
  enable: false
  mobile: false

# canvas_nest
# https://github.com/hustcc/canvas-nest.js
canvas_nest:
  enable: false
  color: '0,0,255' #color of lines, default: '0,0,0'; RGB values: (R,G,B).(note: use ',' to separate.)
  opacity: 0.7 # the opacity of line (0~1), default: 0.5.
  zIndex: -1 # z-index property of the background, default: -1.
  count: 99 # the number of lines, default: 99.
  mobile: false

# Typewriter Effect (打字效果)
# https://github.com/disjukr/activate-power-mode
activate_power_mode:
  enable: false
  colorful: true # open particle animation (冒光特效)
  shake: true #  open shake (抖動特效)
  mobile: false

# Mouse click effects: fireworks (鼠標點擊效果: 煙火特效)
fireworks:
  enable: false
  zIndex: 9999 # -1 or 9999
  mobile: false

# Mouse click effects: Heart symbol (鼠標點擊效果: 愛心)
click_heart:
  enable: false
  mobile: false

# Mouse click effects: words (鼠標點擊效果: 文字)
ClickShowText:
  enable: false
  text:
    # - I
    # - LOVE
    # - YOU
  fontSize: 15px
  random: false
  mobile: false

# Default display mode (網站默認的顯示模式)
# light (default) / dark
display_mode: light

# Beautify (美化頁面顯示)
beautify:
  enable: false
  field: post # site/post
  title-prefix-icon: # '\f0c1'
  title-prefix-icon-color: # '#F47466'

# Global font settings
# Don't modify the following settings unless you know how they work (非必要不要修改)
font:
  global-font-size:
  code-font-size:
  font-family:
  code-font-family:

# Font settings for the site title and site subtitle
# 左上角網站名字 主頁居中網站名字
blog_title_font:
  font_link:
  font-family:

# The setting of divider icon (水平分隔線圖標設置)
hr_icon:
  enable: true
  icon: # the unicode value of Font Awesome icon, such as '\3423'
  icon-top:

# the subtitle on homepage (主頁subtitle)
subtitle:
  enable: false
  # Typewriter Effect (打字效果)
  effect: true
  # loop (循環打字)
  loop: true
  # source 調用第三方服務
  # source: false 關閉調用
  # source: 1  調用一言網的一句話(簡體) https://hitokoto.cn/
  # source: 2  調用一句網(簡體) http://yijuzhan.com/
  # source: 3  調用今日詩詞(簡體) https://www.jinrishici.com/
  # subtitle 會先顯示 source , 再顯示 sub 的內容
  source: false
  # 如果關閉打字效果,subtitle 只會顯示 sub 的第一行文字
  sub:

# Loading Animation (加載動畫)
preloader: false

# aside (側邊欄)
# --------------------------------------

aside:
  enable: true
  hide: false
  button: true
  mobile: true # display on mobile
  position: right # left or right
  card_author:
    enable: true
    description:
    button:
      enable: true
      icon: fab fa-github
      text: Follow Me
      link: https://github.com/xxxxxx
  card_announcement:
    enable: true
    content: This is my Blog
  card_recent_post:
    enable: true
    limit: 5 # if set 0 will show all
    sort: date # date or updated
    sort_order: # Don't modify the setting unless you know how it works
  card_categories:
    enable: true
    limit: 8 # if set 0 will show all
    expand: none # none/true/false
    sort_order: # Don't modify the setting unless you know how it works
  card_tags:
    enable: true
    limit: 40 # if set 0 will show all
    color: false
    sort_order: # Don't modify the setting unless you know how it works
  card_archives:
    enable: true
    type: monthly # yearly or monthly
    format: MMMM YYYY # eg: YYYY年MM月
    order: -1 # Sort of order. 1, asc for ascending; -1, desc for descending
    limit: 8 # if set 0 will show all
    sort_order: # Don't modify the setting unless you know how it works
  card_webinfo:
    enable: true
    post_count: true
    last_push_date: true
    sort_order: # Don't modify the setting unless you know how it works

# busuanzi count for PV / UV in site
# 訪問人數
busuanzi:
  site_uv: true
  site_pv: true
  page_pv: true

# Time difference between publish date and now (網頁運行時間)
# Formal: Month/Day/Year Time or Year/Month/Day Time
runtimeshow:
  enable: false
  publish_date:

# Aside widget - Newest Comments
newest_comments:
  enable: false
  sort_order: # Don't modify the setting unless you know how it works
  limit: 6
  storage: 10 # unit: mins, save data to localStorage
  avatar: true

# Bottom right button (右下角按鈕)
# --------------------------------------

# Conversion between Traditional and Simplified Chinese (簡繁轉換)
translate:
  enable: false
  # The text of a button
  default: 繁
  # the language of website (1 - Traditional Chinese/ 2 - Simplified Chinese)
  defaultEncoding: 2
  # Time delay
  translateDelay: 0
  # The text of the button when the language is Simplified Chinese
  msgToTraditionalChinese: '繁'
  # The text of the button when the language is Traditional Chinese
  msgToSimplifiedChinese: '簡'

# Read Mode (閲讀模式)
readmode: true

# dark mode
darkmode:
  enable: true
  # Toggle Button to switch dark/light mode
  button: true
  # Switch dark/light mode automatically (自動切換 dark mode和 light mode)
  # autoChangeMode: 1  Following System Settings, if the system doesn't support dark mode, it will switch dark mode between 6 pm to 6 am
  # autoChangeMode: 2  Switch dark mode between 6 pm to 6 am
  # autoChangeMode: false
  autoChangeMode: false

# Don't modify the following settings unless you know how they work (非必要請不要修改 )
# Choose: readmode,translate,darkmode,hideAside,toc,chat,comment
# Don't repeat 不要重複
rightside_item_order:
  enable: false
  hide: # readmode,translate,darkmode,hideAside
  show: # toc,chat,comment

# Lightbox (圖片大圖查看模式)
# --------------------------------------
# You can only choose one, or neither (只能選擇一個 或者 兩個都不選)

# medium-zoom
# https://github.com/francoischalifour/medium-zoom
medium_zoom: false

# fancybox
# http://fancyapps.com/fancybox/3/
fancybox: true

# Tag Plugins settings (標籤外掛)
# --------------------------------------

# mermaid
# see https://github.com/mermaid-js/mermaid
mermaid:
  enable: false
  # built-in themes: default/forest/dark/neutral
  theme:
    light: default
    dark: dark

# Note (Bootstrap Callout)
note:
  # Note tag style values:
  #  - simple    bs-callout old alert style. Default.
  #  - modern    bs-callout new (v2-v3) alert style.
  #  - flat      flat callout style with background, like on Mozilla or StackOverflow.
  #  - disabled  disable all CSS styles import of note tag.
  style: flat
  icons: true
  border_radius: 3
  # Offset lighter of background in % for modern and flat styles (modern: -12 | 12; flat: -18 | 6).
  # Offset also applied to label tag variables. This option can work with disabled note tag.
  light_bg_offset: 0

# other
# --------------------------------------

# Pjax
# It may contain bugs and unstable, give feedback when you find the bugs.
# https://github.com/MoOx/pjax
pjax:
  enable: false
  exclude:
    # - xxxx
    # - xxxx

# Inject the css and script (aplayer/meting)
aplayerInject:
  enable: false
  per_page: true

# Snackbar (Toast Notification 彈窗)
# https://github.com/polonel/SnackBar
# position 彈窗位置
# 可選 top-left / top-center / top-right / bottom-left / bottom-center / bottom-right
snackbar:
  enable: false
  position: bottom-left
  bg_light: '#49b1f5' # The background color of Toast Notification in light mode
  bg_dark: '#1f1f1f' # The background color of Toast Notification in dark mode

# https://instant.page/
# prefetch (預加載)
instantpage: false

# https://github.com/vinta/pangu.js
# Insert a space between Chinese character and English character (中英文之間添加空格)
pangu:
  enable: false
  field: site # site/post

# Lazyload (圖片懶加載)
# https://github.com/verlok/vanilla-lazyload
lazyload:
  enable: false
  field: site # site/post
  placeholder:
  blur: false

# PWA
# See https://github.com/JLHwung/hexo-offline
# ---------------
# pwa:
#   enable: false
#   manifest: /pwa/manifest.json
#   apple_touch_icon: /pwa/apple-touch-icon.png
#   favicon_32_32: /pwa/32.png
#   favicon_16_16: /pwa/16.png
#   mask_icon: /pwa/safari-pinned-tab.svg

# Open graph meta tags
# https://developers.facebook.com/docs/sharing/webmasters/
Open_Graph_meta: true

# Add the vendor prefixes to ensure compatibility
css_prefix: true

# Inject
# Insert the code to head (before '</head>' tag) and the bottom (before '</body>' tag)
# 插入代碼到頭部 </head> 之前 和 底部 </body> 之前
inject:
  head:
    # - <link rel="stylesheet" href="/xxx.css">
  bottom:
    # - <script src="xxxx"></script>

# CDN
# Don't modify the following settings unless you know how they work
# 非必要請不要修改
CDN:
  # main
  main_css:
  main:
  utils:

  # pjax
  pjax:

  # comments
  gitalk:
  gitalk_css:
  blueimp_md5:
  valine:
  disqusjs:
  disqusjs_css:
  utterances:
  twikoo:
  waline:
  giscus:

  # share
  addtoany:
  sharejs:
  sharejs_css:

  # search
  local_search:
  algolia_js:
  algolia_search_v4:
  instantsearch_v4:

  # math
  mathjax:
  katex:
  katex_copytex:
  katex_copytex_css:
  mermaid:

  # count
  busuanzi:

  # background effect
  canvas_ribbon:
  canvas_fluttering_ribbon:
  canvas_nest:

  lazyload:
  instantpage:
  typed:
  pangu:

  # photo
  fancybox_css_v4:
  fancybox_v4:
  medium_zoom:

  # snackbar
  snackbar_css:
  snackbar:

  # effect
  activate_power_mode:
  fireworks:
  click_heart:
  ClickShowText:

  # fontawesome
  fontawesomeV6:

  # Conversion between Traditional and Simplified Chinese
  translate:

  # flickr-justified-gallery
  flickr_justified_gallery_js:
  flickr_justified_gallery_css:

  # aplayer
  aplayer_css:
  aplayer_js:
  meting_js:

  # Prism.js
  prismjs_js:
  prismjs_lineNumber_js:
  prismjs_autoloader:

配置中文語言

 
修改_config.yml文件中language值為 zh_CN
 

配置菜單項

需要在_config.butterfly.yml文件中修改menu內容,默認是被注釋掉了,配置如下

上面菜單根據自己需要修改,英文可以直接修改成中文,后面的url不能修改,否則會匹配不到路由,展示不出菜單,|| 符號后面的是圖標,如果需要修改可以到https://fa5.dashgame.com/#/網站中查詢自己需要的圖標。

如下就配置了一些菜單,項目啟動時就能在右上角看到這些菜單

 

創建標簽頁、分類頁  (該主題默認未創建標簽頁和分類頁,如果不創建,並且開啟該菜單會報404錯誤)

3. 創建標簽頁

$ hexo new page tags

執行上面命令會在 source 目錄中創建 tags/index.md 文件,需要修改文件的部分內容

如上,1 需要修改title,標簽頁面的標題 ,2 新增值項 type : "tags" (固定寫法,用於butterfly主題對路由匹配及博客tags信息的生成)

4. 創建分類頁

$ hexo new page categories

執行后,修改 categories/index.md 文件內容為

  • 和標簽頁一樣重要的type屬性一定要配置categories

 

本文為了內容簡單且易入門,沒有對音樂、視頻、友情鏈接等頁面創建做出描述,可到相關網站查找創建方法

博客內容寫作

上面對博客項目進行了簡單配置,詳細配置需要參照官方文檔來配置。配置完主題后,以后就只需要對文章內容進行修改或添加新文章,無需改任何配置。

Hexo的文章內容編寫都需要在本地Nodejs的項目中進行,內容一般由 標准的markdown語法 和 butterfly標簽外掛來構建。

首先了解下futterfly標簽外掛的作用及使用,然后編寫一篇完整的博文。

標簽外掛

除了標准的mackdown語法以外,butterfly還提供了額外的一些組件標簽(非標准mackdown語法,butterfly以外的地方使用可能不生效且會報錯)

 
 

Front-matter

markdown允許在頁面中定義一些額外屬性(相當於變量),Hexo框架會讀取每個md文件的front-matter傳給butterfly主題框架使用。每個頁面或文章的一些相關信息設置需要用到。如文章分類,創建時間以及文章頂部標題都需要在 front-matter中配置。

front-matter 定義在md文件頂部,由 --- 符號包括。

page matter

hexo new page [頁面名稱] 命令創建的頁面中的front-matter都屬於 page matter,

---
title:
date:
updated:
type:
comments:
description:
keywords:
top_img:
mathjax:
katex:
aside:
aplayer:
highlight_shrink:
---

如下為每個字段的解釋,在開發時也不是所有字段都能用到,根據需要書寫

post matter

使用 hexo new post [文章名稱] 創建的md文件

---
title:
date:
updated:
tags:
categories:
keywords:
description:
top_img:
comments:
cover:
toc:
toc_number:
toc_style_simple:
copyright:
copyright_author:
copyright_author_href:
copyright_url:
copyright_info:
mathjax:
katex:
aplayer:
highlight_shrink:
aside:
---

 

  • 上方為文章頁面可以定義的一些相關信息,如 文章分類、文章標簽、創建時間、文章作者、文章封面圖片等信息。

創建新文章

執行如下命令創建一個新的文章

$ hexo new post [文章名稱] 

完整的文章頁面文件

查看代碼

---

title: java8函數式編程
date: 2022-02-19 14:17:52
cover: /res/java8函數式編程/cover.jpg
tags: [java,java8,函數式編程]
categories:
    - java
---
**什么是函數式編程?**

百度百科: 函數式編程,是一種編程范式,它將電腦運算視為函數運算,並且避免使用程序狀態以及易變對象。其中,λ演算為該語言最重要的基礎。而且,λ演算的函數可以接受函數作為輸入參數和輸出返回值。

講人話: 函數式編程一種編程范式,允許使用一種表達式(lambda表達式)來表示一個函數

# 函數式接口

> Java語言中函數式編程,通過Java8版本提供的`函數式接口規范`來實現,它指的是有且只有一個未實現的方法的接口,一般通過`FunctionalInterface`這個注解來表明某個接口是一個函數式接口(非必須,如果標注了該注解,編譯器檢查接口是否符合函數式接口規范,如出現兩個及以上數量的普通方法,編譯器會報錯)。函數式接口是Java支持函數式編程的基礎。java8及以上版本才支持。



## 入門

使用Consumer作為示例,它是一個函數式接口,包含一個抽象方法accept,這個方法只有輸入而無輸出。
現在我們要定義一個Consumer對象,傳統的方式是這樣定義的:

```java
Consumer c = new Consumer() {
    @Override
    public void accept(Object o) {
        System.out.println(o);
    }
};
```

而在Java8中,針對函數式編程接口,可以這樣定義:

```java
Consumer c = (o) -> {
    System.out.println(o);
};  
```



上面已說明,函數式編程接口都只有一個抽象方法,因此在采用這種寫法時,編譯器會將這段函數編譯后當作該抽象方法的實現。
如果接口有多個抽象方法,編譯器就不知道這段函數應該是實現哪個方法的了。
因此,=后面的函數體我們就可以看成是accept函數的實現。

- 輸入:->前面的部分,即被()包圍的部分。此處只有一個輸入參數,實際上輸入是可以有多個的,如兩個參數時寫法:(a, b);當然也可以沒有輸入,此時直接就可以是()
- 函數體:->后面的部分,即被{}包圍的部分;可以是一段代碼。
- 輸出:函數式編程可以沒有返回值,也可以有返回值。如果有返回值時,需要代碼段的最后一句通過return的方式返回對應的值

當函數體中只有一個語句時,可以去掉{}進一步簡化:

```java
Consumer c = (o) -> System.out.println(o);
```

然而這還不是最簡的,由於此處只是進行打印,調用了System.out中的println靜態方法對輸入參數直接進行打印,因此可以簡化成以下寫法:

```java
Consumer c = System.out::println;
```

它表示的意思就是針對輸入的參數將其調用System.out中的靜態方法println進行打印。
到這一步就可以感受到函數式編程的強大能力。
通過最后一段代碼,我們可以簡單的理解函數式編程,Consumer接口直接就可以當成一個函數了,這個函數接收一個輸入參數,然后針對這個輸入進行處理;當然其本質上仍舊是一個對象,但我們已經省去了諸如老方式中的對象定義過程,直接使用一段代碼來給函數式接口對象賦值。
而且最為關鍵的是,這個函數式對象因為本質上仍舊是一個對象,因此可以做為其它方法的參數或者返回值,可以與原有的代碼實現無縫集成!

## Java預設函數式接口

> 下面對Java中的幾個預先定義的函數式接口及其經常使用的類進行分析學習。在`java.util.function`包下提供了很多函數式接口,這里挑幾個常用的進行講解。

### Consumer

Consumer是一個函數式編程接口; 顧名思義,Consumer的意思就是消費,即針對某個東西我們來使用它,因此它包含有一個有輸入而無輸出的accept接口方法;
除accept方法,它還包含有andThen這個方法;
其定義如下:

```java
default Consumer<T> andThen(Consumer<? super T> after) {
    Objects.requireNonNull(after);
    return (T t) -> { accept(t); after.accept(t); };
}
```

可見這個方法就是指定在調用當前Consumer后是否還要調用其它的Consumer;
使用示例:

```java
public static void consumerTest() {
    Consumer f = System.out::println;
    Consumer f2 = n -> System.out.println(n + "-F2");

    //執行完F后再執行F2的Accept方法
    f.andThen(f2).accept("test");

    //連續執行F的Accept方法
    f.andThen(f).andThen(f).andThen(f).accept("test1");
}
```



### Function

Function也是一個函數式編程接口;它代表的含義是“函數”,而函數經常是有輸入輸出的,因此它含有一個apply方法,包含一個輸入與一個輸出;
除apply方法外,它還有compose與andThen及indentity三個方法,其使用見下述示例;

```java
/**
 * Function測試
 */
public static void functionTest() {
    Function<Integer, Integer> f = s -> s++;
    Function<Integer, Integer> g = s -> s * 2;

    /**
     * 下面表示在執行F時,先執行G,並且執行F時使用G的輸出當作輸入。
     * 相當於以下代碼:
     * Integer a = g.apply(1);
     * System.out.println(f.apply(a));
     */
    System.out.println(f.compose(g).apply(1));

    /**
     * 表示執行F的Apply后使用其返回的值當作輸入再執行G的Apply;
     * 相當於以下代碼
     * Integer a = f.apply(1);
     * System.out.println(g.apply(a));
     */
    System.out.println(f.andThen(g).apply(1));

    /**
     * identity方法會返回一個不進行任何處理的Function,即輸出與輸入值相等; 
     */
    System.out.println(Function.identity().apply("a"));
}
```



### Predicate

Predicate為函數式接口,predicate的中文意思是“斷定”,即判斷的意思,判斷某個東西是否滿足某種條件; 因此它包含test方法,根據輸入值來做邏輯判斷,其結果為True或者False。
它的使用方法示例如下:

```
/**
 * Predicate測試
 */
private static void predicateTest() {
    Predicate<String> p = o -> o.equals("test");
    Predicate<String> g = o -> o.startsWith("t");

    /**
     * negate: 用於對原來的Predicate做取反處理;
     * 如當調用p.test("test")為True時,調用p.negate().test("test")就會是False;
     */
    Assert.assertFalse(p.negate().test("test"));

    /**
     * and: 針對同一輸入值,多個Predicate均返回True時返回True,否則返回False;
     */
    Assert.assertTrue(p.and(g).test("test"));

    /**
     * or: 針對同一輸入值,多個Predicate只要有一個返回True則返回True,否則返回False
     */
    Assert.assertTrue(p.or(g).test("ta"));
}
```

# Stream

> Stream可以對多個元素進行一系列的操作,也可以支持對某些操作進行並發處理。Java8中對集合、數組進行了stream的實現,方便開發人員通過stream對集合或數組進行數據操作。



##  Stream對象的創建

Stream對象的創建途徑有以下幾種

a. 創建空的Stream對象

```java
Stream stream = Stream.empty();
```

b. 通過集合類中的stream或者parallelStream方法創建;

```java
Stream<String> stream = Arrays.stream(new String[]{"1", "2", "3"});
List<String> list = Arrays.asList("a", "b", "c", "d");
Stream listStream = list.stream();                   //獲取串行的Stream對象
Stream parallelListStream = list.parallelStream();   //獲取並行的Stream對象  
```

c. 通過Stream中的of方法創建:

```
Stream s = Stream.of("test");
Stream s1 = Stream.of("a", "b", "c", "d");
```

d. 通過Stream中的iterate方法創建:
iterate方法有兩個不同參數的方法:

```java
public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f);  
public static<T> Stream<T> iterate(T seed, Predicate<? super T> hasNext, UnaryOperator<T> next)
```

其中第一個方法將會返回一個無限有序值的Stream對象:它的第一個元素是seed,第二個元素是f.apply(seed); 第N個元素是f.apply(n-1個元素的值);生成無限值的方法實際上與Stream的中間方法類似,在遇到中止方法前一般是不真正的執行的。因此無限值的這個方法一般與limit等方法一起使用,來獲取前多少個元素。
當然獲取前多少個元素也可以使用第二個方法。
第二個方法與第一個方法生成元素的方式類似,不同的是它返回的是一個有限值的Stream;中止條件是由hasNext來斷定的。

第二種方法的使用示例如下:

```
/**
 * 本示例表示從1開始組裝一個序列,第一個是1,第二個是1+1即2,第三個是2+1即3..,直接10時中止;
 * 也可簡化成以下形式:
 *        Stream.iterate(1,
 *        n -> n <= 10,
 *        n -> n+1).forEach(System.out::println);
 * 寫成以下方式是為簡化理解
 */
Stream.iterate(1,
        new Predicate<Integer>() {
            @Override
            public boolean test(Integer integer) {
                return integer <= 10;
            }
        },
    new UnaryOperator<Integer>() {
        @Override
        public Integer apply(Integer integer) {
            return integer+1;
        }
}).forEach(System.out::println);
```

e. 通過Stream中的generate方法創建
與iterate中創建無限元素的Stream類似,不過它的每個元素與前一元素無關,且生成的是一個無序的隊列。也就是說每一個元素都可以隨機生成。因此一般用來創建常量的Stream以及隨機的Stream等。
示例如下:

```
/**
 * 隨機生成10個Double元素的Stream並將其打印
 */
Stream.generate(new Supplier<Double>() {
    @Override
    public Double get() {
        return Math.random();
    }
}).limit(10).forEach(System.out::println);

//上述寫法可以簡化成以下寫法:
Stream.generate(() -> Math.random()).limit(10).forEach(System.out::println);
```

## Stream對象的使用

Stream對象提供多個非常有用的方法,這些方法可以分成兩類:
中間操作:將原始的Stream轉換成另外一個Stream;如filter返回的是過濾后的Stream。
終端操作:產生的是一個結果或者其它的復合操作;如count或者forEach操作。

下面就幾個比較常用的方法舉例說明其用法:

### filter

用於對Stream中的元素進行過濾,返回一個過濾后的Stream
其方法定義如下



```java
Stream<T> filter(Predicate<? super T> predicate);
```

使用示例:

```
Stream<String> s = Stream.of("test", "t1", "t2", "teeeee", "aaaa");
//查找所有包含t的元素並進行打印
s.filter(n -> n.contains("t")).forEach(System.out::println);
```

###  map

元素一對一轉換。
它接收一個Funcation參數,用其對Stream中的所有元素進行處理,返回的Stream對象中的元素為Function對原元素處理后的結果
其方法定義如下:

```
<R> Stream<R> map(Function<? super T, ? extends R> mapper);
```

示例,假設我們要將一個String類型的Stream對象中的每個元素添加相同的后綴.txt,如a變成a.txt,其寫法如下:

```
Stream<String> s = Stream.of("test", "t1", "t2", "teeeee", "aaaa");
s.map(n -> n.concat(".txt")).forEach(System.out::println);
```

### flatMap

元素一對多轉換:對原Stream中的所有元素使用傳入的Function進行處理,每個元素經過處理后生成一個多個元素的Stream對象,然后將返回的所有Stream對象中的所有元素組合成一個統一的Stream並返回;
方法定義如下:

```
<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);
```

示例,假設要對一個String類型的Stream進行處理,將每一個元素的拆分成單個字母,並打印:

```java
Stream<String> s = Stream.of("test", "t1", "t2", "teeeee", "aaaa");
s.flatMap(n -> Stream.of(n.split(""))).forEach(System.out::println);
```

打包發布

hexo提供了 資源清理,生成靜態資源,一鍵部署功能,建議生成資源前 先清理

清理資源

$ hexo clean
  • 執行該命令后,會刪除根目錄下生成的public目錄

生成靜態頁

$ hexo generate   簡寫: hexo g
  • 靜態頁面生成后默認會在項目目錄下的public目錄中,因為是靜態頁面,我們可以手動拿去部署在nginx等靜態資源服務器上。

一鍵發布配置

一鍵發布需要引入相對應的插件以及在_config.yml中配置一鍵發布的信息,一鍵發布執行前並不需熬手動執行生成靜態頁。

該文以github為例,利用一鍵發布功能,將靜態頁發布到github.io中

1. 創建github.io倉庫

倉庫名稱必須以 .github.io 結尾,前綴必須是github的用戶名,必須是一個公共倉庫,如下,最終生成的訪問鏈接為 https://huahuadelei.github.io/,github pages一個用戶只能有一個以用戶名為前綴的倉庫

2. 安裝插件github發布插件

在項目下執行如下命令安裝插件

$ npm install hexo-deployer-git --save

3. 配置_config.yml部署相關信息

_config.yml最下方補充相關配置信息。

# Deployment
## Docs: https://hexo.io/docs/one-command-deployment
deploy:
  type: 'git'
  repo: 'git@github.com:huahuadelei/hexo-test.github.io.git'
  branch: 'main'

4. 配置本地sshkey到github中(授權)

一般使用ssh用戶目錄都會有一對ssh密鑰對。如果沒有使用 ssh-keygen 命令進行生成

找到用戶目錄中 ~.ssh/id_rsa.pub 文件,把內容復制到github中

  • 點擊Add key即可添加完畢

5. 執行命令部署網站

在項目根目錄下,打開命令行執行

$ hexo deploy

執行完畢后,如下命令行展示

此時查看github倉庫也是已經有了數據

 

訪問github pages網站查看部署內容,https:// + 剛剛創建的倉庫名稱,https://huahuadelei.github.io/

首頁

內容頁

  • 從截圖中可以看出 之前配置的菜單已經在左上角顯示出來了。
  • 項目中默認的helloword頁面也是被展示出來了
  • 頁面中的用戶頭像、用戶名稱以及每個頁面上方的top圖片也都是可以定制化,具體請參照butterfly主題官方教程

 

開發建議

使用Hexo開發博客及維護的一個過程基本上都需要在本地進行,開發流程大致分為: Markdown源內容編寫 > Hexo生成靜態網頁 > 使用Hexo部署插件一鍵發布到遠程。

Hexo最終生成/部署的是一個靜態網頁,也就是它不需要數據庫環境來存儲數據,數據都被編譯到Html文件中。那么基於NodeJS的Hexo項目就是我們博客的源數據。如果項目丟失遠程的網站將無法繼續維護,所以建議將Hexo項目放在gitee或github上的私有倉庫中(公共倉庫也行,主要考慮有一鍵部署功能的配置信息會暴露),以后對項目的改動都建議提交到遠程。

 

相關資源

建議大家對Butterfly官方文章全部查看一邊后再定制化配置自己的博客,官方教程更為詳細,可更精細的定制自己的博客頁面。

建議桉順序查看這些文章教程

 

建議看不懂繁體字的轉為簡體后再閱讀


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM