Vue3 零基础每日笔记(036):动手封装 useTitle 与 useToggle——最小的组合式函数

一、前言

上篇懂了"为什么",本篇开始"动手"。选两个最简单的下手:useTitle (响应式改网页标题)和 useToggle(布尔开关)。麻雀虽小五脏俱全------返回值怎么设计、初始值怎么兜底、怎么命名,组合式函数的全部基础规范都在这两个十行函数里。

二、useTitle:让网页标题变成响应式数据

目标 APIconst title = useTitle(),改 title.value 页面标签实时变。

先想清楚实现三步:读当前标题作初始值 → 数据变时写回 document.title → 返回数据。

js 复制代码
// src/composables/useTitle.js
import { ref, watch } from 'vue'

export function useTitle(newTitle) {
  // 初始值:传了就用传的,没传就读当前标题
  const title = ref(newTitle ?? document.title)

  // 数据变 → 写回浏览器标签
  watch(title, (val) => {
    document.title = val
  }, { immediate: true })   // immediate:进来先同步一次

  return title
}
vue 复制代码
<!-- 使用 -->
<template>
  <p>页面标签实时变化:</p>
  <button @click="title = `(${count} 条未读)我的应用`">模拟新消息</button>
  <button @click="title = '我的应用'">清除未读</button>
  <p>{{ count }} 条未读</p>
</template>

<script setup>
import { ref } from 'vue'
import { useTitle } from '@/composables/useTitle'

const count = ref(3)
const title = useTitle('我的应用')
</script>

设计复盘(每个细节都有讲究):

  1. newTitle ?? document.title :参数可选的兜底写法,两种用法都支持------useTitle() 纯托管、useTitle('xxx') 带初始值
  2. immediate: true:保证"进来那一刻"标题就被同步(比如接管了一个已经乱七八糟的标题)
  3. 返回 ref 而不是字符串 :返回 ref 调用方才能改、页面才响应------组合式函数返回的一律是"活的数据"

【截图位置:点击按钮后浏览器标签页标题变化的效果】

三、useToggle:布尔开关 + 任意两值切换

目标 APIconst [state, toggle] = useToggle()------数组解构的返回形式(和 012 篇 toRefs 的对象形式并列,两种都要会)。

js 复制代码
// src/composables/useToggle.js
import { ref } from 'vue'

export function useToggle(init = false) {
  const state = ref(init)

  /**
   * 切换状态
   * @param {boolean} [value] 可选:直接指定目标值
   */
  function toggle(value) {
    // 传了值就用传的,没传就取反
    state.value = value ?? !state.value
  }

  return [state, toggle]
}
vue 复制代码
<template>
  <!-- 场景 1:开关弹窗 -->
  <button @click="toggle()">弹窗开关:{{ open ? '开' : '关' }}</button>

  <!-- 场景 2:明文/密文切换,直接指定值 -->
  <input :type="showPwd ? 'text' : 'password'" v-model="pwd" />
  <button @click="toggle(true)">显示明文</button>
  <button @click="toggle(false)">隐藏</button>
</template>

<script setup>
import { useToggle } from '@/composables/useToggle'

const [open, toggle] = useToggle()          // 弹窗开关
const [showPwd, setPwdVisible] = useToggle(false)  // 密码可见性
const pwd = ref('')
</script>

设计复盘:

  1. 返回数组 [state, toggle] :调用方解构时可以随意重命名(toggle / setPwdVisible),数组按位置对号,特别适合"一数据一方法"的小函数
  2. value ?? !state.value:toggle() 无参取反、toggle(true) 定点设置,一个函数两种用法
  3. JSDoc 注释:写上参数说明,同事用你的函数时 IDE 有提示------协作从注释开始

对象形式返回(项目里统一风格时用):

js 复制代码
// 同一逻辑的另一种返回形态
return { state, toggle }
// 使用:const { state, toggle } = useToggle()

数组形式 适合"元素少且位置固定";对象形式适合成员多、要按名取用的场景。VueUse 两种混用(简单函数用数组,复杂的用对象),你的项目定死一种即可。

四、进阶:把两个函数组合起来

组合式函数的精髓是可以互相组合。写一个 useDisclosure(弹窗控制器),内部用 useToggle:

js 复制代码
// src/composables/useDisclosure.js
import { useToggle } from './useToggle'

