Vue.js 学习总结(11)—— Vue3 Hook 函数实战总结

前言

在 Vue 3 中,Hook 函数是一种特殊的函数,用于封装可重用的逻辑和状态管理。Hook 函数允许你在 Vue 组件中提取和复用逻辑,而不是将所有逻辑都放在组件的选项对象中。它们可以帮助你更好地组织代码,提高代码的可维护性和可测试性。Hook 函数的特点:

  1. 可重用性:Hook 函数可以在多个组件中重复使用,避免了重复编写相同的逻辑。

  2. 逻辑封装:将特定的逻辑封装在 Hook 函数中,使组件的代码更加清晰和易于理解。

  3. 状态管理:Hook 函数可以用于管理组件的状态,包括响应式数据和副作用。

  4. 测试友好:由于 Hook 函数是独立的函数,可以更容易地进行单元测试。

一、Hook 函数的使用方法

创建 Hook 函数,Hook 函数通常是一个普通的 JavaScript 函数,可以接受参数并返回一个对象或函数。例如,以下是一个简单的 Hook 函数,用于管理一个计数器:

import { reactive, toRefs } from 'vue';
   export function useCounter(initialValue = 0) {
     const state = reactive({
       count: initialValue,
     });
     const increment = () => {
       state.count++;
     };
     const decrement = () => {
       state.count--;
     };
     return {
      ...toRefs(state),
       increment,
       decrement,
     };
   }

二、在组件中使用 Hook 函数

在 Vue 组件中,可以通过导入 Hook 函数并调用它来使用其中的逻辑和状态。例如,以下是一个使用 useCounter Hook 函数的组件:

<template>
     <div>
       <p>Count: {{ count }}</p>
       <button @click="increment">Increment</button>
       <button @click="decrement">Decrement</button>
     </div>
   </template>

   <script>
   import { useCounter } from './hooks/useCounter';

   export default {
     setup() {
       const { count, increment, decrement } = useCounter();
       return {
         count,
         increment,
         decrement,
       };
     },
   };
</script>

三、Hook 函数的应用场景

  1. 状态管理:Hook 函数可以用于管理组件的状态,例如计数器、表单数据、加载状态等。

  2. 副作用管理:可以使用 Hook 函数来管理副作用,如订阅事件、定时器、异步请求等。

  3. 逻辑复用:将通用的逻辑封装在 Hook 函数中,以便在多个组件中重复使用,例如数据验证、权限检查等。

四、常见的 HOOK 函数案例

一、数据获取 Hook。假设你经常需要在不同组件中进行数据获取操作,可以创建一个数据获取 Hook。

import { ref, onMounted } from 'vue';

export function useDataFetch(apiUrl) {
  const data = ref(null);
  const loading = ref(true);
  const error = ref(null);

  onMounted(async () => {
    try {
      const response = await fetch(apiUrl);
      if (!response.ok) {
        throw new Error('Network response was not ok');
      }
      data.value = await response.json();
    } catch (err) {
      error.value = err;
    } finally {
      loading.value = false;
    }
  });

  return { data, loading, error };
}

 使用示例:

<template>
  <div v-if="loading">Loading...</div>
  <div v-else-if="error">{{ error.message }}</div>
  <div v-else>
    <!-- 展示获取到的数据 -->
    <p>{{ data.someProperty }}</p>
  </div>
</template>

<script>
import { useDataFetch } from './yourHooks';

export default {
  setup() {
    const { data, loading, error } = useDataFetch('https://your-api-url.com/data');
    return { data, loading, error };
  },
};
</script>

 二、表单验证 Hook。用于处理表单验证逻辑。

import { ref } from 'vue';

export function useFormValidation() {
  const formData = ref({});
  const errors = ref({});

  const validate = () => {
    // 假设这里进行一些简单的验证,比如检查某个字段是否为空
    if (!formData.value.username) {
      errors.value.username = 'Username is required';
    } else {
      delete errors.value.username;
    }
    // 可以根据实际需求扩展更多验证逻辑
    return Object.keys(errors.value).length === 0;
  };

  return { formData, errors, validate };
}

使用示例:

<template>
  <form @submit.prevent="submitForm">
    <input v-model="formData.username" />
    <p v-if="errors.username">{{ errors.username }}</p>
    <button>Submit</button>
  </form>
</template>

<script>
import { useFormValidation } from './yourHooks';

export default {
  setup() {
    const { formData, errors, validate } = useFormValidation();
    const submitForm = () => {
      if (validate()) {
        // 处理表单提交逻辑
      }
    };
    return { formData, errors, submitForm };
  },
};
</script>

三、鼠标位置跟踪 Hook。跟踪鼠标在页面上的位置

 使用示例:

<template>
  <div>Mouse position: {{ x }}, {{ y }}</div>
</template>

<script>
import { useMousePosition } from './yourHooks';

export default {
  setup() {
    const { x, y } = useMousePosition();
    return { x, y };
  },
};
</script>

五、Vue3 自定义 Hooks 为什么这么好用?

1、组合式 API 和选项 API

