阅读 272

中秋佳节-嫦娥奔月

我正在参加中秋创意投稿大赛,详情请看:中秋创意投稿大赛

序言

中秋节快到了,在掘金中看到了该活动,我也想来凑凑热闹~,嘿嘿嘿。在这祝大家中秋节快乐~

思路

中秋节我觉得首先得有一轮明月,我还在纠结月亮皎洁好呀还是稍微带点黄好,哈哈哈哈,最后还是选择带点黄色。

然后单一轮明月还是太空了,得整点星星,星星要的挺多,就使用canvas来生成它。

最后捏,嫦娥奔月,就想着月亮在我页面上在右上,那就从左下做曲线运动上来叭,抵达月亮就显示祝福语~

浏览器:chrome

开整~

嫦娥奔月样图.png

设计

月亮

先实现右上的一轮明月,创建一个月亮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;
}
复制代码

重点部分

  1. 创建星星类
  2. 发光由透明度实现
  3. 使用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;
}
复制代码

这里需要了解二阶贝塞尔曲线~,我就偷懒放大佬链接了

推荐:juejin.cn/post/684490…

//嫦娥移动函数
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/

再一次祝大家中秋节快乐~