Initial commit

This commit is contained in:
ZSCGR
2024-04-07 22:09:43 +08:00
commit 774480fb90
162 changed files with 7288 additions and 0 deletions
+2
View File
@@ -0,0 +1,2 @@
# Auto detect text files and perform LF normalization
* text=auto
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 419 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 177 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 225 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 150 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

+126
View File
@@ -0,0 +1,126 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>原神主题网站 | Genshin Theme</title>
<!-- 样式文件 | CSS file -->
<link rel="stylesheet" href="indexstyle.css" type="text/css" />
</head>
<body>
<!--日志弹窗-->
<div id="changelog-modal" class="changelog-modal">
<div class="changelog-content">
<h2 id="logtitle">(由JS控制)</h2>
<p id="groupdescribe">-----------------------------讨论群 856992001-----------------------------<br></p>
<p id="logtext">(由JS控制)</p>
</div>
</div>
<!--功能区-->
<div class="buttons-container">
<!--更新日志按钮-->
<div id="changelog-button" class="changelog-button">
<i class="changelog-icon"></i>
</div>
</div>
<!--网站主体-->
<div class="shell" id="shell">
<div class="header">
<h2 class="title">原神 · 印象</h2>
<h3 class="subtitle">Genshin | Character image</h3>
</div>
<div class="timeline">
<!-- 可莉 -->
<div class="item" data-text="2023.06.12 上线">
<div class="content">
<a href="./webs/KleeWeb/klee.html" target="_blank"><img src="./img/01.jpg" alt="" class="img"></a>
<h2 class="content-title">Klee</h2>
<p class="content-desc">
“那边那个小红帽是谁?” <br />
“一个经常闯祸的火花骑士。”
</p>
</div>
</div>
<!-- 纳西妲 -->
<div class="item" data-text="2023.06.20 上线">
<div class="content">
<a href="./webs/NahidaWeb/nahida.html" target="_blank"><img src="./img/02.jpeg" alt="" class="img"></a>
<h2 class="content-title">Nahida</h2>
<p class="content-desc">
“净善宫里藏着什么?” <br />
“藏着美好与悲伤。”
</p>
</div>
</div>
<!-- 绮良良 -->
<div class="item" data-text="2023.06.24 上线">
<div class="content">
<a href="./webs/KiraraWeb/kirara.html" target="_blank"><img src="./img/03.jpg" alt="" class="img"></a>
<h2 class="content-title">Kirara</h2>
<p class="content-desc">
“送快递是什么感觉?” <br />
“在超时与未超时之间反复徘徊......”
</p>
</div>
</div>
<!-- 多莉 -->
<div class="item" data-text="2023.06.27 上线">
<div class="content">
<a href="./webs/DoriWeb/dori.html" target="_blank"><img src="./img/04.jpg" alt="" class="img"></a>
<h2 class="content-title">Dori</h2>
<p class="content-desc">
“什么是双赢?” <br />
“多莉会告诉你答案。”
</p>
</div>
</div>
<!-- 芭芭拉 -->
<div class="item" data-text="2023.06.27 上线">
<div class="content">
<a href="./webs/BabaraWeb/babara.html" target="_blank"><img src="./img/05.jpg" alt="" class="img"></a>
<h2 class="content-title">Babara</h2>
<p class="content-desc">
“人们总是会对任何美好报以憧憬, <br />
“天籁之声也不例外。”
</p>
</div>
</div>
<!-- 敬请期待 -->
<div class="item" data-text="未来会是谁呢……?">
<div class="content">
<a href="#"><img src="./img/last.jpg" alt="" class="img"></a>
<h2 class="content-title"></h2>
<p class="content-desc">
讨论群: 856992001<br />
将你的创造展示于群星 。
</p>
</div>
</div>
</div>
</div>
<!-- 引入 JS文件 -->
<script src="./jquery.min.js"></script>
<script src="./indexscript.js"></script>
</body>
</html>
+136
View File
@@ -0,0 +1,136 @@
// 禁用右键菜单
document.addEventListener('contextmenu', function (event) {
event.preventDefault();
});
// ===============================网页主体==========================
(function ($) {
$.fn.timeline = function () {
var selectors = {
id: $(this),
item: $(this).find(".item"),
activeClass: "item--active",
img: ".img"
};
// 将第一个时间轴项目激活,并设置时间轴背景图片为第一个项目的图片
selectors.item.eq(0).addClass(selectors.activeClass);
selectors.id.css(
"background-image",
"url(" +
selectors.item.first()
.find(selectors.img)
.attr("src") +
")"
);
// 获取时间轴项目的总数
var itemLength = selectors.item.length;
// 当页面滚动时,触发滚动事件
$(window).scroll(function () {
var max, min;
// 获取页面滚动的距离
var pos = $(this).scrollTop();
selectors.item.each(function (i) {
// 获取当前时间轴项目的最小和最大高度
min = $(this).offset().top; //min:元素距离文档顶部的距离
max = $(this).height() + $(this).offset().top; //max:元素距离文档顶部的距离 + 元素的高度
var that = $(this);
// 如果滚动到最后一个项目,并且超过了当前项目高度的一半,
// 则将最后一个项目设置为激活状态,并设置背景图片为最后一个项目的图片
if (i == itemLength - 2 && pos > min + $(this).height() / 2) {
selectors.item.removeClass(selectors.activeClass);
selectors.id.css(
"background-image",
"url(" +
selectors.item.last()
.find(selectors.img)
.attr("src") +
")"
);
selectors.item.last().addClass(selectors.activeClass);
}
// 如果当前滚动位置在当前项目的最小和最大高度之间,
// 则将当前项目设置为激活状态,并设置背景图片为当前项目的图片
else if (pos <= max && pos >= min - 220) {
selectors.id.css(
"background-image",
"url(" +
$(this)
.find(selectors.img)
.attr("src") +
")"
);
selectors.item.removeClass(selectors.activeClass);
$(this).addClass(selectors.activeClass);
}
});
});
};
})(jQuery)
/*
最后,我们调用 timeline 插件并传入时间轴的 ID 作为参数。
这将启用时间轴插件并为该时间轴绑定滚动事件。
*/
$("#shell").timeline();
//================================================================【日志功能】==================================================
const changelogButton = document.getElementById('changelog-button'); //日志功能点击按钮
const changelogModal = document.getElementById('changelog-modal'); //
changelogButton.addEventListener('click', toggleChangelogModal);
function toggleChangelogModal() {
changelogModal.style.display = 'block';
changelogModal.classList.toggle('fade-in');
changelogModal.classList.toggle('fade-out');
}
var isFirstClick = true;
document.addEventListener('click', function (event) {
//第一次弹窗默认弹窗,点击哪里都能关闭弹窗
if (isFirstClick == true) {
//移除弹窗的渐入动画、增加淡出动画
changelogModal.classList.remove('fade-in');
changelogModal.classList.add('fade-out');
//淡出动画的CSS持续时间为0.5s,因此这0.5s内,弹窗的display="none"需要延迟0.5s执行
setTimeout(function () {
changelogModal.style.display = 'none';
}, 500 // 0.5秒延时,和CSS代码中的 fade-out 持续时间一致
);
isFirstClick = false;
}
//第二次点击弹窗之后,只能点击弹窗外的地方才能关闭
else if (!changelogModal.contains(event.target) && !changelogButton.contains(event.target)) {
//逻辑同上
changelogModal.classList.remove('fade-in');
changelogModal.classList.add('fade-out');
setTimeout(function () {
changelogModal.style.display = 'none';
}, 500);
}
});
//更新日志设置(模板字符串)
const logTitle = document.getElementById("logtitle");
const logText = document.getElementById("logtext");
const title = "6.27 V3.0网站更新日志";
const content = `
<br>
1.【多莉】还有【芭芭拉】的主题页面登场!全球计数器同步上线!~<br>
2.【纳西妲】新增中文语音 “呐呐”,欢迎体验<br>
3. 优化了其它逻辑<br>
`;
logTitle.innerHTML = `<h2>${title}</h2>`;
logText.innerHTML = `<p>${content}</p>`;
+354
View File
@@ -0,0 +1,354 @@
/* ==========================网页主体========================= */
* {
padding: 0;
margin: 0;
-webkit-user-select: none;
/* Safari 和 Chrome */
-moz-user-select: none;
/* Firefox */
-ms-user-select: none;
/* Internet Explorer/Edge */
user-select: none;
/* 标准语法 */
}
.shell {
width: 100%;
position: relative;
padding: 80px 0;
transition: 0.3s ease 0s;
background-attachment: fixed;
background-size: cover;
}
.shell:before {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
background: rgba(99, 99, 99, 0.8);
content: "";
}
.header {
width: 100%;
text-align: center;
margin-bottom: 80px;
position: relative;
}
.title {
color: #fff;
font-size: 46px;
font-weight: normal;
margin: 0;
}
.timeline {
display: flex;
margin: 0 auto;
flex-wrap: wrap;
flex-direction: column;
max-width: 700px;
position: relative;
}
.content-title {
font-weight: normal;
font-size: 66px;
margin: -10px 0 0 0;
transition: 0.4s;
padding: 0 10px;
box-sizing: border-box;
color: #fff;
}
.content-desc {
margin: 0;
font-size: 15px;
box-sizing: border-box;
color: rgba(255, 255, 255, 0.7);
line-height: 25px;
}
.timeline:before {
position: absolute;
left: 50%;
width: 2px;
height: 100%;
margin-left: -1px;
content: "";
background: rgba(255, 255, 255, 0.07);
}
.item {
padding: 40px 0;
opacity: 0.3;
filter: blur(2px);
transition: 0.5s;
box-sizing: border-box;
width: calc(50% - 40px);
display: flex;
position: relative;
transform: translateY(-80px);
/* 元素之间的距离 */
margin-bottom: 200px;
}
/* 伪元素样式 */
.item:before {
content: attr(data-text);
letter-spacing: 3px;
width: 100%;
position: absolute;
color: rgba(255, 255, 255, 0.5);
font-size: 13px;
border-left: 2px solid rgba(255, 255, 255, 0.5);
top: 70%;
margin-top: -5px;
padding-left: 15px;
opacity: 0;
right: calc(-100% - 56px);
font: 900 20px '';
letter-spacing: 5px;
}
.item:nth-child(even) {
align-self: flex-end;
}
/* 改变伪元素的产生位置,对称产生 */
.item:nth-child(even):before {
right: auto;
text-align: right;
left: calc(-100% - 56px);
padding-left: 0;
border-left: none;
border-right: 2px solid rgba(255, 255, 255, 0.5);
padding-right: 15px;
}
/* 滚动到对应元素的位置 */
.item--active {
opacity: 1;
/* transform: translateY(0); */
filter: blur(0px);
}
/* 激活状态鼠标悬浮变化 */
.item--active:hover {
width: 360px;
}
/* 图片旁边的伪元素文字 */
.item--active:before {
top: 70%;
transition: 0.3s all 0.2s;
opacity: 1;
}
.item--active .content-title {
margin: -50px 0 20px 0;
}
.img {
max-width: 100%;
box-shadow: 0 10px 15px rgba(0, 0, 0, 0.4);
}
.subtitle {
color: rgba(255, 255, 255, 0.5);
font-size: 16px;
letter-spacing: 5px;
margin: 10px 0 0 0;
font-weight: normal;
}
.footer {
padding: 95px 0;
text-align: center;
}
.footer a {
color: #999;
display: inline-block;
}
@media only screen and (max-width: 767px) {
.item {
align-self: baseline !important;
width: 100%;
padding: 0 30px 150px 80px;
}
.item:before {
left: 10px !important;
padding: 0 !important;
top: 50px;
text-align: center !important;
width: 60px;
border: none !important;
}
.item:last-child {
padding-bottom: 40px;
}
}
@media only screen and (max-width: 767px) {
.timeline:before {
left: 40px;
}
}
/* ==================日志============ */
/* 功能区大盒子 */
.buttons-container {
position: fixed;
top: 20px;
left: 20px;
display: flex;
align-items: center;
z-index: 8888;
}
/* 更新日志按钮 */
.changelog-button {
width: 40px;
height: 40px;
background-color: rgba(255, 255, 255, 0.5);
border-radius: 5%;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
}
.changelog-button:hover {
background-color: #e5e2e2;
}
.changelog-icon {
width: 24px;
height: 24px;
background-image: url("./img/log_icon.png");
/* 替换为你的更新日志图标的路径 */
background-size: cover;
}
/* 日志弹窗样式 */
.changelog-modal {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 60%;
height: 70%;
background-color: rgba(8, 8, 8, 0.9);
/* 淡红色背景 */
z-index: 9999;
overflow: auto;
border-radius: 1%;
}
.changelog-content #logtitle {
text-align: center;
font-size: 20px;
margin-bottom: 30px;
}
.changelog-content #groupdescribe {
text-align: center;
font-size: 15px;
font-weight: 400;
color: rgb(188, 230, 96);
}
.changelog-content #logtext {
text-align: left;
font-size: 15px;
}
.changelog-content {
/* 公告文字颜色 */
color: rgb(188, 230, 96);
/* 白色文字 */
padding: 20px;
border-radius: 10px;
margin: 20px;
font-size: 16px;
line-height: 1.5;
}
.fade-in {
animation: fade-in 0.5s ease-in-out forwards;
}
.fade-out {
animation: fade-out 0.5s ease-in-out forwards;
}
@keyframes fade-in {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes fade-out {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
@media (max-width: 768px) {
/* 小屏幕设备的日志弹窗样式 */
#changelog-modal {
width: 90%;
height: 70%;
}
.changelog-content #logtitle {
text-align: center;
font-size: 15px;
margin-bottom: 30px;
}
.changelog-content #groupdescribe {
text-align: center;
font-size: 10px;
font-weight: 400;
color: rgb(230, 216, 29)
}
.changelog-content #logtext {
text-align: left;
font-size: 10px;
}
}
+5
View File
File diff suppressed because one or more lines are too long
+12
View File
@@ -0,0 +1,12 @@
1.新增语音:
①中文语音:“嗷呜” 、“略略略”、“呜..”
②日语语音:“哒咩”、“呜nia”、“呜..”
③刘照坤老师的可莉彩蛋语音
④花玲老师的可莉彩蛋语音
2.新增功能:永久保存本地的点击数
3.添加Windows客户端版本(群文件在群里~)
4.新增两个语音模式选项 “仅哒哒哒”、“彩蛋”
5.优化了语言选择栏的文本显示逻辑
6.减小了移动端可莉图像的大小和移动速度
7.新增“版本日志”功能,点击左上角就可以查看本网站的更新日志了!
+2
View File
@@ -0,0 +1,2 @@
1.「可莉哒哒哒」移进了网页的二级入口
2. 设置网站首页的目的是为未来编写其它角色的主体网页做准备
+3
View File
@@ -0,0 +1,3 @@
1.全新角色展示页面 『纳西妲』 上线。目前仅开发了中文语音。从首页第二个角色标签点入即可。
2.我们将在不久的将来上线全球计数器功能,目前的功能已经开发完毕,接下来我们还需要进行部署和线上测试,请大家敬请期待
3.有更多建议和想法,欢迎加入我们的讨论群一起讨论。
+1
View File
@@ -0,0 +1 @@
1.本次上线了大家最期待的功能【全球计数器】
+1
View File
@@ -0,0 +1 @@
1.新任务【绮良良】的主页登场!绮良良的全球点击计数器也同步上线!
+3
View File
@@ -0,0 +1,3 @@
1.【多莉】还有【芭芭拉】的主题页面登场!全球计数器同步上线!~
2.【纳西妲】新增中文语音 “呐呐”,欢迎体验
3. 优化了其它逻辑
+80
View File
@@ -0,0 +1,80 @@
# 原神角色の主题网站……持续更新~
本网站所参考的源码:[Herta Kuru~](https://github.com/duiqt/herta_kuru) |
このウェブサイトは、参考元のソースコード:[Herta Kuru~](https://github.com/duiqt/herta_kuru) |
The source code referenced by this website: [Herta Kuru~](https://github.com/duiqt/herta_kuru)
感谢 [@Seseren_kr](https://twitter.com/Seseren_kr) 提供的GIF图片 |
[@Seseren_kr](https://twitter.com/Seseren_kr) さんが提供してくれたGIF画像に感謝します|
Thanks [@Seseren_kr](https://twitter.com/Seseren_kr) for the gif picture
角色版权归米哈游所有 |
キャラクターの著作権はmiHoYoに帰属します |
The art the relevant copyright of Genshin Impact belongs to miHoYo/HoYoverse.
---
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+130
View File
@@ -0,0 +1,130 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title id="doc-title">Babara~</title><!--change-->
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
<link rel="stylesheet" href="./babarastyle.css" type="text/css" /><!--change-->
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<script src="https://code.iconify.design/iconify-icon/1.0.2/iconify-icon.min.js"></script>
<link href="img/favicon.ico" rel="shortcut icon">
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
</head>
<body>
<div id="welcome-page">
<h2>Click to Continue</h2>
<br />
<img src="./img/welcome.gif">
</div>
<!--功能区-->
<div class="buttons-container">
<!-- 音乐播放按钮-->
<div id="volume-control" class="volume-control">
<i id="volume-icon" class="volume-icon"></i>
</div>
</div>
<!--主体部分 | Main page-->
<main class="wrapper">
<div id="wrapper-background-filter"></div>
<div id="wrapper-background"></div>
<img src="img/background.gif" class="preload" />
<div id="content">
<div id="title-container">
<h1 id="page-title">Welcome to Babara's Page~ &nbsp;</h1>
<img id="title-img" alt="img of Babara" class="shake" src="img/favicon.png">
</div>
<div id="container">
<select id="language-selector">
<option id="lan1" value="cn" selected>Chinese</option>
<option id="lan2" value="ja">Japanese</option>
<option id="lan3" value="en">English</option>
</select>
<select id="mode-selector">
<option id="mode1">Default</option>
<!-- <option id="mode2">Just Dadada</option>
<option id="mode3">Easter egg</option> -->
</select>
</div>
<hr id="subtitle-seperator" />
<h2 id="page-descriptions">
The website for Babara, the shiniest idol in Genshin Impact.
</h2>
<div id="counter-container">
<h3 id="counter-descriptions">Babara has been performed for</h3>
<br />
<br />
<p id="global-counter">0</p>
<p id="local-counter">0</p>
<br />
<br />
<button id="counter-button">
Let Babara Performes~!
</button>
</div>
<hr />
<div id="grid">
<noscript>Your browser does not support JavaScript or JavaScript has been
disabled.<br />This website relies on JavaScript, so please enable it
or use another browser.</noscript>
</div>
</div>
</main>
<!-- 尾部部分 | Footer -->
<div id="footer">
<img id="babara-card" loading="lazy" src="" alt="" /> <!--由JS控制src的具体路径-->
<div id="footer-text">
<p id="footer-repository-text">
You can check out the Gitee repository here:
</p>
<p>
<!--这里填写本网站的Github地址-->
<a href="https://gitee.com/KleeGitee/Klee" target="_blank">
<span class="footer-icon-text"
id="footer-repository-text-2">Web_OF_Genshin (Gitee)</span></a>
</p>
<br/>
<p id="footer-repository-text3">
This website is based on the repository source code changes
</p>
<p>
<!--source code-->
<a href="https://github.com/duiqt/herta_kuru" target="_blank"><iconify-icon icon="mdi:github" id="github-footer-icon"
class="footer-icon"></iconify-icon><span class="footer-icon-text"
id="footer-repository-text-4">SourceCode's repository</span></a>
</p>
<br/>
<p id="credits-gif">Babara gif made by</p>
<p>
<a href="https://twitter.com/Seseren_kr" target="_blank"><iconify-icon icon="mdi:twitter"
id="twitter-footer-icon" class="footer-icon"></iconify-icon><span
class="footer-icon-text">@Seseren_kr</span></a>
</p>
</div>
</div>
<script src="./babarascript.js" async></script>
</body>
</html>
+62
View File
@@ -0,0 +1,62 @@
<?php
//加载数据库信息
require_once('../config.php');
// 创建连接
$conn = new mysqli($servername, $username, $password, $dbname);
// 连接成功,可以进行数据库操作
$sql = "SELECT globalcount FROM ys WHERE name = 'babara'";
// 执行查询
$result = $conn->query($sql);
if ($_SERVER["REQUEST_METHOD"] === "POST") {
// 处理 POST 请求
//接收前端数据
$localcount = $_POST["localcount"];
//检查查询结果
if ($result->num_rows > 0) {
$row = $result->fetch_assoc();
$globalCount = $row['globalcount'];
// 将本地计数值加给全局计数
$globalCount += $localcount;
// 更新数据库中的全局计数值
$updateSql = "UPDATE ys SET globalcount = $globalCount WHERE name = 'babara';";
if ($conn->query($updateSql) === TRUE) {
// 更新成功
echo "更新成功";
} else {
// 更新失败
echo "更新失败: " . $conn->error;
}
} else {
// 没有找到全局计数值
echo "没有找到全局计数值";
}
// 返回响应
//echo "这是 POST 请求的响应";
} elseif ($_SERVER["REQUEST_METHOD"] === "GET") {
// 处理 GET 请求
if ($result->num_rows > 0) {
// 有数据返回
$rows = array();
while ($row = $result->fetch_assoc()) {
$rows[] = $row;
}
// 将查询结果转换为 JSON 格式发送回前端
echo json_encode($rows);
} else {
// 无数据返回
echo "没有数据";
}
// 返回响应
//echo "这是 GET 请求的响应";
} else {
// 不支持其他请求方法
http_response_code(405); // 返回“Method Not Allowed”状态码
echo "不支持的请求方法";
}
?>
+613
View File
@@ -0,0 +1,613 @@
// 禁用右键菜单
document.addEventListener('contextmenu', function (event) {
event.preventDefault();
});
//图片摇摆
const img = document.getElementById('title-img');
// 定期执行动画
setInterval(() => {
// 添加 CSS 类来触发动画
img.classList.add('shake');
// 设置一个定时器,在一段时间后移除 CSS 类停止动画
setTimeout(() => {
img.classList.remove('shake');
}, 2500); // 动画持续时间为 2.5 秒
}, 5000); // 每隔 5 秒执行一次动画
//=================================================================【BGM】=============================================================
// 欢迎页面淡出控制,音乐控制
var isMusicPlayed = false; // 记录音乐是否已经播放
var isWelcomed = false; //记录您是否已离开欢迎页面
var BGM = new Audio("./music/Babara's song.mp3"); //BGM
document.addEventListener("click", function (event) {
if (!isWelcomed) {
removeWelcomePageAndPlayMusic();
}
});
function removeWelcomePageAndPlayMusic() {
var welcomePage = document.getElementById("welcome-page");
welcomePage.style.opacity = 0;
setTimeout(function () {
welcomePage.style.display = "none";
}, 500);
if (!isMusicPlayed && !isWelcomed) {
playBackgroundMusic();
isMusicPlayed = true;
isWelcomed = true;
}
}
function playBackgroundMusic() {
BGM.loop = true; // 循环播放
BGM.play(); // 播放BGM
BGM.volume = 0.1;
}
//音乐播放控制
var volumeControl = document.getElementById("volume-control");
var volumeIcon = document.getElementById("volume-icon");
//音乐暂停和播放逻辑
volumeControl.addEventListener("click", function () {
if (!isMusicPlayed) {
// Play music
BGM.play();
volumeIcon.style.animationPlayState = "running";
isMusicPlayed = true;
} else {
// Pause music
BGM.pause();
volumeIcon.style.animationPlayState = "paused";
isMusicPlayed = false;
}
});
// ===================================================【多语言支持】============================================
var audioList = []; // 角色音频
let firstSquish = true; //第一次点击
//多语言支持
//语言属性数组
const LANGUAGES = {
//默认
"_": { fallbackLanguage: "cn" },
//中文语音、文本、海报
"cn": {
audioList: [
//0-3:默认模式 mode1
"audio/CN_voice/芭芭拉冲呀.mp3",
"audio/CN_voice/哒哒哒.mp3",
"audio/CN_voice/打起精神来哟.mp3",
"audio/CN_voice/哼哼哼哼哼.mp3",
],
texts: {
"page-title": "芭芭拉闪耀登场~",
"doc-title": "Kirakira~",
"page-descriptions": "给芭芭拉写的小网站,对,就是那个原神中最闪耀的偶像!",
"counter-descriptions": "芭芭拉已经演唱了~",
"counter-button": ["演奏~", "哒~哒哒哒哒~哒~哒!"],
"credits-gif": "鸣谢:Seseren_kr提供的芭芭拉GIF图片",
"footer-repository-text": "本网站的Gitee仓库在这儿:",
"footer-repository-text-2": "原神主题网站代码仓库",
"footer-repository-text3": "鸣谢:duiqt提供的本网站基础源代码",
"footer-repository-text-4": "Herta_kuru"
},
cardImage: "img/banner_cn.jpg"
},
//日文语音、文本、海报
"ja": {
audioList: [
//0-3:默认模式 mode1
"audio/CN_voice/芭芭拉冲呀.mp3",
"audio/CN_voice/哒哒哒.mp3",
"audio/CN_voice/打起精神来哟.mp3",
"audio/CN_voice/哼哼哼哼哼.mp3",
],
texts: {
"page-title": "バーバラキラキラ",
"doc-title": "キラキラ",
"page-descriptions": "このサイトはバーバラのために作られた、 あの原神の最も輝いているアイドルです",
"counter-descriptions": "歌唱回数~",
"counter-button": "キラキラー!",
"credits-gif": "感謝: Seseren_kr さんが提供してくれたバーバラのGIF画像",
"footer-repository-text": "こちらはこのページGitee (Mainland China) リポジトリ:",
"footer-repository-text-2": "原神主题网站代码仓库",
"footer-repository-text3": "感謝:duiqt さんが提供してくれたこのウェブサイトの基礎ソースコード",
"footer-repository-text-4": "Herta_kuru"
},
cardImage: "img/banner_jp.jpg"
},
//英文语音、文本、海报
"en": {
audioList: [
//0-3:默认模式 mode1
"audio/CN_voice/芭芭拉冲呀.mp3",
"audio/CN_voice/哒哒哒.mp3",
"audio/CN_voice/打起精神来哟.mp3",
"audio/CN_voice/哼哼哼哼哼.mp3",
],
texts: {
"page-title": "Welcome to Babara kirakira~",
"doc-title": "Kirakira~",
"page-descriptions": "The website for Babara, the shiniest idol in Genshin Impact",
"counter-descriptions": "The Babara~ has been performed for",
"counter-button": "Kirakira~",
"credits-gif": "Acknowledgment: GIF images of Babara provided by Seseren_kr.",
"footer-repository-text": "You can check out the Gitee repository (Mainland China) here:",
"footer-repository-text-2": "原神主题网站代码仓库",
"footer-repository-text3": "Special thanks to duiqt for providing the source code for this website.",
"footer-repository-text-4": "Herta_kuru"
},
cardImage: "img/banner_en.jpg"
}
};
//设置语言选择器的文本语言
function refreshLanguageSelector(selectedLanguage) {
switch (selectedLanguage) {
case "cn":
document.getElementById("lan1").innerHTML = "🌏中文";
document.getElementById("lan2").innerHTML = "日文";
document.getElementById("lan3").innerHTML = "英文";
break;
case "ja":
document.getElementById("lan1").innerHTML = "中国語";
document.getElementById("lan2").innerHTML = "🌏日本語";
document.getElementById("lan3").innerHTML = "英語";
break;
case "en":
document.getElementById("lan1").innerHTML = "Chinese";
document.getElementById("lan2").innerHTML = "Japanese";
document.getElementById("lan3").innerHTML = "🌏English";
break;
default:
break;
}
}
//设置模式选择器的文本语言
function refreshModeSelector(selectedLanguage) {
switch (selectedLanguage) {
case "cn":
document.getElementById("mode1").innerHTML = "默认模式";
// document.getElementById("mode2").innerHTML = "只要哒哒哒";
// document.getElementById("mode3").innerHTML = "隐藏彩蛋";
break;
case "ja":
document.getElementById("mode1").innerHTML = "デフォルトモード";
// document.getElementById("mode2").innerHTML = "ダダダだけ";
// document.getElementById("mode3").innerHTML = "ひみつ";
break;
case "en":
document.getElementById("mode1").innerHTML = "DefaultMode";
// document.getElementById("mode2").innerHTML = "Just Dadada";
// document.getElementById("mode3").innerHTML = "Easter egg";
break;
default:
break;
}
}
//获取默认语言并赋值给语言选择框
var current_language = localStorage.getItem("lang") || "cn";
if (current_language != "cn") {
document.getElementById("language-selector").value = current_language;
};
//通过获取当前语言和对应的文本数组,遍历文本数组中的每个键值对。如果文本值是一个数组,就从数组中随机选择一个元素作为新的文本内容,并将其更新到对应的 HTML 元素中
function randomChoice(myArr) {
const randomIndex = Math.floor(Math.random() * myArr.length);
const randomItem = myArr[randomIndex];
return randomItem;
};
//核心函数!动态刷新动态文本内容(将新的DOM值渲染到前端)
function refreshDynamicTexts() {
let curLang = LANGUAGES[current_language];
let localTexts = curLang.texts;
Object.entries(localTexts).forEach(([textId, value]) => {
if (value instanceof Array)
if (document.getElementById(textId) != undefined)
document.getElementById(textId).innerHTML = randomChoice(value);
});
};
//定义函数:根据当前语言,渲染页面
function multiLangMutation() {
let curLang = LANGUAGES[current_language]; //获取当前的网站语言
let localTexts = curLang.texts; //获取当前语言的文本数组
Object.entries(localTexts).forEach(([textId, value]) => { //将各个DOM元素的值变为文本值
if (!(value instanceof Array))
if (document.getElementById(textId) != undefined)
document.getElementById(textId).innerHTML = value;
});
refreshDynamicTexts() //刷新动态文本内容(将新的DOM值渲染到前端)
document.getElementById("babara-card").src = curLang.cardImage; //动态获取klee-card在当前语言文本环境下的Dom元素并更新
var selectedLanguage = document.getElementById("language-selector").value;
refreshLanguageSelector(selectedLanguage) //更新语言选择器的文本语言
refreshModeSelector(selectedLanguage) //更新模式选择器的文本语言
};
/*
curLang 变量获取了当前选择的网站语言对应的语言对象(假设为 LANGUAGES 全局对象中的一个属性)。
localTexts 变量获取了当前语言对象中的文本数组。
使用 Object.entries() 方法遍历 localTexts 中的键值对。
对于每一个键值对,解构赋值为 [textId, value],其中 textId 是 DOM 元素的 IDvalue 是对应的文本值。
首先检查 value 是否为数组,如果不是数组,表示是单个文本值(例如字符串)。
检查当前网页是否存在具有对应 textId 的 DOM 元素(通过 document.getElementById(textId) 来判断)。
如果存在对应的 DOM 元素,则将其内部的 HTML 内容更新为 value。
这样就实现了根据当前语言选择动态更新网页中的文本内容。
*/
multiLangMutation() //初始化网站语言
//通过这段代码,当语言选择器的值发生变化时,会根据选择的语言重新渲染页面的文本内容和动态图片,实现动态调整网站语言的功能。
document.getElementById("language-selector").addEventListener("change", (ev) => {
current_language = ev.target.value;
localStorage.setItem("lang", ev.target.value);
multiLangMutation();
});
//=======================================================================【按钮点击、计数器】============================================
// 初始化计数器
//本地计数器
const localCounter = document.querySelector('#local-counter'); //获取展示本地点击数的DOM元素
let localCount = localStorage.getItem('count-local-babara') || 0; //获取本地点击数的值
localCounter.textContent = localCount.toLocaleString('en-US'); //使用美式英语的格式进行格式化。这样可以确保数值以适当的方式显示,例如添加千位分隔符
let prevTime = 0;
//获取时间戳
const getTimestamp = () => Date.parse(new Date());
//点击按钮事件
const counterButton = document.querySelector('#counter-button');
counterButton.addEventListener('click', (e) => {
prevTime = getTimestamp(); //当前时间
localCount++;
localStorage.setItem('count-local-babara', localCount); //缓存localCount到本地
localCounter.textContent = localCount.toLocaleString('en-US');
triggerRipple(e); //按钮的水波纹效果
playKirakira(); //播放可莉语音
animateBabara(); //播放可莉动画
});
//===================================================================【资源缓存】========================================================
var cachedObjects = {};
function tryCachedObject(origUrl) {
// 检查对象是否已经被缓存
if (cachedObjects[origUrl]) {
return cachedObjects[origUrl];
} else {
// 开始缓存
fetch(origUrl)
.then((response) => response.blob())
.then((blob) => {
// 为对象创建一个blob URL
const blobUrl = URL.createObjectURL(blob);
// 通过在cachedObjects对象中存储blob URL来获取缓存的对象
cachedObjects[origUrl] = blobUrl;
})
.catch((error) => {
console.error(`Error caching object from ${origUrl}: ${error}`);
});
return origUrl;
}
};
//缓存所有资源
function cacheAllResources() {
// 缓存图片资源
for (let i = 1; i < 7; i++) {
const imageUrl = `img/animation/${i}.gif`;
tryCachedObject(imageUrl);
}
// 缓存中文音频资源(含通用语音资源)
const cnAudioList = LANGUAGES.cn.audioList;
cnAudioList.forEach((audioUrl) => {
tryCachedObject(audioUrl);
});
// 缓存日文音频资源(含通用语音资源)
const jaAudioList = LANGUAGES.ja.audioList;
jaAudioList.forEach((audioUrl) => {
tryCachedObject(audioUrl);
});
//只需要执行一次该功能
firstLoadClick = false;
}
// 当页面加载完成后触发缓存资源
// var firstLoadClick = true;
// window.addEventListener('click', cacheAllResources);
//========================================================================【按钮点击后的动画、音频】================================================
//返回当前语言的音频数组
function getLocalAudioList() {
return LANGUAGES[current_language].audioList;
};
//从音频数组中获取一个随机的音频URL(传入一个当前模式。curMode==mode1 默认模式,cueMode==mode3
function getRandomAudioUrl(curMode) {
var localAudioList = getLocalAudioList()
//根据模式产生符合模式的音频下标
if (curMode == "mode1") {
randomIndex = Math.floor(Math.random() * 4); //默认语音的文件是:文件下标0-3.这儿的数字就写4.
}
// if (curMode == "mode3") {
// randomIndex = Math.floor(Math.random() * 17); //文件下标0-16.这儿的数字就写14. 【这儿写彩蛋对应的audioList下标】
// }
const randomItem = localAudioList[randomIndex];
return randomItem;
};
//播放音频
var isFirstVoice = true;
function playKirakira() {
//先获取当前的模式:1-默认;2-只哒哒哒;3-彩蛋
const modeSelectElement = document.getElementById("mode-selector");
const modeSelectedOption = modeSelectElement.options[modeSelectElement.selectedIndex];
const curMode = modeSelectedOption.id;
//要播放的音频Url
let audioUrl;
//根据当前模式获取符合模式语音的 AudioURL
switch (curMode) {
//curMode==mode1 默认模式
case "mode1": {
if (isFirstVoice == true) {//随机获取一个音频的URL,第一个必定是哒哒哒哒哒哒
isFirstVoice = false;
audioUrl = getLocalAudioList()[1] //First play fixed Dadadadadada
} else {
audioUrl = getRandomAudioUrl(curMode);
}
}; break;
//curMode==mode2 只哒哒哒
// case "mode2": {
// audioUrl = getLocalAudioList()[1]
// }; break;
//cueMode==mode3 彩蛋
// case "mode3": {
// if (isFirstVoice == true) {//随机获取一个音频的URL,第一个必定是哒哒哒
// isFirstVoice = false;
// audioUrl = getLocalAudioList()[1] //First play fixed Dadada
// } else {
// audioUrl = getRandomAudioUrl(curMode);
// }
// }; break;
}
//根据音频URL从本地获取音频资源。同时将该音频缓存到本地
let audio = new Audio(tryCachedObject(audioUrl)); //【缓存貌似可以删除】
//播放音频后监听音频结束事件,并在音频播放结束时将音频元素从 DOM 中移除
audio.play();
audio.addEventListener("ended", function () {
this.remove();
});
};
function animateBabara() {
let id = null;
const random = Math.floor(Math.random() * 6) + 1; //1-6GIF
const elem = document.createElement("img");
elem.src = tryCachedObject(`img/animation/${random}.gif`);
//下面根据不同的窗口改变可莉动画的样式(响应式)
const screenWidth = window.innerWidth;
if (screenWidth > 768) {
elem.style.position = "absolute";
elem.style.right = "-500px";
elem.style.top = counterButton.getClientRects()[0].bottom + scrollY - 430 + "px"
elem.style.zIndex = "-10";
document.body.appendChild(elem);
let pos = -500;
const limit = window.innerWidth + 500;
clearInterval(id);
id = setInterval(() => {
if (pos >= limit) {
clearInterval(id);
elem.remove()
} else {
pos += 20;
elem.style.right = pos + 'px';
}
}, 12);
} else {
//移动端,把动画变小、变慢一点
elem.style.position = "absolute";
elem.style.right = "-500px";
elem.style.top = counterButton.getClientRects()[0].bottom + scrollY - 180 + "px"
elem.style.zIndex = "-10";
elem.style.width = "250px"; // 设置宽度为 200px(让移动端方便观看)
elem.style.height = "auto"; // 自动计算高度,保持纵横比
document.body.appendChild(elem);
let pos = -500;
const limit = window.innerWidth + 500;
clearInterval(id);
id = setInterval(() => {
if (pos >= limit) {
clearInterval(id);
elem.remove()
} else {
pos += 10;
elem.style.right = pos + 'px';
}
}, 12);
}
};
//点击 counter-button 元素时,会在点击位置出现一个水波纹效果。
function triggerRipple(e) {
let ripple = document.createElement("span");
ripple.classList.add("ripple");
const counter_button = document.getElementById("counter-button");
counter_button.appendChild(ripple);
let x = e.clientX - e.target.offsetLeft;
let y = e.clientY - e.target.offsetTop;
ripple.style.left = `${x}px`;
ripple.style.top = `${y}px`;
setTimeout(() => {
ripple.remove();
}, 300);
};
// ==========================================【全球计数器】======================================
//算法思路:先前的项目已经实现了永久保存本地计数。接下来要实现统计全球技术:
//1.为了节省流量,规定每一分钟自动上传一次【本次点击数】(定义一个区别于 localCount 的新变量 thisTimeCount
//2.发送Ajax,发送 thisTimeCount 服务端返回 globalCount渲染到页面,同时将本地的 thisTimeCount 清零
var thisTimeCounts = 0; //本次轮询Ajax之前的点击数
var intervalID = setInterval(updateGlobalCount, 15000);//间隔多久上传一次,单位ms
//点击一次按钮,thisTimeCount++
$(document).ready(function () {
$('#counter-button').click(function () {
thisTimeCounts++ //本次定时轮询Ajax之前的点击数 +1
});
});
//上传数据
function updateGlobalCount() {
$.ajax({
url: './babara.php',
method: 'POST',
async: false,
data: { localcount: thisTimeCounts },
success: function(response) {
// 处理成功响应
console.log(response);
thisTimeCounts = 0;
$('#local-counter').text(localCount);
},
error: function(error) {
// 处理错误响应
console.error("请求失败: " + error);
}
});
}
//首次访问网站的时候,立即获取 globalCounts并刷新 (页面加载完成后立即执行)
document.addEventListener("DOMContentLoaded", function () {
$.ajax({
url: './babara.php',
method: 'GET',
dataType: 'json',
headers: {
'ajax-requests': 'true'
},
/*data: {
thistimecountFromFront: thisTimeCounts, //将前端的 thisTimeCount 传给后端,参数名为 thistimecountFromFront
},*/
success: function (response) {
var globalcount = response[0].globalcount;
//console.log(response);
console.log("初始化成功,globalcountsFromBackend = " + globalcount)
var globalCountElement = document.getElementById("global-counter");
globalCountElement.textContent = (globalcount).toLocaleString('en-US')
},
error: function (error) {
console.log(error);
}
});
});
// 定时轮询后端获取 globalCounts
setInterval(function () {
$.ajax({
url: './babara.php',
method: 'GET',
dataType: 'json',
headers: {
'ajax-requests': 'true'
},
//type: 'text',
/*data: {
thistimecountFromFront: thisTimeCounts, //将前端的 thisTimeCount 传给后端,参数名为 thistimecountFromFront
},*/
success: function (response) {
var globalcount = response[0].globalcount;
console.log("前端收到了后端返回的全球计数 = " + globalcount)
//thisTimeCounts = 0; //将前端本地点击数清零
var globalCountElement = document.getElementById("global-counter"); //获取全球计数器DOM
globalCountElement.textContent = (globalcount).toLocaleString('en-US') //更新全球计数器的值
},
error: function (error) {
console.log(error);
}
});
}, 5000); // 每5s执行一次
+479
View File
@@ -0,0 +1,479 @@
* {
margin: 0;
padding: 0;
/* disable double_tap zoom on mobile devices */
-ms-touch-action: manipulation;
touch-action: manipulation;
/* strange margin-right occurs when vw<500px */
overflow-x: hidden;
}
body {
/* 底部颜色 */
background-color: rgba(233, 233, 233);
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI Adjusted", "Segoe UI", "Liberation Sans", 'Roboto', sans-serif;
font-size: 1.5em;
/* 顶部文字颜色 */
color: #2c5f74;
/* 禁用右键和选中 */
-webkit-user-select: none;
/* Chrome, Safari, Opera */
-moz-user-select: none;
/* Firefox */
-ms-user-select: none;
/* Internet Explorer/Edge */
user-select: none;
}
/* 欢迎页面 */
#welcome-page {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(36, 110, 194, 0.8);
color: rgb(255, 254, 254);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
z-index: 9999;
opacity: 1;
transition: opacity 0.5s;
}
#welcome-page img {
width: 30%;
}
/* 功能区大盒子 */
.buttons-container {
position: fixed;
top: 20px;
left: 20px;
display: flex;
align-items: center;
z-index: 8888;
}
/* 播放按钮 */
.volume-control {
width: 40px;
height: 40px;
background-color: rgba(241, 243, 244, 0.6);
border-radius: 50%;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
/* 按钮和右边按钮间隔20px */
margin-right: 20px;
}
.volume-control:hover {
background-color: #e5e2e2;
}
.volume-icon {
width: 24px;
height: 24px;
background-image: url("./img/volume_icon.png");
background-size: cover;
animation: rotate-icon 5s infinite linear;
}
@keyframes rotate-icon {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
.wrapper {
position: relative;
}
#wrapper-background {
position: absolute;
width: 100%;
height: 100%;
background-image: url("img/background.gif");
background-repeat: no-repeat;
background-position: 50%;
background-size: contain;
z-index: -30;
}
#wrapper-background-filter {
/* 背景颜色 */
background-color: rgba(66, 156, 208, 0.9);
position: absolute;
width: 100%;
height: 100%;
z-index: -20;
}
.preload {
position: absolute;
left: 0;
top: 0;
visibility: hidden;
}
#content {
margin: 2vh auto;
width: 80vw;
}
h1 {
text-align: center;
font-size: 3em;
font-weight: bold;
}
h2 {
text-align: center;
font-weight: bold;
font-size: 1.5em;
}
hr {
/* 分割线 */
border-bottom: 6px dashed rgb(227, 226, 223);
border-top: none;
border-left: none;
border-right: none;
}
#title-container {
display: flex;
justify-content: center;
}
#page-title {
text-align: left;
}
/* logo */
#title-img {
height: 3.8em;
}
@keyframes shake {
0% {
transform: rotate(-5deg);
}
50% {
transform: rotate(5deg);
}
100% {
transform: rotate(-5deg);
}
}
.shake {
animation: shake 1s linear infinite;
}
#container {
display: flex;
justify-content: center;
align-items: center;
margin-top: 20px;
margin-bottom: 10px;
text-align: center;
}
#container select {
margin: 0 10px;
}
#language-selector,
#mode-selector {
width: 200px;
height: 40px;
/* 选择框颜色 */
background-color: #dee6eb;
border: none;
border-radius: 5px;
font-size: 16px;
text-align: center;
text-align-last: center;
padding: 10px;
margin: 0 10px;
color: rgb(38, 36, 36);
appearance: none;
-webkit-appearance: none;
-moz-appearance: none;
cursor: pointer;
outline: none;
}
#language-selector:hover,
#mode-selector:hover {
box-shadow: 0 0 10px #dee6eb;
}
#language-selector option {
text-align: center;
background-color: #dee6eb;
color: rgb(118, 114, 114);
}
#subtitle-seperator {
margin-bottom: 10px;
}
#counter-container {
text-align: center;
font-weight: bold;
margin: 64px 0;
}
#counter-container>p {
text-shadow: #dee6eb 0 0 10px, #dee6eb 0 0 10px, #dee6eb 0 0 10px, #dee6eb 0 0 10px, #dee6eb 0 0 10px;
}
/* 全球计数器文字颜色 */
#global-counter {
color: #2d9cd7;
font-size: 4em;
text-shadow:
-1px -1px 0 black,
1px -1px 0 black,
-1px 1px 0 black,
1px 1px 0 black; /* 描边效果 */
}
/* 本地计数器文字颜色 */
#local-counter {
color: #2d9cd7;
font-size: 1.5em;
}
#counter-button {
/* 动画触发按钮颜色 */
background-color: #19457e;
border: none;
border-radius: 16px;
color: rgb(203, 213, 222);
padding: 16px 32px;
text-decoration: none;
font-size: 1em;
font-family: 'Roboto', sans-serif;
font-weight: bold;
margin-top: 16px;
position: relative;
overflow: hidden;
box-shadow: 6px 7px 40px -4px rgba(43, 42, 42, 0.2);
cursor: pointer;
transition: background-color 0.1s ease-in-out, scale 0.1s cubic-bezier(0.075, 0.82, 0.165, 1);
}
/* 动画触发按钮的悬挂颜色 */
#counter-button:hover {
background-color: #10305d;
}
#counter-button:active {
scale: 0.95;
}
#counter-button span {
position: absolute;
border-radius: 50%;
background-color: #ffffff50;
width: 100px;
height: 100px;
margin-top: -50px;
margin-left: -50px;
animation: ripple 1s;
opacity: 0;
}
@keyframes ripple {
from {
opacity: 1;
transform: scale(0);
}
to {
opacity: 0;
transform: scale(10);
}
}
#footer {
background-color: rgb(253, 250, 244);
color: black;
padding: 16px 10vw;
display: flex;
gap: 30px;
align-items: center;
justify-content: center;
}
/* babara banner 图片样式 */
#babara-card {
min-width: 256px;
max-width: 720px;
height: auto;
border-top-left-radius: 2% 3.5%;
border-top-right-radius: 2% 3.5%;
border-bottom-left-radius: 2% 3.5%;
border-bottom-right-radius: 2% 3.5%;
}
.footer-icon {
display: inline-block;
vertical-align: middle;
font-size: 2em;
}
#twitter-footer-icon {
color: #1d9bf0;
}
#github-footer-icon {
color: #000000;
}
.footer-icon-text {
display: inline-block;
vertical-align: middle;
font-weight: bold;
margin-left: 6px;
}
/* #footer-repository-text {
margin-top: 32px;
margin-bottom: 16px;
} */
@media screen and (max-width: 2240px) {
.grid-item {
width: calc(20% - 10px);
}
}
@media screen and (max-width: 1920px) {
.grid-item {
width: calc(25% - 10px);
}
}
@media screen and (max-width: 1512px) {
body {
font-size: 1.25em;
}
#subtitle-seperator {
margin-top: 3px;
margin-bottom: 11px;
}
}
@media screen and (max-width: 1280px) {
.grid-item {
width: calc(100% / 3 - 10px);
}
#footer {
flex-wrap: wrap;
}
#footer-text {
text-align: center;
}
#footer-header-text {
margin-bottom: 8px;
}
#footer-repository-text {
margin-top: 16px;
margin-bottom: 8px;
}
}
@media screen and (max-width: 1265px) {
body {
font-size: 1em;
}
#subtitle-seperator {
margin-top: 6px;
margin-bottom: 12px;
}
}
@media screen and (max-width: 854px) {
.grid-item {
width: calc(20% - 10px);
}
}
@media screen and (max-width: 510px) {
h1 {
font-size: 2.5em;
}
h2 {
font-size: 1.25em;
}
#subtitle-seperator {
margin-top: 8px;
margin-bottom: 13px;
}
}
@media screen and (max-width: 500px) {
.grid-item {
width: calc(100% - 10px);
}
}
@media screen and (max-width: 430px) {
h1 {
font-size: 2em;
}
#subtitle-seperator {
margin-top: 10px;
}
}
#access-via-mirror,
#access-via-pages {
font-size: small;
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 294 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 146 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 155 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 226 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 146 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 127 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 156 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 156 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 252 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 252 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 226 KiB

