接着上一章的制作锦鲤。现在我们要实现水中涟漪。首先我们先创建一个波纹组件。
波纹组件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>
评论(0)