打死也要学完的vue

目录

创建一个 Vue 应用#

应用实例#

根组件#

挂载应用#

DOM 中的根组件模板#

应用配置#

多个应用实例#

模板语法#

文本插值#

原始 HTML#

Attribute 绑定#

简写#

布尔型 Attribute#

动态绑定多个值#

使用 JavaScript 表达式#

仅支持表达式#

调用函数#

受限的全局访问#

指令 Directives#

参数 Arguments#

动态参数#

修饰符 Modifiers#

响应式基础#

声明响应式状态#

响应式代理 vs. 原始值#

声明方法#

DOM 更新时机#

深层响应性#

有状态方法#

计算属性#

基础示例#

计算属性缓存 vs 方法#

可写计算属性#

最佳实践#

Getter 不应有副作用#

避免直接修改计算属性值#

Class 与 Style 绑定#

绑定 HTML class#

绑定对象#

绑定数组#

在组件上使用#

绑定内联样式#

绑定对象#

绑定数组#

自动前缀#

样式多值#

条件渲染#

v-if#

v-else#

Vue is awesome!

v-else-if#

上的 v-if#

创建一个 Vue 应用#

应用实例#

每个 Vue 应用都是通过 createApp 函数创建一个新的 应用实例

js

import { createApp } from 'vue'
​
const app = createApp({
  /* 根组件选项 */
})

根组件#

我们传入 createApp 的对象实际上是一个组件,每个应用都需要一个“根组件”,其他组件将作为其子组件。

如果你使用的是单文件组件,我们可以直接从另一个文件中导入根组件。

js

import { createApp } from 'vue'
// 从一个单文件组件中导入根组件
import App from './App.vue'
​
const app = createApp(App)

虽然本指南中的许多示例只需要一个组件,但大多数真实的应用都是由一棵嵌套的、可重用的组件树组成的。例如,一个待办事项 (Todos) 应用的组件树可能是这样的:

App (root component)
├─ TodoList
│  └─ TodoItem
│     ├─ TodoDeleteButton
│     └─ TodoEditButton
└─ TodoFooter
   ├─ TodoClearButton
   └─ TodoStatistics

我们会在指南的后续章节中讨论如何定义和组合多个组件。在那之前,我们得先关注一个组件内到底发生了什么。

挂载应用#

应用实例必须在调用了 .mount() 方法后才会渲染出来。该方法接收一个“容器”参数,可以是一个实际的 DOM 元素或是一个 CSS 选择器字符串:

html

js

app.mount('#app')

应用根组件的内容将会被渲染在容器元素里面。容器元素自己将不会被视为应用的一部分。

.mount() 方法应该始终在整个应用配置和资源注册完成后被调用。同时请注意,不同于其他资源注册方法,它的返回值是根组件实例而非应用实例。

DOM 中的根组件模板#

当在未采用构建流程的情况下使用 Vue 时,我们可以在挂载容器中直接书写根组件模板:

html

js

import { createApp } from 'vue'
​
const app = createApp({
  data() {
    return {
      count: 0
    }
  }
})
​
app.mount('#app')

当根组件没有设置 template 选项时,Vue 将自动使用容器的 innerHTML 作为模板。

应用配置#

应用实例会暴露一个 .config 对象允许我们配置一些应用级的选项,例如定义一个应用级的错误处理器,用来捕获所有子组件上的错误:

js

app.config.errorHandler = (err) => {
  /* 处理错误 */
}

应用实例还提供了一些方法来注册应用范围内可用的资源,例如注册一个组件:

js

app.component('TodoDeleteButton', TodoDeleteButton)

这使得 TodoDeleteButton 在应用的任何地方都是可用的。我们会在指南的后续章节中讨论关于组件和其他资源的注册。你也可以在 API 参考中浏览应用实例 API 的完整列表。

确保在挂载应用实例之前完成所有应用配置!

多个应用实例#

应用实例并不只限于一个。createApp API 允许你在同一个页面中创建多个共存的 Vue 应用,而且每个应用都拥有自己的用于配置和全局资源的作用域。

js

const app1 = createApp({
  /* ... */
})
app1.mount('#container-1')
​
const app2 = createApp({
  /* ... */
})
app2.mount('#container-2')

