Hexo设置少量固定的动态背景图

文章目录

  • 前言
  • 先准备素材
  • 问题分析
  • 代码实现
    • 逻辑写在哪
    • 先搭建基本框架
    • 然后添加图片链接
    • 动画效果
  • 前言
  • 先准备素材
  • 问题分析
  • 代码实现
    • 逻辑写在哪
    • 先搭建基本框架
    • 然后添加图片链接
    • 动画效果

前言

在以前的这篇文章中,我们设置了一些动态背景。

这次我们加一丁点优化,为下一次做准备。

先准备素材

还是老样子,准备四张照片,然后压缩。这是我找到的四张照片:

1号背景图片

2号背景图片

3号背景图片

4号背景图片

当然,这些都是通过iloveImg压缩掉了,每张图片大概 500 K B 500KB 500KB 800 K B 800KB 800KB不等。

用这些图片我们先做一个有限的轮播效果。

问题分析

我们现在先选用 4 4 4div元素进行基本的轮播实现。

为什么是 4 4 4个呢?

如果是 2 2 2个轮播的话,容错很低,如果有一个较大的图片,加载可能会出现闪回。这个在Hexo设置背景图片轮播效果已经得到了证实。

如果是 3 3 3个轮播的话,很难计算。因为有很多3无法整除的情况,可能会出现因为时间精确度不够产生的闪回。

4 4 4个的话,目前而言容错稍高。当然我并没有测试出极端情况,只是比较稳妥的是 4 4 4张轮播。

具体而言,轮播又要如何做呢?

之前我们已经提到,单纯使用bodybackground属性设置遮罩与背景图片已经不足够了。最大的问题就是linear-gradient在关键帧之间没有渐变的过程。

所以我们最后还是返璞归真,使用培训班经常教的拉图像框的形式。

简单描述的话,就是有一个占满整个屏幕的div作为可视框图。为了方便描述,我们将他记为carousel-framecarousel-frame的长度宽度都是浏览器的 100 % 100\% 100%,并且位置是固定在浏览器中的,并不随着滚轮的移动而移动。

然后呢,我们用上一个长度超出carousel-frame 4 4 4倍的div,叫做carousel-bannercarousel-bannercarousel-frame的里面,或者并行也可以。因为carousel-frame已经占满了一整个屏幕,剩下的内容其实看不见的。

正因为carousel-banner一共超出了 4 4 4倍,所以可以放下 4 4 4张浏览器可视页面大小的图片作为我们当前显示的背景图。

我们通过控制carousel-banner的左边界位置来控制当前图片显示。

这种思想其实很多地方都能够看到,因为这样的话就只需要加载一张图片,然后所有需要图片的元素访问这个图片的一个部分就可以了。

最后呢,为了让背景图片看起来不那么像广告那种轮播图一样单调,我们还是把控制左边界的过程省略掉,通过不透明度的设置屏蔽掉。这样就好了。

那么CSS大概又如何设计动画呢?

我们就简单用流程图展示一下:

25%
25%
25%
25%
第一张图片
第二张图片
第三张图片
第四张图片

代码实现

好了,废话也说了这么多了,也该show me the code了。

为了保证绝对的速度,我们直接使用原生JavaScript创建这些内容。一方面是使得在readyStateloading的时候就直接加载所有内容,另一方面也是因为CSSJS两种文件的加载都会稍有误差,在网速较快的时候表现并不明显,但是图片较大或者网速较慢都会产生很尴尬的时间错位,然后图片就会闪回。这可是很难看的。

逻辑写在哪

我们在source/js/utils.js文件中,找到这么一段:

  if (document.readyState === 'loading') {document.addEventListener('readystatechange', onPageLoaded, { once: true });} else {onPageLoaded();}

我们来添加一个函数,变成这样:

  if (document.readyState === 'loading') {document.addEventListener('readystatechange', onPageLoaded, { once: true });addBackgroundImageDiv();} else {onPageLoaded();}

这个函数的具体定义就可以直接写在下面:

function addBackgroundImageDiv () { }

当然,你会注意到下面还有一个定义:

NexT.utils = {...
}

如果写在里面,所有的函数将无法识别。并不清楚其中的缘由。

