一、效果图
先上最终效果图:
具体效果可参考iview官方界面iView - 一套高质量的UI组件库
大波浪效果,使用的是three.js的官方例子,需要先安装three.js支持,具体可以看官方实例 three.js examples (threejs.org)
二、代码
1.安装threejs
npm install --save three
2.代码(复制可用)
components文件夹新建组件waves.vue,直接复制代码如下,可直接运行:
<template>
<div id="iviewBg"></div>
</template>
<script>
import * as THREE from "three";
显示右上角fps框
// import Stats from "./stats.module";
import { onMounted } from "vue";
export default {
props: {
//控制x轴波浪的长度
amountX: {
type: Number,
default: 50,
},
//控制y轴波浪的长度
amountY: {
type: Number,
default: 50,
},
//控制点颜色
color: {
type: String,
default: "#097bdb",
},
//控制波浪的位置
top: {
type: Number,
default: 350,
},
},
setup(props) {
const SEPARATION = 100;
// let stats;
let container, camera, scene, renderer;
let particles,
count = 0;
let mouseX = 0;
let windowHalfX = window.innerWidth / 2;
function init() {
container = document.createElement("div");
document.getElementById("iviewBg").appendChild(container);
//创建透视相机
camera = new THREE.PerspectiveCamera(
75, //摄像机视锥体垂直视野角度
window.innerWidth / window.innerHeight, //摄像机视锥体长宽比
1, //摄像机视锥体近端面
10000 //摄像机视锥体远端面
);
//设置相机z轴视野
camera.position.z = 1000;
//创建场景
scene = new THREE.Scene();
const numParticles = props.amountX * props.amountY;
const positions = new Float32Array(numParticles * 3);
const scales = new Float32Array(numParticles);
let i = 0,
j = 0;
// 初始化粒子位置和大小
for (let ix = 0; ix < props.amountX; ix++) {
for (let iy = 0; iy < props.amountY; iy++) {
positions[i] = ix * SEPARATION - (props.amountX * SEPARATION) / 2; // x
positions[i + 1] = 0; // y
positions[i + 2] = iy * SEPARATION - (props.amountY * SEPARATION) / 2; // z
scales[j] = 1;
i += 3;
j++;
}
}
//是面片、线或点几何体的有效表述。包括顶点位置,面片索引、法相量、颜色值、UV 坐标和自定义缓存属性值。使用 BufferGeometry 可以有效减少向 GPU 传输上述数据所需的开销
const geometry = new THREE.BufferGeometry();
geometry.setAttribute(
"position",
new THREE.BufferAttribute(positions, 3)
);
geometry.setAttribute("scale", new THREE.BufferAttribute(scales, 1));
//着色器材质(ShaderMaterial),设置球的大小,颜色,等
const material = new THREE.ShaderMaterial({
uniforms: {
//设置球的颜色
color: { value: new THREE.Color(props.color) },
},
//控制球的大小
vertexShader:
"attribute float scale; void main() {vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );gl_PointSize = scale * ( 300.0 / - mvPosition.z );gl_Position = projectionMatrix * mvPosition;}",
fragmentShader:
"uniform vec3 color;void main() {if ( length( gl_PointCoord - vec2( 0.5, 0.5 ) ) > 0.475 ) discard;gl_FragColor = vec4( color, 1.0 );}",
});
//一个用于显示点的类。
particles = new THREE.Points(geometry, material);
//往场景中添加点
scene.add(particles);
//alpha - canvas是否包含alpha (透明度)。默认为 false。
//渲染器的背景色默认为黑色,设置渲染器的背景色为透明
renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setClearAlpha(0);
renderer.setSize(window.innerWidth, window.innerHeight);
container.appendChild(renderer.domElement);
//显示右上角fps框
// stats = new Stats();
// container.appendChild(stats.dom);
container.style.touchAction = "none";
//监听鼠标移动事件
container.addEventListener("pointermove", onPointerMove);
//调整波浪的位置
container.style.position = "relative";
container.style.top = `${props.top}px`;
window.addEventListener("resize", onWindowResize);
}
function render() {
camera.position.x += (mouseX - camera.position.x) * 0.05;
camera.position.y = 400;
camera.lookAt(scene.position);
const positions = particles.geometry.attributes.position.array;
const scales = particles.geometry.attributes.scale.array;
// 设置粒子位置和大小
let i = 0,
j = 0;
for (let ix = 0; ix < props.amountX; ix++) {
for (let iy = 0; iy < props.amountY; iy++) {
positions[i + 1] =
Math.sin((ix + count) * 0.3) * 50 +
Math.sin((iy + count) * 0.5) * 50;
scales[j] =
(Math.sin((ix + count) * 0.3) + 1) * 10 +
(Math.sin((iy + count) * 0.5) + 1) * 10;
i += 3;
j++;
}
}
particles.geometry.attributes.position.needsUpdate = true;
particles.geometry.attributes.scale.needsUpdate = true;
renderer.render(scene, camera);
count += 0.1;
}
function onWindowResize() {
windowHalfX = window.innerWidth / 2;
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
//监听鼠标移动事件
function onPointerMove(event) {
console.log(event);
if (event.isPrimary === false) return;
mouseX = event.clientX - windowHalfX;
}
function animate() {
requestAnimationFrame(animate);
render();
//fps 实时更新
// stats.update();
}
onMounted(() => {
init();
animate();
});
return {};
},
};
</script>
<style lang="scss" scoped>
#iviewBg {
width: 100%;
height: 100vh;
background: url("../assets/wavesBg.png") no-repeat;
overflow: hidden;
}
</style>
3.使用
直接在login登录页面引入组件使用
<template>
<wavesBg :top="250"></wavesBg>
<div class="login-container">
</div>
</template>
<script>
import wavesBg from "../components/wavesBg";
export default {
name: "",
components: {
wavesBg,
},
setup() {
return {
};
},
};
</script>
三、背景图片素材
如果不清晰可以去官方界面f12拿,iView - 一套高质量的UI组件库
如下图所示