三亩地 三亩地SAN MU DI · CODE DIARY
ARTICLE DETAIL

日记详情

真实记录编程学习的某一天,欢迎挑你感兴趣的翻一翻。

Vue小记

Vue小记

目录

vue2与vue3生命周期对比

OptionsAPI vs CompositionAPI

OptionsAPI

CompositionAPI

为什么Composition API要在setup中

Composition API多逻辑组织方式

nextTick()

nextTick()原理

nextTick使用场景

nextTick使用位置


vue2与vue3生命周期对比

阶段Vue 2(Options API)Vue 3(Compositions API)说明
创建前beforeCreate——实例刚创建,数据未绑定
创建后createdsetup()数据已绑定,但 DOM 未挂载
挂载前beforeMountonBeforeMount模板编译完成,即将挂载
挂载后mountedonMountedDOM 已挂载,可访问 $el
更新前beforeUpdateonBeforeUpdate数据变化,DOM 未更新
更新后updatedonUpdatedDOM 已更新
卸载前beforeDestroyonBeforeUnmount组件即将销毁
卸载后destroyedonUnmounted组件已销毁
keep-aliveactivated/deactivatedonActivated/onDeactivated缓存组件激活/停用
错误捕获errorCapturedonErrorCaptured子组件错误捕获
SSR相关——onServerPrefetchSSR 数据预取

OptionsAPI vs CompositionAPI

对比Options APIComposition API
适用版本Vue 2/Vue 3Vue 3专属
代码组织按选项类型按逻辑功能
逻辑复用mixinsComposable
学习曲线稍高
适合场景小型项目中大型项目

