Fluid -20- 使用 Fluid 注入功能实现背景视频

本文最后更新于:2022年7月4日 上午

Hexo 本身支持注入功能,可以实现无侵入式调整博客布局。Fluid 支持更优化的注入功能,本文记录 Fluid 代码注入的使用方法,并将背景视频功能转为注入实现。

简介

什么是代码注入

  • 在项目之外将需要修改的代码动态插入到项目中的技术手段

为什么需要代码注入

  • 是的,直接修改源码是完全可以达到目的的,但是源码修改会破坏仓库的代码完整性,问题主要出现在需要对仓库进行更新的时候

  • 修改过的仓库很容易在更新时引入冲突,那时候很可能需要面对自己都不记得为什么改的代码和完全不懂的项目代码做出取舍,实在是很危险、痛苦而且不优雅的

  • 也就是说,我们又要调整项目代码功能,又要保持项目足够“干净”,以便享受将来的更新,此时代码注入的价值便显现出来了

注入代码

Hexo 注入

  • Hexo 注入器 是 Hexo 5 版本自身加入的一项新功能,所以在所有 Hexo 主题都是支持这个功能的。

  • 注入器可以将 HTML 片段注入生成页面的 <head><body> 节点中。

  • 编写注入代码,需要在博客的根目录下创建 scripts 文件夹,然后在里面任意命名创建一个 js 文件即可。

例如创建一个 /blog/scripts/example.js,内容为:

1
hexo.extend.injector.register('body_end', '<script src="/jquery.js"></script>', 'default');

上述代码会在生成的页面 </body> 注入加载 jquery.js 的代码。

  • register 函数可接受三个参数,第一个参数是代码片段注入的位置,接受以下值:
参数 含义
head_begin 注入在 <head> 之后(默认)
head_end 注入在 </head> 之前
body_begin 注入在 <body> 之后
body_end 注入在 </body> 之前
  • 第二个参数是注入的片段,可以是字符串,也可以是一个返回值为字符串的函数。

  • 第三个参数是注入的页面类型,接受以下值:

参数 含义
default 注入到每个页面(默认值)
home 只注入到主页(is_home()true 的页面)
post 只注入到文章页面(is_post()true 的页面)
page 只注入到独立页面(is_page()true 的页面)
archive 只注入到归档页面(is_archive()true 的页面)
category 只注入到分类页面(is_category()true 的页面)
tag 只注入到标签页面(is_tag()true 的页面)

或是其他自定义 layout 名称,例如在Fluid 主题中 about 对应关于页、links 对应友联页

Fluid 注入

  • Fluid 主题也提供了一套注入代码功能,相较于 Hexo 注入功能更细致更丰富,并且支持注入 ejs 代码。

  • 如果你想充分修改主题,又不想直接修改源码影响日后更新,本主题提供了代码注入功能,可以将代码无侵入式加入到主题里。

  • 你可以直接注入 HTML 片段,不过建议你了解一下 EJS 模板引擎,这样你就可以像主题里的 ejs 文件一样编写自己的组件再注入进去。

  • 进入博客目录下 scripts 文件夹(如不存在则创建),在里面创建任意名称的 js 文件,在文件中写入如下内容:

1
2
3
4
hexo.extend.filter.register('theme_inject', function(injects) {
injects.header.file('default', 'source/_inject/test1.ejs', { key: 'value' }, -1);
injects.footer.raw('default', '<script async src="https://xxxxxx" crossorigin="anonymous"></script>');
});
  • headerfooter 是注入点的名称,表示代码注入到页面的什么位置;

  • file 方法表示注入的是文件,第一个参数下面介绍,第二个参数则是文件的路径,第三个参数是传入文件的参数(可省略),第四个参数是顺序(可省略);

  • raw 方法表示注入的是原生代码,第一个参数下面介绍,第二个参数则是一句原生的 HTML 语句;

  • default 表示注入的键名,可以使用任意键名,同一个注入点下的相同键名会使注入的内容覆盖,而不同键名则会让内容依次排列(默认按执行先后顺序,可通过 file 第四个参数指定),这里 default 为主题默认键名,通常会替换掉主题默认的组件;

  • 主题目前提供的注入点如下:

注入点名称 注入范围 存在 default
head <head> 标签中的结尾
header <header> 标签中所有内容
bodyBegin <body> 标签中的开始
bodyEnd <body> 标签中的结尾
footer <footer> 标签中所有内容
postMetaTop 文章页 <header> 标签中 meta 部分内容
postMetaBottom 文章页底部 meta 部分内容
postMarkdownBegin <div class="markdown-body"> 标签中的开始
postMarkdownEnd <div class="markdown-body"> 标签中的结尾
postLeft 文章页左侧边栏
postRight 文章页右侧边栏
postCopyright 文章页版权信息
postRight 文章页右侧边栏
postComments 文章页评论
pageComments 自定义页评论
linksComments 友链页评论

