给Hexo静态博客程序的Azhiyu(安知鱼)主题添加一个人潮汹涌模块

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×

自定义人潮涌动主要增加了以下功能:

支持自定义人物角色图片的行数列数
支持对人物大小,密度,移动速度进行调节
支持隐藏右侧推荐大标签,扩展左侧宽度
调节home_top高度
自定义人潮涌动背景图
定义多张人物总图,每次访问时随机选取
people.js魔改
实现了可以输入任意长,宽,图片大小的功能。

也懒得对比哪里修改了,大家直接把下面覆盖自己的people.js得了(主要是忘了修改了那里了)
  1. //Hexo\themes\anzhiyu\source\js\anzhiyu\people.js

  2. "use strict";
  3. function _toConsumableArray(e) {
  4.   return _arrayWithoutHoles(e) || _iterableToArray(e) || _unsupportedIterableToArray(e) || _nonIterableSpread();
  5. }

  6. function _nonIterableSpread() {
  7.   throw new TypeError(
  8.     "Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."
  9.   );
  10. }

  11. function _unsupportedIterableToArray(e, r) {
  12.   if (e) {
  13.     if ("string" == typeof e) return _arrayLikeToArray(e, r);
  14.     var t = Object.prototype.toString.call(e).slice(8, -1);
  15.     return (
  16.       "Object" === t && e.constructor && (t = e.constructor.name),
  17.       "Map" === t || "Set" === t
  18.         ? Array.from(e)
  19.         : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t)
  20.           ? _arrayLikeToArray(e, r)
  21.           : void 0
  22.     );
  23.   }
  24. }

  25. function _iterableToArray(e) {
  26.   if (("undefined" != typeof Symbol && null != e[Symbol.iterator]) || null != e["@@iterator"]) return Array.from(e);
  27. }

  28. function _arrayWithoutHoles(e) {
  29.   if (Array.isArray(e)) return _arrayLikeToArray(e);
  30. }

  31. function _arrayLikeToArray(e, r) {
  32.   (null == r || r > e.length) && (r = e.length);
  33.   for (var t = 0, a = new Array(r); t < r; t++) a[t] = e[t];
  34.   return a;
  35. }

  36. function _classCallCheck(e, r) {
  37.   if (!(e instanceof r)) throw new TypeError("Cannot call a class as a function");
  38. }

  39. function _defineProperties(e, r) {
  40.   for (var t = 0; t < r.length; t++) {
  41.     var a = r[t];
  42.     (a.enumerable = a.enumerable || !1),
  43.       (a.configurable = !0),
  44.       "value" in a && (a.writable = !0),
  45.       Object.defineProperty(e, a.key, a);
  46.   }
  47. }

  48. function _createClass(e, r, t) {
  49.   return r && _defineProperties(e.prototype, r), t && _defineProperties(e, t), e;
  50. }
  51. var peopleConfig = {
  52.   src: Array.isArray(GLOBAL_CONFIG.peoplecanvas.img)
  53.     ? GLOBAL_CONFIG.peoplecanvas.img[Math.floor(Math.random() * GLOBAL_CONFIG.peoplecanvas.img.length)]
  54.     : GLOBAL_CONFIG.peoplecanvas.img,
  55.   background_image: GLOBAL_CONFIG.peoplecanvas.background_image || '',
  56.   rows: GLOBAL_CONFIG.peoplecanvas.rows || 15,
  57.   cols: GLOBAL_CONFIG.peoplecanvas.cols || 7,
  58.   scale: GLOBAL_CONFIG.peoplecanvas.scale || 0.3,
  59.   density: GLOBAL_CONFIG.peoplecanvas.density || 1.0,
  60.   speed: GLOBAL_CONFIG.peoplecanvas.speed || 1.0,
  61.   offsetY: GLOBAL_CONFIG.peoplecanvas.offsetY || 0,
  62. },
  63.   randomRange = function (e, r) {
  64.     return e + Math.random() * (r - e);
  65.   },
  66.   randomIndex = function (e) {
  67.     return 0 | randomRange(0, e.length);
  68.   },
  69.   removeFromArray = function (e, r) {
  70.     return e.splice(r, 1)[0];
  71.   },
  72.   removeItemFromArray = function (e, r) {
  73.     return removeFromArray(e, e.indexOf(r));
  74.   },
  75.   removeRandomFromArray = function (e) {
  76.     return removeFromArray(e, randomIndex(e));
  77.   },
  78.   getRandomFromArray = function (e) {
  79.     return e[0 | randomIndex(e)];
  80.   },
  81.   resetPeep = function (e) {
  82.     var r,
  83.       t,
  84.       a = e.stage,
  85.       n = e.peep,
  86.       o = 0.5 < Math.random() ? 1 : -1,
  87.       i = 100 - 250 * gsap.parseEase("power2.in")(Math.random()),
  88.       s = a.height - n.height + i + peopleConfig.offsetY;
  89.     return (
  90.       1 == o ? ((r = -n.width), (t = a.width), (n.scaleX = 1)) : ((r = a.width + n.width), (t = 0), (n.scaleX = -1)),
  91.       (n.x = r),
  92.       (n.y = s),
  93.       {
  94.         startX: r,
  95.         startY: (n.anchorY = s),
  96.         endX: t,
  97.       }
  98.     );
  99.   },
  100.   normalWalk = function (e) {
  101.     var r = e.peep,
  102.       t = e.props,
  103.       a = (t.startX, t.startY),
  104.       n = t.endX,
  105.       o = gsap.timeline(),
  106.       speedMultiplier = peopleConfig.speed;
  107.     return (
  108.       o.timeScale(randomRange(0.5 * speedMultiplier, 1.5 * speedMultiplier)),
  109.       o.to(
  110.         r,
  111.         {
  112.           duration: 10 / speedMultiplier,
  113.           x: n,
  114.           ease: "none",
  115.         },
  116.         0
  117.       ),
  118.       o.to(
  119.         r,
  120.         {
  121.           duration: 0.25 / speedMultiplier,
  122.           repeat: 40,
  123.           yoyo: !0,
  124.           y: a - 10,
  125.         },
  126.         0
  127.       ),
  128.       o
  129.     );
  130.   },
  131.   walks = [normalWalk],
  132.   Peep = (function () {
  133.     function a(e) {
  134.       var r = e.image,
  135.         t = e.rect;
  136.       _classCallCheck(this, a),
  137.         (this.image = r),
  138.         this.setRect(t),
  139.         (this.x = 0),
  140.         (this.y = 0),
  141.         (this.anchorY = 0),
  142.         (this.scaleX = 1),
  143.         (this.walk = null);
  144.     }
  145.     return (
  146.       _createClass(a, [
  147.         {
  148.           key: "setRect",
  149.           value: function (e) {
  150.             (this.rect = e),
  151.               (this.width = e[2]),
  152.               (this.height = e[3]),
  153.               (this.drawArgs = [this.image].concat(_toConsumableArray(e), [0, 0, this.width, this.height]));
  154.           },
  155.         },
  156.         {
  157.           key: "render",
  158.           value: function (e, scale) {
  159.             var s = scale || 1;
  160.             e.save(),
  161.               e.translate(this.x, this.y),
  162.               e.scale(this.scaleX * s, s),
  163.               e.drawImage.apply(e, _toConsumableArray(this.drawArgs)),
  164.               e.restore();
  165.           },
  166.         },
  167.       ]),
  168.       a
  169.     );
  170.   })(),
  171.   img = document.createElement("img");
  172. (img.onload = init), (img.src = peopleConfig.src);
  173. let peoplecanvasEl = document.getElementById("peoplecanvas");

  174. let ctx = peoplecanvasEl ? peoplecanvasEl.getContext("2d") : undefined,
  175.   stage = {
  176.     width: 0,
  177.     height: 0,
  178.   },
  179.   allPeeps = [],
  180.   availablePeeps = [],
  181.   crowd = [];

  182. // 添加全局变量来跟踪初始化状态
  183. let isInitializing = false;
  184. let currentImageSrc = '';

  185. // 修改PJAX事件监听器
  186. document.addEventListener("pjax:success", e => {
  187.   const newPeoplecanvasEl = document.getElementById("peoplecanvas");
  188.   if (newPeoplecanvasEl && !isInitializing) {
  189.     isInitializing = true;

  190.     // 完全清理之前的状态
  191.     cleanupPeopleCanvas();

  192.     peoplecanvasEl = newPeoplecanvasEl;
  193.     ctx = peoplecanvasEl ? peoplecanvasEl.getContext("2d") : undefined;

  194.     // 重新选择随机图片(如果配置了多张图片)
  195.     let newImageSrc;
  196.     if (Array.isArray(GLOBAL_CONFIG.peoplecanvas.img)) {
  197.       newImageSrc = GLOBAL_CONFIG.peoplecanvas.img[Math.floor(Math.random() * GLOBAL_CONFIG.peoplecanvas.img.length)];
  198.     } else {
  199.       newImageSrc = GLOBAL_CONFIG.peoplecanvas.img;
  200.     }

  201.     // 只有当图片真的改变时才重新加载
  202.     if (newImageSrc !== currentImageSrc) {
  203.       currentImageSrc = newImageSrc;
  204.       peopleConfig.src = newImageSrc;

  205.       // 创建新的图片对象
  206.       const newImg = document.createElement("img");
  207.       newImg.onload = function () {
  208.         // 替换全局图片引用
  209.         img.src = newImg.src;
  210.         img.onload = null; // 清除旧的onload

  211.         setTimeout(() => {
  212.           if (!peoplecanvasEl || !isInitializing) return;

  213.           initializePeopleCanvas();
  214.           isInitializing = false;

  215.           console.log('人潮汹涌模块重新初始化完成');
  216.         }, 100);
  217.       };

  218.       newImg.onerror = function () {
  219.         console.error('人潮汹涌图片加载失败:', newImageSrc);
  220.         isInitializing = false;
  221.       };

  222.       newImg.src = newImageSrc;
  223.     } else {
  224.       // 图片相同,直接重新初始化
  225.       setTimeout(() => {
  226.         if (!peoplecanvasEl || !isInitializing) return;

  227.         initializePeopleCanvas();
  228.         isInitializing = false;

  229.         console.log('人潮汹涌模块重新初始化完成(相同图片)');
  230.       }, 100);
  231.     }
  232.   }
  233. });

  234. // 新增清理函数
  235. function cleanupPeopleCanvas() {
  236.   // 停止所有动画
  237.   crowd.forEach(function (peep) {
  238.     if (peep.walk) {
  239.       peep.walk.kill();
  240.       peep.walk = null;
  241.     }
  242.   });

  243.   // 移除事件监听器
  244.   window.removeEventListener("resize", resize);
  245.   gsap.ticker.remove(render);

  246.   // 清空所有数组
  247.   crowd.length = 0;
  248.   availablePeeps.length = 0;
  249.   allPeeps.length = 0;

  250.   // 清空画布
  251.   if (peoplecanvasEl && ctx) {
  252.     ctx.clearRect(0, 0, peoplecanvasEl.width, peoplecanvasEl.height);
  253.   }
  254. }

  255. // 新增初始化函数
  256. function initializePeopleCanvas() {
  257.   if (!peoplecanvasEl) return;

  258.   // 设置背景图片
  259.   if (peopleConfig.background_image) {
  260.     document.documentElement.style.setProperty('--peoplecanvas-bg-image', `url(${peopleConfig.background_image})`);
  261.   }

  262.   // 重新创建人物精灵图
  263.   createPeeps();

  264.   // 重新初始化
  265.   resize();
  266.   gsap.ticker.add(render);
  267.   window.addEventListener("resize", resize);
  268. }

  269. // 修改原有的init函数
  270. function init() {
  271.   if (!peoplecanvasEl || isInitializing) return;

  272.   currentImageSrc = peopleConfig.src;
  273.   initializePeopleCanvas();
  274. }

  275. function createPeeps() {
  276.   for (
  277.     var e = peopleConfig.rows,
  278.     r = peopleConfig.cols,
  279.     t = e * r,
  280.     a = img.naturalWidth / e,
  281.     n = img.naturalHeight / r,
  282.     o = 0;
  283.     o < t;
  284.     o++
  285.   )
  286.     allPeeps.push(
  287.       new Peep({
  288.         image: img,
  289.         rect: [(o % e) * a, ((o / e) | 0) * n, a, n],
  290.       })
  291.     );
  292. }

  293. function resize() {
  294.   if (peoplecanvasEl && peoplecanvasEl.clientWidth != 0) {
  295.     (stage.width = peoplecanvasEl.clientWidth),
  296.       (stage.height = peoplecanvasEl.clientHeight),
  297.       (peoplecanvasEl.width = stage.width * devicePixelRatio),
  298.       (peoplecanvasEl.height = stage.height * devicePixelRatio),
  299.       crowd.forEach(function (e) {
  300.         e.walk.kill();
  301.       }),
  302.       (crowd.length = 0),
  303.       (availablePeeps.length = 0),
  304.       availablePeeps.push.apply(availablePeeps, allPeeps),
  305.       initCrowd();
  306.   }
  307. }

  308. function initCrowd() {
  309.   var targetCount = Math.floor(allPeeps.length * peopleConfig.density);
  310.   for (var i = 0; i < targetCount && availablePeeps.length; i++) {
  311.     addPeepToCrowd().walk.progress(Math.random());
  312.   }
  313. }

  314. function addPeepToCrowd() {
  315.   var e = removeRandomFromArray(availablePeeps),
  316.     r = getRandomFromArray(walks)({
  317.       peep: e,
  318.       props: resetPeep({
  319.         peep: e,
  320.         stage: stage,
  321.       }),
  322.     }).eventCallback("onComplete", function () {
  323.       removePeepFromCrowd(e);
  324.       if (crowd.length < Math.floor(allPeeps.length * peopleConfig.density)) {
  325.         addPeepToCrowd();
  326.       }
  327.     });
  328.   return (
  329.     (e.walk = r),
  330.     crowd.push(e),
  331.     crowd.sort(function (e, r) {
  332.       return e.anchorY - r.anchorY;
  333.     }),
  334.     e
  335.   );
  336. }

  337. function removePeepFromCrowd(e) {
  338.   removeItemFromArray(crowd, e), availablePeeps.push(e);
  339. }

  340. function render() {
  341.   if (!peoplecanvasEl) return;
  342.   (peoplecanvasEl.width = peoplecanvasEl.width),
  343.     ctx.save(),
  344.     ctx.scale(devicePixelRatio, devicePixelRatio),
  345.     crowd.forEach(function (e) {
  346.       e.render(ctx, peopleConfig.scale);
  347.     }),
  348.     ctx.restore();
  349. }