总之,放在utils.js中的话,就不需要在模板文件中引入script标签了,也不用在意打包之后的路径该怎么办了。

先搭建基本框架

对于我们的思路呢,我们就一步步开始实现。我们先创建DOM元素:

// create dom element for background images
// ----------------------------------------
const opacityMask = document.createElement("div");
opacityMask.style.background = "linear-gradient(#fff, #ffced9, #fff)";
opacityMask.style.position = "fixed";
opacityMask.style.top = "0";
opacityMask.style.left = "0";
opacityMask.style.content = "";
opacityMask.style.width = "100%";
opacityMask.style.height = "100%";
opacityMask.style.opacity = "0.8";
opacityMask.style.zIndex = "-1";
const imageContainer = document.createElement("div");
imageContainer.style.position = "fixed";
imageContainer.style.top = "0";
imageContainer.style.left = "0";
imageContainer.style.content = "";
imageContainer.style.width = "100%";
imageContainer.style.height = "100%";
imageContainer.style.zIndex = "-2";
const imageScroller = document.createElement("div");
imageScroller.id = "image-scroller";
imageScroller.style.position = "fixed";
imageScroller.style.top = "0";
imageScroller.style.left = "0";
imageScroller.style.content = "";
imageScroller.style.width = "400%";
imageScroller.style.height = "100%";
imageScroller.style.display = "flex";
imageContainer.style.justifyContent = "space-around";
imageContainer.style.alignContent = "center";
imageContainer.style.alignItems = "center";
imageScroller.style.zIndex = "-3";
document.body.appendChild(opacityMask);
document.body.appendChild(imageContainer);
document.body.appendChild(imageScroller);
// well done! basic frames established!

当然,你也一定能找到更简单的写法。我这一步步操作过来只是单纯为了逻辑清晰。

然后添加图片链接

然后,我们再将图片放进去:

// url for background images
// -------------------------
const BASE_URL = 'http://images.sakebow.cn/bgimage/'
const DEVICES = ['pc']
const imgWindowUrl = { 'pc': ['/race-miku.jpg', '/masuri-miku.jpg', '/planet-miku.jpg', '/4mikus.jpg'
] };
for (const imgUrlItem of imgWindowUrl['pc']) {const imageFrameItemContainer = document.createElement("div");imageFrameItemContainer.style.width = imageContainer.style.width;imageFrameItemContainer.style.height = "100%";imageFrameItemContainer.innerHTML = "<img" +" src='" + BASE_URL + DEVICES[0] + imgUrlItem + "'" +" style='width: 100%; height: 100%;'" +" alt='network broken?' />";imageScroller.appendChild(imageFrameItemContainer);
}
// well done! all images ready!

在这里你能看到我的一些没必要的设计,这些其实是我为了以后做拓展用的。当然也不一定会做就是了。(诶嘿~⭐)

动画效果

在搭建了框架、设置了图片链接后,我们就可以准备开始轮播的操作了。

当然,你可能会想到再去style.styl文件中写一些css。但很可惜的是,别忘了,我们可是在loading状态下,所有的内容都是不可用的。

于是,就连动画效果我们也要创建style标签并编辑动画效果:

