首页
Preview

vue3 composition-api实现波纹涟漪

接着上一章的制作锦鲤。现在我们要实现水中涟漪。首先我们先创建一个波纹组件。

j.gif

波纹组件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>

版权声明:本文内容由TeHub注册用户自发贡献,版权归原作者所有,TeHub社区不拥有其著作权,亦不承担相应法律责任。 如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

点赞(0)
收藏(0)
Hedy
大家好!我是一位前端开发工程师,拥有6年以上的前端开发经验。我熟练掌握HTML、CSS、JavaScript等语言,能够灵活运用各种前端框架,如Vue、React、Uniapp、Flutter等。我注重理论与实践相结合,能够为学员提供丰富的案例和实践项目,并以生动、易懂的语言为学员讲解前端开发的核心知识和技能。我不仅注重传授技能,更关注学员的职业发展,希望通过我的教学,帮助学员成为一名优秀的前端开发工程师。

评论(0)

添加评论