Vue2 提供的编程方式是 Options API,即选项式 API。我们需要在 data 里面定义变量,在 methods 里面定义方法,在 computed 定义计算后的逻辑。

图片

在开发功能的时候,我们需要在 data 、methods、computed 之间来回找代码。如果功能非常复杂, data 、methods、computed 等里面的代码就会非常长,不好维护。

图片

后来 Vue3 出现了,它提供的编程方式是 Composition API,即组合式 API。在开发功能的时候,我们根据逻辑功能去组织代码,一个功能所定义的所有 API 会放在一起。

图片

但是如果业务功能太复杂,script 标签里面的代码也会又臭又长,而且并不是很多人都有加注释的习惯,所以时间长了也不好维护。

图片

那能不能把相同逻辑功能的代码分别放到到不同的文件里,其他地方想用的时候直接导入就可以复用了呢?有的,自定义 Hooks 出现了。

2、自定义 Hooks 介绍

Vue 的自定义 Hooks 是一种封装可重用逻辑的方式。它允许你将复杂的逻辑提取出来,形成独立的函数,然后在不同的组件中复用。这样可以避免在多个组件中重复编写相同的逻辑,提高代码的可读性和可维护性。通俗易懂来说就是:

1.将可复用的功能逻辑放到一个 js 文件里面,并通过 export  导出。

2.定义 Hooks 的时候,js 的文件名和方法名通常以 use 开头,例如 useAddOrder、useChangeData。

3.通过 import  导入相关的 js 文件,引用时通过解构显示相关的变量和方法。

3、自定义 Hooks 案例

3.1 案例1

创建一个简单的计数器 Hooks

图片

使用 Hooks

<template>
  <div>
    <p>count: {{ count }}</p>
    <el-divider></el-divider>
    <el-button type="primary" @click="increment">新增</el-button>
    <el-button type="success" @click="decrement">减少</el-button>
  </div>
</template>
<script setup>
// 导入 hooks
import { useCounter } from "../hooks/useCounter";
// 解构引入
const { count, increment, decrement } = useCounter();
</script>

图片

3.2 案例2

创建一个监听浏览器窗口大小变化的 Hooks

图片

使用 Hooks

<template>
  <div>
     <p>浏览器窗口宽度: {{ width }}</p>
    <p>浏览器窗口高度: {{ height }}</p>
  </div>
</template>
<script setup>
// 导入 hooks
import { useWindowResize } from "../hooks/useWindowResize";
// 解构引入
const { width, height } = useWindowResize();
</script>

图片

4、自定义 Hooks 优势

所谓的自定义 Hooks 就是在开发 Vue3 项目时,我们将 script 里面相同逻辑功能的变量和方法等封装到一个 js 文件里面,然后通过 export导出。然后在任何页面都可以通过导入、解构的方式使用,大大提高代码的复用性。自定义 Hooks 将相同的功能代码从一堆代码中解耦出来,让组件结构更清晰,便于维护。

图片

Hooks 直译是“钩子”,所以又把这些定义的 js 叫做钩子函数。

Felgo是一个使用Qt框架的游戏开发工具,它基于Lua作为脚本语言,提供了丰富的游戏开发库和工具。在Felgo中实现玩家与物体的碰撞检测,你可以使用其内置的物理引擎,如Physics模块。以下是一个简单的步骤概述: 1. 首先,你需要在`player.qml`中定义一个玩家对象。这可能包括一个QObject或GameObject子类,其中包含位置、大小和运动相关的属性。添加一个`Collidable`组件,表示对象可被碰撞检测。 ```qml import Felgo 1.0 Player { id: player Collidable { colliderShape: BoxCollider { size: Size(50, 50) } // 代表玩家的尺寸 } anchors.fill: parent } ``` 2. 在`box.qml`中定义一个静态物体(box),同样使用`Collidable`组件,指定碰撞形状。 ```qml Box { id: box Collidable { colliderShape: BoxCollider { size: Size(100, 100) } // 代表box的尺寸 } anchors.centerIn: parent } ``` 3. 在`Main.qml`中,你需要集成这些部件,并监听碰撞事件。你可以通过继承自`QMLPhysicsComponent`并在`onCollide`信号处理函数中处理碰撞。例如: ```qml import Felgo 1.0 Window { visible: true width: 640 height: 480 Component.onCompleted: { physicsWorld = PhysicsWorld { // 创建一个物理世界 onCollide: { var colliders = arguments[0].colliders; // 获取碰撞的两个组件 if (colliders.contains(player)) { // 玩家与box碰撞的逻辑 console.log("Player collided with box"); // 这里可以更新游戏状态、动画或其他交互响应 } } } playerComponent = engine.rootObjects[player.id].component; boxComponent = engine.rootObjects[box.id].component; physicsWorld.addCollider(playerComponent.colliderShape); physicsWorld.addCollider(boxComponent.colliderShape); } // 添加player和box到舞台上 Player { ... } Box { ... } } ``` 4. 在`Main.qml`中,记得启用物理世界,并将玩家和box的碰撞器添加到世界中。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一杯甜酒

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值