代码雨
1. 效果
1.1. 代码雨效果演示
1.2. 工具栏配置
字体: 代码雨代码大小 速度: 代码雨速度 持久: 代码飘落持续度
2. 实现
2.1. 实现步骤
代码雨是一种炫酷的动态效果,可以通过使用 HTML5 <canvas>
元素和 JavaScript 来实现。在以下的代码中,我们使用了 Vue 3 的 <script setup>
语法来编写组件逻辑。
首先,在模板中,我们创建了一个具有特定类名 .canvas-wrap
的容器元素,用于容纳 <canvas>
元素和工具栏。然后,我们在 <canvas>
元素上设置了 ID 为 "canvas"。
接下来,在 <script setup>
部分,我们引入了 onMounted
和 ref
方法,它们都是 Vue 3 提供的功能。我们创建了三个响应式引用:fontSize
,speed
,long
,分别用于控制字体大小、下落速度和持续时间。
然后,我们定义了一个 initCanvas
函数,用于初始化画布。在该函数中,我们首先通过 querySelector
获取到容器元素和 <canvas>
元素,并设置了画布的宽度和高度为容器元素的宽度和高度。
接下来,我们使用 <canvas>
的上下文对象 getContext("2d")
获取 2D 渲染上下文。然后,我们清除画布,以便绘制新的帧。
然后,我们设置了文字的颜色、字体大小,并使用循环遍历数组 arr
,该数组长度等于容器宽度除以字体大小,用于存储每个字符下落的位置。
在循环中,我们使用 fillText
方法绘制随机选取的字符,在合适的位置上,初始位置为 index * 字体大小
和 item + 字体大小
。其中,item
为数组中的元素,表示每个字符下落的位置。
然后,我们更新数组中的元素值,如果字符超出容器高度或随机数大于持续时间,则重置其位置为 0;否则,将字符位置增加字体大小。
最后,我们根据设定的速度刷新画布,可以通过 setTimeout 或 requestAnimationFrame 来实现动画效果。
在 onMounted
生命周期钩子函数中,我们调用了 initCanvas
函数,以确保在组件挂载后执行初始化画布的操作。
此外,我们还提供了一个工具栏,可以通过 Vue 的双向数据绑定来控制代码雨效果的参数,例如:字体大小、下落速度和持续时间。点击“刷新”按钮时,会重新初始化画布,从而应用新的参数设置。
通过以上步骤,我们成功实现了一个简单的代码雨效果!
2.2. 代码
<script setup>
import { onMounted, ref } from "vue";
const [fontSize, speed, long] = [ref(8), ref(40), ref(960)];
const text = "abcdefgasdkflasdflasfkls8491042890128039".split("");
const initCanvas = () => {
const wrap = document.querySelector(".canvas-wrap");
const arr = new Array(Math.ceil(wrap.clientWidth / fontSize.value)).fill(0);
const canvas = document.querySelector("#canvas");
canvas.width = wrap.clientWidth;
canvas.height = wrap.clientHeight;
const ctx = canvas.getContext("2d");
ctx.clearRect(0, 0, canvas.clientWidth, canvas.clientHeight);
const initRain = () => {
ctx.fillStyle = "rgba(0, 0, 0, 0.05)"; // 填充背景颜色
ctx.fillRect(0, 0, canvas.clientWidth, canvas.clientHeight); // 背景
ctx.fillStyle = "rgba(0, 255, 0, 1)"; // 文字颜色
ctx.font = `${fontSize.value}px Arial`;
arr.forEach((item, index) => {
ctx.fillText(
text[Math.floor(Math.random() * text.length)],
index * fontSize.value,
item + fontSize.value
);
arr[index] =
item > canvas.clientHeight || Math.random() * 1000 > long.value
? 0
: item + fontSize.value;
});
speed.value > 0
? setTimeout(initRain, speed.value)
: requestAnimationFrame(initRain);
};
initRain();
};
onMounted(() => {
initCanvas();
});
</script>
<template>
<div class="canvas-wrap">
<canvas id="canvas"></canvas>
<div class="tools">
字体:<el-input-number
v-model="fontSize"
:min="1"
:max="50"
size="small"
/> 速度:<el-input-number
v-model="speed"
:min="0"
:max="1000"
:step="10"
size="small"
/> 持久:<el-input-number
v-model="long"
:min="0"
:max="1000"
:step="10"
size="small"
/>
<el-button @click="initCanvas" size="small">刷新</el-button>
</div>
</div>
</template>
<style lang="scss">
.canvas-wrap {
width: 100%;
height: calc(100vh - 135px);
border: 1px solid silver;
box-sizing: border-box;
font-size: 12px;
.tools {
padding: 5px 10px;
margin-top: 5px;
border: 1px solid silver;
}
}
</style>