// keyframe to roll images
// -------------------------------
// create style element
const imageRollStyle = document.createElement('style');
// set animation time for all
const EPOCH_TIME = "64s ";
// set animation style for all
const ANIMATION_DEFAULT_SETTINGS = "linear infinite both running ";
// set keyframes into style element
imageRollStyle.innerHTML = `@keyframes image-roll {0%  { left: 0; } 24% { left: 0; } 25% { left: -100%; } 49% { left: -100%; } 50% { left: -200%; }74% { left: -200%; } 75% { left: -300%; } 99% { left: -300%; } 100%{ left: 0; }
}@keyframes image-translate-child-1 {0%  { scale: 1; opacity: 0 } 2% { scale: 1; opacity: 1; } 23% { scale: 1.1; } 25%, 100% { scale: 1.1; opacity: 0; }
}
#image-scroller>div:nth-child(1) {animation: ${EPOCH_TIME + ANIMATION_DEFAULT_SETTINGS} image-translate-child-1;
}@keyframes image-translate-child-2 {0%, 25%  { scale: 1; opacity: 0 } 27% { scale: 1; opacity: 1; } 48% { scale: 1.1; } 50%, 100% { scale: 1.1; opacity: 0; }
}
#image-scroller>div:nth-child(2) {animation: ${EPOCH_TIME + ANIMATION_DEFAULT_SETTINGS} image-translate-child-2;
}@keyframes image-translate-child-3 {0%, 50%  { scale: 1; opacity: 0 } 52% { scale: 1; opacity: 1; } 73% { scale: 1.1; } 75%, 100% { scale: 1.1; opacity: 0; }
}
#image-scroller>div:nth-child(3) {animation: ${EPOCH_TIME + ANIMATION_DEFAULT_SETTINGS} image-translate-child-3;
}@keyframes image-translate-child-4 {0%, 75%  { scale: 1; opacity: 0 } 77% { scale: 1; opacity: 1; } 98% { scale: 1.1; } 100% { scale: 1.1; opacity: 0; }
}
#image-scroller>div:nth-child(4) {animation: ${EPOCH_TIME + ANIMATION_DEFAULT_SETTINGS} image-translate-child-4;
}`;
// well done! now images can be rolling with fadeIn and fadeOut style, as well as scale 1.1x slowly

如果需要稳妥的话,也需要在keyframes的基础上额外增加一些适配,比如-moz-keyframes-webkit-keyframes等等诸如此类的玩意儿。

在这里就不多说了,如果加上的话这个教程就没完没了了。

最后,我们让style标签加入页面中去:

// 将style样式存放到head标签
// ----------------------
document.getElementsByTagName('head')[0].appendChild(imageRollStyle);
imageScroller.style.animation = `${EPOCH_TIME + ANIMATION_DEFAULT_SETTINGS} image-roll`;
// well done! keyframes in effect!

看起来一切都可行了!

不出意外的话,这些就够出现效果了。—
title: Hexo设置少量固定的动态背景图
date: 2023-12-25 09:07:10
categories:

  • customize
    tags:
  • customize
  • css
    mathjax: true

前言

在以前的这篇文章中,我们探讨了如何在body上设置静态背景。

由于动态背景的示意图制作成本稍高,暂时以文字描述替代。后续将根据实际情况安排动态示意图的展示。

先准备素材

还是老样子,准备四张照片,然后压缩。这是我找到的四张照片:

1号背景图片

2号背景图片

3号背景图片

4号背景图片

当然,这些都是通过iloveImg压缩掉了,每张图片大概 500 K B 500KB 500KB 800 K B 800KB 800KB不等。

用这些图片我们先做一个有限的轮播效果。

问题分析

我们现在先选用 4 4 4div元素进行基本的轮播实现。

为什么是 4 4 4个呢?

如果是 2 2 2个轮播的话,容错很低,如果有一个较大的图片,加载可能会出现闪回。这个在Hexo设置背景图片轮播效果已经得到了证实。

如果是 3 3 3个轮播的话,很难计算。因为有很多3无法整除的情况,可能会出现因为时间精确度不够产生的闪回。

4 4 4个的话,目前而言容错稍高。当然我并没有测试出极端情况,只是比较稳妥的是 4 4 4张轮播。

具体而言,轮播又要如何做呢?

之前我们已经提到,单纯使用bodybackground属性设置遮罩与背景图片已经不足够了。最大的问题就是linear-gradient在关键帧之间没有渐变的过程。

所以我们最后还是返璞归真,使用培训班经常教的拉图像框的形式。

简单描述的话,就是有一个占满整个屏幕的div作为可视框图。为了方便描述,我们将他记为carousel-framecarousel-frame的长度宽度都是浏览器的 100 % 100\% 100%,并且位置是固定在浏览器中的,并不随着滚轮的移动而移动。

然后呢,我们用上一个长度超出carousel-frame 4 4 4倍的div,叫做carousel-bannercarousel-bannercarousel-frame的里面,或者并行也可以。因为carousel-frame已经占满了一整个屏幕,剩下的内容其实看不见的。

正因为carousel-banner一共超出了 4 4 4倍,所以可以放下 4 4 4张浏览器可视页面大小的图片作为我们当前显示的背景图。

