vue需要学习的点

对MVVM的理解

MVVM 是 Model-View-ViewModel 的缩写

  • Model 代表数据模型,也可以在 Model 中定义数据修改和操作的业务逻辑。
  • View 代表 UI 组件, 它负责将数据模型转化成 UI 展现出来。
  • ViewModel 监听模型数据的改变和控制视图行为 、处理用户交互, 简单理解就是⼀个同步View 和 Model 的对象, 连接 Model 和 View

这种架构下,开发者只需关注业务逻辑,不需要手动操作DOM,不需要关注数据状态的同步问题, 复杂的数据状态维护完全由 MVVM 来统⼀管理


常用vue命令

指令 作用说明 典型用法示例
v-text 将元素的文本内容替换为表达式的值(替代 {``{}} <p v-text="msg"></p>
v-html 将元素的 innerHTML 更新为表达式的内容(会有 XSS 风险) <div v-html="rawHtml"></div>
v-show 根据表达式的真假切换元素的 display CSS 属性实现显示隐藏 <div v-show="isVisible"></div>
v-if 条件渲染,表达式为真时渲染该元素,假时销毁元素(不占 DOM) <p v-if="show">显示内容</p>
v-else v-if 的反向条件,必须紧接 v-ifv-else-if 之后 <p v-else>隐藏内容</p>
v-else-if v-if 的"else if"分支,用于链式条件判断 <p v-else-if="otherCondition">内容</p>
v-for 列表渲染,用于遍历数组或对象生成一组元素 <li v-for="item in items" :key="item.id">{``{ item.text }}</li>
v-bind 动态绑定 HTML 属性或组件 prop,简写为 : <img :src="imgSrc">
v-on 监听 DOM 事件或组件自定义事件,简写为 @ <button @click="handleClick">点我</button>
v-model 双向数据绑定,通常用于表单控件(input、select、textarea 等) <input v-model="username">
v-pre 跳过该元素和子元素的编译,进行原样输出(提高性能,调试时用) <span v-pre>{``{ rawMustache }}</span>
v-cloak 保证 Vue 编译完成之后再显示元素,避免闪烁(通常配合 CSS 使用) <div v-cloak>内容</div>
v-once 元素和组件只渲染一次,之后的更新不会渲染该元素 <span v-once>{``{ message }}</span>

如何自定义vue命令

项目 Vue 2 Vue 3
注册方式 Vue.directive() / 组件内 directives app.directive() / 组件内 directives
生命周期钩子名称 bind, inserted, update, componentUpdated, unbind created, beforeMount, mounted, beforeUpdate, updated, beforeUnmount, unmounted
生命周期更多钩子 较少,只匹配关键阶段 更细粒度,更符合组件生命周期
指令 API 对象格式 vs Vue 3 类似,只是钩子不同 同 Vue 2,但钩子名称改进
参数和修饰符 支持 binding.value, binding.arg, binding.modifiers 同 Vue 2

vue的生命周期

1. Vue 2 生命周期钩子

Vue 2 的生命周期可以分为四个阶段:

阶段 钩子函数 说明
创建阶段 beforeCreate 实例初始化时调用,数据观测和事件未初始化
created 实例已创建,数据观测和事件已初始化
挂载阶段 beforeMount 挂载开始之前,相关 DOM 还未渲染
mounted 挂载完成,DOM 已插入页面
更新阶段 beforeUpdate 数据更新后,DOM 重新渲染前调用
updated 组件 DOM 重新渲染并更新后调用
销毁阶段 beforeDestroy 实例销毁前调用
destroyed 实例销毁完成,解绑所有事件,清理资源

2. Vue 3 生命周期钩子

Vue 3 基于组合式 API 升级,仍保留选项式生命周期,同时对生命周期做了更多补充。整体钩子和 Vue 2 类似,具体列表:

阶段 钩子函数 说明
创建阶段 beforeCreate Vue 3 依然支持,但在组合式 API 不常用
created 同上
挂载阶段 beforeMount 挂载开始之前
mounted 挂载完成
更新阶段 beforeUpdate 数据更新前,DOM 渲染之前调用
updated DOM 更新完成后调用
卸载阶段 beforeUnmount 实例卸载前调用(Vue 3 新增)
unmounted 实例卸载后调用(Vue 3 新增)

3. Vue 3 组合式 API 中的生命周期钩子

Vue 3 新增了组合式 API(setup 函数),通过如下函数注册生命周期钩子:

生命周期阶段 组合式 API 钩子函数 说明
创建 onBeforeMount(() => {}) 挂载之前
onMounted(() => {}) 挂载完成
更新 onBeforeUpdate(() => {}) 更新之前
onUpdated(() => {}) 更新完成
卸载 onBeforeUnmount(() => {}) 卸载之前
onUnmounted(() => {}) 卸载完成
激活和停用 onActivated(() => {}) keep-alive 组件激活
onDeactivated(() => {}) keep-alive 组件停用

vue的响应式原理

1.vue2

核心是依赖收集 + 发布订阅模式,使用 Object.defineProperty 对对象的属性进行 getter/setter 拦截。

javascript 复制代码
function defineReactive(obj, key, val) {
  const dep = new Dep()

  Object.defineProperty(obj, key, {
    get() {
      if (Dep.target) { // Dep.target 指当前扫描的 watcher
        dep.addDep(Dep.target)
      }
      return val
    },
    set(newVal) {
      if (newVal !== val) {
        val = newVal
        dep.notify() // 通知所有 watcher 更新
      }
    }
  })
}

限制和缺点:

  • 只能监听对象已有属性,新增新属性不会自动响应式(需要用 Vue.set)
  • 数组的变化通过变异方法(push、pop等)重写实现响应式
  • 只能监听到对象的一级属性,深层嵌套需要递归监听

2.vue3

基于 ES6 的 Proxy 实现响应式。代理整个对象,拦截所有属性的访问/修改/删除,不需要递归每个子属性。原理:对目标对象做代理,所有访问通过 get、set 拦截完成。

javascript 复制代码
function reactive(target) {
  return new Proxy(target, {
    get(target, key, receiver) {
      // 依赖收集
      track(target, key)
      return Reflect.get(target, key, receiver)
    },
    set(target, key, value, receiver) {
      const result = Reflect.set(target, key, value, receiver)
      // 触发依赖
      trigger(target, key)
      return result
    }
  })
}

3.总结

方面 Vue 2 (Object.defineProperty) Vue 3 (Proxy)
技术实现 对对象属性逐个用 defineProperty 拦截 Proxy 包裹整个对象进行拦截
支持新增/删除属性 不支持,需要用 Vue.set 天生支持
数组响应式 通过重写数组变异方法实现 数组作为对象代理自然支持
依赖收集粒度 只能对属性做依赖收集 基于操作符拦截,更精准,按需追踪
性能 需要递归遍历,性能压力大 性能更好,按需依赖追踪
实现复杂度 需要递归遍历、手动处理数组 简洁,统一代理所有操作

vue的diff算法

Vue 基于虚拟 DOM 实现渲染,每次状态变化产生新 VNode 树,会通过 Diff 算法比较新旧 VNode 树的差异,根据差异调用最少的 DOM 操作,实现 DOM 最小化更新。

处理方式 意义 操作 指针变化
旧前 vs 新前 顺序未变,头部对比 patch,指针+1 oldStart++, newStart++
旧后 vs 新后 顺序未变,尾部对比 patch,指针-1 oldEnd--, newEnd--
旧后 vs 新前 右移节点至左 patch + 移动旧尾节点 oldEnd--, newStart++
旧前 vs 新后 左移节点至右 patch + 移动旧前节点 oldStart++, newEnd--
其它(key查找) 复用已有节点或新增节点 移动或插入节点 根据具体操作调整指针
新节点剩余 新增节点 创建新节点 newStart++ 或 newEnd--
旧节点剩余 删除多余节点 删除节点 oldStart++ 或 oldEnd--

vue的Optional API 和Composition API

1. Options API(选项式 API)

这是 Vue 2 以及 Vue 3 依然支持的传统写法,开发者通过预定义的组件选项(Options)来组织代码,比如 datamethodscomputedwatchprops 等。

特点:

  • 代码组织结构清晰,基于 Vue 约定的选项划分功能。
  • 易于初学者理解,适合小中型项目。
  • 组件逻辑往往按功能划分,但可能导致同一功能分散在多个选项内,随着组件变复杂难以维护。

示例代码

javascript 复制代码
export default {
  data() {
    return {
      count: 0
    }
  },
  computed: {
    doubled() {
      return this.count * 2
    }
  },
  methods: {
    increment() {
      this.count++
    }
  },
  watch: {
    count(newVal, oldVal) {
      console.log('count changed:', newVal)
    }
  }
}

2. Composition API(组合式 API)

Vue 3 引入的新方式,开发者通过在 setup() 函数内使用函数调用和响应式 API(如 refreactivecomputedwatch 等)组合逻辑代码。

特点:

  • 逻辑复用和组合更灵活:可以把相关代码片段封装成可复用的函数(composables)。
  • 更适合大型项目和复杂组件,避免 Options API 中不同选项间逻辑分散问题。
  • 代码布局更灵活,方便按业务功能组织代码而非选项划分。
  • 需要了解一定的响应式原理,对初学者有一定门槛。
javascript 复制代码
import { ref, computed, watch } from 'vue'

export default {
  setup() {
    const count = ref(0)
    const doubled = computed(() => count.value * 2)

    function increment() {
      count.value++
    }

    watch(count, (newVal, oldVal) => {
      console.log('count changed:', newVal)
    })

    return {
      count,
      doubled,
      increment
    }
  }
}

vue中的逻辑复用

1. Options API 的逻辑复用方式及局限

主要手段
  • mixins(混入)
  • extends(继承)

这些机制允许把一段逻辑写在一个 mixin 对象或基类组件中,然后被多个组件复用。

javascript 复制代码
// mixin.js
export const myMixin = {
  data() {
    return {
      count: 0
    }
  },
  methods: {
    increment() {
      this.count++
    }
  }
}
javascript 复制代码
import { myMixin } from './mixin'

export default {
  mixins: [myMixin],
  mounted() {
    this.increment()
  }
}
局限和问题
  • **命名冲突:**不同 mixin 可能有相同的 data、methods、computed 名称,产生冲突难以管理。

  • **隐式依赖和状态来源混乱:**mixin 里面有状态和方法,组件使用后状态来自何处不直观,增加理解和维护成本。

  • **逻辑难以拆分和组合:**mixin 是扁平的配置,无法像函数那样灵活接收参数、返回结果、依赖注入。

  • **追踪调用关系困难:**逻辑分散在多个 mixin,调试时难以跟踪和维护。

  • 扩展继承复杂度: 使用 extends 形式继承 父组件逻辑时,继承链越长越复杂,状态管理困难。

2.Composition API 的逻辑复用 ------ Composable 函数

核心思想
  • 将一块响应式逻辑封装到一个普通函数中(称为 composable 函数)
  • 函数内部使用 refreactivecomputedwatch 等 API
  • 通过返回对象暴露响应式数据和方法给调用组件使用
javascript 复制代码
import { ref, computed } from 'vue'

export function useCounter(initialValue = 0) {
  const count = ref(initialValue)
  const doubled = computed(() => count.value * 2)

  function increment() {
    count.value++
  }

  return {
    count,
    doubled,
    increment
  }
}
javascript 复制代码
import { useCounter } from './useCounter'

export default {
  setup() {
    const { count, doubled, increment } = useCounter(5)

    return {
      count,
      doubled,
      increment
    }
  }
}

Vue递归组件

html 复制代码
<script setup>
import { defineProps } from 'vue'

const props = defineProps({
  items: {
    type: Array,
    required: true
  }
})
</script>

<template>
  <ul>
    <li v-for="item in items" :key="item.id">
      {{ item.label }}
      <!-- 如果有子项,则递归调用自身 -->
      <RecursiveMenu v-if="item.children && item.children.length" :items="item.children" />
    </li>
  </ul>
</template>

<script>
import { defineComponent } from 'vue'

export default defineComponent({
  name: 'RecursiveMenu'
})
</script>

vue异步组件

javascript 复制代码
import { defineAsyncComponent } from 'vue'

const AsyncComp = defineAsyncComponent({
  // 必须是返回 Promise 的函数
  loader: () => import('./YourComponent.vue'),

  // 加载超时时间,超过时展示错误组件
  timeout: 3000,

  // 组件加载时显示的占位组件
  loadingComponent: LoadingSpinner,

  // 加载失败时显示的错误组件
  errorComponent: ErrorComponent,

  // 重试次数(默认 0)
  retries: 1
})
javascript 复制代码
<template>
  <div>
    <h2>异步组件示例</h2>
    <AsyncComp />
  </div>
</template>

<script setup>
import { defineAsyncComponent } from 'vue'
import LoadingSpinner from './LoadingSpinner.vue'
import ErrorComponent from './ErrorComponent.vue'

const AsyncComp = defineAsyncComponent({
  loader: () => import('./HeavyComponent.vue'),
  loadingComponent: LoadingSpinner,
  errorComponent: ErrorComponent,
  timeout: 5000
})
</script>

在vue2中

javascript 复制代码
export default {
  components: {
    AsyncExample: () => import('./AsyncExample.vue')
  }
}

vue的keep-alive

  • keep-alive 是一个 Vue全局组件
  • keep-alive 本身不会渲染出来,也不会出现在父组件链中
  • keep-alive 包裹动态组件时,会缓存不活动的组件,而不是销毁它们

keep-alive 接收三个参数:

  • include :可传字符串、正则表达式、数组 ,名称匹配成功的组件会被缓存
  • exclude :可传字符串、正则表达式、数组 ,名称匹配成功的组件不会被缓存
  • max :可传数字 ,限制缓存组件的最大数量

include 和 exclude ,传数组 情况居多。

keep-alive 主要做了以下部分:

  • created :初始化一个 cache、keys ,前者用来存缓存组件的虚拟dom集合,后者用来存缓组件的key集合
  • mounted :实时监听 include、exclude 这两个的变化,并执行相应操作
  • destroyed :删除掉所有缓存相关的东西

使用场景:

html 复制代码
<keep-alive :include="allowList" :exclude="noAllowList" :max="amount">
    <router-view></router-view>
</keep-alive>
html 复制代码
<keep-alive :include="allowList" :exclude="noAllowList" :max="amount">
    <component :is="currentComponent"></component>
</keep-alive>

当组件被<keep-alive>包裹时,会触发两个额外的生命周期钩子:

activated

当被缓存的组件重新激活时调用。适用于需要重新触发数据更新或DOM操作的场景,例如恢复定时器或重新请求数据。

deactivated

当被缓存的组件失活时调用。适用于清理工作,例如清除定时器或取消未完成的请求。


vuex和pinia

1. Vuex

简介
  • Vuex 是 Vue 官方推出的状态管理库,面向 Vue 2 设计,也支持 Vue 3。
  • 强调集中式存储管理,所有组件的状态集中到 store 中,使用"单一状态树"。
  • 基于 Flux 架构,采用 mutations 进行状态同步修改,actions 处理异步逻辑。
核心概念
  • State(状态):集中维护的响应式数据。
  • Mutations:唯一修改 state 的方法,必须是同步函数。
  • Actions :处理异步逻辑,通过 commit 触发 mutations。
  • Getters:类似计算属性,对 state 数据进行包装和过滤。
  • Modules:当应用复杂时,支持模块化拆分 store。
javascript 复制代码
import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

const store = new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    increment(state) {
      state.count++
    }
  },
  actions: {
    incrementAsync({ commit }) {
      setTimeout(() => {
        commit('increment')
      }, 1000)
    }
  },
  getters: {
    doubleCount(state) {
      return state.count * 2
    }
  }
})