动态视频背景注入实现

背景

思路

  • fluid 的注入更加灵活,此处选择 fluid 的注入方式
  • 按照流程创建注入环境
  • 创建注入代码文件
  • 将文件嵌入到 headerbodybegin
  • 相应修改主题配置

实现

  1. 在博客根目录创建 scripts 文件夹,在其中创建 page.js 文件,内容为:
1
2
3
4
5
hexo.extend.filter.register('theme_inject', function(injects) {
//injects.header.file('default', 'source/_inject/test1.ejs', { key: 'value' }, -1);
injects.bodyBegin.file('default', "source/_inject/bodyBegin.ejs");
injects.header.file('video-banner', 'source/_inject/header.ejs', { key: 'value' }, -1);
});

将两个文件嵌入到指定位置,由于 bodybegin 是空的,这里采用覆盖 default 的方式

  1. 现在创建注入的两个文件,创建 source/_inject 文件夹,在其中创建文件 header.ejsbodyBegin.ejs 文件

  2. bodyBegin.ejs

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    <div>
    <div class='real_mask' style="
    background-color: rgba(0,0,0,0.3);
    width: 100%;
    height: 100%;
    position: fixed;
    z-index: -777;
    "></div>
    <div id="banner_video_insert">
    </div>
    <div id='vvd_banner_img'>
    </div>
    </div>
    <div id="banner"></div>
  3. header.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
<%
var banner_video = theme.index.banner_video
var banner_img = page.banner_img || theme.index.banner_img
var banner_img_height = page.banner_img_height || theme.index.banner_img_height
var banner_mask_alpha = page.banner_mask_alpha || theme.index.banner_mask_alpha
%>
<script type="text/javascript" src="/vvd_js/jquery.js"></script>

<div class="banner" id='banner' >

<div class="full-bg-img" >

<% if(banner_video){ %>
<script>
var ua = navigator.userAgent;
var ipad = ua.match(/(iPad).*OS\s([\d_]+)/),
isIphone = !ipad && ua.match(/(iPhone\sOS)\s([\d_]+)/),
isAndroid = ua.match(/(Android)\s+([\d.]+)/),
isMobile = isIphone || isAndroid;

function set_video_attr(id){

var height = document.body.clientHeight
var width = document.body.clientWidth
var video_item = document.getElementById(id);

if (height / width < 0.56){
video_item.setAttribute('width', '100%');
video_item.setAttribute('height', 'auto');
} else {
video_item.setAttribute('height', '100%');
video_item.setAttribute('width', 'auto');
}
}

$.getJSON('/vvd_js/video_url.json', function(data){
if (true){
var video_list_length = data.length
var seed = Math.random()
index = Math.floor(seed * video_list_length)

video_url = data[index][0]
pre_show_image_url = data[index][1]

banner_obj = document.getElementById("banner")
banner_obj.style.cssText = "background: url('" + pre_show_image_url + "') no-repeat; background-size: cover;"

vvd_banner_obj = document.getElementById("vvd_banner_img")

vvd_banner_content = "<img id='banner_img_item' src='" + pre_show_image_url + "' style='height: 100%; position: fixed; z-index: -999'>"
vvd_banner_obj.innerHTML = vvd_banner_content
set_video_attr('banner_img_item')

if (!isMobile) {
video_html_res = "<video id='video_item' style='position: fixed; z-index: -888;' muted='muted' src=" + video_url + " autoplay='autoplay' loop='loop'></video>"
document.getElementById("banner_video_insert").innerHTML = video_html_res;
set_video_attr('video_item')
}
}
});

if (!isMobile){
window.onresize = function(){
set_video_attr('video_item')
}
}
</script>
<% } %>
</div>
</div>
</div>
  1. 修改主题配置文件 _config.fluid.yml

    1. 覆盖默认 banner 图为纯透明的 png 图像

      将所有的 banner_img 替换为 https://101.43.39.125/HexoFiles/new/bg-trans.png

    2. 添加 index/banner_video ,设置为 true

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      #---------------------------
      # 首页
      # Home Page
      #---------------------------
      index:
      # 首页 Banner 头图,可以是相对路径或绝对路径,以下相同
      # Path of Banner image, can be a relative path or an absolute path, the same on other pages
      banner_img: https://101.43.39.125/HexoFiles/new/bg-trans.png

      # 首页 Banner 使用随机视频
      # true 开启 false 关闭
      banner_video: true

    3. 将所有 banner_mask_alpha 设置为 0

  2. 其余的如 source/vvd_js 文件和之前相同即可。

参考资料


Fluid -20- 使用 Fluid 注入功能实现背景视频
https://www.zywvvd.com/notes/hexo/theme/fluid/fluid-inject/fluid-inject/
作者
Yiwei Zhang
发布于
2022年6月30日
许可协议