我们通过控制carousel-banner的左边界位置来控制当前图片显示。

这种思想其实很多地方都能够看到,因为这样的话就只需要加载一张图片,然后所有需要图片的元素访问这个图片的一个部分就可以了。

最后呢,为了让背景图片看起来不那么像广告那种轮播图一样单调,我们还是把控制左边界的过程省略掉,通过不透明度的设置屏蔽掉。这样就好了。

那么CSS大概又如何设计动画呢?

我们就简单用流程图展示一下:

25%
25%
25%
25%
第一张图片
第二张图片
第三张图片
第四张图片

代码实现

好了,废话也说了这么多了,也该show me the code了。

为了保证绝对的速度,我们直接使用原生JavaScript创建这些内容。一方面是使得在readyStateloading的时候就直接加载所有内容,另一方面也是因为CSSJS两种文件的加载都会稍有误差,在网速较快的时候表现并不明显,但是图片较大或者网速较慢都会产生很尴尬的时间错位,然后图片就会闪回。这可是很难看的。

逻辑写在哪

我们在source/js/utils.js文件中,找到这么一段:

  if (document.readyState === 'loading') {document.addEventListener('readystatechange', onPageLoaded, { once: true });} else {onPageLoaded();}

我们来添加一个函数,变成这样:

  if (document.readyState === 'loading') {document.addEventListener('readystatechange', onPageLoaded, { once: true });addBackgroundImageDiv();} else {onPageLoaded();}

这个函数的具体定义就可以直接写在下面:

function addBackgroundImageDiv () { }

当然,你会注意到下面还有一个定义:

NexT.utils = {...
}

如果写在里面,所有的函数将无法识别。并不清楚其中的缘由。

总之,放在utils.js中的话,就不需要在模板文件中引入script标签了,也不用在意打包之后的路径该怎么办了。

先搭建基本框架

对于我们的思路呢,我们就一步步开始实现。我们先创建DOM元素:

// create dom element for background images
// ----------------------------------------
const opacityMask = document.createElement("div");
opacityMask.style.background = "linear-gradient(#fff, #ffced9, #fff)";
opacityMask.style.position = "fixed";
opacityMask.style.top = "0";
opacityMask.style.left = "0";
opacityMask.style.content = "";
opacityMask.style.width = "100%";
opacityMask.style.height = "100%";
opacityMask.style.opacity = "0.8";
opacityMask.style.zIndex = "-1";
const imageContainer = document.createElement("div");
imageContainer.style.position = "fixed";
imageContainer.style.top = "0";
imageContainer.style.left = "0";
imageContainer.style.content = "";
imageContainer.style.width = "100%";
imageContainer.style.height = "100%";
imageContainer.style.zIndex = "-2";
const imageScroller = document.createElement("div");
imageScroller.id = "image-scroller";
imageScroller.style.position = "fixed";
imageScroller.style.top = "0";
imageScroller.style.left = "0";
imageScroller.style.content = "";
imageScroller.style.width = "400%";
imageScroller.style.height = "100%";
imageScroller.style.display = "flex";
imageContainer.style.justifyContent = "space-around";
imageContainer.style.alignContent = "center";
imageContainer.style.alignItems = "center";
imageScroller.style.zIndex = "-3";
document.body.appendChild(opacityMask);
document.body.appendChild(imageContainer);
document.body.appendChild(imageScroller);
// well done! basic frames established!

当然,你也一定能找到更简单的写法。我这一步步操作过来只是单纯为了逻辑清晰。

然后添加图片链接

然后,我们再将图片放进去:

// url for background images
// -------------------------
const BASE_URL = 'http://images.sakebow.cn/bgimage/'
const DEVICES = ['pc']
const imgWindowUrl = { 'pc': ['/race-miku.jpg', '/masuri-miku.jpg', '/planet-miku.jpg', '/4mikus.jpg'
] };
for (const imgUrlItem of imgWindowUrl['pc']) {const imageFrameItemContainer = document.createElement("div");imageFrameItemContainer.style.width = imageContainer.style.width;imageFrameItemContainer.style.height = "100%";imageFrameItemContainer.innerHTML = "<img" +" src='" + BASE_URL + DEVICES[0] + imgUrlItem + "'" +" style='width: 100%; height: 100%;'" +" alt='network broken?' />";imageScroller.appendChild(imageFrameItemContainer);
}
// well done! all images ready!

