我正在参加中秋创意投稿大赛,详情请看:中秋创意投稿大赛
序言
中秋节快到了,在掘金中看到了该活动,我也想来凑凑热闹~,嘿嘿嘿。在这祝大家中秋节快乐~
思路
中秋节我觉得首先得有一轮明月,我还在纠结月亮皎洁好呀还是稍微带点黄好,哈哈哈哈,最后还是选择带点黄色。
然后单一轮明月还是太空了,得整点星星,星星要的挺多,就使用canvas来生成它。
最后捏,嫦娥奔月,就想着月亮在我页面上在右上,那就从左下做曲线运动上来叭,抵达月亮就显示祝福语~
浏览器:chrome
开整~
设计
月亮
先实现右上的一轮明月,创建一个月亮id为moon。在自己添加四个坑坑洼洼类名为moon_circle
<div id="sky">
<div id="moon">
<!--这四个为月亮上的坑坑洼洼-->
<div class="moon_circle"></div>
<div class="moon_circle"></div>
<div class="moon_circle"></div>
<div class="moon_circle"></div>
</div>
</div>
为月亮和坑坑洼洼写样式,坑坑洼洼也用圆代替了,嘿嘿嘿(我不是好懒哈~)
* {
padding: 0;
margin: 0;
}
body {
width: 100vw;
height: 100vh;
background-color: #000;
overflow: hidden;
}
/*将月亮放在右上*/
#sky {
display: flex;
justify-content: flex-end;
}
/*月亮*/
#moon {
width: 200px;
height: 200px;
margin: 20px 20px 0 0;
background-color: rgba(245, 243, 233, 0.9);
border-radius: 50%;
box-shadow: 0 0 40px 10px rgb(201, 201, 201);
/*为了让月亮时不时发光发亮*/
animation: moonShadow 2s ease-in-out infinite alternate;
/*为后面的坑坑洼洼提供位置*/
position: relative;
}
/*月亮阴影变化,发光*/
@keyframes moonShadow {
0% {
box-shadow: 0 0 20px 5px rgb(201, 201, 201);
}
100% {
box-shadow: 0 0 30px 10px rgb(128, 128, 128);
}
}
/*坑坑洼洼*/
.moon_circle:nth-of-type(1) {
width: 20px;
height: 20px;
border-radius: 50%;
top: 50%;
left: 70%;
position: absolute;
box-sizing: border-box;
background-color: rgb(168, 168, 168);
border: 1px solid rgb(63, 60, 60);
opacity: 0.1;
}
.moon_circle:nth-of-type(2) {
width: 40px;
height: 40px;
border-radius: 50%;
top: 24%;
left: 20%;
position: absolute;
box-sizing: border-box;
background-color: rgb(168, 168, 168);
border: 1px solid rgb(63, 60, 60);
opacity: 0.1;
}
.moon_circle:nth-of-type(3) {
width: 25px;
height: 25px;
border-radius: 50%;
top: 70%;
left: 40%;
position: absolute;
box-sizing: border-box;
background-color: rgb(168, 168, 168);
border: 1px solid rgb(63, 60, 60);
opacity: 0.1;
}
.moon_circle:nth-of-type(4) {
width: 24px;
height: 24px;
border-radius: 50%;
top: 10%;
left: 60%;
position: absolute;
box-sizing: border-box;
background-color: rgb(168, 168, 168);
border: 1px solid rgb(63, 60, 60);
opacity: 0.1;
}
漫天繁星
星星从远处看差不多像圆点,我也用圆来代替了,嘿嘿嘿
由于星星数量多,我就想着用canvas来实现星星
<div id="sky">
<!--创建画布canvas-->
<canvas id="mycanvas"></canvas>
<div id="moon">
<div class="moon_circle"></div>
<div class="moon_circle"></div>
<div class="moon_circle"></div>
<div class="moon_circle"></div>
</div>
</div>
给画布一个绝对布局,防止影响到月亮
#mycanvas {
position: absolute;
}
重点部分
- 创建星星类
- 发光由透明度实现
- 使用requestAnimationFrame实现变化
/** @type {HTMLCanvasElement} */
//背景星星函数
function backgroundAni() {
var canvas = document.querySelector("#mycanvas");
//获取屏幕宽高
var sw = window.innerWidth;
var sh = window.innerHeight;
//获取画布上下文
var ctx = canvas.getContext("2d");
//创建画布大小
canvas.width = sw;
canvas.height = sh;
//星星构造函数
function Star() {
//初始化
//坐标x,y
this.x = Math.random() * sw;
this.y = Math.random() * sh;
//星星的半径
this.r = 0.5 + Math.random() * 1;
//初始不透明度
this.opacity = Math.random();
//不透明度变换速度
this.opaSpeed = 0.002 + Math.random() * 0.002;
//绘制方法
this.draw = function () {
ctx.beginPath();
ctx.arc(this.x, this.y, this.r, 0, 2 * Math.PI, false);
ctx.fillStyle = this.color;
ctx.fill();
ctx.closePath();
}
//更新星星的透明度,那么就会感觉一闪一闪
this.update = function () {
//颜色,透明度变换
let tempOp = this.opacity + this.opaSpeed;
if (tempOp >= 1) {
this.opaSpeed = -0.005;
tempOp = this.opacity + this.opaSpeed;
} else if (tempOp <= 0) {
this.opaSpeed = 0.005;
tempOp = this.opacity + this.opaSpeed;
}
this.color = `rgba(255, 255, 255, ${tempOp})`;
this.opacity = tempOp;
}
}
//装着星星的数组
var stars = [];
//600个星星
for (let i = 0; i < 600; i++) {
stars.push(new Star());
}
//动画运动
function loop() {
//每次运行都得清除上一次的画布内容
ctx.clearRect(0, 0, sw, sh);
//此时再将这次的显示上去
for (const star of stars) {
star.update();
star.draw();
}
requestAnimationFrame(loop);
}
loop();
}
//星星函数入口
backgroundAni();
嫦娥奔月
贴一张图片充当嫦娥,然后根据二阶贝塞尔公式做一个曲线运动,抵达之后消失,显示祝福文本
<div id="sky">
<canvas id="mycanvas"></canvas>
<div id="moon">
<div class="moon_circle"></div>
<div class="moon_circle"></div>
<div class="moon_circle"></div>
<div class="moon_circle"></div>
</div>
<div id="text">
<div>共赏圆月</div>
<div>喜迎中秋</div>
</div>
</div>
为嫦娥div添加类名,给与样式,文本也添加
.changEer {
position: absolute;
width: 100px;
height: 100px;
/*把嫦娥当成背景图片*/
background-image: url("./images/changE01.png");
background-repeat: no-repeat;
z-index: 99;
/*嫦娥出发的起点*/
top: 700px;
left: 0;
}
#text {
position: absolute;
color: red;
top: 45%;
left: 45%;
font-size: 24px;
letter-spacing: 2px;
//嫦娥未到那么是不显示的
display: none;
}
这里需要了解二阶贝塞尔曲线~,我就偷懒放大佬链接了
//嫦娥移动函数
function changEerMove() {
//创建嫦娥元素
let changeEerDiv = document.createElement("div");
changeEerDiv.classList.add("changEer");
document.querySelector("#sky").appendChild(changeEerDiv);
//获取起始点元素
let moon = document.querySelector("#moon");
let changEer = document.querySelector(".changEer");
//p1为起点坐标,即开始嫦娥坐标
let p1 = [changEer.offsetLeft, changEer.offsetTop];
//p2为终点坐标,即到达月亮坐标
let p2 = [moon.offsetLeft + 50, moon.offsetTop + 50];
//初始百分比为0,在起点
let t = 0;
//控制点
let cp = [100, 300];
/*
* 二阶贝塞尔曲线
* t 当前百分比
* p1 起点坐标
* p2 终点坐标
* cp 控制点
*/
function towBezier(t, p1, cp, p2) {
const [x1, y1] = p1;
const [cx, cy] = cp;
const [x2, y2] = p2;
let x = (1 - t) * (1 - t) * x1 + 2 * t * (1 - t) * cx + t * t * x2;
let y = (1 - t) * (1 - t) * y1 + 2 * t * (1 - t) * cy + t * t * y2;
return [x, y];
}
//move移动函数
function move() {
//百分比大于1的时候就证明已经到了月亮了
if(t > 1) {
//移除嫦娥
document.querySelector("#sky").removeChild(changeEerDiv);
//显示祝福语
document.querySelector("#text").style.display = "block";
return;
}
//播放,更新嫦娥坐标,更新百分比
requestAnimationFrame(()=>{
let [newx, newy] = towBezier(t, p1, cp, p2);
changeEerDiv.style.left = newx + "px";
changeEerDiv.style.top = newy + "px";
t += 0.001;
move();
});
}
//播放入口
move();
}
//嫦娥移动入口
changEerMove();
一个嫦娥奔月的页面就完成了(简陋也还是有的哈哈哈)
结语
演示地址:zhongqiu.web.cloudendpoint.cn/
再一次祝大家中秋节快乐~