复制代码

然后在主题配置文件中peoplecanvas项添加以下配置,这里ai生成的时候行和列搞反了,实际上rows是总图的列数,cols是总图的行数,反正能跑就懒得改了。 有些图片因为拆分后单个人物大小的问题,需要调整缩放比例和垂直偏移,如果加载出来看不到有人在跑,可能就是太高了或低了,可以先想缩放调小点,看看是高还是低,先调了垂直偏移。 具体参数搭配要看使用的总图的单个人物大小,大家多试一试找到合适的参数。
  1. peoplecanvas:
  2.   enable: true
  3.   img:  https://testingcf.jsdelivr.net/gh/kingkare/owo/img/ahugecrowd.webp
  4.   background_image: https://testingcf.jsdelivr.net/gh/kingkare/owo/img/2025-04-01.png #背景图
  5.   #下面是新增的
  6.   rows: 13 # 精灵图列数,默认15
  7.   cols: 4 # 精灵图行数,默认7
  8.   scale: 0.5 # 人物大小缩放比例 (0.1-1.0),默认1.0
  9.   density: 0.6 # 人物密度 (0.1-2.0),默认1.0
  10.   speed: 0.8 # 人物移动速度 (0.1-3.0),默认1.0
  11.   offsetY: 148 # 垂直位置偏移 (-200 到 200,负值向上,正值向下),默认0