在这里你能看到我的一些没必要的设计,这些其实是我为了以后做拓展用的。当然也不一定会做就是了。(诶嘿~⭐)

动画效果

在搭建了框架、设置了图片链接后,我们就可以准备开始轮播的操作了。

当然,你可能会想到再去style.styl文件中写一些css。但很可惜的是,别忘了,我们可是在loading状态下,所有的内容都是不可用的。

于是,就连动画效果我们也要创建style标签并编辑动画效果:

// keyframe to roll images
// -------------------------------
// create style element
const imageRollStyle = document.createElement('style');
// set animation time for all
const EPOCH_TIME = "64s ";
// set animation style for all
const ANIMATION_DEFAULT_SETTINGS = "linear infinite both running ";
// set keyframes into style element
imageRollStyle.innerHTML = `@keyframes image-roll {0%  { left: 0; } 24% { left: 0; } 25% { left: -100%; } 49% { left: -100%; } 50% { left: -200%; }74% { left: -200%; } 75% { left: -300%; } 99% { left: -300%; } 100%{ left: 0; }
}@keyframes image-translate-child-1 {0%  { scale: 1; opacity: 0 } 2% { scale: 1; opacity: 1; } 23% { scale: 1.1; } 25%, 100% { scale: 1.1; opacity: 0; }
}
#image-scroller>div:nth-child(1) {animation: ${EPOCH_TIME + ANIMATION_DEFAULT_SETTINGS} image-translate-child-1;
}@keyframes image-translate-child-2 {0%, 25%  { scale: 1; opacity: 0 } 27% { scale: 1; opacity: 1; } 48% { scale: 1.1; } 50%, 100% { scale: 1.1; opacity: 0; }
}
#image-scroller>div:nth-child(2) {animation: ${EPOCH_TIME + ANIMATION_DEFAULT_SETTINGS} image-translate-child-2;
}@keyframes image-translate-child-3 {0%, 50%  { scale: 1; opacity: 0 } 52% { scale: 1; opacity: 1; } 73% { scale: 1.1; } 75%, 100% { scale: 1.1; opacity: 0; }
}
#image-scroller>div:nth-child(3) {animation: ${EPOCH_TIME + ANIMATION_DEFAULT_SETTINGS} image-translate-child-3;
}@keyframes image-translate-child-4 {0%, 75%  { scale: 1; opacity: 0 } 77% { scale: 1; opacity: 1; } 98% { scale: 1.1; } 100% { scale: 1.1; opacity: 0; }
}
#image-scroller>div:nth-child(4) {animation: ${EPOCH_TIME + ANIMATION_DEFAULT_SETTINGS} image-translate-child-4;
}`;
// well done! now images can be rolling with fadeIn and fadeOut style, as well as scale 1.1x slowly

如果需要稳妥的话,也需要在keyframes的基础上额外增加一些适配,比如-moz-keyframes-webkit-keyframes等等诸如此类的玩意儿。

在这里就不多说了,如果加上的话这个教程就没完没了了。

最后,我们让style标签加入页面中去:

// 将style样式存放到head标签
// ----------------------
document.getElementsByTagName('head')[0].appendChild(imageRollStyle);
imageScroller.style.animation = `${EPOCH_TIME + ANIMATION_DEFAULT_SETTINGS} image-roll`;
// well done! keyframes in effect!

看起来一切都可行了!

不出意外的话,这些就够出现效果了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/451148.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MySQL 用户管理

重点&#xff1a; 视图&#xff0c;函数&#xff0c;存储过程&#xff0c;触发器&#xff0c;事件&#xff08; 了解 &#xff09; 用户管理&#xff0c;密码管理 grant revoke 权限管理 MySQL 架构&#xff08; 了解 &#xff09; 存储引擎&#xff1a;MyISAM 和 InnoDB …

展馆设计的必备要素有哪些

