接着上一章的制作锦鲤。现在我们要实现水中涟漪。首先我们先创建一个波纹组件。
波纹组件Wave
<template> <!-- 显示波纹的组件 --> <div class="WaveRoot" :style="{ left: `${x - 50}px`, top: `${y - 50}px`, }" /> </template> <script lang="ts"> import { defineComponent, onMounted } from "vue"; export default defineComponent({ name: "Wave", // x、y 波纹的位置 props: { x: { type: Number, default: 0 }, y: { type: Number, default: 0 }, }, setup(_, ctx) { onMounted(() => { window.setTimeout(() => { ctx.emit("end"); }, 6000); }); }, }); </script> <style lang="scss" scoped> .WaveRoot { position: absolute; left: 0; top: 0; width: 100px; height: 100px; border: 1.8px solid currentColor; border-radius: 100%; pointer-events: none; animation: appear 5s both; &::before { content: ""; position: absolute; width: 80%; height: 80%; left: calc(10% - 1px); top: calc(10% - 1px); border: 1.4px solid currentColor; border-radius: 100%; } &::after { content: ""; position: absolute; width: 60%; height: 60%; left: calc(20% - 1px); top: calc(20% - 1px); border: 1.2px solid currentColor; border-radius: 100%; } } @keyframes appear { 0% { transform: scale(0); opacity: 0; } 10% { transform: scale(0.1); opacity: 0.3; } 100% { transform: scale(2.5); opacity: 0; } } </style>
创建一个多波纹排序的组件waveLayer
组件用来管理波纹和显示涟漪的层
<template> <div class="WaveLayerRoot"> <Wave v-for="waveProps in stageState.waveList" class="WaveElement" :key="waveProps.id" :x="waveProps.position.x" :y="waveProps.position.y" @end="removeWave(waveProps)" /> </div> </template> <script lang="ts"> import { defineComponent, reactive} from "vue"; import Wave from "./Wave.vue"; import { Point } from "../core/Point"; import { useMouse } from "../core/useMouse"; import { useClick } from "../core/useClick"; import { useTicker } from "../core/useTicker"; import { WaveModel } from "../core/WaveModel"; /** * 波纹状态管理 */ type LayerState = { waveList: WaveModel[]; }; export default defineComponent({ name: "WaveLayer", components: { Wave }, setup(_, ctx) { // 状态 const stageState = reactive<LayerState>({ waveList: [], }); // 位置 const { mousePos: destination } = useMouse(); // 添加波纹 const addWave = (x: number, y: number) => { const RND = 100; const rndX = (Math.random() - 0.5) * RND; const rndY = (Math.random() - 0.5) * RND; stageState.waveList.push(new WaveModel(new Point(x + rndX, y + rndY))); }; // 移除波纹 const removeWave = (wave: WaveModel) => { stageState.waveList = stageState.waveList.filter((w) => w !== wave); }; // 定时增加涟漪,跟背景石头一样 useTicker(() => { if (Math.random() < 0.93) { return; } addWave(destination.x, destination.y); }, 100); useClick(() => { addWave(destination.x, destination.y); }); return { stageState, addWave, removeWave, }; }, }); </script> <style scoped lang="scss"> .WaveLayerRoot { position: absolute; top: 0; left: 0; width: 100%; height: 100%; .WaveElement { color: rgb(129, 170, 189); } } </style>
创建一个WaveModel用来管理涟漪位置和数量
import { Point } from "./Point"; let instanseCount = 0; export class WaveModel { readonly id = instanseCount++; readonly position: Point; constructor(p: Point) { this.position = p; } }
使用
<template> <!--合成背景、锦鲤和涟漪--> <stage-bg class="StageRoot" > <FishLayer :maxFish="maxFish" @count-changed="fishCountChanged" /> <wave-layer /> </stage-bg> </template> <script lang="ts"> import FishLayer from "./FishLayer.vue"; import {defineComponent} from "vue"; import StageBg from "./stageBg.vue"; import WaveLayer from "./waveLayer.vue"; export default defineComponent({ name: "stageFish", components: {WaveLayer, StageBg, FishLayer}, props: { maxFish: { type: Number, default: 50 }, }, setup(props,ctx) { console.log('33333',props.maxFish) //锦鲤数量变化时的事件 const fishCountChanged = (count: number) => { ctx.emit('count-changed', count); } return { fishCountChanged } } }) </script>