Vue学习记录
Vue 概述
Vue 是一款构建用户界面的 JS 框架。基于 HTML、CSS 和 JS 构建,并提供了一套声明式的、组件化的编程模型,帮助你高效地开发用户界面。
Vue 基于标准 HTML 拓展了一套模板语法,使得我们可以声明式地描述最终输出的 HTML 和 JavaScript 状态之间的关系。Vue 会自动跟踪 JS 状态并在其发生变化时响应式地更新 DOM。
Vue 可以开发单页应用(SPA)、全栈/服务器渲染(SSR)、Jamstack/静态站点生成(SSG)
API 风格
- 选项式 API:用包含多个选项的对象来描述组件的逻辑,例如 data、methods 和 mounted。选项所定义的属性都会暴露在函数内部的 this 上,它会指向当前的组件实例。
示例:
1 | <script> |
- 组合式 API:使用导入的 API 函数来描述组件逻辑
1 | <script setup> |
vue 使用
- 安装 node.js 18.3 以上版本
- 在项目创建文件安装并执行 vue
npm create vue@latest - 启动
1 | cd <your-project-name> |
- 发布:
npm run build,会在./dist 文件夹中为你的应用创建一个生产环境的构建版本。 - 创建一个应用实例,在 app.js 文件
1 | import { createApp } from 'vue' |
vue 语法
基础语法
文本插值
,双大括号标签会被替换为相应组件实例中 msg 属性的值。同时每次 msg 属性更改时它也会同步更新。 `Message: ` --- 支持表达式:1 | {{ number + 1 }} |
原始 HTML
双大括号会将数据解释为纯文本,而不是 HTML。若想插入 HTML,你需要使用 v-html 指令:
1 | <p>Using text interpolation: {{ rawHtml }}</p> |
Attribute 绑定
v-bind:v-bind 指令指示 Vue 将元素的 id attribute 与组件的 dynamicId 属性保持一致
1 | <div v-bind:id="dynamicId"></div> |
v-bind:可简写为:
动态绑定多个值:
1 | <div v-bind="objectOfAttrs"></div> |
1 | const objectOfAttrs = { |
内置指令
指令:指令的任务是在其表达式的值变化时响应式地更新 DOM,某些指令会需要一个“参数”,在指令名后通过一个冒号隔开做标识。例如用 v-bind 指令来响应式地更新一个 HTML attribute。
参数:同样在指令参数上也可以使用一个 JavaScript 表达式,需要包含在一对方括号内:
1 | <!-- 这里的 attributeName 会作为一个 JavaScript 表达式被动态执行,计算得到的值会被用作最终的参数。 --> |
动态参数的限制:值的类型应该是一个字符串,或者为 null,我们可以使用计算属性替换复杂的表达式
修饰符:修饰符是以点开头的特殊后缀,表明指令需要以一些特殊的方式被绑定。例如.prevent,会告知 v-on 指令触发事件的默认行为。
响应式基础
ref()
在组合式 API 中,推荐使用 ref() 函数来声明响应式状态:
1 | import { ref } from "vue"; |
ref()接收参数,并将其包裹在一个有.value 属性的 ref 对象中返回:
1 | const count = ref(0); |
**在组件模版中访问 ref,请从组件的 setup()函数中声明并返回它们,在模板中使用 ref 时,我们不需要附加 .value,ref 会自动解包<div>{{ count }}</div>;
1 | import { ref } from "vue"; |
当我们使用 ref 时,Vue 会自动监测 ref 值的变化,并且相应的更新 DOM。当一个组件首次渲染时,Vue 会追踪在渲染过程中使用的每一个 ref。然后当一个 ref 被修改时,它会触发追踪它的组件的一次重新渲染。
.value 属性给予了 Vue 一个机会来检测 ref 何时被访问或修改。在其内部,Vue 在它的 getter 中执行追踪,在它的 setter 中执行触发。
Ref 的深层响应性:Ref 可以持有任何类型的值,包括深层嵌套的对象、数组或者 JavaScript 内置的数据结构,这使得它的值具有深层的响应性,这意味着即使改变嵌套对象或数组时,变化也会被检测到:
1 | import { ref } from "vue"; |
当修改了响应式状态时,DOM 会自动更新,可以使用 nextTick()来等待 DOM 更新完成后在执行额外的代码。
reactive()
ref 是将值包装成了一个响应式对象,而 reactive()是使对象本身具有响应性,因此使用时不需要.value
reactive() 将深层地转换对象:当访问嵌套对象时,它们也会被 reactive() 包装。当 ref 的值是一个对象时,ref() 也会在内部调用它。
reactive() 返回的是一个原始对象的代理(Proxy),并不是原始对象。只有代理对象是响应式的,更改原始对象不会触发更新。因此,使用 Vue 的响应式系统的最佳实践是仅使用你声明对象的代理版本。
对同一个原始对象调用 reactive() 会总是返回同样的代理对象,而对一个已存在的代理对象调用 reactive() 会返回其本身:
reactive()局限性:
- 只能用于对象类型,不能持有 string、boolean 等原始类型
- 由于 Vue 的响应式跟踪是通过属性访问实现的,因此我们必须始终保持对响应式对象的相同引用。这意味着我们不能轻易地“替换”响应式对象,因为这样的话与第一个引用的响应性连接将丢失
- 当我们将响应式对象的原始类型属性解构为本地变量时,或者将该属性传递给函数时,我们将丢失响应性连接
响应式对象是 JavaScript 代理,其行为就和普通对象一样。不同的是,Vue 能够拦截对响应式对象所有属性的访问和修改,以便进行依赖追踪和触发更新。
解包的细节:
- 一个 ref 会在作为响应式对象的属性被访问或修改时自动解包。它的行为就像一个普通的属性
- 如果将一个新的 ref 赋值给一个关联了已有 ref 的属性,那么它会替换掉旧的 ref
数组和集合的注意事项: - 与 reactive 对象不同的是,当 ref 作为响应式数组或原生集合类型 (如 Map) 中的元素被访问时,它不会被解包
计算属性
使用计算属性来描述依赖响应式状态的复杂逻辑,示例:
1 | <script setup> |
computed() 方法期望接收一个 getter 函数,返回值为一个计算属性 ref。和其他一般的 ref 类似,你可以通过 publishedBooksMessage.value 访问计算结果。计算属性 ref 也会在模板中自动解包,因此在模板表达式中引用时无需添加 .value
Vue 的计算属性会自动追踪响应式依赖。它会检测到 publishedBooksMessage 依赖于 author.books,所以当 author.books 改变时,任何依赖于 publishedBooksMessage 的绑定都会同时更新。
计算属性缓存:计算属性值会基于其响应式依赖被缓存。一个计算属性仅会在其响应式依赖更新时才重新计算。这意味着只要 author.books 不改变,无论多少次访问 publishedBooksMessage 都会立即返回先前的计算结果,而不用重复执行 getter 函数。
计算属性默认是只读的,若尝试修改,会出现警告,可以通过同时提供 getter 和 setter 来创建可写:
1 | <script setup> |
类与样式绑定
绑定 Class
绑定对象:我们可以给 :class 传递一个对象来动态切换 class:
1 | <div :class="{ active: isActive }"></div> |
表示 active 是否存在取决于数据属性 isActive 的真假值
示例:
1 | const isActive = ref(true); |
1 | <div |
渲染的结果会是:<div class="static active"></div>;
绑定内联样式
:style 支持绑定 JavaScript 对象值,对应的是 HTML 元素的 style 属性
示例:
1 | const styleObject = reactive({ |
条件渲染
- v-if:v-if 指令用于条件性地渲染一块内容。这块内容只会在指令的表达式返回真值时才被渲染。
- v-else:为 v-if 添加一个“else 区块”
- v-else-if:相应于 v-if 的“else if 区块”
- v-show:按条件显示一个元素的指令是 v-show
1 | <button @click="awesome = !awesome">Toggle</button> |
- v-if 是按条件渲染,条件区块内的事件监听器和子组件都会被销毁与重建。
- v-if 也是惰性的:如果在初次渲染时条件值为 false,则不会做任何事。条件区块只有当条件首次变为 true 时才被渲染。
- v-show:元素无论初始条件如何,始终会被渲染,只有 CSS display 属性会被切换。
v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。因此,如果需要频繁切换,则使用 v-show 较好;如果在运行时绑定条件很少改变,则 v-if 会更合适
列表渲染
v-for 指令基于一个数组来渲染一个列表。v-for 指令的值需要使用 item in items 形式的特殊语法,其中 items 是源数据的数组,而 item 是迭代项的别名
1 | const items = ref([{ message: 'Foo' }, { message: 'Bar' }]) |
v-for 也支持使用可选的第二个参数表示当前项的位置索引。
1 | <li v-for="(item, index) in items"> |
通过 key 管理状态:为每个元素对应的块提供一个唯一的 key attribute
1 | <div v-for="item in items" :key="item.id"> |
Vue 默认按照“就地更新”的策略来更新通过 v-for 渲染的元素列表。当数据项的顺序改变时,Vue 不会随之移动 DOM 元素的顺序,而是就地更新每个元素,确保它们在原本指定的索引位置上渲染。
组件上使用 v-for
1 | <MyComponent |
事件处理
监听事件
- v-on(简写@):来监听 DOM 事件,并在事件触发时执行对应的 JavaScript
用法:v-on:click=”handler” 或 @click=”handler”
事件修饰符:
1 | <!-- 单击事件将停止传递 --> |
按键修饰符:在监听键盘事件时,我们经常需要检查特定的按键。Vue 允许在 v-on 或 @ 监听按键事件时添加按键修饰符。
1 | <!-- 仅在 `key` 为 `Enter` 时调用 `submit` --> |
你可以直接使用 KeyboardEvent.key 暴露的按键名称作为修饰符,但需要转为 kebab-case 形式。
鼠标按键修饰符
- .left
- .right
- .middle
表单输入绑定
v-model 会根据所使用的元素自动使用对应的 DOM 属性和事件组合
1 | <p>Message is: {{ message }}</p> |
监听器
watch()在每次响应式状态发生变化时触发回调函数
示例:
1 | <script setup> |
watch 的第一个参数是数据源,可以是一个响应式对象、一个 getter 函数、或多个数据源组成的数据,直接给 watch() 传入一个响应式对象,会隐式地创建一个深层侦听器——该回调函数在所有嵌套的变更时都会被触发:
1 | const obj = reactive({ count: 0 }); |
一个返回响应式对象的 getter 函数,只有在返回不同的对象时,才会触发回调:
1 | watch( |
watch 默认是懒执行的:仅当数据源变化时,才会执行回调。但在某些场景中,我们希望在创建侦听器时,立即执行一遍回调。举例来说,我们想请求一些初始数据,然后在相关状态更改时重新请求数据。
我们可以通过传入 immediate: true 选项来强制侦听器的回调立即执行:
1 | watch( |
模版引用
使用 ref 来直接访问底层 DOM 元素,它允许我们在一个特定的 DOM 元素或子组件实例被挂载后,获得对它的直接引用。
1 | <input ref="input" /> |
要在组合式 API 中获取引用,我们可以使用辅助函数 useTemplateRef()
1 | <script setup> |
Props
一个组件需要显式声明它所接受的 props,这样 Vue 才能知道外部传入的哪些是 props
在使用