Files
cdn/code/html/react-day-night-toggle-theme-animation/index.html
T
2025-08-27 07:44:56 +08:00

444 lines
12 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8" />
<title>白昼黑夜切换器</title>
<link
rel="stylesheet"
href="https://cdn.oplist.org/gh/ldxw/cdn@master/code/html/react-day-night-toggle-theme-animation/css/normalize-5.0.0.min.css"
/>
<style>
@import url("https://fonts.googleapis.com/css?family=Gloria+Hallelujah");
* {
box-sizing: border-box;
}
body {
background: #7ec0ee;
margin: 0;
padding: 0;
height: 100vh;
width: 100vw;
overflow: hidden;
display: flex;
align-items: center;
justify-content: center;
font-size: 3rem;
font-family: "Gloria Hallelujah", cursive;
font-weight: bold;
color: #fafafa;
}
</style>
</head>
<body>
<div id="root">Loading...</div>
<!-- 修正CDN链接格式,删除多余空引号 -->
<script src="https://cdn.jsdmirror.cn/npm/react@16.3.0-alpha.1/umd/react.development.js"></script>
<script src="https://cdn.jsdmirror.cn/npm/react-dom@16.3.0-alpha.1/umd/react-dom.development.js"></script>
<script src="https://cdn.jsdmirror.cn/npm/styled-components@2.2.1/dist/styled-components.min.js"></script>
<script>
function _defineProperty(obj, key, value) {
if (key in obj) {
Object.defineProperty(obj, key, {
value: value,
enumerable: true,
configurable: true,
writable: true,
});
} else {
obj[key] = value;
}
return obj;
}
function _extends() {
_extends =
Object.assign ||
function (target) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i];
for (var key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) {
target[key] = source[key];
}
}
}
return target;
};
return _extends.apply(this, arguments);
}
const {
React,
ReactDOM,
styled: { default: styled, keyframes },
} = window;
const { createContext, Component } = React;
const { render } = ReactDOM;
const THEME_CONSTANTS = {
NIGHT: "night",
DAY: "day",
};
// 修正时间判断逻辑(原d<6语法错误,应取getHours()
const d = new Date();
const hours = d.getHours();
const defaultValue =
hours < 6 || hours > 19 ? THEME_CONSTANTS.NIGHT : THEME_CONSTANTS.DAY;
const ThemeContext = createContext(defaultValue);
const $night = "#111";
const $day = "#7ec0ee";
const $starColor = "#fefcd7";
const $sunColor = "#f9fa57";
const $size = 25;
const $transitionDuration = 0.75;
const $skyChangeDuration = 0.5;
const $positionX = 20;
const $positionY = 10;
const Container = styled.div`
background-color: ${(p) =>
p.theme === THEME_CONSTANTS.NIGHT ? $night : $day};
height: 100vh;
transition: background ${$skyChangeDuration} ease;
width: 100vw;
`;
// 修正BigStar组件,补充闭合花括号
const BigStar = styled.div`
border-radius: 100%;
height: ${$size}vh;
left: ${$positionX}vw;
position: absolute;
top: ${$positionY}vh;
transition: transform ${$transitionDuration}s ease 0s;
width: ${$size}vh;
z-index: 2;
`;
// 修正extend语法对齐
const Moon = BigStar.extend`
background-color: ${$starColor};
box-shadow: 0px 0px 50px #eee;
overflow: hidden;
transform: ${(p) =>
p.theme === THEME_CONSTANTS.NIGHT
? "scale(1)"
: "scale(0.5) translateX(-75vw) translateY(-120vh)"};
&:after {
box-shadow: inset 10px 10px 10px #bbb;
border-radius: 100%;
content: "";
display: block;
height: 100%;
width: 100%;
}
`;
const Craters = styled.div`
background-color: #ddd;
border-radius: 100%;
opacity: 0.5;
position: absolute;
top: 15%;
left: 15%;
height: ${$size * 0.25}vh;
width: ${$size * 0.25}vh;
&:before {
background-color: #ddd;
content: "";
display: block;
border-radius: 100%;
height: 50%;
width: 50%;
position: absolute;
top: 110%;
}
&:after {
background-color: #ddd;
content: "";
display: block;
border-radius: 100%;
height: 30%;
width: 30%;
position: absolute;
top: 80%;
right: 110%;
}
`;
const CloudMove = keyframes`
0% {
transform: translateX(300%);
opacity: 0;
}
50% {
opacity: .75;
}
25%, 75% {
opacity: 0;
}
100% {
transform: translateX(-300%);
opacity: 0;
}
`;
const Star = styled.div`
background: ${(p) =>
p.theme === THEME_CONSTANTS.NIGHT ? $starColor : $day};
border-radius: 100%;
height: ${(p) => p.size}px;
left: ${(p) => p.x}vw;
position: absolute;
top: ${(p) => p.y}vh;
opacity: ${(p) => (p.theme === THEME_CONSTANTS.NIGHT ? 1 : 0)};
transition: background ${$transitionDuration}s ease 0s,
opacity ${$transitionDuration}s ease 0s;
width: ${(p) => p.size}px;
z-index: 1;
`;
// 修正extend语法对齐
const Sun = BigStar.extend`
background-color: ${$sunColor};
box-shadow: 0px 0px 150px yellow;
transform: ${(p) =>
p.theme === THEME_CONSTANTS.NIGHT
? "scale(0.5) translateX(75vw) translateY(200vh)"
: "scale(1)"};
`;
const Features = styled.div`
height: 50%;
width: 50%;
position: absolute;
right: 15%;
bottom: 15%;
transition: opacity 0.15s ease 0s;
transition-delay: 0.75s;
opacity: ${(p) => (p.show ? "1" : "0")};
`;
const Blink = keyframes`
0%, 5%, 7%, 100% {
transform: scaleY(1);
}
6% {
transform: scaleY(0);
}
`;
const Eye = styled.div`
border-radius: 100%;
height: 15%;
width: 15%;
background-color: black;
position: absolute;
top: 25%;
animation: ${Blink} 10s infinite 1s;
transform-origin: center;
&:after {
background-color: #fff;
border-radius: 100%;
content: "";
height: 40%;
width: 40%;
position: absolute;
top: 5%;
right: 30%;
display: block;
}
`;
const LeftEye = Eye.extend`
left: 25%;
`;
const RightEye = Eye.extend`
left: 75%;
`;
const Smile = styled.div`
width: 55%;
height: 25%;
border-style: solid;
border-width: 4px;
border-top-color: transparent;
border-left-color: transparent;
border-right-color: transparent;
border-bottom-color: black;
border-radius: 100%;
position: absolute;
top: 35%;
left: 50%;
transform: translateX(-50%);
`;
const Face = ({ show }) =>
React.createElement(
Features,
{ show: show },
React.createElement(LeftEye, null),
React.createElement(RightEye, null),
React.createElement(Smile, null)
);
const ThemeToggleInput = styled.input`
cursor: pointer;
z-index: 3;
height: 100%;
width: 100%;
position: absolute;
top: 0;
left: 0;
opacity: 0;
&:checked ~ div {
transform: translateX(20px);
}
`;
const ThemeToggleContainer = styled.div`
left: 10px;
position: fixed;
top: 10px;
width: 50px;
height: 30px;
border: 4px solid
${(p) => (p.theme === THEME_CONSTANTS.NIGHT ? "#fff" : "dodgerblue")};
border-radius: 30px;
transition: border-color 0.25s ease 0s;
`;
const ThemeToggleSwitch = styled.div`
height: 20px;
width: 20px;
background: ${(p) =>
p.theme === THEME_CONSTANTS.NIGHT ? $starColor : $sunColor};
border-radius: 100%;
position: absolute;
top: 50%;
margin-top: -10px;
left: 1px;
transform: translateX(0px);
transition: background 0.25s ease 0s, transform 0.25s ease 0s;
`;
const ThemeToggle = ({ onChange, checked }) =>
React.createElement(
ThemeContext.Consumer,
null,
(theme) =>
React.createElement(
ThemeToggleContainer,
{ theme: theme },
React.createElement(ThemeToggleInput, {
type: "checkbox",
onChange: onChange,
checked: checked,
title: "Toggle theme",
}),
React.createElement(ThemeToggleSwitch, { theme: theme })
)
);
const BackDrop = ({ stars }) =>
React.createElement(
ThemeContext.Consumer,
null,
(theme) =>
React.createElement(
Container,
{ theme: theme },
React.createElement(
Sun,
{ theme: theme },
React.createElement(Face, {
show: theme === THEME_CONSTANTS.DAY,
})
),
React.createElement(
Moon,
{ theme: theme },
React.createElement(Face, {
show: theme === THEME_CONSTANTS.NIGHT,
}),
React.createElement(Craters, null)
),
stars.map((star, idx) =>
React.createElement(
Star,
_extends({ key: `star--${idx}` }, star, { theme: theme })
)
)
)
);
const generateItems = (
numberOfItems = 5,
sizeLimit = 10,
animationDuration = 10
) => {
const items = [];
for (let i = 0; i < numberOfItems; i++) {
items.push({
animated: Math.random() > 0.75,
delay: Math.floor(Math.random() * animationDuration),
duration: Math.floor(Math.random() * animationDuration + 5),
size: Math.floor(Math.random() * sizeLimit + 1),
x: Math.floor(Math.random() * 100 + 1),
y: Math.floor(Math.random() * 100 + 1),
});
}
return items;
};
class App extends Component {
constructor(...args) {
super(...args);
_defineProperty(this, "state", {
theme: defaultValue,
});
_defineProperty(
this,
"toggle",
(e) => {
const { theme } = this.state;
this.setState({
theme:
theme === THEME_CONSTANTS.NIGHT
? THEME_CONSTANTS.DAY
: THEME_CONSTANTS.NIGHT,
});
}
);
}
// 修正render方法定义(原写在constructor内,不符合React规范)
render() {
const { stars } = this.props;
const { theme } = this.state;
return React.createElement(
ThemeContext.Provider,
{ value: theme },
React.createElement(BackDrop, { stars: stars }),
React.createElement(ThemeToggle, {
checked: theme === THEME_CONSTANTS.NIGHT, // 修正checked判断逻辑
onChange: this.toggle,
})
);
}
}
_defineProperty(App, "defaultProps", { stars: generateItems(20, 4) });
render(
React.createElement(App, null),
document.querySelector("#root")
);
</script>
</body>
</html>