1、空间的设计 展馆要想配得上优秀这两个字眼&#xff0c;那么比较基本的表现就是要具有美感&#xff0c;要规划&#xff0c;合理美观的造型&#xff0c;并在此基础上重视互动融合&#xff0c;既要拥有特色具有创意的风格&#xff0c;又要能够和整个空间和谐又统一。布展内容结…

Python入门:生成器迭代器

一、列表生成式 现在有个需求&#xff0c;列表[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]&#xff0c;要求你把列表里的每个值加1&#xff0c;怎么实现&#xff1f;你可能会想到2种方式 二逼青年版 1 2 3 4 a [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] b [] for i in a:b.append(i1) print(b) …

ele-h5项目使用vue3+vite+vant4开发:第四节、业务组件-SearchView组件开发

需求分析 展示切换动画搜索框输入文字&#xff0c;自动发送请求搜索结果展示搜索状态维护历史搜索展示&#xff0c;点击历史搜索后发送请求历史搜索更多切换动画效果 <script setup lang"ts"> import OpSearch from /components/OpSearch.vue import { ref } f…

Sequine - Sequencing Animation and Visual Scripting

Sequine是Unity的通用序列工具和可视化脚本。您还可以按需播放动画片段,而不受 Animator 控制器的限制! 以下是可以使用工具进行的工作: 直接序列动画剪辑,不受animator控制器的限制 用可堆叠行为序列文本动画 序列脚本功能/命令执行 序列可以存在于任何类型的Unity对象中,…

05 MP之ActiveRecord模式+SimpleQuery

1. ActiveRecord ActiveRecord(活动记录&#xff0c;简称AR)&#xff0c;是一种领域模型模式&#xff0c;特点是一个模型类对应关系型数据库中的一个表&#xff0c;而模型类的一个实例对应表中的一行记录。 其目标是通过围绕一个数据对象, 进行全部的CRUD操作。 1.1 让实体类…

nginx初学者指南

一、启动、停止和重新加载配置 前提&#xff1a;先要启动nginx 在Windows上启动nginx的步骤如下&#xff1a; 1. 下载并安装nginx。可以从nginx官网下载适合自己操作系统的版本&#xff0c;一般是zip压缩包&#xff0c;解压到指定目录中。 2. 进入nginx的安装目录&#xff…

【LeetCode】每日一题 2024_2_4 Nim 游戏(找规律,博弈论)

文章目录 LeetCode&#xff1f;启动&#xff01;&#xff01;&#xff01;题目&#xff1a;Nim 游戏题目描述代码与解题思路 LeetCode&#xff1f;启动&#xff01;&#xff01;&#xff01; 题目&#xff1a;Nim 游戏 题目链接&#xff1a;292. Nim 游戏 题目描述 代码与解题…

Leetcode—32. 最长有效括号【困难】(动态规划及ranges::max()使用)

2024每日刷题&#xff08;110&#xff09; Leetcode—32. 最长有效括号 栈实现代码 class Solution { public:int longestValidParentheses(string s) {stack<int> st;st.push(-1);int n s.size();int maxn 0;for(int i 0; i < n; i) {if(s[i] () {st.push(i);}…

【20240131】USB相机(查看设备列表、打开设备)

USB相机采集 1、v4l2查看设备列表2、查看具体设备信息3、在桌面打开USB相机 1、v4l2查看设备列表 打开终端&#xff0c;输入&#xff1a;v4l2-ctl --list-devices usb设备在Webcam: Webcam栏&#xff0c;分别是video9和video10&#xff0c;下一步&#xff1a;确定哪一个是接入…

Android 摄像头切换录像失败

1.问题描述 &#xff08;1&#xff09;打开Android Camera &#xff08;2&#xff09;点击录像 &#xff08;3&#xff09;APP提示can’t connect the camera &#xff0c;无法录像 2.问题分析 对有问题的设备抓取log进行分析查看 从log看,发生错误的原因是摄像头不支持19…

2024.2.3

单向循环链表的头插 头删 尾插和尾删 //头结点插入 Linklist insere_element(Linklist head,datatype element) {Linklist screat();s->dataelement;if(NULLhead){heads;}else{Linklist phead;while(p->next!head){pp->next;}s->nexthead;heads;p->nexthead;}r…