Vue3基础知识-Hook实现逻辑复用、代码解耦

一、完整代码示例。

1. 自定义 Hook:hooks/useMousePosition.js

javascript 复制代码
import { reactive, onMounted, onUnmounted } from 'vue'

/*
hook本质:
    一个普通函数,内部利用Vue3的reactive、onMounted等API封装"响应式数据+逻辑+生命周期"
    最后返回需要暴露的数据或方法。
hook好处:
    逻辑复用:如果多个组件都需要 "监听鼠标位置",只需调用 useMousePosition() 即可,无需重复写监听代码。
    逻辑集中:比Vue 的mixin更清晰,避免命名冲突。
    响应式联动:hook可以返回响应式对象供其他组件使用
*/

// 自定义 hook:命名通常以 use 开头
export default function() {
    // 1. 响应式数据:存储鼠标坐标
    const mouse = reactive({
        x: 0,
        y: 0
    })

    // 2. 方法:更新鼠标坐标
    function updatePosition(e) {
        mouse.x = e.pageX
        mouse.y = e.pageY
    }

    // 3. 生命周期钩子:组件挂载后开始监听
    onMounted(() => {
        window.addEventListener('mousemove', updatePosition)
    })

    // 4. 生命周期钩子:组件卸载前停止监听(避免内存泄漏)。原生事件自行移除
    onUnmounted(() => {
        window.removeEventListener('mousemove', updatePosition)
    })

    // 5. 暴露响应式数据(供组件使用)
    return mouse
}

2. 组件使用:App.vue

在组件中引入并调用自定义 Hook,无需关心内部实现,直接使用响应式的鼠标坐标。

html 复制代码
<template>
  <div>
    鼠标位置:x={{ mouse.x }}, y={{ mouse.y }}
  </div>
</template>

<script>
// 引入自定义 hook
  import useMousePosition from './hooks/useMousePosition'
  export default {
    name:'App',
    setup(){
      //useMousePosition()用于获取响应式对象,同时其内部的生命周期函数会被绑定当前vc实例上
      const mouse = useMousePosition()
      return {
        mouse
      }
    }
  }
</script>

二、代码解析