OptionsAPI

  • 在OptionsAPI中使用TypeScript时,需要为每个选项属性分别定义类型。例如,在data函数中定义的数据需要单独定义类型,methods中的方法也需要定义参数和返回值的类型等。这使得类型定义分散在整个组件定义中,代码结构相对复杂。
    export default { // 数据 data() { return { count: 0, name: '张三' } }, // 计算属性 computed: { doubleCount() { return this.count * 2 } }, // 方法 methods: { increment() { this.count++ } }, // 生命周期 mounted() { console.log('mounted') } }
    export default { data() { return { count: 0 } }, computed: { double() { return this.count * 2 , methods: { add() { this.count++ } }, mounted() { console.log('count:', this.count) } }

    CompositionAPI

  • 由于以函数形式组织逻辑,在setup函数中可以更方便地进行整体的类型定义。可以对setup函数的输入参数和返回值进行类型定义,并且在自定义组合函数中也能很好地定义类型。这种方式与TypeScript的函数类型系统结合得更加紧密,代码的类型定义更加简洁清晰。
    <script setup> import { ref, computed, onMounted } from 'vue' // 数据 const count = ref(0) const name = ref('张三') // 计算属性 const doubleCount = computed(() => count.value * 2) // 方法 function increment() { count.value++ } // 生命周期 onMounted(() => { console.log('mounted') }) </script>
    import { ref, computed, onMounted } from 'vue' export default { setup() { const count = ref(0) const double = computed(() => count.val* 2) function add() { count.value++ } onMounted(() => { console.log('count:', count.value) }) return { count, double, add } } }

    核心优势

    特性说明
    逻辑复用通过useXxx()组合函数轻松复用逻辑
    代码组织相关逻辑集中,利于大型项目维护
    类型推断更好的ts支持
    更小体积更灵活的tree-shaking,减小包体积
    逻辑复用示例
    // useCount.js export function useCount() { const count = ref(0) function add() { count.value++ } return { count, add } } // 组件中使用 const { count, add } = useCount()

    为什么Composition API要在setup中

Composition API必须在setup阶段调用。Vue 3 的 Composition API 本质上是一组 函数 API ( ref 、 reactive 、 onMounted 等),它们的设计原理是:在组件创建阶段(setup)同步调用,返回响应式数据或注册生命周期回调。

setup是VUE3的入口点

组件实例创建 ↓ setup() 执行 ← Composition API 在这里生效 ↓ template 编译 / DOM 渲染 ↓ onMounted() 执行

Vue 2 的 data 、 methods 、 computed 是分散在各个选项中,由 Vue 内部在适当时机调用。

Vue 3 统一改为 setup() 入口,所有逻辑在里面通过函数调用注册。

<script setup> 是 setup() 的 语法糖 ,让代码更简洁:

普通写法

export default { setup() { const count = ref(0) function increment() { count.value++ } onMounted(() => { console.log('mounted') }) return { count, increment } } }

<script setup>写法:

<script setup> const count = ref(0) function increment() { count.value++ } onMounted(() => { console.log('mounted') }) // 无需 return,模板直接用 count、increment </script>

图解流程

普通 setup(): ┌─────────────────────────────────┐ │ setup() { │ │ const count = ref(0) ← 注册响应式 │ onMounted(...) ← 注册生命周期回调 │ return { count } ← 暴露给模板 │ } │ └────────────────────────────────── <script setup>: ┌───────────────────────────────── │ <script setup> │ │ const count = ref(0) ← 注册响应式(编译器自动处理) │ onMounted(...) ← 注册生命周期(编译器自动处理) │ // 无需 return ← 编译器自动暴露给模板 │ </script> │ └─────────────────────────────────┘
问题答案
为什么在 setup 中?setup 是 Vue 3 的初始化入口,Composition API 函数需要在组件创建时同步调
<script setup> 是什么?etup 的语法糖,省去 return 语句,编译器自动处理暴露逻辑
可以不用吗?Vue 3 仍支持 Options API,但 Composition API 是未来趋势

Composition API多逻辑组织方式

核心思想:按功能分组,使用Composables(组合函数)

方式一:使用Composables(推荐)

把相关逻辑抽离到独立的"组合函数"文件中:

src/ composables/ useCount.js # 计数相关 useSearch.js # 搜索相关逻辑 useAuth.js # 认证相关逻辑

useCount.js

import { ref, computed } from 'vue' export function useCount() { const count = ref(0) const double = computed(() => count.value * 2) function increment() { count.value++ } function reset() { count.value = 0 } return { count, double, increment, reset } }

useSearch.js

import { ref } from 'vue' export function useSearch() { const keyword = ref('') const results = ref([]) async function search() { // 搜索逻辑 } return { keyword, results, search } }

组件中使用

<script setup> import { useCount } from '@/composables/useCount' import { useSearch } from '@/composables/useSearch / 按逻辑分组,互不影响 const { count, double, increment } =useCount() const { keyword, results, search } = useSearch() </script>

方式二:在setup中按功能分区

<script setup> import { ref, computed, onMounted,onUnmounted } from 'vue' // ========== 1. 用户相关逻辑 ========== const userName= ref('') const userInfo = ref({}) function fetchUser() { /* ... */ } // ========== 2. 分页相关逻辑 ========== const page = ref(1) const pageSize = ref(10) const total = ref(0) function nextPage() { page.value++ } function prevPage() { page.value-- } // ========== 3. 弹窗相关逻辑 ========== const visible = ref(false) function openModal() { visible.value = true } function closeModal() { visible.value = false } // ========== 生命周期 ========== onMounted(() => { fetchUser() }) onUnmounted(() => { /* 清理 */ }) </script>
场景推荐方式
逻辑需复用Composables( useXxx.js )
逻辑不复杂,不复用setup 内分区注释

nextTick()

Vue的DOM更新是异步的,不会立即生效,多个数据变化会合并成一次DOM更新提高性能,nextTick用于在DOM更新完成后执行回调。

流程图

数据变化 → 触发更新 → 加入更新队列 → nextTick → 执行回调 → DOM 已更新 ↑ ↓ | | └── 同步代码继续执行 回调函数中获取到最新 DOM

nextTick()原理

Promise+队列机制

Vue3内部维护一个callbacks(回调队列),存放nextTick的回调函数,由microtask执行

callbacksmicrotask
Vue内部维护的数组,存放所有nextTick的回调js执行机制(任务队列)
存储待执行的函数执行这些函数的时机/方式
依赖microtask执行提供执行能力

Vue用microtask来异步执行callbacks中的回调,比setTimeOut更快,保证在DOM更新后第一时间执行

nextTick使用场景

需要等Vue更新完DOM后再执行操作时,就用nextTick

Vue数据变化->DOM更新是异步的->需要nextTick

  • 当需要确保DOM已经更新时
  • 当需要访问组件引用或DOM元素时
  • 当需要在数据变更后执行依赖DOM操作时

nextTick使用位置

位置可用说明
setup()数据响应式已建立,但DOM未渲染
onMounted()DOM挂载完成,等待子组件渲染
onUpdated()DOM更新后,需等待本次更新完成
methods最常见,数据变化后操作DOM
watch响应数据变化,执行DOM操作
computed不推荐,computed是同步的
beforeCreatesetup()之前,响应式未建立

场景对应位置

场景推荐位置
数据变化后获取DOMmethods或watch
组件挂载后初始化onMounted
组件更新后操作DOMonMounted
异步操作后获取DOMasync/await+nextTick

router

路由是URL路径到组件的映射(如/home->Home组件)

router-view vs router-link

router-view:用于渲染,路由出口,渲染匹配到的组件(根据URL在router-view中显示对应组件)。当一个路由被匹配时,它的组件将会渲染在 < router-view > 中。可以不需要router-link,URL变化时自动渲染对应组件。

router-link:用于跳转,url路径发生变化,导航链接,点击切换路由(默认渲染为<a>),可以将某个链接或者按钮转换成一个具有路由功能的链接。可以不需要router-view,单纯做导航触发。

二者可以组合使用,也可以分开使用。

行为含义
跳转URL 路径发生变化(如 /home → /about )
渲染根据 URL 在 router-view 中显示对应组件

只有跳转到内部组件才使用router-view渲染

URL 变化 │ ├── http://xxx ──→ 外部链接 ──→ 浏览器跳转,整个页面卸载 │ └── /about ──→ Vue Router 处理 │ ├── 路由表有匹配 ──→ router-view 渲染对应组件 │ └── 路由表无匹配 ──→ 渲染 404

路由跳转的两种方式

方式代码
组件式<router-link to="/home">首页</router-link>
JS 编程式router.push('/home')
← 返回列表