复制代码
大家根据自己的来调

自定义背景图
找到这个文件修改样式 Hexo\themes\anzhiyu\source\css\_layout\home_top.styl
  1.   #peoplecanvas
  2.     width: 100%;
  3.     height: 100%;
  4.     background-image: var(--peoplecanvas-bg-image, none);
  5.     background-size: cover;
  6.     background-position: center;
  7.     background-repeat: no-repeat;
  8.     border-radius: 12px;
复制代码
找到这个文件修改样式:Hexo\themes\anzhiyu\source\js\anzhiyu\people.js 注意看里面注释的新增位置
  1. var peopleConfig = {
  2.     src: GLOBAL_CONFIG.peoplecanvas.img,

  3.         //在此新增
  4.     background_image: GLOBAL_CONFIG.peoplecanvas.background_image || '',
  5.     //...


  6. function init() {
  7.   if (!peoplecanvasEl) return;
  8.   
  9.   // 在此新增
  10.   if (peopleConfig.background_image) {
  11.     document.documentElement.style.setProperty('--peoplecanvas-bg-image', `url(${peopleConfig.background_image})`);
  12.   }
  13.   createPeeps(), resize(), gsap.ticker.add(render), window.addEventListener("resize", resize);
  14. }


  15.     setTimeout(() => {
  16.       if (!peoplecanvasEl) return;
  17.       
  18.       //在此新增
  19.       if (peopleConfig.background_image) {
  20.         document.documentElement.style.setProperty('--peoplecanvas-bg-image', `url(${peopleConfig.background_image})`);
  21.       }
  22.       resize(), gsap.ticker.add(render), window.addEventListener("resize", resize);
复制代码
修改_config.anzhiyu.yml,设定背景图片
  1. # 首页随便逛逛people模式 而非技能点模式,关闭后为技能点模式需要配置creativity.yml
  2. peoplecanvas:
  3.   enable: true
  4.   img: #总图
  5.   background_image:  #背景图 只要添加一行这个设置背景图地址既可
  6.   ...
复制代码
然后执行Hexo三步命令即可!

回复 收藏
分享
  • 微信

    微信扫码分享

  • 复制链接

回复

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

hot.热文换一批
最新热评 加载中...
牛马论坛(niumabbs.com),一个专注于分享日常新鲜事、职场工作点滴、摸鱼乐趣与各类生活感悟的交流平台。

    关注我们

  • 加入Q群
  • 微信客服
  • QQ客服
Copyright © 2026 NIUMABBS 版权所有 All Rights Reserved. 劰载中...
开灯 在本版发帖
扫一扫添加微信客服
QQ客服返回顶部
快速回复 返回顶部 返回列表