/**
 * 弹窗/抽屉控制器
 * @returns {{ isOpen: import('vue').Ref<boolean>, open: Function, close: Function, toggle: Function }}
 */
export function useDisclosure(init = false) {
  const [isOpen, rawToggle] = useToggle(init)

  return {
    isOpen,
    open: () => rawToggle(true),
    close: () => rawToggle(false),
    toggle: () => rawToggle()
  }
}
vue 复制代码
<template>
  <button @click="open">打开确认弹窗</button>

  <div v-if="isOpen" class="mask" @click.self="close">
    <div class="box">
      确定要删除吗?
      <button @click="close">取消</button>
      <button @click="onConfirm">确定</button>
    </div>
  </div>
</template>

<script setup>
import { useDisclosure } from '@/composables/useDisclosure'

const { isOpen, open, close } = useDisclosure()

function onConfirm() {
  console.log('执行删除')
  close()
}
</script>

<style scoped>
.mask { position: fixed; inset: 0; background: rgba(0,0,0,.5);
  display: flex; align-items: center; justify-content: center; }
.box { background: #fff; padding: 20px; border-radius: 8px; }
</style>

open / close / toggle 语义分明的弹窗控制器,一个项目里每个弹窗都用它------这就是 031 篇 Teleport 弹窗的官方搭档。函数调用函数,能力不断叠加,这就是"组合式"三个字的含义。

【截图位置:弹窗打开、点遮罩关闭的运行效果】

五、踩坑记录

  1. useTitle 在 SSR/无 window 环境报错document 不存在------需要兼容 SSR 时加 typeof document !== 'undefined' 判断(本系列走 SPA,先知道有这回事)
  2. 返回了死值return title.value 返回的是当时的字符串,调用方怎么改页面都不动------永远返回 ref
  3. toggle 里的坑value ?? !state.value 若写成 value || !state.value,传 false 会被 || 当 falsy 吞掉变成取反------nullish 合并符(??)才区分 false 和空
  4. 忘记可选括号useToggle 定义成 function useToggle(init) 但调用写 useToggle()------init 是 undefined,ref(undefined) 的布尔判断是 false,恰好能用但类型不干净,养成 init = false 给默认值的习惯
  5. 一个文件塞十个函数:useTitle 和 useToggle 混在一个文件里 export------一个函数一个文件,index.js 统一导出,按需 import

六、今日小结

  • useTitle:ref + watch(immediate) 三件套,返回活 ref 是铁律
  • useToggle:[state, toggle] 数组返回便于重命名;value ?? !value 兼容定点设置
  • 返回形态二选一:数组(小而固定)/ 对象(成员多),项目内统一
  • useDisclosure 示范函数组合函数------"组合式"的真正含义

下篇预告

继续造下一组:useMouse / useWindowSize------第一次在组合式函数里操作 window 事件监听,生命周期清理的模板写法会固化成肌肉记忆。下一篇 037。

相关推荐
专业程序开发源1 小时前
springboot旅游推荐系统82074-计算机课程设计、毕业设计
java·vue.js·spring boot·后端·php·课程设计·旅游
晚安日记wanna1 小时前
Vue3 script setup 的四层追问答到第三层才算过关
前端·vue.js·面试
six_2 小时前
RiverPlusCOM Web:不用安装的在线串口调试助手
vue.js·程序员
摸鱼仙人~3 小时前
React 原理进阶:彻底理解 re-render、React.memo、useMemo 与 useCallback
前端·vue.js
Bs_MoneyMagnet8 小时前
基于springboot+vue的滑雪场票务与装备租赁系统的设计与实现 源码+文档
java·vue.js·spring boot·后端·spring·毕业设计·计算机毕业设计
Z小明18 小时前
第 6 章 组件进阶
前端·vue.js
ID346107442020 小时前
【课程设计】基于Spring Boot+Vue的游戏账号租赁系统的设计与实现-计算机毕设 附源码50345
javascript·vue.js·spring boot·python·node.js·php·课程设计
FYKJ_20101 天前
【毕设分享】基于Web的校园兼职信息发布与申请系统07059
前端·vue.js·spring boot·mysql·typescript·spark·课程设计
志尊宝1 天前
Vue3 零基础每日笔记(032):Suspense 与异步组件——懒加载与顶层 await 终极方案
前端·javascript·vue.js·笔记·html5