+5
View File
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+131
View File
@@ -0,0 +1,131 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title id="doc-title">❤Duang~</title><!--change-->
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
<link rel="stylesheet" href="./doristyle.css" type="text/css" /><!--change-->
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<script src="https://code.iconify.design/iconify-icon/1.0.2/iconify-icon.min.js"></script>
<link href="img/favicon.ico" rel="shortcut icon">
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
</head>
<body>
<div id="welcome-page">
<h2>Click to Continue</h2>
<br />
<img src="./img/welcome.gif">
</div>
<!--功能区-->
<div class="buttons-container">
<!-- 音乐播放按钮-->
<div id="volume-control" class="volume-control">
<i id="volume-icon" class="volume-icon"></i>
</div>
</div>
<!--主体部分 | Main page-->
<main class="wrapper">
<div id="wrapper-background-filter"></div>
<div id="wrapper-background"></div>
<img src="img/background.gif" class="preload" />
<div id="content">
<div id="title-container">
<h1 id="page-title">Welcome to DORI's Duang~ &nbsp;</h1>
<img id="title-img" alt="img of Kirara" class="shake" src="img/favicon.png">
</div>
<div id="container">
<select id="language-selector">
<option id="lan1" value="cn" selected>Chinese</option>
<option id="lan2" value="ja">Japanese</option>
<option id="lan3" value="en">English</option>
</select>
<select id="mode-selector">
<option id="mode1">Default</option>
<option id="mode2">Just Duang</option>
<!-- <option id="mode3">Easter egg</option> -->
</select>
</div>
<hr id="subtitle-seperator" />
<h2 id="page-descriptions">
The website for Dori, the <del>moral</del> profiteering Genshin
Impact merchant out there.
</h2>
<div id="counter-container">
<h3 id="counter-descriptions">Dori has been Duang~ed for</h3>
<br />
<br />
<p id="global-counter">0</p>
<p id="local-counter">0</p>
<br />
<br />
<button id="counter-button">
Let Dori Duang~!
</button>
</div>
<hr />
<div id="grid">
<noscript>Your browser does not support JavaScript or JavaScript has been
disabled.<br />This website relies on JavaScript, so please enable it
or use another browser.</noscript>
</div>
</div>
</main>
<!-- 尾部部分 | Footer -->
<div id="footer">
<img id="dori-card" loading="lazy" src="" alt="" /> <!--由JS控制src的具体路径-->
<div id="footer-text">
<p id="footer-repository-text">
You can check out the Gitee repository here:
</p>
<p>
<!--这里填写本网站的Github地址-->
<a href="https://gitee.com/KleeGitee/Klee" target="_blank">
<span class="footer-icon-text"
id="footer-repository-text-2">Web_OF_Genshin (Gitee)</span></a>
</p>
<br/>
<p id="footer-repository-text3">
This website is based on the repository source code changes
</p>
<p>
<!--source code-->
<a href="https://github.com/duiqt/herta_kuru" target="_blank"><iconify-icon icon="mdi:github" id="github-footer-icon"
class="footer-icon"></iconify-icon><span class="footer-icon-text"
id="footer-repository-text-4">SourceCode's repository</span></a>
</p>
<br/>
<p id="credits-gif">Dori gif made by</p>
<p>
<a href="https://twitter.com/Seseren_kr" target="_blank"><iconify-icon icon="mdi:twitter"
id="twitter-footer-icon" class="footer-icon"></iconify-icon><span
class="footer-icon-text">@Seseren_kr</span></a>
</p>
</div>
</div>
<script src="./doriscript.js" async></script>
</body>
</html>
+62
View File
@@ -0,0 +1,62 @@
<?php
//加载数据库信息
require_once('../config.php');
// 创建连接
$conn = new mysqli($servername, $username, $password, $dbname);
// 连接成功,可以进行数据库操作
$sql = "SELECT globalcount FROM ys WHERE name = 'dori'";
// 执行查询
$result = $conn->query($sql);
if ($_SERVER["REQUEST_METHOD"] === "POST") {
// 处理 POST 请求
//接收前端数据
$localcount = $_POST["localcount"];
//检查查询结果
if ($result->num_rows > 0) {
$row = $result->fetch_assoc();
$globalCount = $row['globalcount'];
// 将本地计数值加给全局计数
$globalCount += $localcount;
// 更新数据库中的全局计数值
$updateSql = "UPDATE ys SET globalcount = $globalCount WHERE name = 'dori';";
if ($conn->query($updateSql) === TRUE) {
// 更新成功
echo "更新成功";
} else {
// 更新失败
echo "更新失败: " . $conn->error;
}
} else {
// 没有找到全局计数值
echo "没有找到全局计数值";
}
// 返回响应
//echo "这是 POST 请求的响应";
} elseif ($_SERVER["REQUEST_METHOD"] === "GET") {
// 处理 GET 请求
if ($result->num_rows > 0) {
// 有数据返回
$rows = array();
while ($row = $result->fetch_assoc()) {
$rows[] = $row;
}
// 将查询结果转换为 JSON 格式发送回前端
echo json_encode($rows);
} else {
// 无数据返回
echo "没有数据";
}
// 返回响应
//echo "这是 GET 请求的响应";
} else {
// 不支持其他请求方法
http_response_code(405); // 返回“Method Not Allowed”状态码
echo "不支持的请求方法";
}
?>
+626
View File
@@ -0,0 +1,626 @@
// 禁用右键菜单
document.addEventListener('contextmenu', function (event) {
event.preventDefault();
});
//图片摇摆
const img = document.getElementById('title-img');
// 定期执行动画
setInterval(() => {
// 添加 CSS 类来触发动画
img.classList.add('shake');
// 设置一个定时器,在一段时间后移除 CSS 类停止动画
setTimeout(() => {
img.classList.remove('shake');
}, 2500); // 动画持续时间为 2.5 秒
}, 5000); // 每隔 5 秒执行一次动画
//=================================================================【BGM】=============================================================
// 欢迎页面淡出控制,音乐控制
var isMusicPlayed = false; // 记录音乐是否已经播放
var isWelcomed = false; //记录您是否已离开欢迎页面
var BGM = new Audio("./music/Thanks for Your Patronage! - HOYO-MiX.mp3"); //BGM
document.addEventListener("click", function (event) {
if (!isWelcomed) {
removeWelcomePageAndPlayMusic();
}
});
function removeWelcomePageAndPlayMusic() {
var welcomePage = document.getElementById("welcome-page");
welcomePage.style.opacity = 0;
setTimeout(function () {
welcomePage.style.display = "none";
}, 500);
if (!isMusicPlayed && !isWelcomed) {
playBackgroundMusic();
isMusicPlayed = true;
isWelcomed = true;
}
}
function playBackgroundMusic() {
BGM.loop = true; // 循环播放
BGM.play(); // 播放BGM
BGM.volume = 0.1;
}
//音乐播放控制
var volumeControl = document.getElementById("volume-control");
var volumeIcon = document.getElementById("volume-icon");
//音乐暂停和播放逻辑
volumeControl.addEventListener("click", function () {
if (!isMusicPlayed) {
// Play music
BGM.play();
volumeIcon.style.animationPlayState = "running";
isMusicPlayed = true;
} else {
// Pause music
BGM.pause();
volumeIcon.style.animationPlayState = "paused";
isMusicPlayed = false;
}
});
// ===================================================【多语言支持】============================================
var audioList = []; // 角色音频
let firstSquish = true; //第一次点击
//多语言支持
//语言属性数组
const LANGUAGES = {
//默认
"_": { fallbackLanguage: "cn" },
//中文语音、文本、海报
"cn": {
audioList: [
//0-7:默认模式 mode1
"audio/CN_voice/Duang.mp3",
"audio/CN_voice/嘿哟.mp3",
"audio/CN_voice/看我哒.mp3",
"audio/CN_voice/啦啦啦.mp3",
"audio/CN_voice/留下摩拉来.mp3",
"audio/CN_voice/魔灯显灵.mp3",
"audio/CN_voice/想午睡吗.mp3",
"audio/CN_voice/早安.mp3",
],
texts: {
"page-title": "多莉 Duang~",
"doc-title": "摩拉爱我,我爱摩拉~",
"page-descriptions": "给多莉酱写的小网站,对,就是那个<del>良心的</del>奸商的《原神》商人!",
"counter-descriptions": ["多莉已经Duang了~", "多莉已经赚了~摩拉"],
"counter-button": ["Duang~", "+1¥"],
"credits-gif": "鸣谢:Seseren_kr提供的多莉GIF图片",
"footer-repository-text": "本网站的Gitee仓库在这儿:",
"footer-repository-text-2": "原神主题网站代码仓库",
"footer-repository-text3": "鸣谢:duiqt提供的本网站基础源代码",
"footer-repository-text-4": "Herta_kuru"
},
cardImage: "img/banner_cn.jpg"
},
//日文语音、文本、海报
"ja": {
audioList: [
//0-7:默认模式 mode1
"audio/CN_voice/Duang.mp3",
"audio/CN_voice/嘿哟.mp3",
"audio/CN_voice/看我哒.mp3",
"audio/CN_voice/啦啦啦.mp3",
"audio/CN_voice/留下摩拉来.mp3",
"audio/CN_voice/魔灯显灵.mp3",
"audio/CN_voice/想午睡吗.mp3",
"audio/CN_voice/早安.mp3",
],
texts: {
"page-title": "ドリーDuang",
"doc-title": "Duang~",
"page-descriptions": "このサイトはドリーのために作られた、 あの原神の <del>良心的</del> あくとく商人です",
"counter-descriptions": "Duang-数",
"counter-button": "+1$",
"credits-gif": "感謝: Seseren_kr さんが提供してくれたドリーのGIF画像",
"footer-repository-text": "こちらはこのページGitee (Mainland China) リポジトリ:",
"footer-repository-text-2": "原神主题网站代码仓库",
"footer-repository-text3": "感謝:duiqt さんが提供してくれたこのウェブサイトの基礎ソースコード",
"footer-repository-text-4": "Herta_kuru"
},
cardImage: "img/banner_jp.jpg"
},
//英文语音、文本、海报
"en": {
audioList: [
//0-7:默认模式 mode1
"audio/CN_voice/Duang.mp3",
"audio/CN_voice/嘿哟.mp3",
"audio/CN_voice/看我哒.mp3",
"audio/CN_voice/啦啦啦.mp3",
"audio/CN_voice/留下摩拉来.mp3",
"audio/CN_voice/魔灯显灵.mp3",
"audio/CN_voice/想午睡吗.mp3",
"audio/CN_voice/早安.mp3",
],
texts: {
"page-title": "Welcome to DORI's Duang~",
"doc-title": "Duang~",
"page-descriptions": "The website for Dori, the <del>moral</del> profiteering Genshin Impact merchant out there.",
"counter-descriptions": "Dori has been Duang~ed for",
"counter-button": "Duang~",
"credits-gif": "Acknowledgment: GIF images of Dori provided by Seseren_kr.",
"footer-repository-text": "You can check out the Gitee repository (Mainland China) here:",
"footer-repository-text-2": "原神主题网站代码仓库",
"footer-repository-text3": "Special thanks to duiqt for providing the source code for this website.",
"footer-repository-text-4": "Herta_kuru"
},
cardImage: "img/banner_en.jpg"
}
};
//设置语言选择器的文本语言
function refreshLanguageSelector(selectedLanguage) {
switch (selectedLanguage) {
case "cn":
document.getElementById("lan1").innerHTML = "🌏中文";
document.getElementById("lan2").innerHTML = "日文";
document.getElementById("lan3").innerHTML = "英文";
break;
case "ja":
document.getElementById("lan1").innerHTML = "中国語";
document.getElementById("lan2").innerHTML = "🌏日本語";
document.getElementById("lan3").innerHTML = "英語";
break;
case "en":
document.getElementById("lan1").innerHTML = "Chinese";
document.getElementById("lan2").innerHTML = "Japanese";
document.getElementById("lan3").innerHTML = "🌏English";
break;
default:
break;
}
}
//设置模式选择器的文本语言
function refreshModeSelector(selectedLanguage) {
switch (selectedLanguage) {
case "cn":
document.getElementById("mode1").innerHTML = "默认模式";
document.getElementById("mode2").innerHTML = "只要Duang~";
// document.getElementById("mode3").innerHTML = "隐藏彩蛋";
break;
case "ja":
document.getElementById("mode1").innerHTML = "デフォルトモード";
document.getElementById("mode2").innerHTML = "Duang~だけ";
// document.getElementById("mode3").innerHTML = "ひみつ";
break;
case "en":
document.getElementById("mode1").innerHTML = "DefaultMode";
document.getElementById("mode2").innerHTML = "Just Duang";
// document.getElementById("mode3").innerHTML = "Easter egg";
break;
default:
break;
}
}
//获取默认语言并赋值给语言选择框
var current_language = localStorage.getItem("lang") || "cn";
if (current_language != "cn") {
document.getElementById("language-selector").value = current_language;
};
//通过获取当前语言和对应的文本数组,遍历文本数组中的每个键值对。如果文本值是一个数组,就从数组中随机选择一个元素作为新的文本内容,并将其更新到对应的 HTML 元素中
function randomChoice(myArr) {
const randomIndex = Math.floor(Math.random() * myArr.length);
const randomItem = myArr[randomIndex];
return randomItem;
};
//核心函数!动态刷新动态文本内容(将新的DOM值渲染到前端)
function refreshDynamicTexts() {
let curLang = LANGUAGES[current_language];
let localTexts = curLang.texts;
Object.entries(localTexts).forEach(([textId, value]) => {
if (value instanceof Array)
if (document.getElementById(textId) != undefined)
document.getElementById(textId).innerHTML = randomChoice(value);
});
};
//定义函数:根据当前语言,渲染页面
function multiLangMutation() {
let curLang = LANGUAGES[current_language]; //获取当前的网站语言
let localTexts = curLang.texts; //获取当前语言的文本数组
Object.entries(localTexts).forEach(([textId, value]) => { //将各个DOM元素的值变为文本值
if (!(value instanceof Array))
if (document.getElementById(textId) != undefined)
document.getElementById(textId).innerHTML = value;
});
refreshDynamicTexts() //刷新动态文本内容(将新的DOM值渲染到前端)
document.getElementById("dori-card").src = curLang.cardImage; //动态获取klee-card在当前语言文本环境下的Dom元素并更新
var selectedLanguage = document.getElementById("language-selector").value;
refreshLanguageSelector(selectedLanguage) //更新语言选择器的文本语言
refreshModeSelector(selectedLanguage) //更新模式选择器的文本语言
};
/*
curLang 变量获取了当前选择的网站语言对应的语言对象(假设为 LANGUAGES 全局对象中的一个属性)。
localTexts 变量获取了当前语言对象中的文本数组。
使用 Object.entries() 方法遍历 localTexts 中的键值对。
对于每一个键值对,解构赋值为 [textId, value],其中 textId 是 DOM 元素的 IDvalue 是对应的文本值。
首先检查 value 是否为数组,如果不是数组,表示是单个文本值(例如字符串)。
检查当前网页是否存在具有对应 textId 的 DOM 元素(通过 document.getElementById(textId) 来判断)。
如果存在对应的 DOM 元素,则将其内部的 HTML 内容更新为 value。
这样就实现了根据当前语言选择动态更新网页中的文本内容。
*/
multiLangMutation() //初始化网站语言
//通过这段代码,当语言选择器的值发生变化时,会根据选择的语言重新渲染页面的文本内容和动态图片,实现动态调整网站语言的功能。
document.getElementById("language-selector").addEventListener("change", (ev) => {
current_language = ev.target.value;
localStorage.setItem("lang", ev.target.value);
multiLangMutation();
});
//=======================================================================【按钮点击、计数器】============================================
// 初始化计数器
//本地计数器
const localCounter = document.querySelector('#local-counter'); //获取展示本地点击数的DOM元素
let localCount = localStorage.getItem('count-local-dori') || 0; //获取本地点击数的值
localCounter.textContent = localCount.toLocaleString('en-US'); //使用美式英语的格式进行格式化。这样可以确保数值以适当的方式显示,例如添加千位分隔符
let prevTime = 0;
//获取时间戳
const getTimestamp = () => Date.parse(new Date());
//点击duang的按钮事件
const counterButton = document.querySelector('#counter-button');
counterButton.addEventListener('click', (e) => {
prevTime = getTimestamp(); //当前时间
localCount++;
localStorage.setItem('count-local-dori', localCount); //缓存localCount到本地
localCounter.textContent = localCount.toLocaleString('en-US');
triggerRipple(e); //按钮的水波纹效果
playDuang(); //播放可莉语音
animateDori(); //播放可莉动画
});
//===================================================================【资源缓存】========================================================
var cachedObjects = {};
function tryCachedObject(origUrl) {
// 检查对象是否已经被缓存
if (cachedObjects[origUrl]) {
return cachedObjects[origUrl];
} else {
// 开始缓存
fetch(origUrl)
.then((response) => response.blob())
.then((blob) => {
// 为对象创建一个blob URL
const blobUrl = URL.createObjectURL(blob);
// 通过在cachedObjects对象中存储blob URL来获取缓存的对象
cachedObjects[origUrl] = blobUrl;
})
.catch((error) => {
console.error(`Error caching object from ${origUrl}: ${error}`);
});
return origUrl;
}
};
//缓存所有资源
function cacheAllResources() {
// 缓存图片资源
for (let i = 1; i < 3; i++) {
const imageUrl = `img/animation/${i}.gif`;
tryCachedObject(imageUrl);
}
// 缓存中文音频资源(含通用语音资源)
const cnAudioList = LANGUAGES.cn.audioList;
cnAudioList.forEach((audioUrl) => {
tryCachedObject(audioUrl);
});
// 缓存日文音频资源(含通用语音资源)
const jaAudioList = LANGUAGES.ja.audioList;
jaAudioList.forEach((audioUrl) => {
tryCachedObject(audioUrl);
});
//只需要执行一次该功能
firstLoadClick = false;
}
// 当页面加载完成后触发缓存资源
// var firstLoadClick = true;
// window.addEventListener('click', cacheAllResources);
//========================================================================【按钮点击后的动画、音频】================================================
//返回当前语言的音频数组
function getLocalAudioList() {
return LANGUAGES[current_language].audioList;
};
//从音频数组中获取一个随机的音频URL(传入一个当前模式。curMode==mode1 默认模式,cueMode==mode3
function getRandomAudioUrl(curMode) {
var localAudioList = getLocalAudioList()
//根据模式产生符合模式的音频下标
if (curMode == "mode1") {
randomIndex = Math.floor(Math.random() * 8); //默认语音的文件是:文件下标0-8.这儿的数字就写8.
}
// if (curMode == "mode3") {
// randomIndex = Math.floor(Math.random() * 17); //文件下标0-16.这儿的数字就写14. 【这儿写彩蛋对应的audioList下标】
// }
const randomItem = localAudioList[randomIndex];
return randomItem;
};
//播放音频
var isFirstVoice = true;
function playDuang() {
//先获取当前的模式:1-默认;2-只哒哒哒;3-彩蛋
const modeSelectElement = document.getElementById("mode-selector");
const modeSelectedOption = modeSelectElement.options[modeSelectElement.selectedIndex];
const curMode = modeSelectedOption.id;
//要播放的音频Url
let audioUrl;
//根据当前模式获取符合模式语音的 AudioURL
switch (curMode) {
//curMode==mode1 默认模式
case "mode1": {
if (isFirstVoice == true) {//随机获取一个音频的URL,第一个必定是哒哒哒
isFirstVoice = false;
audioUrl = getLocalAudioList()[0] //First play fixed Duang
} else {
audioUrl = getRandomAudioUrl(curMode);
}
}; break;
//curMode==mode2 只哒哒哒
case "mode2": {
audioUrl = getLocalAudioList()[0]
}; break;
//cueMode==mode3 彩蛋
// case "mode3": {
// if (isFirstVoice == true) {//随机获取一个音频的URL,第一个必定是哒哒哒
// isFirstVoice = false;
// audioUrl = getLocalAudioList()[1] //First play fixed Dadada
// } else {
// audioUrl = getRandomAudioUrl(curMode);
// }
// }; break;
}
//根据音频URL从本地获取音频资源。同时将该音频缓存到本地
let audio = new Audio(tryCachedObject(audioUrl)); //【缓存貌似可以删除】
//播放音频后监听音频结束事件,并在音频播放结束时将音频元素从 DOM 中移除
audio.play();
audio.addEventListener("ended", function () {
this.remove();
});
};
function animateDori() {
let id = null;
const random = Math.floor(Math.random() * 2) + 1; //1-2GIF
const elem = document.createElement("img");
elem.src = tryCachedObject(`img/animation/${random}.gif`);
//下面根据不同的窗口改变多莉动画的样式(响应式)
const screenWidth = window.innerWidth;
if (screenWidth > 768) {
elem.style.position = "absolute";
elem.style.right = "-500px";
elem.style.top = counterButton.getClientRects()[0].bottom + scrollY - 430 + "px"
elem.style.zIndex = "-10";
document.body.appendChild(elem);
let pos = -500;
const limit = window.innerWidth + 500;
clearInterval(id);
id = setInterval(() => {
if (pos >= limit) {
clearInterval(id);
elem.remove()
} else {
pos += 20;
elem.style.right = pos + 'px';
}
}, 12);
} else {
//移动端,把动画变小、变慢一点
elem.style.position = "absolute";
elem.style.right = "-500px";
elem.style.top = counterButton.getClientRects()[0].bottom + scrollY - 180 + "px"
elem.style.zIndex = "-10";
elem.style.width = "250px"; // 设置宽度为 200px(让移动端方便观看)
elem.style.height = "auto"; // 自动计算高度,保持纵横比
document.body.appendChild(elem);
let pos = -500;
const limit = window.innerWidth + 500;
clearInterval(id);
id = setInterval(() => {
if (pos >= limit) {
clearInterval(id);
elem.remove()
} else {
pos += 10;
elem.style.right = pos + 'px';
}
}, 12);
}
};
//点击 counter-button 元素时,会在点击位置出现一个水波纹效果。
function triggerRipple(e) {
let ripple = document.createElement("span");
ripple.classList.add("ripple");
const counter_button = document.getElementById("counter-button");
counter_button.appendChild(ripple);
let x = e.clientX - e.target.offsetLeft;
let y = e.clientY - e.target.offsetTop;
ripple.style.left = `${x}px`;
ripple.style.top = `${y}px`;
setTimeout(() => {
ripple.remove();
}, 300);
};
// ==========================================【全球计数器】======================================
//算法思路:先前的项目已经实现了永久保存本地计数。接下来要实现统计全球技术:
//1.为了节省流量,规定每一分钟自动上传一次【本次点击数】(定义一个区别于 localCount 的新变量 thisTimeCount
//2.发送Ajax,发送 thisTimeCount 服务端返回 globalCount渲染到页面,同时将本地的 thisTimeCount 清零
var thisTimeCounts = 0; //本次轮询Ajax之前的点击数
var intervalID = setInterval(updateGlobalCount, 15000);//间隔多久上传一次,单位ms
//点击一次按钮,thisTimeCount++
$(document).ready(function () {
$('#counter-button').click(function () {
thisTimeCounts++ //本次定时轮询Ajax之前的点击数 +1
});
});
//上传数据
function updateGlobalCount() {
$.ajax({
url: './dori.php',
method: 'POST',
async: false,
data: { localcount: thisTimeCounts },
success: function(response) {
// 处理成功响应
console.log(response);
thisTimeCounts = 0;
$('#local-counter').text(localCount);
},
error: function(error) {
// 处理错误响应
console.error("请求失败: " + error);
}
});
}
//首次访问网站的时候,立即获取 globalCounts并刷新 (页面加载完成后立即执行)
document.addEventListener("DOMContentLoaded", function () {
$.ajax({
url: './dori.php',
method: 'GET',
dataType: 'json',
headers: {
'ajax-requests': 'true'
},
/*data: {
thistimecountFromFront: thisTimeCounts, //将前端的 thisTimeCount 传给后端,参数名为 thistimecountFromFront
},*/
success: function (response) {
var globalcount = response[0].globalcount;
//console.log(response);
console.log("初始化成功,globalcountsFromBackend = " + globalcount)
var globalCountElement = document.getElementById("global-counter");
globalCountElement.textContent = (globalcount).toLocaleString('en-US')
},
error: function (error) {
console.log(error);
}
});
});
// 定时轮询后端获取 globalCounts
setInterval(function () {
$.ajax({
url: './dori.php',
method: 'GET',
dataType: 'json',
headers: {
'ajax-requests': 'true'
},
//type: 'text',
/*data: {
thistimecountFromFront: thisTimeCounts, //将前端的 thisTimeCount 传给后端,参数名为 thistimecountFromFront
},*/
success: function (response) {
var globalcount = response[0].globalcount;
console.log("前端收到了后端返回的全球计数 = " + globalcount)
//thisTimeCounts = 0; //将前端本地点击数清零
var globalCountElement = document.getElementById("global-counter"); //获取全球计数器DOM
globalCountElement.textContent = (globalcount).toLocaleString('en-US') //更新全球计数器的值
},
error: function (error) {
console.log(error);
}
});
}, 5000); // 每5s执行一次
+479
View File
@@ -0,0 +1,479 @@
* {
margin: 0;
padding: 0;
/* disable double_tap zoom on mobile devices */
-ms-touch-action: manipulation;
touch-action: manipulation;
/* strange margin-right occurs when vw<500px */
overflow-x: hidden;
}
body {
/* 底部颜色 */
background-color: rgba(233, 233, 233);
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI Adjusted", "Segoe UI", "Liberation Sans", 'Roboto', sans-serif;
font-size: 1.5em;
/* 顶部文字颜色 */
color: #441d7a;
/* 禁用右键和选中 */
-webkit-user-select: none;
/* Chrome, Safari, Opera */
-moz-user-select: none;
/* Firefox */
-ms-user-select: none;
/* Internet Explorer/Edge */
user-select: none;
}
/* 欢迎页面 */
#welcome-page {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(42, 21, 72, 0.8);
color: rgb(241, 241, 8);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
z-index: 9999;
opacity: 1;
transition: opacity 0.5s;
}
#welcome-page img {
width: 30%;
}
/* 功能区大盒子 */
.buttons-container {
position: fixed;
top: 20px;
left: 20px;
display: flex;
align-items: center;
z-index: 8888;
}
/* 播放按钮 */
.volume-control {
width: 40px;
height: 40px;
background-color: rgba(71, 13, 98, 0.5);
border-radius: 50%;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
/* 按钮和右边按钮间隔20px */
margin-right: 20px;
}
.volume-control:hover {
background-color: #e5e2e2;
}
.volume-icon {
width: 24px;
height: 24px;
background-image: url("./img/volume_icon.png");
background-size: cover;
animation: rotate-icon 5s infinite linear;
}
@keyframes rotate-icon {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
.wrapper {
position: relative;
}
#wrapper-background {
position: absolute;
width: 100%;
height: 100%;
background-image: url("img/background.gif");
background-repeat: no-repeat;
background-position: 50%;
background-size: contain;
z-index: -30;
}
#wrapper-background-filter {
/* 背景颜色 */
background-color: rgba(192, 114, 201, 0.9);
position: absolute;
width: 100%;
height: 100%;
z-index: -20;
}
.preload {
position: absolute;
left: 0;
top: 0;
visibility: hidden;
}
#content {
margin: 2vh auto;
width: 80vw;
}
h1 {
text-align: center;
font-size: 3em;
font-weight: bold;
}
h2 {
text-align: center;
font-weight: bold;
font-size: 1.5em;
}
hr {
/* 分割线 */
border-bottom: 6px dashed #f0dd4a;
border-top: none;
border-left: none;
border-right: none;
}
#title-container {
display: flex;
justify-content: center;
}
#page-title {
text-align: left;
}
/* logo */
#title-img {
height: 3.8em;
}
@keyframes shake {
0% {
transform: rotate(-5deg);
}
50% {
transform: rotate(5deg);
}
100% {
transform: rotate(-5deg);
}
}
.shake {
animation: shake 1s linear infinite;
}
#container {
display: flex;
justify-content: center;
align-items: center;
margin-top: 20px;
margin-bottom: 10px;
text-align: center;
}
#container select {
margin: 0 10px;
}
#language-selector,
#mode-selector {
width: 200px;
height: 40px;
/* 选择框颜色 */
background-color: #decc43;
border: none;
border-radius: 5px;
font-size: 16px;
text-align: center;
text-align-last: center;
padding: 10px;
margin: 0 10px;
color: rgb(38, 36, 38);
appearance: none;
-webkit-appearance: none;
-moz-appearance: none;
cursor: pointer;
outline: none;
}
#language-selector:hover,
#mode-selector:hover {
box-shadow: 0 0 10px #decc43;
}
#language-selector option {
text-align: center;
background-color: #decc43;
color: rgb(118, 114, 114);
}
#subtitle-seperator {
margin-bottom: 10px;
}
#counter-container {
text-align: center;
font-weight: bold;
margin: 64px 0;
}
#counter-container>p {
text-shadow: #decc43 0 0 10px, #decc43 0 0 10px, #decc43 0 0 10px, #decc43 0 0 10px, #decc43 0 0 10px;
}
/* 全球计数器文字颜色 */
#global-counter {
color: #7a6f0a;
font-size: 4em;
text-shadow:
-1px -1px 0 black,
1px -1px 0 black,
-1px 1px 0 black,
1px 1px 0 black; /* 描边效果 */
}
/* 本地计数器文字颜色 */
#local-counter {
color: #7a6f0a;
font-size: 1.5em;
}
#counter-button {
/* 动画触发按钮颜色 */
background-color: #c6b427;
border: none;
border-radius: 16px;
color: rgb(49, 7, 77);
padding: 16px 32px;
text-decoration: none;
font-size: 1em;
font-family: 'Roboto', sans-serif;
font-weight: bold;
margin-top: 16px;
position: relative;
overflow: hidden;
box-shadow: 6px 7px 40px -4px rgba(43, 42, 42, 0.2);
cursor: pointer;
transition: background-color 0.1s ease-in-out, scale 0.1s cubic-bezier(0.075, 0.82, 0.165, 1);
}
/* 动画触发按钮的悬挂颜色 */
#counter-button:hover {
background-color: #f0d50d;
}
#counter-button:active {
scale: 0.95;
}
#counter-button span {
position: absolute;
border-radius: 50%;
background-color: #ffffff50;
width: 100px;
height: 100px;
margin-top: -50px;
margin-left: -50px;
animation: ripple 1s;
opacity: 0;
}
@keyframes ripple {
from {
opacity: 1;
transform: scale(0);
}
to {
opacity: 0;
transform: scale(10);
}
}
#footer {
background-color: rgb(253, 250, 244);
color: black;
padding: 16px 10vw;
display: flex;
gap: 30px;
align-items: center;
justify-content: center;
}
/* dori banner 图片样式 */
#dori-card {
min-width: 256px;
max-width: 720px;
height: auto;
border-top-left-radius: 2% 3.5%;
border-top-right-radius: 2% 3.5%;
border-bottom-left-radius: 2% 3.5%;
border-bottom-right-radius: 2% 3.5%;
}
.footer-icon {
display: inline-block;
vertical-align: middle;
font-size: 2em;
}
#twitter-footer-icon {
color: #1d9bf0;
}
#github-footer-icon {
color: #000000;
}
.footer-icon-text {
display: inline-block;
vertical-align: middle;
font-weight: bold;
margin-left: 6px;
}
/* #footer-repository-text {
margin-top: 32px;
margin-bottom: 16px;
} */
@media screen and (max-width: 2240px) {
.grid-item {
width: calc(20% - 10px);
}
}
@media screen and (max-width: 1920px) {
.grid-item {
width: calc(25% - 10px);
}
}
@media screen and (max-width: 1512px) {
body {
font-size: 1.25em;
}
#subtitle-seperator {
margin-top: 3px;
margin-bottom: 11px;
}
}
@media screen and (max-width: 1280px) {
.grid-item {
width: calc(100% / 3 - 10px);
}
#footer {
flex-wrap: wrap;
}
#footer-text {
text-align: center;
}
#footer-header-text {
margin-bottom: 8px;
}
#footer-repository-text {
margin-top: 16px;
margin-bottom: 8px;
}
}
@media screen and (max-width: 1265px) {
body {
font-size: 1em;
}
#subtitle-seperator {
margin-top: 6px;
margin-bottom: 12px;
}
}
@media screen and (max-width: 854px) {
.grid-item {
width: calc(20% - 10px);
}
}
@media screen and (max-width: 510px) {
h1 {
font-size: 2.5em;
}
h2 {
font-size: 1.25em;
}
#subtitle-seperator {
margin-top: 8px;
margin-bottom: 13px;
}
}
@media screen and (max-width: 500px) {
.grid-item {
width: calc(100% - 10px);
}
}
@media screen and (max-width: 430px) {
h1 {
font-size: 2em;
}
#subtitle-seperator {
margin-top: 10px;
}
}
#access-via-mirror,
#access-via-pages {
font-size: small;
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 143 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 147 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 147 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 147 KiB

