Vue使用基于 HTML 的模板语法,能声明式地将其组件实例的数据绑定到DOM。所有Vue 模板可以被符合规范的浏览器和 HTML 解析器解析。Vue 会将模板编译成高度优化的 JavaScript 代码。结合响应式系统,当应用状态变更时,Vue 能够智能地推导出需要重新渲染的组件的最少数量,并应用最少的 DOM 操作。也支持使用JSX手写渲染函数,但不会享受到和模板同等级别的编译时优化。
Vue在所有的数据绑定中都支持完整的 JavaScript 表达式,表达式都会被作为 JavaScript,以当前组件实例为作用域解析执行。每个绑定仅支持单一表达式,即一段能够被求值的 JavaScript 代码,一个简单的判断方法是是否可以合法地写在 return 后面。因此,可以在绑定的表达式中使用组件暴露的方法,但绑定在表达式中的方法在组件每次更新时都会被重新调用,因此不应该产生任何副作用,比如改变数据或触发异步操作。
模板中的表达式将被沙盒化,仅能够访问到暴露的有限的常用内置全局对象列表。然而可以自行在app.config.globalProperties上显式地添加它们,供所有的Vue表达式使用。
模板数据绑定形式:
指令attribute的期望值为一个 JavaScript 表达式(v-for、v-on 和 v-slot例外)。一个指令的任务是在其表达式的值变化时响应式地更新DOM。某些指令会需要一个“参数”,在指令名后通过一个冒号隔开做标识。指令参数上也可以使用一个JavaScript表达式包含在一对方括号内作为动态参数,它作为JavaScript表达式被动态执行,计算得到的值会被用作最终的参数:
修饰符是指令参数中以点开头的特殊后缀,表明指令需要以一些特殊的方式被绑定。.prevent 修饰符会告知 v-on 指令对触发的事件调用 event.preventDefault()。
v-html 指令,更新元素的 innerHTML,期望的绑定值类型为string。
若想插入 HTML需要使用 v-html 指令,在当前组件实例上,将元素的 innerHTML 与 v-html对应的属性保持同步。不能使用 v-html 来拼接组合模板,因为 Vue 不是一个基于字符串的模板引擎。在使用 Vue 时,应当使用组件作为 UI 重用和组合的基本单元。在网站上动态渲染任意 HTML 是非常危险的,因为这非常容易造成 XSS 漏洞。请仅在内容安全可信时再使用 v-html,并且永远不要使用用户提供的 HTML 内容。
v-if 指令用于条件性地渲染一块内容。这块内容只会在指令的表达式返回真值时才被渲染。v-else-if 提供的是相应于 v-if 的“else if 区块”。它可以连续多次重复使用。也可以使用 v-else 为 v-if 添加一个“else 区块”。一个 v-else 或v-else-if元素必须跟在一个 v-if 或者 v-else-if 元素后面,否则它将不会被识别。可以在元素上使用 v-if/v-else-if/v-else,该元素作为多个元素的包装器,且不包含在最终渲染的结果中。v-if 是真正的条件渲染,是惰性的,直到条件第一次为真才会渲染条件块,条件为假则条件块内的事件监听器和子组件被销毁,存在更高的切换开销,所以适合运行时条件切换少的场景。
v-show用法基本类似,不同之处在于 v-show 会在 DOM 渲染中保留该元素;v-show 仅切换了该元素上名为 display 的 CSS 属性,且不能在上使用。v-show 实际是基于CSS的display属性进行切换,无论初始条件如何都会渲染,更高的初始渲染开销,所以适合条件切换频繁的场景。
v-for 指令基于一个数组来渲染一个列表。v-for 指令的值需要使用 item in items 形式的特殊语法,其中 items 是源数据的数组,而 item 是迭代项的别名。v-for 也支持使用可选的第二个参数表示当前项的位置索引(v-for="(item, index) in items")。每个 v-for 作用域都可以访问到父级作用域。也可以使用 of 作为分隔符来替代 in。也可以使用 v-for 来遍历一个对象的所有属性,遍历的顺序会基于对该对象调用 Object.keys() 的返回值来决定,三个参数分别是属性值,属性名,位置索引。v-for 可以直接接受一个整数值num,会将该模板基于 1...num 的取值范围重复多次。也可以在 标签上使用 v-for 来渲染一个包含多个元素的块。
Vue 默认按照“就地更新”的策略来更新通过 v-for 渲染的元素列表。当数据项的顺序改变时,Vue 不会随之移动 DOM 元素的顺序,而是就地更新每个元素,确保它们在原本指定的索引位置上渲染。默认模式是高效的,但只适用于列表渲染输出的结果不依赖子组件状态或者临时 DOM 状态 (例如表单输入值) 的情况。为了使得可以跟踪每个节点,从而重用和重新排序现有的元素,需要为每个元素对应的块提供一个唯一的 key attribute。当使用 时,key 应该被放置在 容器上。推荐在任何可行的时候为 v-for 提供一个 key attribute,除非所迭代的 DOM 内容非常简单 (例如:不包含组件或有状态的 DOM 元素),或者有意采用默认行为来提高性能。key 绑定的值期望是一个基础类型的值,例如字符串或 number 类型。不要用对象作为 v-for 的 key。
可以直接在组件上使用 v-for,也需要提供key。但是,这不会自动将任何数据传递给组件,因为组件有自己独立的作用域。为了将迭代后的数据传递到组件中,还需要传递 props。不自动将 item 注入组件的原因是,这会使组件与 v-for 的工作方式紧密耦合。明确其数据的来源可以使组件在其他情况下重用。
Vue 能够侦听响应式数组的变更方法,并在它们被调用时触发相关的更新。这些变更方法包括:push、pop、shift、unshift、splice、sort、reverse。变更方法,就是会对调用它们的原数组进行变更。而对于非变更方法filter、concat 、slice,即不会更改原数组,而总是返回一个新数组,需要将旧的数组替换为新的。由于Vue 实现了一些巧妙的方法来最大化对 DOM 元素的重用,因此用另一个包含部分重叠对象的数组来做替换,仍会是一种非常高效的操作。
如果需要显示数组经过过滤或排序后的内容,而不实际变更或重置原始数据,则可以创建返回已过滤或已排序数组的计算属性。在计算属性不可行的情况下 (例如在多层嵌套的 v-for 循环中),可以使用methods方法操作中间态。在计算属性中使用 reverse() 和 sort() 的时候务必小心!这两个方法将变更原始数组,计算函数中不应该这么做。请在调用这些方法之前创建一个原数组的副本。
同时使用 v-if 和 v-for 是不推荐的,因为这样二者的优先级不明显。当它们同时存在于一个节点上时,v-if 比 v-for 的优先级更高,Vue3中则相反,v-for 的优先级比 v-if 高。这意味着在 Vue2 中 v-if 的条件将无法访问到 v-for 作用域内定义的变量别名,解决办法是在外新包装一层 再在其上使用 v-for 可以解决这个问题 。
但如果只有少部分因为 v-if 而不渲染,容易浪费 v-if的计算,因此最佳实践是先使用计算属性 computed 把data处理好,再用 v-for 渲染已处理好的。
在 Vue 中,class 和 style 表达式的类型可以是字符串、对象或数组。:class(或:style)指令和一般的 class(或style) attribute 共存。在组件上同样支持字符串、数组和数组形式,使用时,组件上传递的会被添加到组件的根元素上且与该元素上已有的合并。如果组件有多个根元素,而组件的$attrs属性的$attrs.class(style)对应于组件上传递class(style),然后在组件内部指定某个根元素上:class进行接收即可。
字符串形式可以给class(style)传递字符串字面量(同HTML的内联),或者通过:class(:style)传递结果为字符串的表达式。
对象形式通过给:class (v-bind:class 的缩写) 传递一个对象来动态切换 class,对象的属性名对应于class名,对象的属性值的真假值对应于该class名是否存在,对象既可以写成内联字面量的形式,也可以直接绑定一个对象的名字,或者一个返回对象的计算属性。
数组形式通过给:class绑定一个数组来渲染多个 CSS class,数组中的每个元素可以是对象形式或字符串形式。
对象形式通过给:style(v-bind:style 的缩写) 传递一个对象来绑定style,对象的属性键值对分别对应于CSS的属性键值对,其中属性名推荐使用camelCase形式,也可以使用 kebab-cased 形式(即CSS 中的实际名称),对象的属性值对应于CSS属性对的属性值,属性值可以是由多个值构成的数组,仅会渲染浏览器支持的数组中最后一个值。对象既可以写成内联字面量的形式,也可以直接绑定一个对象的名字,或者一个返回对象的计算属性。
数组形式通过给:style绑定一个包含多个样式对象的数组。这些对象会被合并后渲染到同一元素上。
当在:style中使用了需要浏览器特殊前缀的 CSS 属性时,Vue 会自动为他它们加上相应的前缀。Vue 是在运行时检查该属性是否支持在当前浏览器中使用。如果浏览器不支持某个属性,那么将尝试加上各个浏览器特殊前缀,以找到哪一个是被支持的。
使用 v-on 指令 (简写为 @) 来监听 DOM 事件,并在事件触发时执行对应的 JavaScript。用法:v-on:eventName="handler" 或 @eventName="handler"。事件处理器handler的值可以是:
模板编译器会通过检查v-on的值是否是合法的 JavaScript 标识符或属性访问路径来断定是何种形式的事件处理器。foo() 和 count++ 会被视为内联事件处理器;foo、foo.bar 和 foo['bar'] 会被视为方法事件处理器。
为了使得事件处理器方法能更专注于数据逻辑而不用去处理 DOM 事件的细节,Vue 为v-on提供了用.表示的指令后缀的事件修饰符,包
同样,Vue 允许在 v-on 或 @ 监听按键事件时添加按键修饰符,约束特定按键才触发键盘事件。可以直接使用 KeyboardEvent.key 暴露的按键名称作为修饰符,但需要转为 kebab-case 形式。按键修饰符也可以使用链式书写。Vue 为一些常用的按键提供了别名:
系统按键修饰符如下:
请注意,系统按键修饰符和常规按键不同。与 keyup 事件一起使用时,该按键必须在事件发出时处于按下状态,比如,keyup.ctrl 只会在仍然按住 ctrl 但松开了另一个键时被触发。若你单独松开 ctrl 键将不会触发。
.exact 修饰符允许控制触发一个事件所需的确定组合的系统按键修饰符。比如@click.exact仅当没有按下任何系统按键时触发;@click.ctrl.exact仅当按下 Ctrl 且未按任何其他键时才会触发。@click.ctrl当按下 Ctrl 时,即使同时还按下 Alt 或 Shift 也会触发。
鼠标按键修饰符将处理程序限定为由特定鼠标按键触发的事件,如下:
为了避免在前端处理表单时手动将表单输入框的内容与JavaScript的值手动连接绑定和更改事件监听器的麻烦,Vue提供了v-model指令。
v-model可用于各种不同类型的输入,包括 、
1. 文本类型的 和
2. 和 会绑定 checked property 并侦听 change 事件;
3.
v-model也支持布尔值、数组或集合值,可将多个复选框绑定到同一数组或集合值,或将多选
对于单选按钮,复选框和选择器选项,v-model 绑定的值通常是静态的字符串 (或者对复选框是布尔值),可以通过使用 v-bind 来实现将值绑定到当前组件实例上的动态数据以及将选项值绑定为非字符串的数据类型。
复选框中,true-value 和 false-value 是 Vue 特有的 attributes,仅支持和 v-model 配套使用。v-model的值会在复选框选中(未选中)时设置为true-value(false-value) attributes对应的值,同时true-value 和 false-value支持v-bind来绑定复杂的值。true-value 和 false-value attributes 不会影响 value attribute,因为浏览器在表单提交时,并不会包含未选择的复选框。为了保证这两个属性对应的值的其中之一被表单提交,请使用单选按钮作为替代。
单选按钮中,:value绑定的值将在选中的时候被赋值给v-model值。
对于需要使用IME的语言 (中文,日文和韩文等),v-model不会在IME输入还在拼字阶段时触发更新。如果你的确想在拼字阶段也触发更新,请直接使用自己的 input 事件监听器和 value 绑定而不要使用 v-model。
修饰符:
v-model 可以在组件上使用以实现双向绑定。默认情况下,v-model 在组件上都是使用 modelValue 作为 prop,并以 update:modelValue 作为对应的事件,组件上v-model可以通过指定一个参数来更prop名称和事件名称,而且通过这种指定参数的方式可以在单个组件实例上创建多个 v-model 双向绑定。组件的 v-model 上所添加的自定义修饰符,可以通过 modelModifiers prop 在组件内访问到,modelModifiers prop 的默认值是一个空对象,当修饰符被组件上的v-model使用时,修饰符作为modeModifiers 对象的一个属性且其值为 true。对于又有参数arg又有修饰符的 v-model 绑定,生成的 prop 名将是 arg + "Modifiers"。在组件上使用v-model需要在组件内通过其中一种方式实现:
(1)将内部原生 元素的 value attribute 绑定到 modelValue prop,当原生的 input 事件触发一个传递新值作为参数的 update:modelValue 自定义事件。
(2)使用一个可写的,同时具有 getter 和 setter 的 computed 属性绑定到组件内的原生 元素的v-model上。get 方法需返回 modelValue prop,而 set 方法需触发相应的事件。
每个Vue组件实例在创建时都需要经历设置好数据侦听,编译模板,挂载实例到 DOM,以及在数据改变时更新 DOM的一系列初始化步骤,并在每个阶段运行称为生命周期钩子的函数,breforeCreate和created,beforeMount和mounted,beforeUpdate和updated,beforeUnmount和unmounted,让开发者有机会在对应的特定阶段运行自己的代码。所有生命周期钩子函数的 this 上下文都会自动指向当前调用它的组件实例,但是,避免用箭头函数来定义生命周期钩子,因为如果这样的话你将无法在函数中通过 this 获取组件实例。
Vue实例里的成员分成两大部分,模版可以直接使用vue实例中的成员:
Vue3 实例生命周期的图表:
Vue2 实例生命周期的图表:
父组件和子组件生命周期钩子执行顺序:父组件等待子组件完成后,才会执行自己对应完成的钩子(更新,挂载,销毁),同时,子组件的初始化(beforeCreate)在父组件beforeMount之后开始。
特殊的 ref attribute支持直接访问底层 DOM 元素,它允许在一个特定的 DOM 元素或子组件实例被挂载后,获得对它的直接引用,比如,需要在组件挂载时将焦点设置到一个 input 元素上,或在一个元素上初始化一个第三方库。组件挂载结束后引用都会作为属性被暴露在当前组件实例的 this.$refs 对象上,只可以在组件挂载后才能访问模板引用ref,如果在模板中的表达式上访问 $refs.input,在初次渲染时会是 null,因为在初次渲染前该元素还不存在。当在 v-for 中使用模板引用时(需要 v3.2.25 及以上版本),相应的ref对应的值是一个数组,并且ref 数组并不保证与源数组相同的顺序。
ref的值类型可以是字符串值,或者使用:ref绑定为一个内联函数((el)=> {})或methods,会在每次组件更新或卸载时都被调用,函数的第一个参数在更新时是元素引用,卸载时是null。
模板引用(ref或:ref)也可以在子组件上使用,引用中获得的值是组件实例。如果子组件使用的是选项式 API,被引用的组件实例和该子组件的 this 完全一致,这意味着父组件对子组件的每一个属性和方法都有完全的访问权,同时,利用expose 选项可以用于限制对子组件实例的访问。这使得在父组件和子组件之间创建紧密耦合的实现细节变得很容易,也因此只应该在绝对需要时才在子组件上使用模板引用。大多数情况下应该首先使用标准的 props 和 emit 接口来实现父子组件交互。
组件允许将 UI 划分为独立的、可重用的部分,Vue 实现了自己的组件模型,使得可以在每个组件内封装自定义内容与逻辑。
当使用构建步骤时,Vue 组件定义在一个单独的 .vue 文件,即单文件组件,简称SFC。 当不使用构建步骤时,一个 Vue 组件在js文件中以一个包含 Vue 特定选项的 JavaScript 对象来定义,其中template选项是一个内联的 JavaScript 字符串或者也可以使用 ID 选择器来指向一个元素 (通常是原生的 元素),Vue 将会使用其内容作为模板来源并会在运行时编译它。.js 文件里默导出组件,但也可以在一个文件中通过具名导出的方式导出多个组件。
组件将会以其注册时的名字作为模板中的标签名,组件注册分为全局注册和局部注册。
全局注册,使用 Vue 应用实例const app = createApp({})的 app.component() 方法,第一个参数是组件名称,第二个参数是组件的实现,进行全局地注册组件,而不需要额外再导入。app.component() 方法可以被链式调用。每一个组件都维护着自己的状态,因为每个组件都是一个新的实例。全局注册存在的问题:
局部注册需要在使用它的父组件中显式导入,并在components选项上注册来暴露给模板,并且只能在该父组件中使用。 components 选项对象的 key 名就是注册的组件名,而值就是相应组件的实现。它的优点是使组件之间的依赖关系更加明确,并且对 tree-shaking 更加友好。请注意:局部注册的组件在后代组件中并不可用。
使用 PascalCase 作为组件名的注册格式。首先PascalCase 是合法的 JavaScript 标识符,这使得在 JavaScript 中导入和注册组件都很容易,同时 IDE 也能提供较好的自动补全。其次,