✨ 我是流萤白沙的「文章捕手」,擅长在文字的星海中打捞精华。每当新的篇章诞生,我就会像整理贝壳一样,将思想的闪光点串成珍珠项链~

本文介绍了如何在Hexo博客中实现樱花漂浮效果的插件。首先,作者在已有的基础上进行修改,创建了适用于shokax主题的插件。文章详细描述了插件的创建步骤,包括在博客根目录下创建JavaScript和Pug文件,并提供了相应的代码。功能代码部分涵盖了漂浮物的生成、更新和绘制逻辑,同时允许用户自定义漂浮物的显示页面和图片。最后,提供了使用方法,指导用户如何设置插件以便在特定页面显示漂浮效果,增强了博客的视觉效果和互动性。

# 前言

在逛其他人博客时,发现很多都有动态效果,我的虽然也有一点(大轮播图和波浪),但左看右看还是感觉单调了一点,于是我发挥聪明才智去抄了一份,做成了插件实现了这个樱花效果。(其实就是把别人代码抄过来改成我能用的格式)

# 实现

# 创建插件

适用于 shokax 主题,如果是其他主题,可以使用 Hexo Injector 或主题提供的注入功能实现。

  1. 博客根目录/scripts 文件夹里创建 sakura.js ,如果没有 scripts 就创建一个。
  2. 博客根目录/views 文件夹里创建 sakura.pug ,如果没有 view 就创建一个。

# 功能代码

  1. 将下面代码复制到 sakura.js 里。
hexo.extend.filter.register('theme_inject', function(injects) {
    injects.bodyEnd.file('sakura','views/sakura.pug',{}, {cache: false});
});
  1. 将下面代码复制到 sakura.pug 里。
