0
点赞
收藏
分享

微信扫一扫

韩式浪漫 - 落雪唯美

毅会 2023-03-30 阅读 58

韩式浪漫 - 落雪唯美_前端

前言

人物:Jimmy -> 我;Ivy -> 妻子;Eric -> 同事

这个小事件,让我有了实现落雪唯美代码效果并写这篇文章的灵感。

上周五(2022-11-11),在吃中午饭的路上,我问了下 Eric

Jimmy:周五了,有什么剧推荐看看的,周末广州要静默防控的节奏。

Eric:有点老的韩剧,但是很推荐看。《孤单又灿烂的神-鬼怪》貌似是 16 年出的,奇幻与现实结合...

Jimmy:没看过,大概多长?

Eric:有 16 集,每集一个小时多点,我之前周末跟女朋友在看。

Bala,Bala...

当晚,我问了下 Ivy,要不要看看《孤单又灿烂的神-鬼怪》这部韩剧,同事推荐,评分还不错。

Ivy:我才不看,韩剧不都偶像派那种,有点无脑

Jimmy:那我自己看

过了一会,Ivy 凑过来看了会,啊,真香。

韩式浪漫 - 落雪唯美_Math_02

周末两人看了两天,还把两个人看得感动流眼泪了~

不行,这么唯美伤感的片子,不应该只有我们流眼泪💧

糟糕,还有落雪时分,男女主角两人相拥的画面也太美了吧,不行,我得再感动一下 Ivy,给个小惊喜给她。

心动效果

实现的效果如下图所示:

韩式浪漫 - 落雪唯美_前端_03

实现讲解

如上图所示,我们实现了如下的功能:

  • 背景图上加了 사랑해요 的文字。(什么意思?读者自行百度)
  • 心形❤️跳动
  • 落雪效果

好,下面我们一个一个来讲解。

秉承代码即文档的理念加上注释理解

我们的 html 文件格式很简单:

<!-- 文本 -->
<div class="iLoveYou">사랑해요</div>
<!-- 心形 -->
<div class="heart"></div>
<!-- 雪花 -->
<canvas id="nightSky"></canvas>

文本处理。这里采用了文本渐变的方式处理:

.iLoveYou {
  background: -webkit-linear-gradient(#fff, @red);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
}

心形❤️跳动。这里只用了一个 div 处理,用到了老生常谈的 ::before::after 两个伪元素,还有 @keyframe 关键帧知识点。

.heart {
  position: absolute;
  opacity: 0.8;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%) rotate(45deg); // 旋转 45 度
  width: @heartSize;
  height: @heartSize;
  background-color:@red;
  z-index: 2;
  margin-left: calc(-@heartSize / 2);
  margin-top: -@heartSize;
  box-shadow: -5px 5px 45px @red;
  animation: heart 0.8s linear infinite; // 关键帧 heart,每 0.8 秒一次循环,无限循环
  &::before, &::after { // 处理心形的椭圆
    content: '';
    position: absolute;
    height: @heartSize;
    width: @heartSize;
    background-color:@red;
    border-radius: 50%;
  }
  &::before {
    top: -50%;
  }
  &::after {
    right: 50%;
  }
}

// 关键帧
@keyframes heart {
  0% {
    transform: rotate(45deg) scale(1.07);
  }
  80% {
    transform: rotate(45deg) scale(1.0);
  }
  100% {
    transform: rotate(45deg) scale(0.8);
  }
}

落雪效果。这个功能是本文的重点内容。我们使用 canvas 来完成。

既然是雪花飘落,那么得有雪花吧。我们创建一个雪花类,如下:

// 雪花类
class SnowFlake {
  constructor(options) {
    this.x = Math.random() * options.width; // x 坐标
    this.y = Math.random() * options.height; // y 坐标
    this.opacity = Math.random(); // 雪花❄️透明度
    this.speedX = this.random(-2, 2); // 水平移动的距离
    this.speedY = this.random(0.5, 1); // 垂直移动的距离
    this.radius = this.random(0.5, 4); // 雪花❄️的半径
  }

  // 生成 min ~ max 的数
  random(min, max) {
    return min + Math.random() * (max - min + 1);
  }
}

画布左上角是原点(0, 0),水平往右为 x 轴正向,垂直往下是 y 轴正向

然后,我们根据实际情况,生成足够多的雪花,也就是调用 new SnowFlake({ width, height }) 的次数。这时,我们生成了这么多雪花当前的位置。那么,我们接下来就是将雪花在这些位置在画布上画出来。

本文的雪花看成一个个圆来绘制。

// 画圆
ctx.beginPath();
ctx.arc(
  particlesArray[i].x,
  particlesArray[i].y,
  particlesArray[i].radius,
  0,
  Math.PI*2,
  false
);
ctx.fillStyle = gradient;// 画笔的颜色
ctx.fill(); // 填充成实心

现在绘制的雪花位置是固定的。接下来,我们需要计算雪花的下一帧的位置,并更新。

particlesArray[i].x += particlesArray[i].speedX;
particlesArray[i].y += particlesArray[i].speedY;

我们对 x 轴的下一帧坐标进行计算:当前的位置 + 该点在新建雪花对象的随机 x 轴的距离y 轴的下一帧坐标计算同理。

然后,我们更新当前的雪花坐标位置。通过关键帧监听雪花掉落的函数实现:

// 更新雪花的状态
function updateSnowFallStatus() {
  ctx.clearRect(0, 0, width, height); // 清空画布
  drawSnowFlakes();
  moveSnowFlakes();
  requestAnimationFrame(updateSnowFallStatus); // 帧动画
};

还有一个问题:雪花飘落,落出画布之外,那怎么处理呢?

因为我们已经预设了雪花的数量,那么,当雪花飘落,落出画布之外,那么落出的这些点,会重新回到画布上方重新飘落(绘制)。

// 如果雪花掉落在地上,则重新从天空掉落
if(particlesArray[i].y > height) {
  particlesArray[i].x = Math.random() * width; // 随机生成位置
  particlesArray[i].y = -50; // 固定上方垂直飘落位置
}

最后实现的效果(可体验)👇

韩式浪漫 - 落雪唯美_Math_04

后文

经过一段时间开发,我把效果给 Ivy 看 👀

JimmyIvy,像不像我们周末看的韩剧的某个场景...

说完之后,我满眼星星✨地看着她~她看了看效果,又看了看我

Ivy:咦,咦,咦,这...哈哈哈

周一去上班

Eric:怎样,看了那部韩剧了?

Jimmy:看了,全看完了,还看哭了...

Eric:牛啊,两天就看完了。看哭,不至于吧...

Jimmy:你不知道还有快进,倍速这玩意的吗?哈哈哈~ 还好这剧是 Happy Ending

韩式浪漫 - 落雪唯美_Math_05


举报

相关推荐

0 条评论