前言
vue支持 SPA 和 SSR 两种开发模式,即单页应用和服务端渲染,重点是SPA。
SPA的页面是用 JS 构建起来的,包括DOM、用户交互、动态数据展示等。
vue框架是一个系统,要完全掌握就要学习它的整个生态,包括它的语法、语义、语用。
从 vue2 到 vue3 的变化:2020年9月18日,vue 3.0.0 版本正式发布上线,大约在2022年2月7日,官方宣布 Vue 3 成为新的默认版本。从 vue2 到 vue3,是一种截断式的变化,所以本文把它们的语法分开介绍,而在语义方面,还是有很多共同的部分,只在必要的地方指出它们在两个版本中的差异性。
本文结构
mindmap
Vue
语法
vue2
全局API
普通实例
vue3
应用实例
模板
通用API
组合式API
选项式API
语义
声明式数据驱动
vue实例
组件
生命周期
配置对象
模板
注入
虚拟DOM树
挂载
响应式
组合式
双向绑定
插槽
混入
自定义指令
语用
vuex
pinia
vue Router
语法
vue2
vue2的API,可大致分为"全局的"和"给普通实例应用的"两部分,普通实例的API由模板、配置选项、实例属性三部分构成,本文根据顺序详细列出每个API的用法。
全局API
- Vue.config
- Vue.config.silent:取消 Vue 所有的日志与警告
- Vue.config.optionMergeStrategies:自定义合并策略
- Vue.config.devtools:配置是否允许 vue-devtools 检查代码。开发版本默认为 true,生产版本默认为 false,生产版本设为 true 可以启用检查
- Vue.config.errorHandler:指定组件的渲染和观察期间未捕获错误的处理函数
- Vue.config.warnHandler:为 Vue 的运行时警告赋予一个自定义处理函数,注意这只会在开发者环境下生效,在生产环境下它会被忽略
- Vue.config.ignoredElements:使 Vue 忽略在 Vue 之外的自定义元素 (使用了 Web Components API),否则,会抛出警告
- Vue.config.keyCodes:用于自定义按键修饰符的别名(Vue 3 已移除,推荐使用具体的按键名(如 @keyup.f2)或者使用事件对象中的 key 属性)
- Vue.config.performance:用于开启浏览器开发者工具的性能追踪
- Vue.config.productionTip:取消 Vue 在启动时生成生产提示
- Vue.extend:用于创建一个组件构造函数,这个构造函数可以用来创建可复用的组件,使用它可以很方便的把组件做成全局通用函数,在需要的地方动态调用
- Vue.nextTick:将回调延迟到下次 DOM 更新循环之后执行,主要使用场景是在数据变化之后需要操作 DOM 的时候
- Vue.set:用于向响应式对象中添加一个属性,并确保这个新属性同样是响应式的,且触发视图更新
- Vue.delete:用于删除对象的属性,并确保这个删除操作是响应式的
- Vue.directive:用于注册或获取全局自定义指令,非常适合于直接操作DOM的场景,只要是需要直接操作DOM的地方,都可以考虑使用自定义指令(比如聚焦、点击防抖)
- Vue.filter:用于注册或获取全局过滤器(Vue 3 已移除)
- Vue.component:注册或获取全局组件
- Vue.use:用于安装 Vue.js 插件,可在插件中添加原型方法、全局指令、全局混入、全局组件
- Vue.mixin:全局注册一个混入,会影响所有之后创建的 Vue 实例(包括第三方组件),谨慎使用
- Vue.compile:用于在运行时将模板字符串编译成渲染函数,通常在需要动态编译模板字符串的场景下使用,例如从用户输入或服务器获取的模板字符串(只在完整版时可用,vue3已移除)
- Vue.observable:用于创建一个响应式的对象,它可以在组件的范围之外管理状态,适用于小型的状态管理需求,无需引入vuex或pinia(在 Vue 3 中已被 reactive() 替代)
- Vue.version:提供字符串形式的 Vue 安装版本号
普通实例
模板
插值表达式
Mustache 标签将会被替代为对应数据对象上 property 的值,无论何时,绑定的数据对象上 property 发生了改变,插值处的内容都会更新。
指令
- v-text:更新元素的 textContent,与插值语法等效
- v-html:更新元素的 innerHTML,内容按普通 HTML 插入,不会作为 Vue 模板进行编译
- v-show:根据表达式之真假值,切换元素的 display 属性
- v-if:根据表达式之真假值,有条件的渲染元素,在切换时元素及它的数据绑定 / 组件被销毁并重建
- v-else:搭配 v-if 或 v-else-if,有条件的渲染元素
- v-else-if:搭配 v-if 或 v-else-if,有条件的渲染元素
- v-for:基于源数据多次渲染元素或模板块
- v-on:绑定事件监听器,简写@
- v-bind:动态地绑定一个或多个 attribute,或一个组件 prop 到表达式
- v-model:表单控件或者组件上创建双向绑定
- v-slot:提供具名插槽或需要接收 prop 的插槽,简写#
- v-pre:跳过这个元素和它的子元素的编译过程
- v-cloak:用于解决在页面加载时未编译的 Mustache 标签(双大括号)闪动问题
- v-once:用于只渲染元素和组件一次,当你知道某个部分永远不会改变时(比如帮助文本、法律条款、固定信息等静态内容),使用v-once可以避免不必要的渲染,提高性能
事件修饰符
- .stop:调用 event.stopPropagation(),阻止事件冒泡,避免父级元素的事件被意外触发
- .prevent:调用 event.preventDefault(),阻止默认行为,很多html元素有默认行为,比如点击链接会跳转页面,提交表单会刷新页面等
- .capture:在捕获阶段触发事件,比如你希望父元素的事件处理器先于子元素触发,就可以在父元素的事件上使用 .capture 修饰符
- .self:只有事件从元素本身发出才触发,典型场景是点击弹框的遮罩层关闭弹框
- .once:最多触发一次处理函数
- .passive:不调用 event.preventDefault(),不阻止默认行为,典型的使用场景是优化滚动性能(在移动端,滚动是默认行为,且滚动事件默认是阻塞的,这意味着浏览器需要等待事件处理函数执行完毕才能进行滚动)
- 键盘按键修饰符:在监听键盘事件时,需要检查详细的按键,通过添加按键修饰符实现(.enter、.tab、.delete、.esc、.space、.up、.down、.left、.right、.ctrl、.alt、.shift、.meta、.exact)
- 鼠标按键修饰符:这些修饰符会限制仅响应特定的鼠标按钮(.left、.right、.middle)
提示:修饰符可以串联,使用修饰符时,顺序很重要,相应的代码会以同样的顺序产生
v-model修饰符
- .lazy:取代 input 监听 change 事件
- .number:输入字符串转为有效的数字
- .trim:输入首尾空格过滤
特殊属性
- key:用于 Vue 的虚拟 DOM 算法,在对比新旧虚拟节点时辨识虚拟节点
- ref:用于给元素或子组件注册引用信息
- is:用于解决 HTML 规范限制和实现动态组件
- functional:用于声明基于模板的函数式组件
内置组件
- component:渲染一个“元组件”为动态组件,根据 is 的值,来决定哪个组件被渲染
- transition:用于单个元素/组件的过渡效果
- transition-group:用于多个元素/组件的过渡效果,当我们需要对一个列表中的元素进行插入、删除或顺序改变的动画时使用
- keep-alive:缓存组件,一般与动态组件(
<component is=""/>)或者v-if(用在其包裹的子组件上,不能用在自身上)结合使用 - slot:用于内容分发的组件,即插槽占位符
配置选项
- data:用于声明组件内部需要响应式更新的数据
- props:用于接收来自父组件的数据
- propsData:用于在创建 Vue 实例时传递 props,主要作用是方便测试(Vue 3 已移除)
- computed:用于声明计算属性
- methods:用于定义可以在组件实例上访问的方法
- watch:用于观察和响应Vue实例上的数据变动
- directives:用于注册局部自定义指令
- filters:用于定义局部过滤器
- components:用于注册局部组件
- parent:允许指定一个组件实例作为当前组件的父级,在大多数情况下,Vue 的模板系统会自动处理父子关系,主要用于在动态创建组件实例时手动指定其父级组件,比如通过 Vue.extend() 或 new Vue() 手动创建组件实例时(Vue 3 已移除)
- mixins:用于将一些可复用的功能(如数据、方法、生命周期钩子等)混入到多个组件中
- extends:用于声明式地扩展一个基础组件,适用于需要基于现有组件创建具有相似功能但需要定制化的新组件场景
- provide:用于祖先组件向子孙后代传递数据(本身不建立响应式绑定,而是依赖传递的数据源自身是否是响应式的)
- inject:用于接收祖先组件提供的数据
- name:允许组件模板递归地调用自身,以及获得更有语义信息的组件树,便于调试
- delimiters:允许自定义插值语法的分隔符
- functional:用于创建一个无状态、无实例、无生命周期的函数式组件(函数式组件适用于纯展示型的组件,它们渲染效率更高)
- model:用于自定义组件的v-model的行为(定制 prop 和 event,默认会把 value 用作 prop 且把 input 用作 event),仅适用于vue2,vue3的v-model机制已重构
- inheritAttrs:用于控制是否启用默认的组件 attribute 透传行为
- comments:用于控制是否保留模板中的 HTML 注释
- el:提供一个在页面上已存在的 DOM 元素作为 Vue 实例的挂载目标
- template:提供模板,模板将会替换挂载的元素
- render:用来创建虚拟节点,render 渲染函数选项若存在,则不会从 template 或 el 选项提取模板,但仍需要el 、$mounte 或其父组件提供挂载点
- renderError:当 render 函数遭遇错误时,提供另外一种渲染输出,其错误将会作为第二个参数传递到 renderError
- beforeCreate:在实例初始化之后,,创建完成之前被调用,实例未完成对选项的处理
- created:在实例创建完成之后调用,实例已完成对部分选项的处理
- beforeMount:在实例被挂载前调用
- mounted:在实例被挂载后调用
- beforeUpdate:在数据发生改变后,DOM 被更新之前被调用
- updated:在数据更改导致的虚拟 DOM 重新渲染和更新完毕之后被调用
- beforeDestroy:实例销毁之前调用,在这一步,实例仍然完全可用
- destroyed:实例销毁后调用
- activated:被 keep-alive 缓存的组件激活时调用
- deactivated:被 keep-alive 缓存的组件失活时调用
- errorCaptured:在捕获一个来自后代组件的错误时被调用
实例属性
- vm.$data:Vue 实例观察的数据对象
- vm.$props:当前组件接收到的 props 对象
- vm.$el:用于直接访问组件实例关联的 DOM 元素
- vm.$options:提供了访问组件初始选项的能力,常用于处理非响应式配置数据或自定义选项
- vm.$parent:用于访问当前组件的父组件实例
- vm.$root:当前组件树的根 Vue 实例,一般在项目中App.vue是根实例的子组件
- vm.$children:当前实例的直接子组件(Vue 3 已移除)
- vm.$slots:用于访问组件插槽内容,不包括作用域插槽
- vm.$scopedSlots:用于访问作用域插槽
- vm.$refs:用于访问注册过ref属性的所有DOM元素或子组件实例
- vm.$isServer:当前 Vue 实例是否运行于服务器
- vm.$attrs:包含了父作用域中不作为 prop 的 attribute 绑定 (vue2中不包含class和style,vue3中包含class和style)
vm.$listeners:包含了父组件传递给子组件的所有事件监听器(Vue 3 已移除,被包含在 $attrs 中)- vm.$watch:观察 Vue 实例上的一个表达式或者一个函数计算结果的变化,表达式只接受简单的键路径,对于更复杂的表达式,用一个函数取代。和选项watch不同,它能在需要的时候动态添加监听器,且能停止监听
- vm.$set:这是全局 Vue.set 的别名,用于向响应式对象中添加一个属性,并确保这个新属性同样是响应式的,且触发视图更新
- vm.$delete:这是全局 Vue.delete 的别名,用于删除对象的属性,并确保这个删除操作是响应式的
- vm.$on:用于监听当前实例上的自定义事件
- vm.$once:监听一个自定义事件,但是只触发一次,一旦触发之后,监听器就会被移除
- vm.$off:用于移除自定义事件监听器
- vm.$emit:用于触发当前实例上的事件
- vm.$mount:如果 Vue 实例在实例化时没有收到 el 选项,则它处于“未挂载”状态,可以使用该函数进行手动挂载
- vm.$forceUpdate:迫使 Vue 实例重新渲染,注意它仅仅影响实例本身和插入插槽内容的子组件,而不是所有子组件
- vm.$nextTick:将回调延迟到下次 DOM 更新循环之后执行,它跟全局方法 Vue.nextTick 一样,不同的是回调的 this 自动绑定到调用它的实例上
- vm.$destroy:完全销毁一个实例,清理它与其它实例的连接,解绑它的全部指令及事件监听器(Vue 3 已移除)
vue3
vue3的API,不能再简单粗暴的分为"全局的"和"给普通实例应用的"两部分了,因为:
- vue3移除了全局的Vue对象,引入了应用实例,它通过createApp()函数创建
- vue3是选项式API和组合式API共存,而不管哪种开发方式,对模板的使用是一样的,于是我将这部分提出来,这样的结构更清晰,方便学习
- 为了拥抱组合式编程和对Tree-Shaking的支持(构建工具能静态分析代码,移除未使用的 API,减少生产环境包体积),vue3主要通过具名导入的方式使用API,而它们要么是通用的函数(组合式与选项式写法中都有用),要么是组合式API函数
基于以上的考虑,我把vue3 API分成了五个部分:应用实例、模板、通用API、组合式API、选项式API。
应用实例
- app.config:
- app.config.errorHandler:用于为应用内抛出的未捕获错误指定一个全局处理函数
- app.config.warnHandler:用于为 Vue 的运行时警告指定一个自定义处理函数
- app.config.performance:在浏览器开发工具的“性能/时间线”页中启用对组件初始化、编译、渲染和修补的性能表现追踪
- app.config.compilerOptions:配置运行时编译器的选项
- app.config.globalProperties:一个用于注册能够被应用内所有组件实例访问到的全局属性的对象
- app.config.optionMergeStrategies:一个用于定义自定义组件选项的合并策略的对象
- app.config.idPrefix:配置此应用中通过 useId() 生成的所有 ID 的前缀
- app.config.throwUnhandledErrorInProduction:强制在生产模式下抛出未处理的错误(默认情况下只会打印在控制台,不会导致程序崩溃)
- app.mount():将应用实例挂载在一个容器元素中
- app.unmount():卸载一个已挂载的应用实例
- app.onUnmount():注册一个回调函数,在应用卸载时调用
- app.component():如果同时传递一个组件名字符串及其定义,则注册一个全局组件;如果只传递一个名字,则会返回用该名字注册的组件
- app.directive():如果同时传递一个名字和一个指令定义,则注册一个全局指令;如果只传递一个名字,则会返回用该名字注册的指令
- app.use():安装一个插件
- app.mixin():应用一个全局混入
- app.provide():提供一个值,可以在应用中的所有后代组件中注入使用
- app.runWithContext():使用当前应用作为注入上下文执行回调函数(解决了全局 provide/inject 在异步场景下的上下文丢失问题)
- app.version:提供当前应用所使用的 Vue 版本号
模板
插值表达式
Mustache 标签将会被替代为对应数据对象上 property 的值,无论何时,绑定的数据对象上 property 发生了改变,插值处的内容都会更新。
指令
- v-text:更新元素的文本内容
- v-html:更新元素的 innerHTML,内容直接作为普通 HTML 插入(会解析其中的html标签),Vue 模板语法是不会被解析的(内容不能使用插值、指令等)
- v-show:基于表达式值的真假性,来改变元素的可见性
- v-if:基于表达式值的真假性,来条件性地渲染元素或者模板片段
- v-else:表示 v-if 或 v-if / v-else-if 链式调用的“else 块”
- v-else-if:表示 v-if 的“else if 块”,可以进行链式调用
- v-for:基于原始数据多次渲染元素或模板块
- v-on:给元素绑定事件监听器
- v-bind:动态的绑定一个或多个 attribute,也可以是组件的 prop
- v-model:在表单输入元素或组件上创建双向绑定,仅限于
<input>、<select>、<textarea>、components - v-slot:用于声明具名插槽或是期望接收 props 的作用域插槽
- v-pre:跳过该元素及其所有子元素的编译,最常见的用例就是显示原始双大括号标签及内容
- v-once:仅渲染元素和组件一次,并跳过之后的更新
- v-memo:当依赖数据未变化时,强制复用当前组件的 VNode,避免重新渲染,用于解决局部高成本渲染问题
- v-cloak:用于隐藏尚未完成编译的 DOM 模板
事件修饰符
- .stop:调用 event.stopPropagation(),阻止事件冒泡,避免父级元素的事件被意外触发
- .prevent:调用 event.preventDefault(),阻止默认行为,很多html元素有默认行为,例如点击链接会跳转页面,提交表单会刷新页面等
- .self:只有事件从元素本身发出才触发,典型场景是点击弹框的遮罩层关闭弹框
- .capture:在捕获阶段触发事件,比如你希望父元素的事件处理器先于子元素触发,就可以在父元素的事件上使用 .capture 修饰符
- .once:最多触发一次处理函数
- .passive:不调用 event.preventDefault(),不阻止默认行为,典型的使用场景是优化滚动性能(在移动端,滚动是默认行为,且滚动事件默认是阻塞的,这意味着浏览器需要等待事件处理函数执行完毕才能进行滚动)
- 键盘按键修饰符:在监听键盘事件时,需要检查详细的按键,通过添加按键修饰符实现(.enter、.tab、.delete、.esc、.space、.up、.down、.left、.right、.ctrl、.alt、.shift、.meta、.exact)
- 鼠标按键修饰符:这些修饰符会限制仅响应特定的鼠标按钮(.left、.right、.middle)
v-model修饰符
- .lazy:监听 change 事件而不是 input
- .number:将输入的合法字符串转为数字
- .trim:移除输入内容两端空格
特殊属性
- key:主要作为 Vue 的虚拟 DOM 算法提示,在比较新旧节点列表时用于识别 vnode
- ref:用于注册模板引用
- is:用于绑定动态组件
- data-allow-mismatch:可以消除激活不匹配警告的特殊 attribute
特殊元素
<component>:一个用于渲染动态组件或元素的“元组件”<slot>:表示模板中的插槽内容出口<template>:当我们想要使用内置指令而不在 DOM 中渲染元素时,<template>标签可以作为占位符使用(与单文件组件顶层的<template>使用有区别,顶层的不支持指令)
内置组件
<Transition>:为单个元素或组件提供动画过渡效果<TransitionGroup>:为列表中的多个元素或组件提供过渡效果<KeepAlive>:缓存包裹在其中的动态切换组件<Teleport>:将其插槽内容渲染到 DOM 中的另一个位置<Suspense>:用于管理嵌套的异步依赖,并在等待这些异步操作完成时提供回退内容
通用API
- createApp():创建一个应用实例
- version:暴露当前所使用的 Vue 版本
- nextTick():等待下一次 DOM 更新刷新的工具方法
- defineComponent():在定义 Vue 组件时提供类型推导的辅助函数
- defineAsyncComponent():创建一个只有在需要时再加载的异步组件(懒加载),在定义路由时,它支持更多配置选项,比 ES 模块动态导入(import())更加细粒度
- defineCustomElement():将 Vue 组件封装成原生自定义元素
- h():创建虚拟 DOM 节点
- cloneVNode():克隆一个 vnode,可在原有基础上添加一些额外的 prop
- isVNode():判断一个值是否为 vnode 类型
- mergeProps():合并多个对象,支持特定属性的处理:class(合并、拼接)、style(合并、覆盖)、onXxx 事件监听器(合并、顺序执行)
- resolveComponent():按名称手动解析已注册的组件,以便在 h() 函数中或者动态渲染时使用该组件(如果你可以直接引入组件就不需使用此方法)
- resolveDirective():按名称手动解析已注册的指令
- withDirectives():用于给 vnode 增加自定义指令
- withModifiers():用于向事件处理函数添加内置 v-on 修饰符
- createRenderer():为特定的目标环境创建一个自定义的渲染器
- createSSRApp():以 SSR 激活模式创建一个应用实例
- renderToString():接收一个 Vue 应用实例作为参数,返回一个 Promise,当 Promise resolve 时得到应用渲染的HTML
- renderToNodeStream():将输入渲染为一个 Node.js Readable stream 实例
- pipeToNodeWritable():将输入渲染并 pipe 到一个 Node.js Writable stream 实例
- renderToWebStream():将输入渲染为一个 Web ReadableStream 实例
- pipeToWebWritable():将输入渲染并 pipe 到一个 Web WritableStream 实例
- renderToSimpleStream():通过一个简单的接口,将输入以 stream 模式进行渲染
- useSSRContext():用于获取已传递给renderToString()或其它服务端渲染API的上下文对象
- PropType
<T>:用于在TS中为组件的props进行更复杂类型标注的工具,允许使用TS的泛型来指定prop的类型 - MaybeRef
<T>:T | Ref<T>的别名 - MaybeRefOrGetter
<T>:T | Ref<T>| (() => T) 的别名 - ExtractPropTypes
<T>:从运行时的 props 选项对象中提取 props 类型,提取到的类型是面向内部的,即组件接收到的是解析后的 props - ExtractPublicPropTypes
<T>:从运行时的 props 选项对象中提取 prop,提取的类型是面向外部的,即父组件允许传递的 props - ComponentCustomProperties:用于增强组件实例类型以支持自定义全局属性(在项目的某个类型声明文件中使用)
- ComponentCustomOptions:用来扩展组件选项类型以支持自定义选项(在项目的某个类型声明文件中使用)
- ComponentCustomProps:用于扩展全局可用的 TSX props,以便在 TSX 元素上使用没有在组件选项上定义过的 props(在项目的某个类型声明文件中使用)
- CSSProperties:用于扩展在样式属性绑定上允许的值的类型
__VUE_OPTIONS_API__:启用/禁用选项式 API 支持(vite、vue-cli、webpack、Rollup都提供了配置入口)__VUE_PROD_DEVTOOLS__:在生产环境中启用/禁用开发者工具支持(vite、vue-cli、webpack、Rollup都提供了配置入口)__VUE_PROD_HYDRATION_MISMATCH_DETAILS__:启用/禁用生产环境构建下激活不匹配的详细警告(vite、vue-cli、webpack、Rollup都提供了配置入口)
组合式API
setup(props,context)
setup()是在组件中使用组合式 API 的入口,使用场景有:
- 需要在非单文件组件中使用组合式 API 时
- 需要在基于选项式 API 的组件中集成基于组合式 API 的代码时。
setup()可以与其它选项式API的选项共存,例如注册自定义指令时,可以用directives 选项,但对于结合单文件组件使用的组合式 API,更推荐通过 <script setup> 以获得更加简洁及符合人体工程学的语法。
setup()有两个参数,第一个是组件的 props,第二个是一个 Setup 上下文对象,该对象暴露了一些在 setup 中可能会用到的值(attrs, slots, emit, expose)。
props是响应式的,解构会丢失响应性,上下文对象是非响应式的,可以安全的解构。
setup()应该同步地返回一个对象,唯一可以使用 async setup() 的情况是,该组件是 Suspense 组件的后裔。
<script setup>
这是setup()函数的语法糖,它有以下特性:
- 没有props和context可以用,但可以通过编译宏函数(无需导入)或其它从vue库导入的函数获取相应的数据。
- 顶层的绑定会被暴露给模板(包括变量,函数声明,以及 import 导入的内容,其中自定义指令必须遵循 vNameOfDirective 的命名规范,即v开头的驼峰写法)。
一些专门用在该语法糖下的API如下:
- defineProps() :定义从父组件传递过来的数据,并可以获得完整的类型推导支持,对该函数进行解构不会丢失数据响应性
- defineSlots() :为组件的插槽定义类型,如果传递的插槽内容不符合定义的类型,TS会给出错误提示
- defineEmits() :定义从父组件传递过来的事件,并可以获得完整的类型推导支持
- defineExpose() :显式指定在
<script setup>组件中要暴露出去的属性(<script setup>的组件默认不会暴露任何属性,而除此外的组件默认暴露所有属性) - defineModel() :用于简化父子组件之间的双向数据绑定的实现
- defineOptions() :在
<script setup>中声明组件选项,不必使用单独的<script>块,大部分选项都能定义,不能定义的选项有, props、emits、expose、slots
功能函数
- ref():接受一个内部值,返回一个响应式的、可更改的ref对象,此对象只有一个指向其内部值的属性.value
- reactive():返回一个对象的响应式代理
- computed():接受一个getter函数,返回一个只读的响应式ref对象
- readonly():接受一个对象(不论是响应式还是普通的)或是一个ref,返回一个原值的只读代理(传入的对象决定了返回的是否是响应式的)
- shallowRef():ref()的浅层作用形式,只有对.value的访问是响应式的
- shallowReactive():reactive()的浅层作用形式,只有根级别的属性是响应式的
- hallowReadonly():readonly()的浅层作用形式,跟层级的属性是只读,深层的属性则可以修改
- watch():侦听一个或多个响应式数据源,并在数据源变化时调用所给的回调函数
- watchEffect():立即运行一个函数,同时响应式地追踪其依赖,并在依赖更改时重新执行
- watchPostEffect():watchEffect() 使用 flush: 'post' 选项时的别名
- watchSyncEffect():watchEffect() 使用 flush: 'sync' 选项时的别名
- onWatcherCleanup():注册一个清理函数,在当前侦听器即将重新运行时执行。只能在 watchEffect 作用函数或 watch 回调函数的同步执行期间调用 (即不能在异步函数的 await 语句之后调用)
- effectScope():创建一个 effect 作用域,可以捕获其中所创建的响应式副作用 (即计算属性和侦听器),这样捕获到的副作用可以一起处理
- getCurrentScope():如果有的话,返回当前活跃的 effect 作用域
- onScopeDispose():在当前活跃的 effect 作用域上注册一个处理回调函数。当相关的 effect 作用域停止时会调用这个回调函数
- isRef():检查某个值是否为 ref
- isReactive():检查一个对象是否是由 reactive() 或 shallowReactive() 创建的代理
- isReadonly():检查传入的值是否为只读对象
- isProxy():检查一个对象是否是由 reactive()、readonly()、shallowReactive() 或 shallowReadonly() 创建的代理
- unref():如果参数是 ref,则返回内部值,否则返回参数本身,这是 val = isRef(val) ? val.value : val 计算的一个语法糖
- toValue():将值、refs 或 getters 规范化为值。这与 unref() 类似,不同的是此函数也会规范化 getter 函数
- toRaw():返回由 reactive()、readonly()、shallowReactive() 或者 shallowReadonly() 创建的代理对应的原始对象
- toRef():可以将值、refs 或 getters 规范化为 refs,也可以基于响应式对象上的一个属性,创建一个对应的 ref,它与其源属性保持同步
- toRefs():将一个响应式对象转换为一个普通对象,这个普通对象的每个属性都是指向源对象相应属性的 ref
- markRaw():将一个对象标记为不可被转为代理,返回该对象本身
- triggerRef():用于手动触发一个浅层ref的依赖更新,通常在对浅引用的内部值进行深度变更后使用
- ustomRef():创建一个自定义的 ref,允许开发者完全控制依赖追踪和更新触发的过程
- provide():提供一个值,可以被后代组件注入
- inject():注入一个由祖先组件或整个应用提供的值
- hasInjectionContext():用于检查当前组件实例是否具有注入上下文的函数,以便安全地使用依赖注入,提高代码的健壮性
- useModel():用于在自定义组件中实现双向数据绑定,可以在所有组合式语法中使用
- useSlots() :包含父组件传递的插槽,不支持类型推导,但可以在所有组合式语法中使用
- useAttrs() :包含当前组件的透传 attributes
- useTemplateRef():获取一个模板引用,效果和ref获取模板引用是一样的,但它更符合编程直觉
- useId():用于生成唯一 ID 的函数,这个ID在同一个组件的多次渲染中是稳定的,并且在不同的组件实例之间不会重复
- useHost():返回当前 Vue 自定义元素的宿主元素(只在通过defineCustomElement()自定义的组件中生效,普通Vue组件中无法使用,宿主元素就是自定义元素本身)
- useShadowRoot():返回当前 Vue 自定义元素的 shadow root
- onBeforeMount():注册一个钩子,在组件被挂载之前被调用
- onMounted():注册一个回调函数,在组件挂载完成后执行
- onBeforeUpdate():注册一个钩子,在组件即将因为响应式状态变更而更新其 DOM 树之前调用
- onUpdated():注册一个回调函数,在组件因为响应式状态变更而更新其 DOM 树之后调用
- onBeforeUnmount():注册一个钩子,在组件实例被卸载之前调用
- onUnmounted():注册一个回调函数,在组件实例被卸载之后调用
- onActivated():注册一个回调函数,若组件实例是
<KeepAlive>缓存树的一部分,当组件被插入到 DOM 中时调用 - onDeactivated():注册一个回调函数,若组件实例是
<KeepAlive>缓存树的一部分,当组件从 DOM 中被移除时调用 - onErrorCaptured():注册一个钩子,在捕获了后代组件传递的错误时调用
- onRenderTracked():注册一个调试钩子,当组件渲染过程中追踪到响应式依赖时调用(仅在开发模式下用于调试)
- onRenderTriggered():注册一个调试钩子,当响应式依赖的变更触发了组件渲染时调用(仅在开发模式下用于调试)
- onServerPrefetch():注册一个异步函数,在组件实例在服务器上被渲染之前调用
选项式API
配置选项
- data:用于声明组件初始响应式状态的函数
- props:用于接收来自父组件的数据
- computed:用于声明要在组件实例上暴露的计算属性
- methods:用于声明要混入到组件实例中的方法
- watch:用于声明在数据更改时调用的侦听回调
- emits:用于声明由组件触发的自定义事件,即使不声明,Vue3仍可通过 $emit 触发事件,但推荐始终声明以提高代码质量
- expose:用于声明当组件实例被父组件通过模板引用访问时暴露的公共属性(默认暴露所有的实例属性)
- provide:用于提供可以被后代组件注入的值
- inject:用于声明要通过从上层提供方匹配并注入进当前组件的属性
- mixins:一个包含组件选项对象的数组,这些选项都将被混入到当前组件的实例中
- extends:要继承的“基类”组件,从实现角度来看,extends 几乎和 mixins 相同,通过 extends 指定的组件将会当作第一个 mixin 来处理
- name:用于显式声明组件展示时的名称,通常在递归组件中使用,以及方便调试
- inheritAttrs:用于控制是否启用默认的组件 attribute 透传行为
- components:一个对象,用于注册对当前组件实例可用的组件
- directives:一个对象,用于注册对当前组件实例可用的指令
- template:用于声明组件的字符串模板
- render:用来创建虚拟节点,render 渲染函数选项若存在,则不会从 template 或 el 选项提取模板,但仍需要el 、$mounte 或其父组件提供挂载点
- compilerOptions:用于配置组件模板的运行时编译器选项(仅适用于使用完整版Vue的情况),在实际开发中,优先考虑通过构建工具配置模板编译行为,而非运行时配置
- slots:在 TS 环境下,为 Vue 组件的插槽声明严格的类型约束,辅助类型推断的选项
- beforeCreate:在组件实例初始化完成之后立即调用
- created:在组件实例处理完所有与状态相关的选项后调用
- beforeMount:在组件被挂载之前调用
- mounted:在组件被挂载之后调用
- beforeUpdate:在组件即将因为一个响应式状态变更而更新其 DOM 树之前调用
- updated:在组件因为一个响应式状态变更而更新其 DOM 树之后调用
- beforeUnmount:在一个组件实例被卸载之前调用
- unmounted:在一个组件实例被卸载之后调用
- activated:若组件实例是
<KeepAlive>缓存树的一部分,当组件被插入到 DOM 中时调用 - deactivated:若组件实例是
<KeepAlive>缓存树的一部分,当组件从 DOM 中被移除时调用 - errorCaptured:在捕获了后代组件传递的错误时调用
- renderTracked:在一个响应式依赖被组件的渲染作用追踪后调用(仅在开发模式下可用)
- renderTriggered:在一个响应式依赖被组件触发了重新渲染之后调用(仅在开发模式下可用)
- serverPrefetch:当组件实例在服务器上被渲染之前要完成的异步函数
实例属性
- $data:从 data 选项函数中返回的对象,会被组件赋为响应式,组件实例将会代理对其数据对象的属性访问
- $props:表示组件当前已解析的 props 对象
- $el:该组件实例管理的 DOM 根节点
- $options:已解析的用于实例化当前组件的组件选项
- $parent:当前组件可能存在的父组件实例(是一个内部实例,不像vue2那样可以访问父组件的方法或状态了),如果当前组件是顶层组件,则为 null
- $root:当前组件树的根组件实例(内部实例),如果当前实例没有父组件,那么这个值就是它自己
- $slots:一个表示父组件所传入插槽的对象
- $refs:一个包含 DOM 元素和组件实例的对象,通过模板引用注册
- $attrs:一个包含了组件所有透传 attributes 的对象(透传 Attributes 是指由父组件传入,且没有被子组件声明为 props 或是组件自定义事件的 attributes 和事件处理函数)
- $watch():用于命令式地创建侦听器的 API,比watch选项更灵活,可以在任何地方动态添加
- $emit():在当前组件触发一个自定义事件,任何额外的参数都会传递给事件监听器的回调函数
- $forceUpdate():强制该组件重新渲染
- $nextTick():等待下一次 DOM 更新刷新的工具方法
- $host:暴露当前 Vue 自定义元素的宿主元素(只在通过 defineCustomElement() 定义的组件中生效,普通 Vue 组件中无法使用,宿主元素就是自定义元素本身)
语义
声明式数据驱动
用声明的方式定义UI和数据的关系,数据变化后系统自动处理更新,背后是框架进行追踪数据变化和管理DOM更新,开发者只关心数据和最终效果就行。
vue实例
实现声明式数据驱动的第一步就是创建vue实例,实例是组件的运行时,基于组件的配置对象创建,vue中有两种实例:(1)根组件实例(2)普通组件实例。
-
根组件实例
vue2:通过new Vue()创建,本质上是一个对象,每个组件都是一个vue实例,只需要一个vue实例就可以生成真实的DOM节点,浏览器中打印该实例,它由三部分组成:(1)$开头的一些实用的方法和属性(2)_下划线开头,vue内部使用的成员,开发者不要使用它们(3)从配置中注入的成员。vue3:通过createApp()创建。
-
普通组件实例
每个组件都有自己的组件实例,一般vue2中通过this访问,vue3中通过this(选项式)或者getCurrentInstance()访问。
组件
组件本质上是扩展的Vue实例:每个组件都是一个Vue实例,但组件更具体,通常是为了复用而创建的。
生命周期
生命周期是组件经历的从创建、挂载、更新、销毁的过程,如果是KeepAlive缓存的组件,还会触发activated(激活)、deactivated(失活)钩子。
父子组件生命周期的触发顺序:父beforeCreate --> 父created--> 父beforeMount--> 子beforeCreate--> 子created--> 子beforeMount--> 子mounted--> 父mounted。
配置对象
配置对象是创建Vue实例时传递的一个对象(选项),包含组件的静态定义信息。
模板
模板是生成虚拟DOM树的材料之一,如果在vue实例中没有render函数就会根据template配置寻找模板,如果也没有template配置,就会寻找el配置的节点的outerHTML作为模板。
注入
将声明式的配置选项注入到vue实例中,比如:data、computed、methods......。
虚拟DOM
根据vue实例(主要有render或模板选项)生成虚拟DOM树,根据虚拟DOM树的变更修改真实DOM,极大的提高性能。
挂载
将模板注入到vue实例中,再用vue实例生成虚拟DOM,用虚拟DOM渲染真实的DOM元素的过程。
响应式
vue2的选项式及vue3的选项式和组合式都要使用响应式的数据,但是它们声明响应式状态和实现响应式的方式是不同的。
选项式API中,会用 data 选项来声明组件的响应式状态,此选项的值应为返回一个对象的函数。
组合式API中,会用reactive()、ref()等函数声明响应式状态,会返回两种类型的响应式数据,一种是proxy代理,一种是{value:...}形式的ref Object。
vue2中使用 Object.defineProperty 把data 选项中的 property 全部转为 getter/setter来实现响应式,因此vue2无法检测到对象属性的添加或删除,需要借助$set和$delete。
vue3(包括选项式和组合式)中数据是基于 JavaScript Proxy (代理) 实现响应式的,reactive使用proxy实现响应式,ref使用getter/setter、reactive、proxy实现响应式。
由于ES6的proxy只能代理对象,要做到代理非对象数据,vue加入了ref方法,它可以代理任何类型的数据,它把原始数据封装成一个{value : ...}形式的对象,再通过getter/setter的方式来实现ref的响应式,这里又有几种情况:
- 如果传入ref的数据是普通非对象原始值,封装成普通的{value : ...}形式的对象
- 如果传入ref的数据是一个对象,封装成{value : reactive(...)}形式的对象,这是为了保证对象深层响应性
- 如果传入ref的数据是一个代理对象,封装成{value : ...}形式的对象,value的值就是这个代理对象
组合式
组合式 API 能够覆盖所有状态逻辑方面的需求,带来了更好的逻辑复用、更灵活的代码组织、更好的类型推导和更小的生产包体积,但也需要用到一小部分选项:比如props,emits,name 和 inheritAttrs。
双向绑定
v-model指令是属性+事件的简写,它有两种使用方式:
-
在表单输入元素上(
<input>、<select>、<textarea>)- 文本类型的
<input>和<textarea>元素会绑定 value property 并侦听 input 事件 <select>会绑定 value property 并侦听 change 事件<input type="checkbox">和<input type="radio">会绑定 checked property 并侦听 change 事件
- 文本类型的
-
在组件上
父组件上会绑定一个名为 modelValue 的 prop,并侦听一个名为 update:modelValue 的事件;在子组件中,可以使用const model = defineModel()接收(用在子组件的表单元素上非常方便,只能用在
<script setup>中),也可以使用props+emit接收(需要根据业务场景灵活使用props和emits),前者等价于:
const props = defineProps(['modelValue']);
const emit = defineEmits(['update:modelValue']);
const model = computed({
get: () => props.modelValue,
set: (value) => emit('update:modelValue', value)
});
插槽
- 默认插槽:没有使用name属性的插槽,或者使用name="default"的插槽,一个组件只能有一个默认插槽,即使它是默认作用域插槽
- 具名插槽:使用了name属性且不设置为default的插槽
- 作用域插槽:可以传递数据给父组件的插槽,它可以是默认插槽也可以是具名插槽
混入
当组件使用混入对象时,所有混入对象的选项将被“混合”进入该组件本身的选项,当组件和混入对象含有同名选项时,这些选项将以恰当的方式进行“合并”:
- 数据对象在内部会进行递归合并,并在发生冲突时以组件数据优先
- 同名钩子函数将合并为一个数组,因此都将被调用。另外,混入对象的钩子将在组件自身钩子之前调用
- 值为对象的选项,例如 methods、components 和 directives,将被合并为同一个对象。两个对象键名冲突时,取组件对象的键值对
语用
- vue-router:为 Vue.js 提供富有表现力、可配置的、方便的路由
- vuex:为 Vue.js 应用程序开发的状态管理模式 + 库
- pinia:符合直觉的 Vue.js 状态管理库
总结
还有一些不是公共的API,其行为可能在不通知的情况下随版本变动,存在破坏性变更的风险,所以故意未在官方文档中公开,但也可用于开发,比如getCurrentInstance()。