vue3从精通到入门22:自定义 Hooks

自定义 Hooks 就是将可重用的逻辑抽象到一个函数中,这样你可以在不同的组件中重复使用这些逻辑,而不必重复编写相同的代码。

使用场景

1. 处理异步数据

当你需要在多个组件中处理异步数据时,可以创建一个自定义 Hook 来封装相关的逻辑。

<!-- useAsyncData.ts -->  
import { ref, onMounted, onUnmounted } from 'vue';  export function useAsyncData(fetchData: () => Promise<any>) {  const data = ref(null);  const error = ref(null);  const isLoading = ref(false);  const fetch = async () => {  try {  isLoading.value = true;  data.value = await fetchData();  } catch (e) {  error.value = e;  } finally {  isLoading.value = false;  }  };  onMounted(fetch);  onUnmounted(() => {  // 清理逻辑(如果需要)  });  return { data, error, isLoading, fetch };  
}

在组件中使用这个自定义 Hook 来处理异步数据:

<!-- MyComponent.vue -->  
<template>  <div>  <div v-if="isLoading">Loading...</div>  <div v-else-if="error">Error: {{ error }}</div>  <div v-else>{{ data }}</div>  <button @click="fetch">Fetch Data</button>  </div>  
</template>  <script setup lang="ts">  
import { useAsyncData } from './useAsyncData';  const fetchData = async () => {  // 模拟异步数据获取  return new Promise((resolve) => {  setTimeout(() => resolve('Async data!'), 2000);  });  
};  const { data, error, isLoading, fetch } = useAsyncData(fetchData);  
</script>

2. 管理表单状态

当处理表单输入时,你可能需要跟踪多个字段的状态,并处理验证逻辑。自定义 Hook 可以帮助你封装这些逻辑。

<!-- useForm.ts -->  
import { ref, watch, computed } from 'vue';  export function useForm(initialValues: any) {  const form = ref(initialValues);  const errors = ref({});  const validate = () => {  // 验证逻辑  errors.value = {}; // 清除之前的错误  // ... 验证字段并设置 errors.value  };  const reset = () => {  form.value = initialValues;  errors.value = {};  };  watch(form, () => {  validate();  }, { deep: true });  return { form, errors, validate, reset };  
}

 在表单组件中使用这个自定义 Hook:

<!-- FormComponent.vue -->  
<template>  <form @submit.prevent="handleSubmit">  <input v-model="form.name" type="text" placeholder="Name" />  <span v-if="errors.name">{{ errors.name }}</span>  <button type="submit">Submit</button>  </form>  
</template>  <script setup lang="ts">  
import { useForm } from './useForm';  const initialFormValues = { name: '' };  
const { form, errors, validate, reset } = useForm(initialFormValues);  const handleSubmit = () => {  if (validate()) {  // 表单验证通过,执行提交逻辑  }  
};  
</script>

3. 处理窗口大小变化

如果你需要在多个组件中响应窗口大小的变化,可以创建一个自定义 Hook 来监听 resize 事件。

<!-- useWindowSize.ts -->  
import {ref,onMounted,onUnmounted
} from 'vue';export function useWindowSize() {const size = ref({width: window.innerWidth,height: window.innerHeight});const updateSize = () => {size.value = {width: window.innerWidth,height: window.innerHeight};};onMounted(() => {window.addEventListener('resize', updateSize);updateSize(); // 初始化尺寸});onUnmounted(() => {window.removeEventListener('resize', updateSize);});return size;
}

在响应窗口大小变化的组件中使用这个自定义 Hook:

<!-- ResponsiveComponent.vue -->  
<template>  <div>  Window width: {{ windowSize.width }}px  <br>  Window height: {{ windowSize.height }}px  </div>  
</template>  <script setup lang="ts">  
import { useWindowSize } from './useWindowSize';  const windowSize = useWindowSize();  
</script>

4. 管理定时器

当你需要在组件中设置和管理定时器时,自定义 Hook 可以帮助你封装定时器的创建和清理逻辑。

<!-- useInterval.ts -->  
import { ref, onMounted, onUnmounted } from 'vue';  export function useInterval(callback: () => void, delay: number | null) {  const intervalId = ref<number | null>(null);  const start = () => {  if (delay !== null) {  intervalId.value = window.setInterval(callback, delay);  }  };  const stop = () => {  if (intervalId.value !== null) {  window.clearInterval(intervalId.value);  intervalId.value = null;  }  };  onMounted(start);  onUnmounted(stop);  return { start, stop };  
}

在需要定时器的组件中使用这个自定义 Hook:

<!-- TimerComponent.vue -->  
<template>  <div>  <button @click="toggleTimer">Toggle Timer</button>  </div>  
</template>  <script setup lang="ts">  
import { useInterval } from './useInterval';  const toggleTimer = ref(false);  const { start, stop } = useInterval(() => {  console.log('Timer ticked!');  
}, toggleTimer.value ? 1000 : null);  const handleToggle = () => {  toggleTimer.value = !toggleTimer.value;  if (toggleTimer.value) {  start();  } else {  stop();  }  
};  
</script>

5. 管理异步状态

在 Vue 组件中处理异步操作(如 API 请求)时,可以使用自定义 Hook 来管理状态。这有助于封装异步逻辑,使得组件代码更加简洁和易于理解。

<!-- useAsyncData.ts -->  
import { ref, onMounted, onUnmounted } from 'vue';  export function useAsyncData<T>(fetchData: () => Promise<T>): { data: T | null; error: Error | null; loading: boolean } {  const data = ref<T | null>(null);  const error = ref<Error | null>(null);  const loading = ref(true);  const fetch = async () => {  try {  data.value = await fetchData();  error.value = null;  } catch (e) {  error.value = e;  } finally {  loading.value = false;  }  };  onMounted(fetch);  // 如果需要取消请求,可以在这里实现逻辑,例如使用 AbortController  // onUnmounted(() => {  //   // 取消请求  // });  return { data, error, loading };  
}

在组件中使用这个自定义 Hook 来处理异步数据:

<!-- AsyncComponent.vue -->  
<template>  <div>  <div v-if="loading">Loading...</div>  <div v-else-if="error">Error: {{ error.message }}</div>  <div v-else>Data loaded: {{ data }}</div>  </div>  
</template>  <script setup lang="ts">  
import { useAsyncData } from './useAsyncData';  const fetchData = async () => {  // 模拟异步请求  await new Promise(resolve => setTimeout(resolve, 2000));  return 'Data from API';  
};  const { data, error, loading } = useAsyncData(fetchData);  
</script>

6. 封装表单处理逻辑

对于常见的表单处理逻辑,如验证、提交等,可以创建一个自定义 Hook 来封装这些功能。

<!-- useForm.ts -->  
import { ref, reactive, watch } from 'vue';  export function useForm<T>(initialValues: T) {  const form = reactive<T>(initialValues);  const errors = reactive<Record<keyof T, string | null>>({} as any);  const validateField = (fieldName: keyof T, validator: (value: any) => string | null) => {  const error = validator(form[fieldName]);  errors[fieldName] = error;  return !error;  };  const validate = () => {  let isValid = true;  for (const fieldName of Object.keys(form) as (keyof T)[]) {  const validator = (form[fieldName] as any).validator;  if (validator) {  isValid = validateField(fieldName, validator) && isValid;  }  }  return isValid;  };  const reset = () => {  Object.keys(form).forEach(key => {  form[key as keyof T] = initialValues[key as keyof T];  });  Object.keys(errors).forEach(key => {  errors[key as keyof T] = null;  });  };  return { form, errors, validate, reset };  
}

在表单组件中使用这个自定义 Hook:

<!-- FormComponent.vue -->  
<template>  <form @submit.prevent="handleSubmit">  <input v-model="form.name" type="text" placeholder="Name" />  <span v-if="errors.name">{{ errors.name }}</span>  <button type="submit">Submit</button>  </form>  
</template>  <script setup lang="ts">  
import { useForm } from './useForm';  const initialValues = {  name: '',  nameValidator: (value: string) => (value.trim() === '' ? 'Name is required' : null)  
};  const { form, errors, validate, reset } = useForm(initialValues);  const handleSubmit = async () => {  if (validate()) {  // 表单验证通过,提交表单逻辑  console.log('Form submitted:', form);  }

7. 封装动画逻辑

动画效果是 Web 应用中常见的交互形式,我们可以使用自定义 Hook 来封装动画逻辑。

<!-- useAnimation.ts -->  
import { ref, onMounted, onUnmounted } from 'vue';  export function useAnimation(duration: number) {  const progress = ref(0);  let animationFrameId: number | null = null;  const startAnimation = () => {  if (animationFrameId) return;  animationFrameId = requestAnimationFrame(animate);  };  const stopAnimation = () => {  if (animationFrameId) {  cancelAnimationFrame(animationFrameId);  animationFrameId = null;  }  };  const animate = () => {  if (progress.value < 1) {  progress.value += 0.01;  animationFrameId = requestAnimationFrame(animate);  } else {  stopAnimation();  }  };  onMounted(startAnimation);  onUnmounted(stopAnimation);  return { progress, startAnimation, stopAnimation };  
}

在组件中使用这个自定义 Hook 来添加动画效果:

<!-- AnimatedComponent.vue -->  
<template>  <div :style="{ opacity: progress }">  <p>This element is animated!</p>  </div>  <button @click="toggleAnimation">Toggle Animation</button>  
</template>  <script setup lang="ts">  
import { useAnimation } from './useAnimation';  const { progress, startAnimation, stopAnimation } = useAnimation(1000); // 动画时长为 1 秒  const toggleAnimation = () => {  if (progress.value === 0) {  startAnimation();  } else {  stopAnimation();  }  
};  
</script>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/815519.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【产品经理修炼之道】- 融资租赁相关业务介绍

一、什么是融资租赁&#xff1f; 根据《民法典》第735条的规定&#xff0c;融资租赁合同是出租人根据承租人对出卖人、租赁物的选择&#xff0c;向出卖人购买租赁物&#xff0c;提供给承租人使用&#xff0c;承租人支付租金的合同。 例如&#xff0c;A工厂因业务发展需要欲购置…

c/c++普通for循环学习

学习一下 for 循环的几种不同方式&#xff0c;了解一下原理及差异 完整的测试代码参考 GitHub &#xff1a;for 循环测试代码 1 常用形态 对于 for 循环来说&#xff0c;最常用的形态如下 for (表达式1; 表达式2; 表达式3) {// code }流程图如下&#xff1a; 编写测试代码…

stack和queue模拟实现

前言 上一期我们介绍了stack和queue的使用&#xff0c;本期我们来模拟实现一下他们&#xff01; 本期内容介绍 容器适配器 deque介绍 为什么stack和queue的底层选择deque为默认容器&#xff1f; stack 模拟现实 queue 模拟实现 什么是容器适配器&#xff1f; 适配器是一种设…

编程新手必看,Python推导式学习总结(16)

介绍&#xff1a; Python推导式是一种简洁、高效的创建列表、字典或集合的方法。它使用一种类似于数学公式的语法&#xff0c;通过一个表达式和一个循环来生成一个新的数据结构。 以下是一些常见的Python推导式&#xff1a; 列表推导式&#xff08;List Comprehension&#xf…

springboot抑郁症科普知识测试系统ssm-java

本系统设计了二种角色&#xff1a;管理员&#xff0c;用户。通过此系统&#xff0c;管理员可以在线视频、案例展示、、测试试卷、测试试题进行测试。以及在线对测试试卷进行批阅和批量删除&#xff0c;用户可以对自己的测试试卷进行测试&#xff0c;对管理员已经批阅过的试卷可…

MySQL——链表

主键&#xff1a;非空 唯一&#xff08;针对整列数据而言&#xff09; 为了方便管理一般主键都是设置为自增 外键&#xff1a;一张表中的一列的值是另一张表的主键&#xff0c;使用外键建立两张数据表的数据关系 一、两张表连接 将两张表格拼接成一个表 1、格式&#xff1a;s…

Linux ln命令

ln 是 Linux 中的一个重要命令&#xff0c;用于创建硬链接或符号链接&#xff08;也称为软链接&#xff09;。链接在 Unix 和 Linux 系统中是文件系统中的一种对象&#xff0c;它引用另一个文件或目录。 以下是 ln 命令的基本用法和选项&#xff1a; 基本语法 ln [选项] 源文…

NL2SQL实践系列(1):深入解析Prompt工程在text2sql中的应用技巧

NL2SQL实践系列(1)&#xff1a;深入解析Prompt工程在text2sql中的应用技巧 NL2SQL基础系列(1)&#xff1a;业界顶尖排行榜、权威测评数据集及LLM大模型&#xff08;Spider vs BIRD&#xff09;全面对比优劣分析[Text2SQL、Text2DSL] NL2SQL基础系列(2)&#xff1a;主流大模型…

cURL error 60: SSL certificate problem: unable to get local issuer certifica 解决

无法获取本地颁发者证书 Windows版本 linux版本解决方案 cURL error 60: SSL certificate problem: unable to get local issuer certifica 解决 Laravel 使用GuzzleHttp请求第三方https接口报错 获取 headers windows 清晰版本 Windows版本 1.到 https://curl.haxx.se/ca/cace…

STK与matlab交互 Astrogator模块 (11)

一、背景知识 前面由于定轨的大作业&#xff0c;关于Astrogator模块的学习有所滞后&#xff0c;在本节将重新聚焦Astrogator模块&#xff0c;在本节中&#xff0c;首先解决的问题是已知两个卫星的轨道六根数&#xff0c;求解其中某一颗卫星LVLH坐标下另一颗卫星的位置速度。这…

AI实践与学习4_大模型之检索增强生成RAG实践

背景 针对AI解题业务场景&#xff0c;靠着ToT、CoT等提示词规则去引导模型的输出答案&#xff0c;一定程度相比Zero-shot解答质量更高&#xff08;正确率、格式&#xff09;等。但是针对某些测试CASE&#xff0c;LLM仍然不能输出期望的正确结果&#xff0c;将AI解题应用生产仍…

AcWing 796. 子矩阵的和——算法基础课题解

AcWing 796. 子矩阵的和 题目描述 输入一个 n 行 m 列的整数矩阵&#xff0c;再输入 q 个询问&#xff0c;每个询问包含四个整数 x1,y1,x2,y2&#xff0c;表示一个子矩阵的左上角坐标和右下角坐标。 对于每个询问输出子矩阵中所有数的和。 输入格式 第一行包含三个整数 n&…

js的函数

在JavaScript中&#xff0c;函数是一段可重复使用的代码块&#xff0c;它可以接收输入&#xff08;参数&#xff09;&#xff0c;执行某些操作&#xff0c;并可能返回输出。以下是JavaScript函数的一些基本示例和详细说明&#xff1a; 1. 基本函数 javascript复制代码 functi…

导航指令生成新篇章:将语义地图转化为机器人眼中的“道路”

引言&#xff1a;导航指令生成的挑战与机遇 在人工智能领域&#xff0c;视觉与语言导航&#xff08;Vision and Language Navigation, VLN&#xff09;任务是一个充满挑战的研究领域&#xff0c;它要求智能体根据自然语言指令在物理环境中进行导航。然而&#xff0c;VLN任务的…

C++取小数运算

搜了半天C如何取小数&#xff0c;都写得*&#xff0c;一点不是我想要的答案&#xff0c;觉得我写的可以的点个赞再走&#xff01; 一句话&#xff1a; 小数部分 原来的数 - 原来的数/1 或者 小数部分 原来的数 - int&#xff08;原来的数&#xff09; 例&#xff1a; 想…

《QT实用小工具·十九》回车跳转到不同的编辑框

1、概述 源码放在文章末尾 该项目实现通过回车键让光标从一个编辑框跳转到另一个编辑框&#xff0c;下面是demo演示&#xff1a; 项目部分代码如下&#xff1a; #ifndef WIDGET_H #define WIDGET_H#include <QWidget>namespace Ui { class Widget; }class Widget : p…

使用SquareLine Studio创建LVGL项目到IMX6uLL平台

文章目录 前言一、SquareLine Studio是什么&#xff1f;二、下载安装三、工程配置四、交叉编译 前言 遇到的问题&#xff1a;#error LV_COLOR_DEPTH should be 16bit to match SquareLine Studios settings&#xff0c;解决方法见# 四、交叉编译 一、SquareLine Studio是什么…

appium driver install uiautomator2 安装失败

报错 Installing ‘uiautomator2’ using NPM install spec ‘appium-uiautomator2-driver’ Error: Encountered an error when installing package: npm command ‘install --save-dev --no-progress --no-audit --omitpeer --save-exact --global-style --no-package-lock…

【全网最全】Maven面试题

目录 一、Maven是什么&#xff1f;为什么要用它&#xff1f; 二、Maven添加依赖需要什么标签&#xff1f; 三、说一说Maven的生命周期&#xff0c;分别是什么命令&#xff1f; 四、Maven都有哪些依赖范围&#xff1f; 五、说一说什么是Maven的依赖传递&#xff1f; 六、什…

汉语拼音中的轻声规则简直让人崩溃

找到方便和合适的与人教社教材中的拼音接近的字体本来就不容易&#xff0c;而准确高效地把短短一篇文字中的轻声全都标对&#xff0c;也是一件让人头大的事&#xff01;