设计哲学
Vue.js是由尤雨溪(Evan You)创建的开源前端框架,首次发布于2014年。Vue的定位是渐进式框架(Progressive Framework)——它可以被逐步采用,从简单的页面增强到复杂的单页应用,开发者可以根据项目需求选择性地使用其功能模块。这种渐进性使Vue既适合小型项目的快速开发,也能支撑大型企业级应用的架构需求。
Vue的核心设计原则包括:易用性( approachable ),即新手可以在短时间内上手并构建应用;灵活性(versatile),即能够适应从简单到复杂的各种场景;高性能(performant),即通过精细的响应式系统和虚拟DOM实现高效的更新。Vue在模板语法与JavaScript逻辑之间取得了优雅的平衡,使开发者可以用声明式的方式描述界面,同时保留完整的JavaScript表达能力。
Vue 3于2020年发布,带来了底层的全面重构:使用Proxy替代Object.defineProperty实现响应式系统,引入了组合式API(Composition API)作为选项式API(Options API)的替代方案,重构了虚拟DOM实现以获得更好的性能,并提供了更优的TypeScript支持。Vue 3保持了与Vue 2的高度兼容性,同时通过Tree Shaking支持使打包体积更小。
模板语法
Vue使用基于HTML的模板语法,允许开发者以声明式方式将DOM绑定到底层Vue实例的数据。模板中的文本插值使用双大括号语法:{{ message }}。插值内容会被自动转义为普通文本,防止XSS攻击。若需要输出原始HTML,应使用v-html指令(需谨慎使用,确保内容可信)。
指令(Directives)是带有v-前缀的特殊属性,用于在表达式的值变化时响应式地更新DOM。常用的指令包括:v-bind(简写为:)动态绑定属性;v-on(简写为@)绑定事件监听器;v-model在表单元素上创建双向数据绑定;v-if、v-else-if、v-else条件渲染;v-for列表渲染;v-show通过CSS display属性切换可见性。
v-if与v-show的区别是面试中的经典问题。v-if是"真正的"条件渲染——条件为假时元素不会被渲染到DOM中,条件切换时组件会被销毁和重建。v-show则始终渲染元素,仅通过CSS控制显示与隐藏。因此,v-if适用于切换频率低的场景(如权限控制),v-show适用于需要频繁切换可见性的场景(如标签页)。
v-for用于渲染列表,语法为v-for="item in items"或v-for="(item, index) in items"。与React类似,v-for也需要为每个列表项提供唯一的key属性,以便Vue能够高效地追踪元素身份。key应当使用具有唯一性和稳定性的值,避免使用数组索引(除非列表永不变化)。
计算属性(Computed Properties)基于依赖的响应式数据缓存计算结果,仅在依赖变化时重新计算。这与方法(Methods)形成对比——方法在每次重新渲染时都会执行。当需要基于现有数据派生出新数据时,应优先使用计算属性。侦听器(Watchers)用于在数据变化时执行副作用操作,适合执行异步或开销较大的操作。
响应式原理
Vue的响应式系统是其最核心的特性,它使得数据变化能够自动驱动视图更新。Vue 2使用Object.defineProperty方法遍历对象的属性,将每个属性转换为getter/setter,在getter中收集依赖(哪些组件或计算属性使用了该属性),在setter中触发依赖更新。这种方式的局限在于:无法检测对象属性的新增和删除(需要使用Vue.set和Vue.delete),无法检测数组索引的直接修改和数组长度的变更。
Vue 3改用ES6的Proxy对象实现响应式系统。Proxy可以拦截对象的基本操作(如属性访问、赋值、删除、枚举等),无需遍历属性即可实现对整个对象的代理。这解决了Vue 2的诸多限制:可以检测属性的新增和删除,可以检测数组索引和length的变化,且初始化性能更好(无需递归遍历嵌套对象,采用懒代理策略)。
响应式系统的核心流程包括:初始化阶段,将数据对象转换为响应式对象(通过reactive或ref);渲染阶段,组件渲染函数访问响应式数据,触发getter,将当前活动的副作用(如组件渲染副作用)收集为依赖;更新阶段,响应式数据被修改,触发setter,通知所有收集的依赖重新执行,从而触发组件重新渲染。
ref是Vue 3中创建响应式基本类型数据的主要方式。它返回一个包含value属性的对象,访问和修改值需要通过.value进行。在模板中,ref会被自动解包,无需使用.value。reactive用于创建响应式对象,适用于复杂数据结构。toRefs可以将reactive对象的属性转换为ref,便于在解构后保持响应性。
组合式API
组合式API(Composition API)是Vue 3引入的新式代码组织方式,作为选项式API(Options API)的替代和补充。它通过一组函数(setup函数或<script setup>语法糖)组织组件逻辑,使相关功能的代码能够聚集在一起,而非分散在data、methods、computed、watch等选项中。
setup函数是组合式API的入口点,在组件创建之前执行,接收props和context两个参数。在setup中,可以使用所有组合式API函数:ref、reactive、computed、watch、生命周期钩子函数(onMounted、onUpdated、onUnmounted等,名称前加on前缀)等。setup函数返回的对象中的属性将暴露给模板和其他选项使用。
<script setup>是Vue 3.2引入的编译时语法糖,它简化了setup函数的书写。在<script setup>中,顶层的变量和函数声明自动暴露给模板使用,无需显式返回。导入的组件可以直接在模板中使用,无需注册。defineProps和defineEmits是编译器宏,用于声明props和emits(在<script setup>中无需导入)。
组合式API的最大优势在于逻辑复用。通过将相关逻辑抽取为可复用的函数(称为"组合式函数"或Composables),可以在多个组件之间共享状态和行为。这与React的自定义Hooks理念异曲同工,但得益于Vue的响应式系统,实现更为简洁——无需依赖数组或复杂的闭包模式来管理多个状态。
组件通信
Vue组件之间的通信方式丰富多样,适用于不同的场景和层级关系。Props和Events是最基础的父子通信方式:父组件通过props向子组件传递数据,子组件通过$emit触发事件向父组件传递信息。Props是单向数据流,子组件不应直接修改props,而应当通过事件请求父组件更新数据。
Provide和Inject用于跨层级组件通信。祖先组件通过provide提供数据,后代组件通过inject注入数据。这在深层嵌套的组件树中避免了逐层传递props的繁琐。但需注意,provide/inject的数据流不是响应式的,除非提供的是响应式对象(如ref或reactive的返回值)。
全局状态管理在复杂应用中通过Vuex(Vue 2)或Pinia(Vue 3官方推荐)实现。Pinia是Vue的新一代状态管理库,API设计更贴近组合式API,支持TypeScript,去除了Vuex中的mutations概念,使状态修改更加直接。Pinia的Store通过defineStore定义,可以在组件中通过调用useStore()获取实例。
组件的v-model是语法糖,本质上是:value绑定和@input/@update:modelValue事件的组合。Vue 3支持多个v-model(通过自定义修饰符和参数),以及自定义v-model的修饰符。这极大地提升了封装可复用表单组件的灵活性。
指令系统
Vue的指令系统不仅包含内置指令,还支持自定义指令,用于在底层DOM操作上封装可复用逻辑。自定义指令通过生命周期钩子(mounted、updated、unmounted等)在元素的不同阶段执行操作。常见的自定义指令应用场景包括:输入框自动聚焦、元素点击外部检测、图片懒加载、权限控制等。
Vue 3的指令钩子与组件生命周期对齐:created(绑定元素属性前)、beforeMount(绑定元素后,插入父节点前)、mounted(插入父节点后)、beforeUpdate(组件更新前)、updated(组件及其子组件更新后)、beforeUnmount(组件卸载前)、unmounted(组件卸载后)。
生态系统
Vue的生态系统以官方维护的核心库为主,保持了高度的一致性和稳定性。Vue Router是官方路由管理器,提供声明式路由映射、嵌套路由、路由守卫、懒加载、滚动行为控制等功能。Vue Router 4与Vue 3深度集成,支持组合式API风格的使用方式。
Nuxt.js是Vue生态中的全栈框架,类似于React生态中的Next.js。它提供服务端渲染、静态站点生成、自动路由(基于文件系统)、模块化架构、API路由等功能。Nuxt 3基于Vue 3和Nitro服务端引擎构建,提供了卓越的性能和开发体验。
Vite是Vue团队开发的下一代前端构建工具,利用浏览器原生ES模块支持实现极速的冷启动和热更新。Vite在开发时使用esbuild进行依赖预构建,生产构建时使用Rollup打包,兼顾了开发效率和产物优化。Vite不仅是Vue项目的首选构建工具,也被React、Svelte等其他框架广泛采用。