script.
  // 漂浮物
  // 新增函数 
  // 首先获取 Url,然后把 Url 通过 // 截成两部分,再从后一部分中截取相对路径。如果截取到的相对路径中有参数,则把参数去掉。
  // 获取相对路径
  function GetUrlRelativePath()
  {
      var url = document.location.toString();
      var arrUrl = url.split("//");
      var start = arrUrl[1].indexOf("/");
      var relUrl = arrUrl[1].substring(start);//stop省略,截取从start开始到结尾的所有字符
      if(relUrl.indexOf("?") != -1){
          relUrl = relUrl.split("?")[0];
      }
      return relUrl;
  }
  var allowAll = true; // true 则允许所有网页存在漂浮物
  // 允许显示漂浮物的网址列表
  var urlAllowList = [
      "/about/",
      "friends/",
  ]
  var isAllowFloat = false;   // 全局变量,允许使用漂浮特效
  // 判断
  function decide(){
      isAllowFloat = true;
      if(!allowAll){
          // 判断当前页面是否为指定页面
          var url = GetUrlRelativePath();
          var i = 0;
          for(;i<urlAllowList.length;i++){
              if(url===urlAllowList[i]){
                  // console.log(i);
                  isAllowFloat = true;
                  break;
              }
          }
          if(i===urlAllowList.length){
              isAllowFloat = false;
          }
      }
      console.log(isAllowFloat)
      if(isAllowFloat)startFloat();
  }
  var stop, staticx;
  var img = new Image();
  img.src = "/assets/float.png"; // 图片
  function Float(x, y, s, r, fn) {
      this.x = x;
      this.y = y;
      this.s = s;
      this.r = r;
      this.fn = fn;
  }
  Float.prototype.draw = function(cxt) {
      cxt.save();
      var xc = 40 * this.s / 4;
      cxt.translate(this.x, this.y);
      cxt.rotate(this.r);
      cxt.drawImage(img, 0, 0, 35 * this.s, 35 * this.s)
      // 漂浮物大小
      cxt.restore();
  }
  Float.prototype.update = function() {
      this.x = this.fn.x(this.x, this.y);
      this.y = this.fn.y(this.y, this.y);
      this.r = this.fn.r(this.r);
      if (this.x > window.innerWidth || this.x < 0 || this.y > window.innerHeight || this.y < 0) {
          this.r = getRandom('fnr');
          if (Math.random() > 0.4) {
              this.x = getRandom('x');
              this.y = 0;
              this.s = getRandom('s');
              this.r = getRandom('r');
          } else {
              this.x = window.innerWidth;
              this.y = getRandom('y');
              this.s = getRandom('s');
              this.r = getRandom('r');
          }
      }
  }
  FloatList = function() {
      this.list = [];
  }
  FloatList.prototype.push = function(float) {
      this.list.push(float);
  }
  FloatList.prototype.update = function() {
      for (var i = 0, len = this.list.length; i < len; i++) {
          this.list[i].update();
      }
  }
  FloatList.prototype.draw = function(cxt) {
      for (var i = 0, len = this.list.length; i < len; i++) {
          this.list[i].draw(cxt);
      }
  }
  FloatList.prototype.get = function(i) {
      return this.list[i];
  }
  FloatList.prototype.size = function() {
      return this.list.length;
  }
  function getRandom(option) {
      var ret, random;
      switch (option) {
      case 'x':
          ret = Math.random() * window.innerWidth;
          break;
      case 'y':
          ret = Math.random() * window.innerHeight;
          break;
      case 's':
          ret = Math.random();
          break;
      case 'r':
          ret = Math.random() * 6;
          break;
      case 'fnx':
          random = -0.5 + Math.random() * 1;
          ret = function(x, y) {
              return x + 0.5 * random - 0.6;
              //x 轴速度
          }
          ;
          break;
      case 'fny':
          random = 0.8 + Math.random() * 0.7
          //y 轴速度
          ret = function(x, y) {
              return y + random;
          }
          ;
          break;
      case 'fnr':
          random = Math.random() * 0.03;
          ret = function(r) {
              return r + random;
          }
          ;
          break;
      }
      return ret;
  }
  function startFloat() {
      requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame || window.oRequestAnimationFrame;
      var canvas = document.createElement('canvas'), cxt;
      staticx = true;
      canvas.height = window.innerHeight;
      canvas.width = window.innerWidth;
      canvas.setAttribute('style', 'position: fixed;left: 0;top: 0;pointer-events: none;');
      canvas.setAttribute('id', 'canvas_float');
      document.getElementsByTagName('body')[0].appendChild(canvas);
      cxt = canvas.getContext('2d');
      var floatList = new FloatList();
      for (var i = 0; i < 10; i++) {
          // 漂浮物数量
          var float, randomX, randomY, randomS, randomR, randomFnx, randomFny;
          randomX = getRandom('x');
          randomY = getRandom('y');
          randomR = getRandom('r');
          randomS = getRandom('s');
          randomFnx = getRandom('fnx');
          randomFny = getRandom('fny');
          randomFnR = getRandom('fnr');
          float = new Float(randomX,randomY,randomS,randomR,{
              x: randomFnx,
              y: randomFny,
              r: randomFnR
          });
          float.draw(cxt);
          floatList.push(float);
      }
      stop = requestAnimationFrame(function() {
          cxt.clearRect(0, 0, canvas.width, canvas.height);
          floatList.update();
          floatList.draw(cxt);
          stop = requestAnimationFrame(arguments.callee);
      })
  }
  window.onresize = function() {
      if(!isAllowFloat)return;
      var canvasSnow = document.getElementById('canvas_float');
      canvasSnow.width = window.innerWidth;
      canvasSnow.height = window.innerHeight;
  }
  function stopp(e) {
      if (!e && document.getElementById("canvas_float")) {
          var child = document.getElementById("canvas_float");
          child.parentNode.removeChild(child);
          window.cancelAnimationFrame(stop);
      } else if (e && !document.getElementById("canvas_float")) {
          decide();
      }
  }
  window.addEventListener("DOMContentLoaded",decide);

js 格式代码如下。

