- A+
所属分类:Web前端
这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助
一、效果图
具体效果可参考iview官方界面iView - 一套高质量的UI组件库
大波浪效果,使用的是three.js的官方例子,需要先安装three.js支持
npm install --save three
具体可以看 three.js examples (threejs.org)
二、代码
//添加容器 <div id="iviewUi" />
<script> //引入three.js import * as THREE from 'three' export default { props: { amountX: { type: Number, default: 50 }, amountY: { type: Number, default: 50 }, //控制点颜色 color: { type: Number, default: '#097bdb' }, top: { type: Number, default: 350 } }, data() { return { count: 0, // 用来跟踪鼠标水平位置 mouseX: 0, windowHalfX: null, // 相机 camera: null, // 场景 scene: null, // 批量管理粒子 particles: null, // 渲染器 renderer: null } }, mounted() { this.init() this.animate() }, methods: { init: function() { const SEPARATION = 100 const SCREEN_WIDTH = window.innerWidth const SCREEN_HEIGHT = window.innerHeight const container = document.createElement('div') this.windowHalfX = window.innerWidth / 2 container.style.position = 'relative' container.style.top = `${this.top}px` container.style.height = `${(SCREEN_HEIGHT - this.top)}px` document.getElementById('iviewUi').appendChild(container) this.camera = new THREE.PerspectiveCamera(75, SCREEN_WIDTH / SCREEN_HEIGHT, 1, 10000) this.camera.position.z = 1000 this.scene = new THREE.Scene() const numParticles = this.amountX * this.amountY const positions = new Float32Array(numParticles * 3) const scales = new Float32Array(numParticles) // 初始化粒子位置和大小 let i = 0 let j = 0 for (let ix = 0; ix < this.amountX; ix++) { for (let iy = 0; iy < this.amountY; iy++) { positions[i] = ix * SEPARATION - ((this.amountX * SEPARATION) / 2) positions[i + 1] = 0 positions[i + 2] = iy * SEPARATION - ((this.amountY * SEPARATION) / 2) scales[j] = 1 i += 3 j++ } } const geometry = new THREE.BufferGeometry() geometry.addAttribute('position', new THREE.BufferAttribute(positions, 3)) geometry.addAttribute('scale', new THREE.BufferAttribute(scales, 1)) // 初始化粒子材质 const material = new THREE.ShaderMaterial({ uniforms: { color: { value: new THREE.Color(this.color) } }, vertexShader: ` attribute float scale; void main() { vec4 mvPosition = modelViewMatrix * vec4( position, 2.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 ); } ` }) this.particles = new THREE.Points(geometry, material) this.scene.add(this.particles) this.renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true }) this.renderer.setSize(container.clientWidth, container.clientHeight) this.renderer.setPixelRatio(window.devicePixelRatio) this.renderer.setClearAlpha(0) container.appendChild(this.renderer.domElement) window.addEventListener('resize', this.onWindowResize, { passive: false }) document.addEventListener('mousemove', this.onDocumentMouseMove, { passive: false }) document.addEventListener('touchstart', this.onDocumentTouchStart, { passive: false }) document.addEventListener('touchmove', this.onDocumentTouchMove, { passive: false }) }, render: function() { this.camera.position.x += (this.mouseX - this.camera.position.x) * 0.05 this.camera.position.y = 400 this.camera.lookAt(this.scene.position) const positions = this.particles.geometry.attributes.position.array const scales = this.particles.geometry.attributes.scale.array // 计算粒子位置及大小 let i = 0 let j = 0 for (let ix = 0; ix < this.amountX; ix++) { for (let iy = 0; iy < this.amountY; iy++) { positions[i + 1] = (Math.sin((ix + this.count) * 0.3) * 100) + (Math.sin((iy + this.count) * 0.5) * 100) scales[j] = (Math.sin((ix + this.count) * 0.3) + 1) * 8 + (Math.sin((iy + this.count) * 0.5) + 1) * 8 i += 3 j++ } } // 重新渲染粒子 this.particles.geometry.attributes.position.needsUpdate = true this.particles.geometry.attributes.scale.needsUpdate = true this.renderer.render(this.scene, this.camera) this.count += 0.1 }, animate: function() { requestAnimationFrame(this.animate) this.render() }, onDocumentMouseMove: function(event) { this.mouseX = event.clientX - this.windowHalfX }, onDocumentTouchStart: function(event) { if (event.touches.length === 1) { this.mouseX = event.touches[0].pageX - this.windowHalfX } }, onDocumentTouchMove: function(event) { if (event.touches.length === 1) { event.preventDefault() this.mouseX = event.touches[0].pageX - this.windowHalfX } }, onWindowResize: function() { this.windowHalfX = window.innerWidth / 2 this.camera.aspect = window.innerWidth / window.innerHeight this.camera.updateProjectionMatrix() this.renderer.setSize(window.innerWidth, window.innerHeight) } } } </script>
三、背景素材
如果不清晰可以去官方界面拿,如下图所示