likes
comments
collection
share

海上生明月,天涯共此时-中秋快乐

作者站长头像
站长
· 阅读数 10

背景

一年一度的中秋又要来临了,中秋月圆之夜,我们望着窗外的那轮明月(阴雨天忽略),是否会思念远方的家人呢?“海上生明月,天涯共此时”这首诗便表达了诗人对家乡亲人的思念。我以此诗为主题,用代码呈现那浓浓的思乡之情。

效果图

代码实现

  1. html部分,我们需要再body中定义几个元素,依次是祝福语部分、诗词展示部分、月亮、星空以及大海五个部分。
 <div class="greeting">
        <div class="greeting_text">
            <p>中秋快乐</p>
            <p>对着漫天的流星许愿吧!</p>
        </div>
    </div>
    <div class="greeting">
        <div class="greeting_box"></div>
    </div>
    <div class="moon"></div>
    <canvas id="stars"></canvas>
    <!-- 海浪 -->
    <canvas id="wave"></canvas>
  1. css部分,这里主要就是使用css实现月亮的形状颜色、动画效果,没什么难度,看下代码基本能看懂。
  body, html {
        padding: 0; 
        margin: 0;
    }
    *:after,*:before {
        -webkit-box-sizing: border-box;
        -moz-box-sizing: border-box;
        box-sizing: border-box;
    }
    .clearfix:before,.clearfix:after {
        content: " ";
        display: table;
    }
    .clearfix:after {
        clear: both;
    }
    body{
        background: #494A5F;
        color: #D5D6E2;
        font-weight: 500;
        font-size: 1.05em;
        font-family: "宋体";
        background: none repeat scroll 0 0 #000000;
    }
    a{ 
        color: rgba(255, 255, 255, 0.6);
        outline: none;
        text-decoration: none;
        -webkit-transition: 0.2s;
        transition: 0.2s;
    }
    a:hover,a:focus{
        color:#74777b;
        text-decoration: none;
    }
    .greeting{
        width: 100%;
        margin-top: 50px;
    }
    .greeting_text {
        border: 1px solid;
        border-radius: 10px;
        color: #FFFFFF;
        cursor: pointer;
        display: table-cell;
        float: right;
        font-family:"Zeyada";
        margin-left: 20px;
        transition: text-shadow 0.5s ease 0s;
        padding: 45px 25px;
        text-align: center;
        text-shadow: 0 0 10px #FFFFFF, 0 0 15px #FFFFFF, 0 0 30px #FFFFFF, 0 0 40px #008000, 0 0 70px #008000, 0 0 80px #008000, 0 0 100px #008000;
        width: 270px;
    }
    .greeting_box {
        border: 1px solid;
        border-radius: 10px;
        color: #FFFFFF;
        cursor: pointer;
        display: table-cell;
        float: right;
        font-family:"Zeyada";
        margin-left: 20px;
        transition: text-shadow 0.5s ease 0s;
        padding: 20px 10px;
        text-align: center;
        text-shadow: 0 0 10px #FFFFFF, 0 0 15px #FFFFFF, 0 0 30px #FFFFFF, 0 0 40px #008000, 0 0 70px #008000, 0 0 80px #008000, 0 0 100px #008000;
        width: 270px;
        writing-mode:vertical-rl;
        white-space: pre;
    }
    .greeting_box:hover {
        text-shadow: 0 0 10px #FFFFFF, 0 0 20px #FFFFFF, 0 0 30px #FFFFFF, 0 0 40px #FFFF00, 0 0 70px #FFFF00, 0 0 80px #FFFF00, 0 0 100px #FFFF00;
    }
    /* 通过透明度实现淡出效果 */
	.greeting_box span{
		opacity: 0;
		transition: opacity 0.5s;
	}
    .moon {
        position: absolute;
        z-index: 1;
        width: 120px;
        height: 120px;
        background-image: linear-gradient(to right,#e4e0b7 10%,#fff 90%);
        box-shadow: 0 0 60px 40px rgba(0,0,255,0.2),inset 0 0 20px 5px rgba(0,0,255,0.1);
        border-radius: 50%;
        filter: blur(2px);
        animation: moon-move 200s linear infinite alternate;
    }
    @keyframes moon-move {
        0% {
            left: 10%;
            top: 20%;
        }
        25% {
            left: 30%;
            top: 18%;
        }
        50% {
            left: 48%;
            top: 15%;
        }
        75% {
            left: 68%;
            top: 18%;
        }
        100% {
            left: 85%;
            top: 20%;
        }
    }
    #stars{
        position:fixed;/*设置定位*/
        top:0;
        left:0;
        z-index:-1;/*使画布基于最低层*/
        background:#0e1729;/*画布背景色*/
    }
    #wave{
        position:fixed;/*设置定位*/
        bottom:0;
        left:0;
        z-index:-1;/*使画布基于最低层*/
        background:#0e1729;/*画布背景色*/
    }
  1. 最后一部分就是最重要的js部分了,它实现了星空部分,包括星星以及星星的分布闪烁、流星的绘制、流星的样式、流星的流动以及诗词的淡化效果展示等重要部分。由于代码过多,就不一一解释了,具体代码如下,基本重要步骤都有注释说明。
  var context;
    var arr = new Array();
    var starCount = 800;
    var rains = new Array();
    var rainCount = 20;

    function init() {
        var stars = document.getElementById("stars");
        windowWidth = window.innerWidth; //当前的窗口的高度
        stars.width = windowWidth;
        stars.height = window.innerHeight;
        context = stars.getContext("2d");
    }

    //创建一个星星对象
    var Star = function () {
        this.x = windowWidth * Math.random();//横坐标
        this.y = 5000 * Math.random();//纵坐标
        this.text = ".";//文本
        this.color = "#fff";//颜色
        this.getColor = function () {
            var _r = Math.random();
            if (_r < 0.5) {
                this.color = "#333";
            } else {
                this.color = "#fff";
            }
        }
        //初始化
        this.init = function () {
            this.getColor();
        }
        //绘制
        this.draw = function () {
            context.fillStyle = this.color;
            context.fillText(this.text, this.x, this.y);
        }
    }
    //页面加载的时候
    window.onload = function () {
        init();
        //画星星
        for (var i = 0; i < starCount; i++) {
            var star = new Star();
            star.init();
            star.draw();
            arr.push(star);
        }
        //画流星
        for (var i = 0; i < rainCount; i++) {
            var rain = new MeteorRain();
            rain.init();
            rain.draw();
            rains.push(rain);
        }
        playStars();//绘制闪动的星星
        playRains();//绘制流星

    }

    //星星闪起来
    function playStars() {
        for (var n = 0; n < starCount; n++) {
            arr[n].getColor();
            arr[n].draw();
        }

        setTimeout("playStars()", 100);
    }

    /*流星雨开始*/
    var MeteorRain = function () {
        this.x = -1;
        this.y = -1;
        this.length = -1;//长度
        this.angle = 30; //倾斜角度
        this.width = -1;//宽度
        this.height = -1;//高度
        this.speed = 1;//速度
        this.offset_x = -1;//横轴移动偏移量
        this.offset_y = -1;//纵轴移动偏移量
        this.alpha = 1; //透明度
        this.color1 = "";//流星的色彩
        this.color2 = ""; //流星的色彩
        /****************初始化函数********************/
        this.init = function () //初始化
        {
            this.getPos();
            this.alpha = 1;//透明度
            this.getRandomColor();
            //最小长度,最大长度
            var x = Math.random() * 80 + 150;
            this.length = Math.ceil(x);
            // x = Math.random()*10+30;
            this.angle = 30; //流星倾斜角
            x = Math.random() + 0.5;
            this.speed = Math.ceil(x); //流星的速度
            var cos = Math.cos(this.angle * 3.14 / 180);
            var sin = Math.sin(this.angle * 3.14 / 180);
            this.width = this.length * cos; //流星所占宽度
            this.height = this.length * sin;//流星所占高度
            this.offset_x = this.speed * cos;
            this.offset_y = this.speed * sin;
        }
        /**************获取随机颜色函数*****************/
        this.getRandomColor = function () {
            var a = Math.ceil(255 - 240 * Math.random());
            //中段颜色
            this.color1 = "rgba(" + a + "," + a + "," + a + ",1)";
            //结束颜色
            this.color2 = "black";
        }
        /***************重新计算流星坐标的函数******************/
        this.countPos = function ()//
        {
            //往左下移动,x减少,y增加
            this.x = this.x - this.offset_x;
            this.y = this.y + this.offset_y;
        }
        /*****************获取随机坐标的函数*****************/
        this.getPos = function () //
        {
            //横坐标200--1200
            this.x = Math.random() * window.innerWidth; //窗口高度
            //纵坐标小于600
            this.y = Math.random() * window.innerHeight; //窗口宽度
        }
        /****绘制流星***************************/
        this.draw = function () //绘制一个流星的函数
        {
            context.save();
            context.beginPath();
            context.lineWidth = 1; //宽度
            context.globalAlpha = this.alpha; //设置透明度
            //创建横向渐变颜色,起点坐标至终点坐标
            var line = context.createLinearGradient(this.x, this.y,
                this.x + this.width,
                this.y - this.height);
            //分段设置颜色
            line.addColorStop(0, "white");
            line.addColorStop(0.3, this.color1);
            line.addColorStop(0.6, this.color2);
            context.strokeStyle = line;
            //起点
            context.moveTo(this.x, this.y);
            //终点
            context.lineTo(this.x + this.width, this.y - this.height);
            context.closePath();
            context.stroke();
            context.restore();
        }
        this.move = function () {
            //清空流星像素
            var x = this.x + this.width - this.offset_x;
            var y = this.y - this.height;
            context.clearRect(x - 3, y - 3, this.offset_x + 5, this.offset_y + 5);
            // context.strokeStyle="red";
            // context.strokeRect(x,y-1,this.offset_x+1,this.offset_y+1);
            //重新计算位置,往左下移动
            this.countPos();
            //透明度增加
            this.alpha -= 0.002;
            //重绘
            this.draw();
        }
    }

    //绘制流星
    function playRains() {

        for (var n = 0; n < rainCount; n++) {
            var rain = rains[n];
            rain.move();//移动
            if (rain.y > window.innerHeight) {//超出界限后重来
                context.clearRect(rain.x, rain.y - rain.height, rain.width, rain.height);
                rains[n] = new MeteorRain();
                rains[n].init();
            }
        }
        setTimeout("playRains()", 2);
    }
    /*流星雨结束*/
    const canvas = document.getElementById('wave');
    const ctx = canvas.getContext('2d');

    canvas.width = window.innerWidth;
    canvas.height = 100;

    const waves = [];

    class Wave {
        constructor(x, y, speed, amplitude, frequency) {
            this.x = x;
            this.y = y;
            this.speed = speed;
            this.amplitude = amplitude;
            this.frequency = frequency;
            this.phase = Math.random() * Math.PI * 2;
        }

        update() {
            this.phase += this.speed;
        }

        draw() {
            ctx.beginPath();
            for (let i = 0; i < canvas.width; i += 10) {
                const y = this.y + Math.sin((i / this.frequency) + this.phase) * this.amplitude;
                ctx.lineTo(i, y);
            }
            ctx.lineTo(canvas.width, canvas.height);
            ctx.lineTo(0, canvas.height);
            ctx.closePath();

            ctx.fillStyle = 'rgba(0, 119, 190, 0.3)';
            ctx.fill();
        }
    }

    function createWaves() {
        const waveHeight = 40;
        const speedFactor = 0.0005;

        for (let i = 0; i < 3; i++) {
            const speed = 0.02 - i * speedFactor;
            const amplitude = waveHeight / (i + 1);
            const frequency = 80 + i * 40;
            waves.push(new Wave(0, canvas.height - (waveHeight * i), speed, amplitude, frequency));
        }
    }

    function updateWaves() {
        for (let wave of waves) {
            wave.update();
        }
    }

    function drawWaves() {
        for (let wave of waves) {
            wave.draw();
        }
    }

    function loop() {
        ctx.clearRect(0, 0, canvas.width, canvas.height);

        updateWaves();
        drawWaves();

        requestAnimationFrame(loop);
    }

    createWaves();
    loop();
    //诗词显示
    var shici = [
        "       望月怀古",
        "                -唐·张九龄",
        "海上生明月,天涯共此时。",
        "情人怨遥夜,竟夕起相思。",
        "灭烛怜光满,披衣觉露滋。",
        "不堪盈手赠,还寝梦佳期。"
    ];
    var box = document.querySelector('.greeting_box');
    var oSpanArr = [];
    // 创建每一列的结构
    shici.forEach(function (item) {
        var oP = document.createElement('p');
        for (var i = 0; i < item.length; i++) {
            // itme[i]
            //创建包裹每一个文字的元素
            var oSpan = document.createElement('span');
            //在元素中添加内容
            oSpan.innerText = item[i];
            //将文字添加到每一列中
            oSpanArr.push(oSpan)
            oP.appendChild(oSpan);
        }
        // 把每一列中的数据插入到页面当中去
        box.appendChild(oP);
    })
    // 等到页面渲染成功之后,添加透明度从而实现动画效果
    setTimeout(function () {
        oSpanArr.forEach(function (item, index) {
            // 添加动画延迟时间
            item.style.transitionDelay = index * 0.12 + 's';
            item.style.opacity = 1;
        })
    }, 100);

需要注意的是我们定义诗词的数组中加入了空格,如果想要空格在展示的时候生效,一定要在诗词展示的元素greeting_box中定义white-space: pre;属性,否则样式会不好看

结尾

你在天之涯,我在海之角,虽然相隔大海重山不能团圆,但好在能共守同一轮明月,共度同一个中秋。谨以此程序祝大家中秋快乐。

转载自:https://juejin.cn/post/7280054182995836940
评论
请登录