// 漂浮物
// 新增函数 
// 首先获取 Url,然后把 Url 通过 // 截成两部分,再从后一部分中截取相对路径。如果截取到的相对路径中有参数,则把参数去掉。
// 获取相对路径
function GetUrlRelativePath()
{
    var url = document.location.toString();
    var arrUrl = url.split("//");
    var start = arrUrl[1].indexOf("/");
    var relUrl = arrUrl[1].substring(start);//stop 省略,截取从 start 开始到结尾的所有字符
    if(relUrl.indexOf("?") != -1){
        relUrl = relUrl.split("?")[0];
    }
    return relUrl;
}
var allowAll = false; //true 则允许所有网页存在漂浮物
// 允许显示漂浮物的网址列表
var urlAllowList = [
    "/about/",
    "/link/friends/",
]
var isAllowFloat = false;   // 全局变量,允许使用漂浮特效
// 判断
function decide(){
    isAllowFloat = true;
    if(!allowAll){
        // 判断当前页面是否为指定页面
        var url = GetUrlRelativePath();
        var i = 0;
        for(;i<urlAllowList.length;i++){
            if(url===urlAllowList[i]){
                // console.log(i);
                isAllowFloat = true;
                break;
            }
        }
        if(i===urlAllowList.length){
            isAllowFloat = false;
        }
    }
    console.log(isAllowFloat)
    if(isAllowFloat)startFloat();
}
var stop, staticx;
var img = new Image();
img.src = "/image/star_float.png"; // 图片
function Float(x, y, s, r, fn) {
    this.x = x;
    this.y = y;
    this.s = s;
    this.r = r;
    this.fn = fn;
}
Float.prototype.draw = function(cxt) {
    cxt.save();
    var xc = 40 * this.s / 4;
    cxt.translate(this.x, this.y);
    cxt.rotate(this.r);
    cxt.drawImage(img, 0, 0, 35 * this.s, 35 * this.s)
    // 漂浮物大小
    cxt.restore();
}
Float.prototype.update = function() {
    this.x = this.fn.x(this.x, this.y);
    this.y = this.fn.y(this.y, this.y);
    this.r = this.fn.r(this.r);
    if (this.x > window.innerWidth || this.x < 0 || this.y > window.innerHeight || this.y < 0) {
        this.r = getRandom('fnr');
        if (Math.random() > 0.4) {
            this.x = getRandom('x');
            this.y = 0;
            this.s = getRandom('s');
            this.r = getRandom('r');
        } else {
            this.x = window.innerWidth;
            this.y = getRandom('y');
            this.s = getRandom('s');
            this.r = getRandom('r');
        }
    }
}
FloatList = function() {
    this.list = [];
}
FloatList.prototype.push = function(float) {
    this.list.push(float);
}
FloatList.prototype.update = function() {
    for (var i = 0, len = this.list.length; i < len; i++) {
        this.list[i].update();
    }
}
FloatList.prototype.draw = function(cxt) {
    for (var i = 0, len = this.list.length; i < len; i++) {
        this.list[i].draw(cxt);
    }
}
FloatList.prototype.get = function(i) {
    return this.list[i];
}
FloatList.prototype.size = function() {
    return this.list.length;
}
function getRandom(option) {
    var ret, random;
    switch (option) {
    case 'x':
        ret = Math.random() * window.innerWidth;
        break;
    case 'y':
        ret = Math.random() * window.innerHeight;
        break;
    case 's':
        ret = Math.random();
        break;
    case 'r':
        ret = Math.random() * 6;
        break;
    case 'fnx':
        random = -0.5 + Math.random() * 1;
        ret = function(x, y) {
            return x + 0.5 * random - 0.6;
            //x 轴速度
        }
        ;
        break;
    case 'fny':
        random = 0.8 + Math.random() * 0.7
        //y 轴速度
        ret = function(x, y) {
            return y + random;
        }
        ;
        break;
    case 'fnr':
        random = Math.random() * 0.03;
        ret = function(r) {
            return r + random;
        }
        ;
        break;
    }
    return ret;
}
function startFloat() {
    requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame || window.oRequestAnimationFrame;
    var canvas = document.createElement('canvas'), cxt;
    staticx = true;
    canvas.height = window.innerHeight;
    canvas.width = window.innerWidth;
    canvas.setAttribute('style', 'position: fixed;left: 0;top: 0;pointer-events: none;');
    canvas.setAttribute('id', 'canvas_float');
    document.getElementsByTagName('body')[0].appendChild(canvas);
    cxt = canvas.getContext('2d');
    var floatList = new FloatList();
    for (var i = 0; i < 10; i++) {
        // 漂浮物数量
        var float, randomX, randomY, randomS, randomR, randomFnx, randomFny;
        randomX = getRandom('x');
        randomY = getRandom('y');
        randomR = getRandom('r');
        randomS = getRandom('s');
        randomFnx = getRandom('fnx');
        randomFny = getRandom('fny');
        randomFnR = getRandom('fnr');
        float = new Float(randomX,randomY,randomS,randomR,{
            x: randomFnx,
            y: randomFny,
            r: randomFnR
        });
        float.draw(cxt);
        floatList.push(float);
    }
    stop = requestAnimationFrame(function() {
        cxt.clearRect(0, 0, canvas.width, canvas.height);
        floatList.update();
        floatList.draw(cxt);
        stop = requestAnimationFrame(arguments.callee);
    })
}
window.onresize = function() {
    if(!isAllowFloat)return;
    var canvasSnow = document.getElementById('canvas_float');
    canvasSnow.width = window.innerWidth;
    canvasSnow.height = window.innerHeight;
}
function stopp(e) {
    if (!e && document.getElementById("canvas_float")) {
        var child = document.getElementById("canvas_float");
        child.parentNode.removeChild(child);
        window.cancelAnimationFrame(stop);
    } else if (e && !document.getElementById("canvas_float")) {
        decide();
    }
}
window.addEventListener("DOMContentLoaded",decide);

# 使用方法

  • 需要所有博客页面都显示漂浮物:将 allowAll = true
  • 指定显示漂浮物的页面:将 allowAll = false ,在 urlAllowList 中列出需要显示漂浮物的网页相对地址。如 /about/
  • 指定漂浮物图片:把 img.src = "/assets/float.png" ,替换成你喜欢的图片 URL。

都做完之后记得素质三连:hexo clean && hexo g && hexo d