export default store

2. Pinia

简介
  • Pinia 是 Vue 官方推荐的新一代状态管理库,设计更简洁友好,完美支持 Vue 3 和 Composition API。
  • 语法更接近普通的模块化 JS,更灵活且易学,支持直接调用操作状态。
核心概念
  • Store 是一个组合式的状态容器。
  • 通过 defineStore 定义 store。
  • 支持直接修改 state(因为内部用 Proxy 劫持,状态依然响应式)。
  • 支持类似计算属性的 getters,以及内置 actions 处理异步和同步逻辑。
javascript 复制代码
import { defineStore } from 'pinia'

// 定义 store
export const useCounterStore = defineStore('counter', {
  state: () => ({ count: 0 }),
  getters: {
    doubleCount: (state) => state.count * 2
  },
  actions: {
    increment() {
      this.count++
    },
    incrementAsync() {
      setTimeout(() => {
        this.increment()
      }, 1000)
    }
  }
})
javascript 复制代码
import { useCounterStore } from './stores/counter'

export default {
  setup() {
    const counter = useCounterStore()
    counter.increment()
    return { counter }
  }
}

3.对比

特性/维度 Vuex Pinia
API 设计 需定义 state, mutations, actions 定义 state、getters、actions,更简洁
异步处理 通过 actions 直接在 actions 中处理异步
使用便利性 比较繁琐 更现代,学习曲线低
TS 支持 支持但复杂 原生 TypeScript 支持友好
Vue 版本 Vue 2/3 都支持 主要面向 Vue 3,Vue 2 有社区支持
模块化 支持模块拆分 自然模块化,多个 store 独立管理
生态和社区 成熟且庞大 新兴且快速增长
功能支持 完整、稳定 轻量、现代、更灵活

