云计算百科
云计算领域专业知识百科平台

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

一、前言

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

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

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

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

// 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
}

<!– 使用 –>
<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>

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

  • newTitle ?? document.title:参数可选的兜底写法,两种用法都支持——useTitle() 纯托管、useTitle('xxx') 带初始值
  • immediate: true:保证"进来那一刻"标题就被同步(比如接管了一个已经乱七八糟的标题)
  • 返回 ref 而不是字符串:返回 ref 调用方才能改、页面才响应——组合式函数返回的一律是"活的数据"
  • 【截图位置:点击按钮后浏览器标签页标题变化的效果】

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

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

    // 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]
    }

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

    设计复盘:

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

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

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

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

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

    // 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()
    }
    }

    <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 弹窗的官方搭档。函数调用函数,能力不断叠加,这就是"组合式"三个字的含义。

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

    五、踩坑记录

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

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

    下篇预告

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

    赞(0)
    未经允许不得转载:网硕互联帮助中心 » Vue3 零基础每日笔记(036):动手封装 useTitle 与 useToggle——最小的组合式函数
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!