简约不简单的万用网页星空背景
AI-摘要
切换
小郭 GPT
AI初始化中...
介绍自己
生成本文简介
推荐相关文章
前往主页
前往tianli博客
效果展示
VUE源码
<script setup>
import { onMounted, ref } from 'vue'
const STAR_COLOR = '#aaa';
const STAR_SIZE = 3;
const STAR_MIN_SCALE = 0.2
const OVERFLOW_THRESHOLD = 50; // 溢出阈值
const STAR_COUNT = (window.innerWidth + window.innerHeight) / 8;
const canvas = ref(null)
var context
let scale = 1 // 缩放比例
let width, height
let stars = []
let pointerX, pointerY // 鼠标指针
let velocity = { x: 0, y: 0, tx: 0, ty: 0, z: 0.0000 } // 速度对象
// 定义触摸输入标志
let touchInput = false;
onMounted(() => {
context = canvas.value.getContext('2d');
drawStars();
})
const drawStars = () => {
generate(); // 生成星星
resize(); // 调整大小
step(); // 运行动画
// 当窗口大小改变时,重新调整大小
window.onresize = resize;
// 当鼠标在canvas上移动时,更新鼠标指针位置
canvas.value.onmousemove = onMouseMove;
// 当触摸屏在canvas上移动时,更新鼠标指针位置
canvas.value.ontouchmove = onTouchMove;
// 当触摸屏离开canvas时,更新鼠标指针位置
canvas.value.ontouchend = onMouseLeave;
// 当鼠标离开文档时,更新鼠标指针位置
document.onmouseleave = onMouseLeave;
}
// 生成星星
const generate = () => {
for (let i = 0; i < STAR_COUNT; i++) {
stars.push({
x: 0,
y: 0,
// 大小为 STAR_MIN_SCALE 到 1 之间的数字
z: STAR_MIN_SCALE + Math.random() * (1 - STAR_MIN_SCALE),
});
}
}
// 将星星放置到随机位置
const placeStar = (star) => {
star.x = Math.random() * width;
star.y = Math.random() * height;
}
// 回收星星并重新放置到新的位置
const recycleStar = (star) => {
// 初始化方向为 'z'
let direction = 'z';
// 获取速度的绝对值
let vx = Math.abs(velocity.x);
let vy = Math.abs(velocity.y);
// 如果速度的绝对值大于 1,则根据速度的大小随机确定方向
if (vx > 1 || vy > 1) {
let axis;
// 如果水平速度大于垂直速度,则根据水平速度的比例随机确定水平或垂直方向
if (vx > vy) {
axis = Math.random() < vx / (vx + vy) ? 'h' : 'v';
} else {
axis = Math.random() < vy / (vx + vy) ? 'v' : 'h';
}
// 根据方向确定具体的移动方向
if (axis === 'h') {
direction = velocity.x > 0 ? 'l' : 'r';
} else {
direction = velocity.y > 0 ? 't' : 'b';
}
}
// 随机设置星星的缩放比例
star.z = STAR_MIN_SCALE + Math.random() * (1 - STAR_MIN_SCALE);
// 根据方向设置星星的位置
if (direction === 'z') {
// 如果方向为 'z',则将星星放置在屏幕中心
star.z = 0.1;
star.x = Math.random() * width;
star.y = Math.random() * height;
} else if (direction === 'l') {
// 如果方向为 'l',则将星星放置在屏幕左侧
star.x = -OVERFLOW_THRESHOLD;
star.y = height * Math.random();
} else if (direction === 'r') {
// 如果方向为 'r',则将星星放置在屏幕右侧
star.x = width + OVERFLOW_THRESHOLD;
star.y = height * Math.random();
} else if (direction === 't') {
// 如果方向为 't',则将星星放置在屏幕顶部
star.x = width * Math.random();
star.y = -OVERFLOW_THRESHOLD;
} else if (direction === 'b') {
// 如果方向为 'b',则将星星放置在屏幕底部
star.x = width * Math.random();
star.y = height + OVERFLOW_THRESHOLD;
}
}
// 调整大小
const resize = () => {
// 获取设备像素比例
scale = window.devicePixelRatio || 1;
// 设置画布的宽度和高度
width = window.innerWidth * scale;
height = window.innerHeight * scale;
canvas.value.width = width;
canvas.value.height = height;
// 将所有星星重新放置到屏幕上
stars.forEach(placeStar);
}
// 动画的每一帧
const step = () => {
// 清空画布
context.clearRect(0, 0, width, height);
// 更新星星的位置和速度
update();
// 绘制星星
render();
// 请求下一帧动画
requestAnimationFrame(step);
}
// 更新星星的位置和速度
const update = () => {
// 缓动速度
velocity.tx *= 0.96;
velocity.ty *= 0.96;
// 更新速度
velocity.x += (velocity.tx - velocity.x) * 0.8;
velocity.y += (velocity.ty - velocity.y) * 0.8;
// 遍历所有星星
stars.forEach((star) => {
// 根据速度和缩放比例更新星星的位置
star.x += velocity.x * star.z;
star.y += velocity.y * star.z;
// 根据速度和缩放比例更新星星的位置(使星星围绕屏幕中心旋转)
star.x += (star.x - width / 2) * velocity.z * star.z;
star.y += (star.y - height / 2) * velocity.z * star.z;
// 更新星星的缩放比例
star.z += velocity.z;
// 如果星星超出屏幕范围,则重新放置到屏幕上
if (
star.x < -OVERFLOW_THRESHOLD ||
star.x > width + OVERFLOW_THRESHOLD ||
star.y < -OVERFLOW_THRESHOLD ||
star.y > height + OVERFLOW_THRESHOLD
) {
recycleStar(star);
}
});
}
// 绘制星星
const render = () => {
// 遍历所有星星
stars.forEach((star) => {
// 设置绘制星星的样式
context.beginPath();
context.lineCap = 'round';
context.lineWidth = STAR_SIZE * star.z * scale;
context.globalAlpha = 0.5 + 0.5 * Math.random();
context.strokeStyle = STAR_COLOR;
// 绘制星星的路径
context.beginPath();
context.moveTo(star.x, star.y);
// 计算星星的尾巴坐标
let tailX = velocity.x * 2;
let tailY = velocity.y * 2;
// 如果尾巴坐标的绝对值小于0.1,则设置为0.5
if (Math.abs(tailX) < 0.1) tailX = 0.5;
if (Math.abs(tailY) < 0.1) tailY = 0.5;
// 绘制星星的尾巴
context.lineTo(star.x + tailX, star.y + tailY);
context.stroke();
});
}
// 移动鼠标指针
const movePointer = (x, y) => {
x /= 5;
y /= 5;
// 如果之前有记录鼠标指针的位置,则计算鼠标指针的移动距离,并更新速度
if (typeof pointerX === 'number' && typeof pointerY === 'number') {
let ox = x - pointerX;
let oy = y - pointerY;
velocity.tx = velocity.tx + (ox / 8) * scale * (touchInput ? 1 : -1);
velocity.ty = velocity.ty + (oy / 8) * scale * (touchInput ? 1 : -1);
}
// 更新鼠标指针的位置
pointerX = x;
pointerY = y;
}
// 当鼠标在 canvas 上移动时的事件处理函数
const onMouseMove = (event) => {
touchInput = false;
movePointer(event.clientX, event.clientY);
}
// 当触摸屏在 canvas 上移动时的事件处理函数
const onTouchMove = (event) => {
touchInput = true;
movePointer(event.touches[0].clientX, event.touches[0].clientY, true);
event.preventDefault();
}
// 当鼠标离开 canvas 时的事件处理函数
const onMouseLeave = () => {
pointerX = null;
pointerY = null;
}
</script>
<template>
<canvas class="canvas" ref="canvas"></canvas>
</template>
<style scoped>
/* 背景星空 */
.canvas {
position: fixed;
width: 100%;
height: 100%;
z-index: 0;
}
</style>
- 感谢你赐予我前进的力量
赞赏者名单
因为你们的支持让我意识到写文章的价值🙏
本文是原创文章,采用 CC BY-NC-ND 4.0 协议,完整转载请注明来自 郭同学的笔记本
评论
匿名评论
隐私政策
你无需删除空行,直接评论以获取最佳展示效果