vue-router

javascript 复制代码
// router/index.js
import { createRouter, createWebHistory } from 'vue-router'
import Home from '../views/Home.vue'
import About from '../views/About.vue'

const routes = [
  { path: '/', component: Home },
  { path: '/about', component: About }
]

const router = createRouter({
  history: createWebHistory(),  // 使用 HTML5 History 模式
  routes
})

export default router
钩子函数 触发时机 是否可阻止导航 是否可访问组件实例
beforeEach 全局路由开始切换
beforeResolve 导航流程最后阶段
afterEach 导航完成
beforeEnter 路由独享守卫
beforeRouteEnter 进入路由组件之前 通过 next 访问
beforeRouteUpdate 路由参数变化,组件复用
beforeRouteLeave 离开路由组件时
相关推荐
用户47949283569158 小时前
同样是 #,锚点和路由有什么区别
前端·javascript
Hero_11278 小时前
在pycharm中install不上需要的包
服务器·前端·pycharm
爱上妖精的尾巴8 小时前
5-26 WPS JS宏数组元素添加删除应用
开发语言·前端·javascript·wps·js宏
是谁眉眼8 小时前
wpsapi
前端·javascript·html
谅望者8 小时前
Flexbox vs Grid:先学哪一个?CSS 布局完全指南(附可视化示例)
前端·css·html·css3·css布局·css flexbox·css grid
老华带你飞9 小时前
商城推荐系统|基于SprinBoot+vue的商城推荐系统(源码+数据库+文档)
java·前端·数据库·vue.js·spring boot·毕设·商城推荐系统
JS.Huang9 小时前
【JavaScript】Pointer Events 与移动端交互
前端·javascript
一 乐9 小时前
物业管理系统|小区物业管理|基于SprinBoot+vue的小区物业管理系统(源码+数据库+文档)
java·前端·数据库·vue.js·spring boot·后端
H_HX1269 小时前
vue3 - 图片放大镜效果实现
前端·vue.js·vue3·vueuse·图片放大镜