海上生明月,天涯共此时-中秋快乐
背景
一年一度的中秋又要来临了,中秋月圆之夜,我们望着窗外的那轮明月(阴雨天忽略),是否会思念远方的家人呢?“海上生明月,天涯共此时”这首诗便表达了诗人对家乡亲人的思念。我以此诗为主题,用代码呈现那浓浓的思乡之情。
效果图
代码实现
- 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>
- 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;/*画布背景色*/
}
- 最后一部分就是最重要的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