vue3 composition-api实现波纹涟漪

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

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

7a00e54bd8220bd1a6a027013e9dda2b.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>


相关文章
|
3月前
|
JavaScript 前端开发 API
深入浅出:Vue 3 Composition API 的魅力与实践
【2月更文挑战第13天】 本文将探索 Vue 3 的核心特性之一——Composition API。通过对比 Options API,本文旨在揭示 Composition API 如何提高代码的组织性和可复用性,并通过实际案例展示其在现代前端开发中的应用。不同于传统的技术文章摘要,我们将通过一个具体的开发场景,引领读者步入 Composition API 的世界,展现它如何优雅地解决复杂组件逻辑的管理问题,从而激发读者探索和运用 Vue 3 新特性的热情。
88 1
|
3月前
|
JavaScript 前端开发 API
深入浅出:Vue 3 Composition API 的魅力
【2月更文挑战第13天】 在前端开发的世界里,Vue.js 一直占据着重要的地位。随着 Vue 3 的推出,Composition API 成为了开发者热议的焦点。本文将从一个独特的视角探讨 Composition API 的核心优势,通过对比 Options API,解析其如何优化代码组织和提升项目的可维护性。我们将通过实际案例,深入理解 Composition API 的使用方法和最佳实践,帮助开发者更好地把握这一新工具,激发前端开发的无限可能。
|
3月前
|
JavaScript API
vue 3.0 所采用的 Composition Api 和 vue 2.0 使用的 Option Api 区别
vue 3.0 所采用的 Composition Api 和 vue 2.0 使用的 Option Api 区别
61 0
|
8天前
|
缓存 JavaScript API
【颠覆想象!】Vue 3全新Reactivity API:解锁响应式编程的终极奥秘,让你的Web应用瞬间变身超能战士!
【8月更文挑战第12天】Vue 3带来了革新性的响应式系统,基于Proxy技术,提升了性能并提供了强大的API。本文通过示例介绍核心API `reactive` 和 `ref` 的使用,展示如何创建、更新响应式对象与引用,探讨深度响应式、响应式数组的管理,以及如何运用计算属性和侦听器优化应用。此外,还介绍了如何构建自定义响应式逻辑,让开发者能更高效地开发高性能Web应用。
19 1
|
10天前
|
API
浅谈 Vue3 的模块拆分与 API 重写
浅谈 Vue3 的模块拆分与 API 重写
|
11天前
|
JavaScript 前端开发 API
谈谈我对Vue 3 中的 Composition、Composition API 和 Composables 之间的区别的理解
谈谈我对Vue 3 中的 Composition、Composition API 和 Composables 之间的区别的理解
|
25天前
|
JavaScript API
vue3响应式转换常用API
vue3响应式转换常用API
|
10天前
|
JavaScript API UED
花了一天的时间,地板式扫盲了 Vue 3 所有 API 盲点
花了一天的时间,地板式扫盲了 Vue 3 所有 API 盲点
|
11天前
|
JavaScript 安全 API
Vue 3 Composition API 与 Options API:全面比较两者的区别和优缺点
Vue 3 Composition API 与 Options API:全面比较两者的区别和优缺点
|
1月前
|
前端开发 API
vue3【详解】选项式 API 实现逻辑复用
vue3【详解】选项式 API 实现逻辑复用
20 1