1. 自定义 Hook 核心逻辑(useMousePosition.js

(1)响应式数据定义
javascript 复制代码
const mouse = reactive({ x: 0, y: 0 })
  • 使用 reactive 创建响应式对象:Vue3 会通过 Proxy 代理该对象,当 mouse.x/mouse.y 变化时,自动触发依赖更新(如模板重新渲染)。
  • 数据作用域:mouse 是 Hook 内部变量,仅通过返回值暴露给组件,避免全局污染。
(2)事件处理函数
javascript 复制代码
function updatePosition(e) {
  mouse.x = e.pageX
  mouse.y = e.pageY
}
  • 接收浏览器 mousemove 事件对象 e,获取 pageX/pageY(鼠标相对于文档左上角的坐标)并更新响应式数据。
  • 该函数是 Hook 内部逻辑,不暴露给组件,实现「封装细节、暴露结果」的设计。
(3)生命周期钩子:绑定与清理事件
javascript 复制代码
// 组件挂载后绑定事件
onMounted(() => {
  window.addEventListener('mousemove', updatePosition)
})

// 组件卸载前清理事件
onUnmounted(() => {
  window.removeEventListener('mousemove', updatePosition)
})
  • 为什么在 onMounted 绑定?
    组件挂载后(onMounted),DOM 已就绪,此时绑定全局事件(window 上的 mousemove)不会丢失,且能确保事件监听与组件生命周期同步。
  • 为什么必须在 onUnmounted 清理?
    addEventListener 是浏览器原生事件,Vue 不会自动解绑。若不清理,组件卸载后事件仍会触发,导致回调函数引用的组件实例无法被垃圾回收,造成内存泄漏
(4)返回响应式数据
javascript 复制代码
return mouse
  • 仅将需要的响应式数据暴露给组件,隐藏 updatePosition 等内部函数,符合「最小暴露原则」,降低组件与 Hook 的耦合度。

2. 组件使用逻辑(App.vue

(1)引入与调用 Hook
javascript 复制代码
import useMousePosition from './hooks/useMousePosition'

setup() {
  const mouse = useMousePosition()
  return { mouse }
}
  • setup 中调用 Hook:setup 是 Vue3 组件的「逻辑入口」,此时调用 Hook,Hook 内部的生命周期钩子会自动绑定到当前组件实例(即 App 组件),确保钩子能按组件生命周期触发。
  • 返回数据给模板:mouse 是响应式对象,模板中引用 mouse.x/mouse.y 时,会自动建立依赖,鼠标移动时模板实时更新。
(2)模板渲染
html 复制代码
<p class="coordinate">x: {{ mouse.x }}px</p>
<p class="coordinate">y: {{ mouse.y }}px</p>
  • 无需编写任何监听逻辑,直接使用 Hook 返回的响应式数据,实现「数据驱动视图」的 Vue 核心思想。

三、自定义 Hook 的优势(对比传统写法)

假设不用 Hook,直接在组件中写监听逻辑,代码会是这样:

javascript 复制代码
// 无 Hook 的组件写法(冗余、难复用)
setup() {
  const mouse = reactive({ x: 0, y: 0 })
  function updatePosition(e) {
    mouse.x = e.pageX
    mouse.y = e.pageY
  }
  onMounted(() => {
    window.addEventListener('mousemove', updatePosition)
  })
  onUnmounted(() => {
    window.removeEventListener('mousemove', updatePosition)
  })
  return { mouse }
}

若有 3 个组件需要监听鼠标位置,上述代码要复制 3 次,而用 Hook 只需调用 useMousePosition() 即可。对比之下,Hook 的优势显而易见:

  1. 逻辑复用:一份代码,多组件共享,减少重复开发。
  2. 代码解耦:组件只关心「使用数据」,Hook 关心「如何获取数据」,职责分明。
  3. 避免冲突 :相比 Vue2 的 mixin,Hook 不会出现命名冲突(数据和方法作用域独立)。

四、扩展:增强 Hook 功能

我们可以轻松扩展这个 Hook 的功能,比如添加「重置鼠标坐标」的方法,让组件能主动控制 Hook 内部逻辑:

javascript 复制代码
// 增强版 useMousePosition.js
export default function useMousePosition() {
  const mouse = reactive({ x: 0, y: 0 })

  function updatePosition(e) {
    mouse.x = e.pageX
    mouse.y = e.pageY
  }

  // 新增:重置鼠标坐标的方法(暴露给组件)
  function resetPosition() {
    mouse.x = 0
    mouse.y = 0
  }

  onMounted(() => {
    window.addEventListener('mousemove', updatePosition)
  })

  onUnmounted(() => {
    window.removeEventListener('mousemove', updatePosition)
  })

  // 返回数据 + 方法
  return { mouse, resetPosition }
}

组件中使用新增方法:

javascript 复制代码
<template>
  <!-- 新增重置按钮 -->
  <button @click="resetPosition">重置坐标</button>
</template>

<script>
setup() {
  // 获取方法并返回给模板
  const { mouse, resetPosition } = useMousePosition()
  return { mouse, resetPosition }
}
</script>

五、总结

  1. Vue3 自定义 Hook 本质:普通函数 + Composition API(响应式 API + 生命周期钩子),封装可复用逻辑。
  2. 核心规范 :以 use 开头命名,仅暴露必要的接口,隐藏内部实现。
  3. 适用场景 :任何需要复用的逻辑(如请求数据 useFetch、定时器 useTimer、本地存储 useLocalStorage 等)。
相关推荐
Simon_He2 小时前
一款适用于 Vue 的高性能流式 Markdown 渲染器,源自我们的 AI 聊天机器人
前端·vue.js·markdown
顽强d石头2 小时前
v-model与.aync的区别
前端·javascript·vue.js
Hilaku2 小时前
我为什么认为 CSS-in-JS 是一个失败的技术?
前端·css·前端框架
月下点灯2 小时前
✨项目上线后产品要求把应用字体改大点📏怎么办?一招教你快速解决🔧
前端·vite
xvmingjiang2 小时前
Vue 3 中监听多个数据变化的几种方法
前端·javascript·vue.js
我有一只臭臭2 小时前
ES5 和 ES6 类的实现
前端·javascript·es6
excel2 小时前
Three.js 实现高分辨率地球边界可视化
前端
LaoZhangAI2 小时前
Google Gemini AI图片编辑完全指南:50+中英对照提示词与批量处理教程(2025年9月)
前端·后端
2301_821046522 小时前
Python的深度学习
开发语言·javascript·ecmascript