如果你正在使用 Vue 来增强服务端渲染 HTML,并且只想要 Vue 去控制一个大型页面中特殊的一小部分,应避免将一个单独的 Vue 应用实例挂载到整个页面上,而是应该创建多个小的应用实例,将它们分别挂载到所需的元素上去。

模板语法#

Vue 使用一种基于 HTML 的模板语法,使我们能够声明式地将其组件实例的数据绑定到呈现的 DOM 上。所有的 Vue 模板都是语法层面合法的 HTML,可以被符合规范的浏览器和 HTML 解析器解析。

在底层机制中,Vue 会将模板编译成高度优化的 JavaScript 代码。结合响应式系统,当应用状态变更时,Vue 能够智能地推导出需要重新渲染的组件的最少数量,并应用最少的 DOM 操作。

如果你对虚拟 DOM 的概念比较熟悉,并且偏好直接使用 JavaScript,你也可以结合可选的 JSX 支持直接手写渲染函数而不采用模板。但请注意,这将不会享受到和模板同等级别的编译时优化。

文本插值#

最基本的数据绑定形式是文本插值,它使用的是“Mustache”语法 (即双大括号):

template

Message: {{ msg }}

双大括号标签会被替换为相应组件实例中 msg 属性的值。同时每次 msg 属性更改时它也会同步更新。

原始 HTML#

双大括号会将数据解释为纯文本,而不是 HTML。若想插入 HTML,你需要使用 v-html 指令:

template

Using text interpolation: {{ rawHtml }}

Using v-html directive:

Using text interpolation: This should be red.

Using v-html directive: This should be red.

这里我们遇到了一个新的概念。这里看到的 v-html attribute 被称为一个指令。指令由 v- 作为前缀,表明它们是一些由 Vue 提供的特殊 attribute,你可能已经猜到了,它们将为渲染的 DOM 应用特殊的响应式行为。这里我们做的事情简单来说就是:在当前组件实例上,将此元素的 innerHTML 与 rawHtml 属性保持同步。

span 的内容将会被替换为 rawHtml 属性的值,插值为纯 HTML——数据绑定将会被忽略。注意,你不能使用 v-html 来拼接组合模板,因为 Vue 不是一个基于字符串的模板引擎。在使用 Vue 时,应当使用组件作为 UI 重用和组合的基本单元。

安全警告

在网站上动态渲染任意 HTML 是非常危险的,因为这非常容易造成 XSS 漏洞。请仅在内容安全可信时再使用 v-html,并且永远不要使用用户提供的 HTML 内容。

Attribute 绑定#

双大括号不能在 HTML attributes 中使用。想要响应式地绑定一个 attribute,应该使用 v-bind 指令:

template

v-bind 指令指示 Vue 将元素的 id attribute 与组件的 dynamicId 属性保持一致。如果绑定的值是 null 或者 undefined,那么该 attribute 将会从渲染的元素上移除。

简写#

因为 v-bind 非常常用,我们提供了特定的简写语法:

template

开头为 : 的 attribute 可能和一般的 HTML attribute 看起来不太一样,但它的确是合法的 attribute 名称字符,并且所有支持 Vue 的浏览器都能正确解析它。此外,他们不会出现在最终渲染的 DOM 中。简写语法是可选的,但相信在你了解了它更多的用处后,你应该会更喜欢它。

接下来的指引中,我们都将在示例中使用简写语法,因为这是在实际开发中更常见的用法。

布尔型 Attribute#

布尔型 attribute 依据 true / false 值来决定 attribute 是否应该存在于该元素上。disabled 就是最常见的例子之一。

v-bind 在这种场景下的行为略有不同:

template

isButtonDisabled 为真值或一个空字符串 (即

在演练场中尝试一下

在上面的例子中,increment 方法会在

Vue is awesome!

Oh no

Toggle

Vue is awesome!

在演练场中尝试一下

一个 v-else 元素必须跟在一个 v-if 或者 v-else-if 元素后面,否则它将不会被识别。

v-else-if#

顾名思义,v-else-if 提供的是相应于 v-if 的“else if 区块”。它可以连续多次重复使用:

template

A
B
C
Not A/B/C

v-else 类似,一个使用 v-else-if 的元素必须紧跟在一个 v-if 或一个 v-else-if 元素后面。