+5
View File
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 247 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 247 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 159 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 163 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 157 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 KiB

+131
View File
@@ -0,0 +1,131 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title id="doc-title">Miaouuuu~</title><!--change-->
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
<link rel="stylesheet" href="kirarastyle.css" type="text/css" /><!--change-->
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<script src="https://code.iconify.design/iconify-icon/1.0.2/iconify-icon.min.js"></script>
<link href="img/favicon.ico" rel="shortcut icon">
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
</head>
<body>
<div id="welcome-page">
<h2>Click to Continue</h2>
<br />
<img src="./img/welcome.gif">
</div>
<!--功能区-->
<div class="buttons-container">
<!-- 音乐播放按钮-->
<div id="volume-control" class="volume-control">
<i id="volume-icon" class="volume-icon"></i>
</div>
</div>
<!--主体部分 | Main page-->
<main class="wrapper">
<div id="wrapper-background-filter"></div>
<div id="wrapper-background"></div>
<img src="img/background.gif" class="preload" />
<div id="content">
<div id="title-container">
<h1 id="page-title">Welcome to Kirara Miaouu~ &nbsp;</h1>
<img id="title-img" alt="img of Kirara" class="shake" src="img/favicon.png">
</div>
<div id="container">
<select id="language-selector">
<option id="lan1" value="cn" selected>Chinese</option>
<option id="lan2" value="ja">Japanese</option>
<option id="lan3" value="en">English</option>
</select>
<select id="mode-selector">
<option id="mode1">Default</option>
<!-- <option id="mode2">Just Dadada</option>
<option id="mode3">Easter egg</option> -->
</select>
</div>
<hr id="subtitle-seperator" />
<h2 id="page-descriptions">
The website for Kirara, the <del>annoying</del> cutest genius Genshin
Impact Cat out there.
</h2>
<div id="counter-container">
<h3 id="counter-descriptions">Kirara has been miaow~ed for</h3>
<br />
<br />
<p id="global-counter">0</p>
<p id="local-counter">0</p>
<br />
<br />
<button id="counter-button">
Let Kirara miaows~!
</button>
</div>
<hr />
<div id="grid">
<noscript>Your browser does not support JavaScript or JavaScript has been
disabled.<br />This website relies on JavaScript, so please enable it
or use another browser.</noscript>
</div>
</div>
</main>
<!-- 尾部部分 | Footer -->
<div id="footer">
<img id="kirara-card" loading="lazy" src="" alt="" /> <!--由JS控制src的具体路径-->
<div id="footer-text">
<p id="footer-repository-text">
You can check out the Gitee repository here:
</p>
<p>
<!--这里填写本网站的Github地址-->
<a href="https://gitee.com/KleeGitee/Klee" target="_blank">
<span class="footer-icon-text"
id="footer-repository-text-2">Web_OF_Genshin (Gitee)</span></a>
</p>
<br/>
<p id="footer-repository-text3">
This website is based on the repository source code changes
</p>
<p>
<!--source code-->
<a href="https://github.com/duiqt/herta_kuru" target="_blank"><iconify-icon icon="mdi:github" id="github-footer-icon"
class="footer-icon"></iconify-icon><span class="footer-icon-text"
id="footer-repository-text-4">SourceCode's repository</span></a>
</p>
<br/>
<p id="credits-gif">Kirara gif made by</p>
<p>
<a href="https://twitter.com/Seseren_kr" target="_blank"><iconify-icon icon="mdi:twitter"
id="twitter-footer-icon" class="footer-icon"></iconify-icon><span
class="footer-icon-text">@Seseren_kr</span></a>
</p>
</div>
</div>
<script src="./kirarascript.js" async></script>
</body>
</html>
+62
View File
@@ -0,0 +1,62 @@
<?php
//加载数据库信息
require_once('../config.php');
// 创建连接
$conn = new mysqli($servername, $username, $password, $dbname);
// 连接成功,可以进行数据库操作
$sql = "SELECT globalcount FROM ys WHERE name = 'kirara'";
// 执行查询
$result = $conn->query($sql);
if ($_SERVER["REQUEST_METHOD"] === "POST") {
// 处理 POST 请求
//接收前端数据
$localcount = $_POST["localcount"];
//检查查询结果
if ($result->num_rows > 0) {
$row = $result->fetch_assoc();
$globalCount = $row['globalcount'];
// 将本地计数值加给全局计数
$globalCount += $localcount;
// 更新数据库中的全局计数值
$updateSql = "UPDATE ys SET globalcount = $globalCount WHERE name = 'kirara';";
if ($conn->query($updateSql) === TRUE) {
// 更新成功
echo "更新成功";
} else {
// 更新失败
echo "更新失败: " . $conn->error;
}
} else {
// 没有找到全局计数值
echo "没有找到全局计数值";
}
// 返回响应
//echo "这是 POST 请求的响应";
} elseif ($_SERVER["REQUEST_METHOD"] === "GET") {
// 处理 GET 请求
if ($result->num_rows > 0) {
// 有数据返回
$rows = array();
while ($row = $result->fetch_assoc()) {
$rows[] = $row;
}
// 将查询结果转换为 JSON 格式发送回前端
echo json_encode($rows);
} else {
// 无数据返回
echo "没有数据";
}
// 返回响应
//echo "这是 GET 请求的响应";
} else {
// 不支持其他请求方法
http_response_code(405); // 返回“Method Not Allowed”状态码
echo "不支持的请求方法";
}
?>
+620
View File
@@ -0,0 +1,620 @@
// 禁用右键菜单
document.addEventListener('contextmenu', function (event) {
event.preventDefault();
});
//图片摇摆
const img = document.getElementById('title-img');
// 定期执行动画
setInterval(() => {
// 添加 CSS 类来触发动画
img.classList.add('shake');
// 设置一个定时器,在一段时间后移除 CSS 类停止动画
setTimeout(() => {
img.classList.remove('shake');
}, 2500); // 动画持续时间为 2.5 秒
}, 5000); // 每隔 5 秒执行一次动画
//=================================================================【BGM】=============================================================
// 欢迎页面淡出控制,音乐控制
var isMusicPlayed = false; // 记录音乐是否已经播放
var isWelcomed = false; //记录您是否已离开欢迎页面
var BGM = new Audio("./music/彩虹猫 (Remix) - soul light-LHPT.mp3"); //BGM
document.addEventListener("click", function (event) {
if (!isWelcomed) {
removeWelcomePageAndPlayMusic();
}
});
function removeWelcomePageAndPlayMusic() {
var welcomePage = document.getElementById("welcome-page");
welcomePage.style.opacity = 0;
setTimeout(function () {
welcomePage.style.display = "none";
}, 500);
if (!isMusicPlayed && !isWelcomed) {
playBackgroundMusic();
isMusicPlayed = true;
isWelcomed = true;
}
}
function playBackgroundMusic() {
BGM.loop = true; // 循环播放
BGM.play(); // 播放BGM
BGM.volume = 0.1;
}
//音乐播放控制
var volumeControl = document.getElementById("volume-control");
var volumeIcon = document.getElementById("volume-icon");
//音乐暂停和播放逻辑
volumeControl.addEventListener("click", function () {
if (!isMusicPlayed) {
// Play music
BGM.play();
volumeIcon.style.animationPlayState = "running";
isMusicPlayed = true;
} else {
// Pause music
BGM.pause();
volumeIcon.style.animationPlayState = "paused";
isMusicPlayed = false;
}
});
// ===================================================【多语言支持】============================================
var audioList = []; // 角色音频
let firstSquish = true; //第一次点击
//多语言支持
//语言属性数组
const LANGUAGES = {
//默认
"_": { fallbackLanguage: "cn" },
//中文语音、文本、海报
"cn": {
audioList: [
//0-5:默认模式 mode1
"audio/CN_voice/嘿咻.mp3",
"audio/CN_voice/喵.mp3",
"audio/CN_voice/喵嗷.mp3",
"audio/CN_voice/挠你哦.mp3",
"audio/CN_voice/跳跃1.mp3",
"audio/CN_voice/跳跃2.mp3",
],
texts: {
"page-title": "绮良良 喵呜~",
"doc-title": "喵喵喵~",
"page-descriptions": "给快递员绮良良写的小网站,对,就是那个<del>烦人的</del>很可爱的《原神》小猫!",
"counter-descriptions": ["绮良良已经喵了", "绮良良已经嗷呜了"],
"counter-button": ["喵呜~", "嗷呜!"],
"credits-gif": "鸣谢:Seseren_kr提供的绮良良GIF图片",
"footer-repository-text": "本网站的Gitee仓库在这儿:",
"footer-repository-text-2": "原神主题网站代码仓库",
"footer-repository-text3": "鸣谢:duiqt提供的本网站基础源代码",
"footer-repository-text-4": "Herta_kuru"
},
cardImage: "img/banner_cn.jpg"
},
//日文语音、文本、海报
"ja": {
audioList: [
//0-5:默认模式 mode1
"audio/CN_voice/嘿咻.mp3",
"audio/CN_voice/喵.mp3",
"audio/CN_voice/喵嗷.mp3",
"audio/CN_voice/挠你哦.mp3",
"audio/CN_voice/跳跃1.mp3",
"audio/CN_voice/跳跃2.mp3",
],
texts: {
"page-title": "綺良々ーにゃー",
"doc-title": "にゃにゃにゃ",
"page-descriptions": "このサイトは綺良々のために作られた、 あの原神の <del>悩ましい</del> かわいいねこ。",
"counter-descriptions": "にゃー数",
"counter-button": "にゃー!",
"credits-gif": "感謝: Seseren_kr さんが提供してくれた綺良々のGIF画像",
"footer-repository-text": "こちらはこのページGitee (Mainland China) リポジトリ:",
"footer-repository-text-2": "原神主题网站代码仓库",
"footer-repository-text3": "感謝:duiqt さんが提供してくれたこのウェブサイトの基礎ソースコード",
"footer-repository-text-4": "Herta_kuru"
},
cardImage: "img/banner_jp.jpg"
},
//英文语音、文本、海报
"en": {
audioList: [
//0-5:默认模式 mode1
"audio/CN_voice/嘿咻.mp3",
"audio/CN_voice/喵.mp3",
"audio/CN_voice/喵嗷.mp3",
"audio/CN_voice/挠你哦.mp3",
"audio/CN_voice/跳跃1.mp3",
"audio/CN_voice/跳跃2.mp3",
],
texts: {
"page-title": "Welcome to Kirara Miaow~ &nbsp;",
"doc-title": "Miaomiaomiao~",
"page-descriptions": "The website for Kirara, an <del>annoying</del> very lovely Genshin Impact CAT out there.",
"counter-descriptions": ["The Kirara~ has been miaowed for", "Kirara has been miaow~ed for"],
"counter-button": "Miaow~",
"credits-gif": "Acknowledgment: GIF images of Kirara provided by Seseren_kr.",
"footer-repository-text": "You can check out the Gitee repository (Mainland China) here:",
"footer-repository-text-2": "原神主题网站代码仓库",
"footer-repository-text3": "Special thanks to duiqt for providing the source code for this website.",
"footer-repository-text-4": "Herta_kuru"
},
cardImage: "img/banner_en.jpg"
}
};
//设置语言选择器的文本语言
function refreshLanguageSelector(selectedLanguage) {
switch (selectedLanguage) {
case "cn":
document.getElementById("lan1").innerHTML = "🌏中文";
document.getElementById("lan2").innerHTML = "日文";
document.getElementById("lan3").innerHTML = "英文";
break;
case "ja":
document.getElementById("lan1").innerHTML = "中国語";
document.getElementById("lan2").innerHTML = "🌏日本語";
document.getElementById("lan3").innerHTML = "英語";
break;
case "en":
document.getElementById("lan1").innerHTML = "Chinese";
document.getElementById("lan2").innerHTML = "Japanese";
document.getElementById("lan3").innerHTML = "🌏English";
break;
default:
break;
}
}
//设置模式选择器的文本语言
function refreshModeSelector(selectedLanguage) {
switch (selectedLanguage) {
case "cn":
document.getElementById("mode1").innerHTML = "默认模式";
// document.getElementById("mode2").innerHTML = "只要哒哒哒";
// document.getElementById("mode3").innerHTML = "隐藏彩蛋";
break;
case "ja":
document.getElementById("mode1").innerHTML = "デフォルトモード";
// document.getElementById("mode2").innerHTML = "ダダダだけ";
// document.getElementById("mode3").innerHTML = "ひみつ";
break;
case "en":
document.getElementById("mode1").innerHTML = "DefaultMode";
// document.getElementById("mode2").innerHTML = "Just Dadada";
// document.getElementById("mode3").innerHTML = "Easter egg";
break;
default:
break;
}
}
//获取默认语言并赋值给语言选择框
var current_language = localStorage.getItem("lang") || "cn";
if (current_language != "cn") {
document.getElementById("language-selector").value = current_language;
};
//通过获取当前语言和对应的文本数组,遍历文本数组中的每个键值对。如果文本值是一个数组,就从数组中随机选择一个元素作为新的文本内容,并将其更新到对应的 HTML 元素中
function randomChoice(myArr) {
const randomIndex = Math.floor(Math.random() * myArr.length);
const randomItem = myArr[randomIndex];
return randomItem;
};
//核心函数!动态刷新动态文本内容(将新的DOM值渲染到前端)
function refreshDynamicTexts() {
let curLang = LANGUAGES[current_language];
let localTexts = curLang.texts;
Object.entries(localTexts).forEach(([textId, value]) => {
if (value instanceof Array)
if (document.getElementById(textId) != undefined)
document.getElementById(textId).innerHTML = randomChoice(value);
});
};
//定义函数:根据当前语言,渲染页面
function multiLangMutation() {
let curLang = LANGUAGES[current_language]; //获取当前的网站语言
let localTexts = curLang.texts; //获取当前语言的文本数组
Object.entries(localTexts).forEach(([textId, value]) => { //将各个DOM元素的值变为文本值
if (!(value instanceof Array))
if (document.getElementById(textId) != undefined)
document.getElementById(textId).innerHTML = value;
});
refreshDynamicTexts() //刷新动态文本内容(将新的DOM值渲染到前端)
document.getElementById("kirara-card").src = curLang.cardImage; //动态获取klee-card在当前语言文本环境下的Dom元素并更新
var selectedLanguage = document.getElementById("language-selector").value;
refreshLanguageSelector(selectedLanguage) //更新语言选择器的文本语言
refreshModeSelector(selectedLanguage) //更新模式选择器的文本语言
};
/*
curLang 变量获取了当前选择的网站语言对应的语言对象假设为 LANGUAGES 全局对象中的一个属性
localTexts 变量获取了当前语言对象中的文本数组
使用 Object.entries() 方法遍历 localTexts 中的键值对
对于每一个键值对解构赋值为 [textId, value]其中 textId DOM 元素的 IDvalue 是对应的文本值
首先检查 value 是否为数组如果不是数组表示是单个文本值例如字符串
检查当前网页是否存在具有对应 textId DOM 元素通过 document.getElementById(textId) 来判断
如果存在对应的 DOM 元素则将其内部的 HTML 内容更新为 value
这样就实现了根据当前语言选择动态更新网页中的文本内容
*/
multiLangMutation() //初始化网站语言
//通过这段代码,当语言选择器的值发生变化时,会根据选择的语言重新渲染页面的文本内容和动态图片,实现动态调整网站语言的功能。
document.getElementById("language-selector").addEventListener("change", (ev) => {
current_language = ev.target.value;
localStorage.setItem("lang", ev.target.value);
multiLangMutation();
});
//=======================================================================【按钮点击、计数器】============================================
// 初始化计数器
//本地计数器
const localCounter = document.querySelector('#local-counter'); //获取展示本地点击数的DOM元素
let localCount = localStorage.getItem('count-local-kirara') || 0; //获取本地点击数的值
localCounter.textContent = localCount.toLocaleString('en-US'); //使用美式英语的格式进行格式化。这样可以确保数值以适当的方式显示,例如添加千位分隔符
let prevTime = 0;
//获取时间戳
const getTimestamp = () => Date.parse(new Date());
//点击喵呜的按钮事件
const counterButton = document.querySelector('#counter-button');
counterButton.addEventListener('click', (e) => {
prevTime = getTimestamp(); //当前时间
localCount++;
localStorage.setItem('count-local-kirara', localCount); //缓存localCount到本地
localCounter.textContent = localCount.toLocaleString('en-US');
triggerRipple(e); //按钮的水波纹效果
playMiaow(); //播放可莉语音
animateKirara(); //播放可莉动画
});
//===================================================================【资源缓存】========================================================
var cachedObjects = {};
function tryCachedObject(origUrl) {
// 检查对象是否已经被缓存
if (cachedObjects[origUrl]) {
return cachedObjects[origUrl];
} else {
// 开始缓存
fetch(origUrl)
.then((response) => response.blob())
.then((blob) => {
// 为对象创建一个blob URL
const blobUrl = URL.createObjectURL(blob);
// 通过在cachedObjects对象中存储blob URL来获取缓存的对象
cachedObjects[origUrl] = blobUrl;
})
.catch((error) => {
console.error(`Error caching object from ${origUrl}: ${error}`);
});
return origUrl;
}
};
//缓存所有资源
function cacheAllResources() {
// 缓存图片资源
for (let i = 1; i < 3; i++) {
const imageUrl = `img/animation/${i}.gif`;
tryCachedObject(imageUrl);
}
// 缓存中文音频资源(含通用语音资源)
const cnAudioList = LANGUAGES.cn.audioList;
cnAudioList.forEach((audioUrl) => {
tryCachedObject(audioUrl);
});
// 缓存日文音频资源(含通用语音资源)
const jaAudioList = LANGUAGES.ja.audioList;
jaAudioList.forEach((audioUrl) => {
tryCachedObject(audioUrl);
});
//只需要执行一次该功能
firstLoadClick = false;
}
// 当页面加载完成后触发缓存资源
// var firstLoadClick = true;
// window.addEventListener('click', cacheAllResources);
//========================================================================【按钮点击后的动画、音频】================================================
//返回当前语言的音频数组
function getLocalAudioList() {
return LANGUAGES[current_language].audioList;
};
//从音频数组中获取一个随机的音频URL(传入一个当前模式。curMode==mode1 默认模式,cueMode==mode3
function getRandomAudioUrl(curMode) {
var localAudioList = getLocalAudioList()
//根据模式产生符合模式的音频下标
if (curMode == "mode1") {
randomIndex = Math.floor(Math.random() * 6); //默认语音的文件是:文件下标0-5.这儿的数字就写6.
}
// if (curMode == "mode3") {
// randomIndex = Math.floor(Math.random() * 17); //文件下标0-16.这儿的数字就写14. 【这儿写彩蛋对应的audioList下标】
// }
const randomItem = localAudioList[randomIndex];
return randomItem;
};
//播放音频
var isFirstVoice = true;
function playMiaow() {
//先获取当前的模式:1-默认;2-只哒哒哒;3-彩蛋
const modeSelectElement = document.getElementById("mode-selector");
const modeSelectedOption = modeSelectElement.options[modeSelectElement.selectedIndex];
const curMode = modeSelectedOption.id;
//要播放的音频Url
let audioUrl;
//根据当前模式获取符合模式语音的 AudioURL
switch (curMode) {
//curMode==mode1 默认模式
case "mode1": {
if (isFirstVoice == true) {//随机获取一个音频的URL,第一个必定是哒哒哒
isFirstVoice = false;
audioUrl = getLocalAudioList()[1] //First play fixed Dadada
} else {
audioUrl = getRandomAudioUrl(curMode);
}
}; break;
//curMode==mode2 只哒哒哒
case "mode2": {
audioUrl = getLocalAudioList()[1]
}; break;
//cueMode==mode3 彩蛋
case "mode3": {
if (isFirstVoice == true) {//随机获取一个音频的URL,第一个必定是哒哒哒
isFirstVoice = false;
audioUrl = getLocalAudioList()[1] //First play fixed Dadada
} else {
audioUrl = getRandomAudioUrl(curMode);
}
}; break;
}
//根据音频URL从本地获取音频资源。同时将该音频缓存到本地
let audio = new Audio(tryCachedObject(audioUrl)); //【缓存貌似可以删除】
//播放音频后监听音频结束事件,并在音频播放结束时将音频元素从 DOM 中移除
audio.play();
audio.addEventListener("ended", function () {
this.remove();
});
};
function animateKirara() {
let id = null;
const random = Math.floor(Math.random() * 1) + 1; //1-1GIF
const elem = document.createElement("img");
elem.src = tryCachedObject(`img/animation/${random}.gif`);
//下面根据不同的窗口改变可莉动画的样式(响应式)
const screenWidth = window.innerWidth;
if (screenWidth > 768) {
elem.style.position = "absolute";
elem.style.right = "-500px";
elem.style.top = counterButton.getClientRects()[0].bottom + scrollY - 430 + "px"
elem.style.zIndex = "-10";
document.body.appendChild(elem);
let pos = -500;
const limit = window.innerWidth + 500;
clearInterval(id);
id = setInterval(() => {
if (pos >= limit) {
clearInterval(id);
elem.remove()
} else {
pos += 20;
elem.style.right = pos + 'px';
}
}, 12);
} else {
//移动端,把动画变小、变慢一点
elem.style.position = "absolute";
elem.style.right = "-500px";
elem.style.top = counterButton.getClientRects()[0].bottom + scrollY - 180 + "px"
elem.style.zIndex = "-10";
elem.style.width = "250px"; // 设置宽度为 200px(让移动端方便观看)
elem.style.height = "auto"; // 自动计算高度,保持纵横比
document.body.appendChild(elem);
let pos = -500;
const limit = window.innerWidth + 500;
clearInterval(id);
id = setInterval(() => {
if (pos >= limit) {
clearInterval(id);
elem.remove()
} else {
pos += 10;
elem.style.right = pos + 'px';
}
}, 12);
}
};
//点击 counter-button 元素时,会在点击位置出现一个水波纹效果。
function triggerRipple(e) {
let ripple = document.createElement("span");
ripple.classList.add("ripple");
const counter_button = document.getElementById("counter-button");
counter_button.appendChild(ripple);
let x = e.clientX - e.target.offsetLeft;
let y = e.clientY - e.target.offsetTop;
ripple.style.left = `${x}px`;
ripple.style.top = `${y}px`;
setTimeout(() => {
ripple.remove();
}, 300);
};
// ==========================================【全球计数器】======================================
//算法思路:先前的项目已经实现了永久保存本地计数。接下来要实现统计全球技术:
//1.为了节省流量,规定每一分钟自动上传一次【本次点击数】(定义一个区别于 localCount 的新变量 thisTimeCount
//2.发送Ajax,发送 thisTimeCount 服务端返回 globalCount渲染到页面,同时将本地的 thisTimeCount 清零
var thisTimeCounts = 0; //本次轮询Ajax之前的点击数
var intervalID = setInterval(updateGlobalCount, 15000);//间隔多久上传一次,单位ms
//点击一次按钮,thisTimeCount++
$(document).ready(function () {
$('#counter-button').click(function () {
thisTimeCounts++ //本次定时轮询Ajax之前的点击数 +1
});
});
//上传数据
function updateGlobalCount() {
$.ajax({
url: './kirara.php',
method: 'POST',
async: false,
data: { localcount: thisTimeCounts },
success: function(response) {
// 处理成功响应
console.log(response);
thisTimeCounts = 0;
$('#local-counter').text(localCount);
},
error: function(error) {
// 处理错误响应
console.error("请求失败: " + error);
}
});
}
//首次访问网站的时候,立即获取 globalCounts并刷新 (页面加载完成后立即执行)
document.addEventListener("DOMContentLoaded", function () {
$.ajax({
url: './kirara.php',
method: 'GET',
dataType: 'json',
headers: {
'ajax-requests': 'true'
},
/*data: {
thistimecountFromFront: thisTimeCounts, //将前端的 thisTimeCount 传给后端,参数名为 thistimecountFromFront
},*/
success: function (response) {
var globalcount = response[0].globalcount;
//console.log(response);
console.log("初始化成功,globalcountsFromBackend = " + globalcount)
var globalCountElement = document.getElementById("global-counter");
globalCountElement.textContent = (globalcount).toLocaleString('en-US')
},
error: function (error) {
console.log(error);
}
});
});
// 定时轮询后端获取 globalCounts
setInterval(function () {
$.ajax({
url: './kirara.php',
method: 'GET',
dataType: 'json',
headers: {
'ajax-requests': 'true'
},
//type: 'text',
/*data: {
thistimecountFromFront: thisTimeCounts, //将前端的 thisTimeCount 传给后端,参数名为 thistimecountFromFront
},*/
success: function (response) {
var globalcount = response[0].globalcount;
console.log("前端收到了后端返回的全球计数 = " + globalcount)
//thisTimeCounts = 0; //将前端本地点击数清零
var globalCountElement = document.getElementById("global-counter"); //获取全球计数器DOM
globalCountElement.textContent = (globalcount).toLocaleString('en-US') //更新全球计数器的值
},
error: function (error) {
console.log(error);
}
});
}, 5000); // 每5s执行一次
+479
View File
@@ -0,0 +1,479 @@
* {
margin: 0;
padding: 0;
/* disable double_tap zoom on mobile devices */
-ms-touch-action: manipulation;
touch-action: manipulation;
/* strange margin-right occurs when vw<500px */
overflow-x: hidden;
}
body {
/* 底部颜色 */
background-color: rgba(233, 233, 233);
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI Adjusted", "Segoe UI", "Liberation Sans", 'Roboto', sans-serif;
font-size: 1.5em;
/* 顶部文字颜色 */
color: #553b07;
/* 禁用右键和选中 */
-webkit-user-select: none;
/* Chrome, Safari, Opera */
-moz-user-select: none;
/* Firefox */
-ms-user-select: none;
/* Internet Explorer/Edge */
user-select: none;
}
/* 欢迎页面 */
#welcome-page {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(192, 157, 69, 0.8);
color: rgb(19, 19, 19);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
z-index: 9999;
opacity: 1;
transition: opacity 0.5s;
}
#welcome-page img {
width: 30%;
}
/* 功能区大盒子 */
.buttons-container {
position: fixed;
top: 20px;
left: 20px;
display: flex;
align-items: center;
z-index: 8888;
}
/* 播放按钮 */
.volume-control {
width: 40px;
height: 40px;
background-color: rgba(22, 21, 21, 0.5);
border-radius: 50%;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
/* 按钮和右边按钮间隔20px */
margin-right: 20px;
}
.volume-control:hover {
background-color: #e5e2e2;
}
.volume-icon {
width: 24px;
height: 24px;
background-image: url("./img/volume_icon.png");
background-size: cover;
animation: rotate-icon 5s infinite linear;
}
@keyframes rotate-icon {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
.wrapper {
position: relative;
}
#wrapper-background {
position: absolute;
width: 100%;
height: 100%;
background-image: url("img/background.gif");
background-repeat: no-repeat;
background-position: 50%;
background-size: contain;
z-index: -30;
}
#wrapper-background-filter {
/* 背景颜色 */
background-color: rgba(175, 162, 44, 0.9);
position: absolute;
width: 100%;
height: 100%;
z-index: -20;
}
.preload {
position: absolute;
left: 0;
top: 0;
visibility: hidden;
}
#content {
margin: 2vh auto;
width: 80vw;
}
h1 {
text-align: center;
font-size: 3em;
font-weight: bold;
}
h2 {
text-align: center;
font-weight: bold;
font-size: 1.5em;
}
hr {
/* 分割线 */
border-bottom: 6px dashed rgb(68, 51, 5);
border-top: none;
border-left: none;
border-right: none;
}
#title-container {
display: flex;
justify-content: center;
}
#page-title {
text-align: left;
}
/* logo */
#title-img {
height: 3.8em;
}
@keyframes shake {
0% {
transform: rotate(-5deg);
}
50% {
transform: rotate(5deg);
}
100% {
transform: rotate(-5deg);
}
}
.shake {
animation: shake 1s linear infinite;
}
#container {
display: flex;
justify-content: center;
align-items: center;
margin-top: 20px;
margin-bottom: 10px;
text-align: center;
}
#container select {
margin: 0 10px;
}
#language-selector,
#mode-selector {
width: 200px;
height: 40px;
/* 选择框颜色 */
background-color: #ebe4a3;
border: none;
border-radius: 5px;
font-size: 16px;
text-align: center;
text-align-last: center;
padding: 10px;
margin: 0 10px;
color: rgb(38, 36, 36);
appearance: none;
-webkit-appearance: none;
-moz-appearance: none;
cursor: pointer;
outline: none;
}
#language-selector:hover,
#mode-selector:hover {
box-shadow: 0 0 10px #756d1f;
}
#language-selector option {
text-align: center;
background-color: #ebe4a3;
color: rgb(118, 114, 114);
}
#subtitle-seperator {
margin-bottom: 10px;
}
#counter-container {
text-align: center;
font-weight: bold;
margin: 64px 0;
}
#counter-container>p {
text-shadow: #975a13 0 0 10px, #975a13 0 0 10px, #975a13 0 0 10px, #975a13 0 0 10px, #975a13 0 0 10px;
}
/* 全球计数器文字颜色 */
#global-counter {
color: #211e04;
font-size: 4em;
text-shadow:
-1px -1px 0 black,
1px -1px 0 black,
-1px 1px 0 black,
1px 1px 0 black; /* 描边效果 */
}
/* 本地计数器文字颜色 */
#local-counter {
color: #2e2c2c;
font-size: 1.5em;
}
#counter-button {
/* 动画触发按钮颜色 */
background-color: #4d4813;
border: none;
border-radius: 16px;
color: rgb(236, 193, 105);
padding: 16px 32px;
text-decoration: none;
font-size: 1em;
font-family: 'Roboto', sans-serif;
font-weight: bold;
margin-top: 16px;
position: relative;
overflow: hidden;
box-shadow: 6px 7px 40px -4px rgba(43, 42, 42, 0.2);
cursor: pointer;
transition: background-color 0.1s ease-in-out, scale 0.1s cubic-bezier(0.075, 0.82, 0.165, 1);
}
/* 动画触发按钮的悬挂颜色 */
#counter-button:hover {
background-color: #3a3608;
}
#counter-button:active {
scale: 0.95;
}
#counter-button span {
position: absolute;
border-radius: 50%;
background-color: #ffffff50;
width: 100px;
height: 100px;
margin-top: -50px;
margin-left: -50px;
animation: ripple 1s;
opacity: 0;
}
@keyframes ripple {
from {
opacity: 1;
transform: scale(0);
}
to {
opacity: 0;
transform: scale(10);
}
}
#footer {
background-color: rgb(253, 250, 244);
color: black;
padding: 16px 10vw;
display: flex;
gap: 30px;
align-items: center;
justify-content: center;
}
/* kirara banner 图片样式 */
#kirara-card {
min-width: 256px;
max-width: 720px;
height: auto;
border-top-left-radius: 2% 3.5%;
border-top-right-radius: 2% 3.5%;
border-bottom-left-radius: 2% 3.5%;
border-bottom-right-radius: 2% 3.5%;
}
.footer-icon {
display: inline-block;
vertical-align: middle;
font-size: 2em;
}
#twitter-footer-icon {
color: #1d9bf0;
}
#github-footer-icon {
color: #000000;
}
.footer-icon-text {
display: inline-block;
vertical-align: middle;
font-weight: bold;
margin-left: 6px;
}
/* #footer-repository-text {
margin-top: 32px;
margin-bottom: 16px;
} */
@media screen and (max-width: 2240px) {
.grid-item {
width: calc(20% - 10px);
}
}
@media screen and (max-width: 1920px) {
.grid-item {
width: calc(25% - 10px);
}
}
@media screen and (max-width: 1512px) {
body {
font-size: 1.25em;
}
#subtitle-seperator {
margin-top: 3px;
margin-bottom: 11px;
}
}
@media screen and (max-width: 1280px) {
.grid-item {
width: calc(100% / 3 - 10px);
}
#footer {
flex-wrap: wrap;
}
#footer-text {
text-align: center;
}
#footer-header-text {
margin-bottom: 8px;
}
#footer-repository-text {
margin-top: 16px;
margin-bottom: 8px;
}
}
@media screen and (max-width: 1265px) {
body {
font-size: 1em;
}
#subtitle-seperator {
margin-top: 6px;
margin-bottom: 12px;
}
}
@media screen and (max-width: 854px) {
.grid-item {
width: calc(20% - 10px);
}
}
@media screen and (max-width: 510px) {
h1 {
font-size: 2.5em;
}
h2 {
font-size: 1.25em;
}
#subtitle-seperator {
margin-top: 8px;
margin-bottom: 13px;
}
}
@media screen and (max-width: 500px) {
.grid-item {
width: calc(100% - 10px);
}
}
@media screen and (max-width: 430px) {
h1 {
font-size: 2em;
}
#subtitle-seperator {
margin-top: 10px;
}
}
#access-via-mirror,
#access-via-pages {
font-size: small;
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More