Vue.js 2 核心概念解析:入门介绍 – wiki基地


Vue.js 2 核心概念解析:入门介绍

Vue.js 是一个渐进式 JavaScript 框架,用于构建用户界面。与 Angular 和 React 等其他框架相比,Vue.js 的设计理念是“渐进式”——这意味着你可以逐步地将它集成到你的项目中。你可以只使用它的一部分来增强现有的 HTML 结构,也可以用它来构建一个完整的、复杂的单页应用(SPA)。

Vue.js 2 版本是其发展历程中的一个重要里程碑,它凭借其简洁的 API、卓越的性能和完善的文档,赢得了全球开发者的喜爱,并在许多企业级项目中得到广泛应用。尽管 Vue 3 已经发布,但 Vue 2 仍然在大量现有项目中活跃,理解其核心概念对于维护和开发这些项目至关重要,也是理解 Vue 3 基础的坚实一步。

本文将深入浅出地介绍 Vue.js 2 的核心概念,帮助初学者快速入门,并为进一步学习打下坚实的基础。我们将从最基础的 Vue 实例开始,逐步探索模板语法、数据绑定、指令、事件处理、计算属性、侦听器、组件系统以及生命周期钩子等关键知识点。

1. 初识 Vue.js:一个简单的开始

Vue.js 的一个主要优势是它的易用性。你可以通过一个简单的 <script> 标签将其引入到你的 HTML 页面中,然后立即开始使用。

“`html




Vue.js 2 入门


{{ message }}


“`

将上面的代码保存为一个 HTML 文件并在浏览器中打开,你会看到一个标题显示着“Hello, Vue 2!”。这段简单的代码展示了 Vue 的几个核心概念:

  1. Vue 库的引入: 通过 <script src="..."> 标签引入 Vue 库。
  2. 挂载元素: <div id="app"> 是 Vue 应用将被挂载的 DOM 元素。
  3. 创建 Vue 实例: new Vue({...}) 创建了一个 Vue 应用的根实例。
  4. el 选项: 指定了 Vue 实例要挂载的 DOM 元素的选择器(#app)。
  5. data 选项: 包含了应用的状态数据。这里的 message 是一个数据属性。
  6. 模板语法 ({{ }}): 在 HTML 中使用双大括号 ({{ }}) 来显示 Vue 实例中的数据。当 message 数据发生变化时,页面上的内容会自动更新,这就是 Vue 的响应式特性。

这是 Vue 应用的基石。接下来,我们将更详细地分解这些概念。

2. Vue 实例 (The Vue Instance)

每个 Vue 应用都是通过创建一个新的 Vue 实例来启动的:

javascript
var vm = new Vue({
// 选项对象
})

这里的 vm 通常被称为 ViewModel,代表着 Vue 实例。Vue 实例选项对象包含了一系列配置选项,用来定义 Vue 应用的行为和数据,其中最基础的是 eldata

  • el (Element):

    • 类型: string | Element
    • 描述: 提供一个在页面上已存在的 DOM 元素作为 Vue 实例的挂载目标。Vue 实例将完全控制这个 DOM 元素及其子元素。这个元素通常是一个容器 <div>。在上面例子中,el: '#app' 告诉 Vue 将实例挂载到 ID 为 app 的元素上。
  • data:

    • 类型: Object | Function (通常在组件中使用 Function)
    • 描述: Vue 实例的数据对象。Vue 会将 data 对象的所有属性代理到 Vue 实例上。这意味着你可以通过 vm.message 来访问 data.message。更重要的是,这些属性是响应式的。当 data 对象的属性值发生变化时,所有使用了这些属性的模板部分都会自动更新。

    “`javascript
    var vm = new Vue({
    el: ‘#app’,
    data: {
    firstName: ‘张’,
    lastName: ‘三’
    }
    })

    // 可以通过 vm.firstName 和 vm.lastName 访问数据
    console.log(vm.firstName); // 输出: 张

    // 改变数据会触发视图更新(如果模板使用了这些数据)
    vm.firstName = ‘李’;
    “`

除了 eldata,Vue 实例还有很多其他重要的选项,比如 methodscomputedwatchcomponentstemplate 等等,我们将在后续章节中逐步介绍。

3. 模板语法 (Template Syntax)

Vue 使用一种基于 HTML 的模板语法,允许你声明式地将 DOM 绑定至底层 Vue 实例的数据。所有的 Vue 模板都是合法的 HTML,可以被符合规范的浏览器及 HTML 解析器解析。

3.1 插值 (Interpolations)

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

html
<span>Message: {{ message }}</span>

双大括号标签会将 data 属性 message 的值作为普通文本插入到它们所在的位置。如果 message 属性发生变化,它也会同步更新。

除了文本,双大括号也可以用来插入 JavaScript 表达式:

“`html
{{ number + 1 }}
{{ message.split(”).reverse().join(”) }}

“`

但是,表达式必须是单个表达式,不能包含控制流语句(如 iffor)或声明语句(如 varconst)。

3.2 指令 (Directives)

指令是带有 v- 前缀的特殊特性。它们的作用是当表达式的值改变时,将一些行为应用到 DOM 上。

我们已经看到一个简单的例子:

“`html

现在你看到我了

“`

这里的 v-if 就是一个指令。它根据表达式 seen 的值的真假来决定是否渲染这个 <p> 元素。

一些指令可以接收一个“参数”,在指令名称之后以冒号表示:

html
<a v-bind:href="url">...</a>

这里 hrefv-bind 指令的参数,它指示 Vue 将元素的 href 属性与 Vue 实例的 url 数据绑定。

另一个常见的指令是 v-on,用于监听 DOM 事件:

html
<button v-on:click="doSomething">按钮</button>

这里 clickv-on 指令的参数,它指示 Vue 监听按钮的点击事件,并在事件发生时执行 doSomething 方法。

为了方便,Vue 为 v-bindv-on 这两个最常用的指令提供了缩写

  • v-bind: 缩写为 :
    html
    <a :href="url">...</a>
  • v-on: 缩写为 @
    html
    <button @click="doSomething">按钮</button>

使用缩写可以使模板更简洁。在后续例子中,我们将优先使用缩写形式。

4. 数据绑定 (Data Binding)

数据绑定是 Vue 核心功能之一,它使得数据和 DOM 保持同步。主要通过以下方式实现:

  • 文本插值 ({{ }}): 将数据显示为文本。
  • 属性绑定 (v-bind:): 将数据绑定到 HTML 元素的属性上。

“`html

{{ message }}

访问百度

绑定 Class
绑定 Style

“`

在上面的例子中:
* :href 将链接的 href 属性动态绑定到 linkUrl 数据。
* :src:alt 分别将图片路径和 alt 文本绑定到对应数据。
* :class 绑定可以是一个对象,对象的键是 class 名称,值是布尔值,决定该 class 是否存在。
* :style 绑定可以是一个对象,对象的键是 CSS 属性名(支持驼峰命名或 kebab-case),值是对应的样式值。

5. 常用指令详解

Vue 提供了许多内置指令来帮助你操作 DOM。除了前面提到的 v-ifv-bindv-on,以下是一些非常常用的指令:

5.1 条件渲染 (Conditional Rendering)

  • v-if: 根据表达式的值,决定是否渲染元素。
    html
    <p v-if="score > 60">及格了</p>
    <p v-else>继续努力</p> <!-- 与 v-if 或 v-else-if 配对使用 -->

    Vue 也提供了 v-else-if 指令来实现“else if”块。v-if 是“惰性”的,如果条件为假,元素及其子元素不会被渲染。

  • v-show: 根据表达式的值,决定元素的显示或隐藏(通过 CSS 的 display 属性)。
    html
    <p v-show="isLoading">正在加载...</p>

    v-show 的元素会始终被渲染并保留在 DOM 中,只是简单地切换其 CSS display 属性。如果需要频繁切换元素的显示状态,v-show 通常比 v-if 性能更好。

5.2 列表渲染 (List Rendering)

  • v-for: 基于源数据多次渲染元素或模板块。
    “`html

    • {{ item.text }}

    • {{ index }} – {{ key }}: {{ value }}


    {{ n }}


    ``v-for的语法是item in items(item, index) in items。对于对象,语法是(value, key) in object(value, key, index) in object`。

    注意 key 的使用: 当 Vue 正在更新使用 v-for 渲染的元素列表时,它默认使用“就地更新”策略。这意味着如果数据项的顺序改变,Vue 不会移动 DOM 元素来匹配数据项的顺序,而是修改现有元素。这效率很高,但可能会有问题,特别是当列表渲染包含状态的子组件或临时 DOM 状态(如表单输入值)时。为了给 Vue 一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素,你需要为每个项提供一个唯一的 key 属性。key 通常是数据项的唯一 ID。使用 v-for 时强烈推荐总是加上 key

5.3 双向绑定 (Two-way Binding)

  • v-model: 在表单输入框或组件上创建双向数据绑定。它会根据控件类型自动选取正确的方法来更新元素:<input type="text"><textarea> 元素使用 value 属性和 input 事件;<input type="checkbox"><input type="radio"> 使用 checked 属性和 change 事件;<select> 使用 value 属性和 change 事件。
    “`html

    输入的内容是: {{ inputText }}


    选中的值是: {{ selected }}


    ``v-model实际上是:value@input的语法糖。例如,在文本输入框上,v-model=”inputText”等价于:value=”inputText” @input=”inputText = $event.target.value”`。

    修饰符: v-model 还有一些有用的修饰符:
    * .lazy: 将输入事件改为 change 事件,从而实现失去焦点或回车时才更新数据。
    * .number: 将用户的输入值自动转为数字类型。
    * .trim: 自动过滤用户输入的首尾空白字符。

    html
    <input v-model.lazy="message">
    <input v-model.number="age" type="number">
    <input v-model.trim="text">

6. 事件处理 (Event Handling)

使用 v-on 指令(或其缩写 @)可以监听 DOM 事件,并在触发时运行 JavaScript 代码。

“`html

计数器: {{ counter }}

“`

6.1 方法事件处理器

在上面的例子中,我们看到了两种处理事件的方式:
1. 直接在 @click 中写 JavaScript 表达式 (counter++)。这适用于简单的表达式。
2. 绑定到一个方法名 (greetwarn)。这是更常见的用法,尤其是当逻辑复杂时,将逻辑放在 methods 选项中定义的方法里更清晰。

在方法事件处理器中,你可以通过 $event 访问原生的 DOM 事件对象。

6.2 事件修饰符 (Event Modifiers)

Vue 提供了事件修饰符来处理一些常见的事件细节,而无需在方法中手动处理。修饰符通过在指令后加 .modiferName 的方式使用:

  • .stop: 阻止事件继续传播 (调用 event.stopPropagation())。
  • .prevent: 阻止元素的默认行为 (调用 event.preventDefault())。
  • .capture: 使用捕获模式添加事件监听器。
  • .self: 只当事件是从侦听器绑定的元素本身触发时才触发回调。
  • .once: 只触发一次回调。
  • .passive: 提高移动端滚动的性能。

“`html


“`

7. 计算属性 (Computed Properties)

在模板中直接使用复杂的表达式会使模板变得臃肿难以维护。例如:

html
{{ message.split('').reverse().join('') }}

如果这个表达式在多个地方使用,或者逻辑更复杂,维护起来就会很麻烦。计算属性正是为了解决这个问题而生。

计算属性是基于它们的响应式依赖进行缓存的。只有当其依赖发生改变时才会重新求值。

“`html

原始字符串: {{ rawString }}

反转字符串 (使用方法): {{ reverseStringMethod() }}

反转字符串 (使用计算属性): {{ reverseStringComputed }}

“`

在上面的例子中,reverseStringComputed 是一个计算属性。它的值依赖于 rawString。当你修改 rawString 时,reverseStringComputed 会重新计算并更新视图。而 reverseStringMethod 是一个普通方法。虽然它们实现了同样的功能,但使用方式和行为有所不同:

  • 使用方式: 计算属性像数据属性一样使用 ({{ reverseStringComputed }}),而方法需要调用 ({{ reverseStringMethod() }})。
  • 缓存: 计算属性会缓存其结果。只要其依赖(rawString)没有改变,即使多次访问 reverseStringComputed,它也不会重新执行 getter 函数。而方法每次被调用时都会重新执行。在上面的例子中,如果你多次访问 reverseStringMethod(),你会看到多次“方法执行”日志,而只有当 rawString 改变时,你才会看到“计算属性求值”的日志(第一次渲染时也会执行)。
  • 适用场景: 计算属性适用于那些依赖于其他数据并需要缓存结果的场景。方法适用于那些需要响应事件或执行副作用(如修改数据、发出请求等)的场景。

计算属性默认只有 getter,但你也可以提供 setter:

javascript
computed: {
fullName: {
// getter
get: function () {
return this.firstName + ' ' + this.lastName;
},
// setter
set: function (newValue) {
var names = newValue.split(' ');
this.firstName = names[0];
this.lastName = names[names.length - 1];
}
}
}

现在当你运行 vmComputed.fullName = '李 四' 时,setter 会被调用,vmComputed.firstNamevmComputed.lastName 会相应更新。

8. 侦听器 (Watchers)

虽然计算属性在大多数需要响应数据变化的场景下是首选,但有时你需要执行一些“副作用”,例如异步操作或开销较大的操作,以响应数据的变化。这时,侦听器 (Watchers) 就派上用场了。

你可以使用 watch 选项来侦听 Vue 实例上的数据变化,并在数据变化时执行自定义的逻辑。

“`html

{{ answer }}


“`

在上面的例子中,我们侦听 question 数据属性的变化。当 question 改变时,watch handler 函数会被调用,从而更新 answer 的状态并模拟一个异步请求。

computed vs watch:

  • Computed: 适用于一个或多个数据属性的组合计算,并且需要缓存结果。它是同步的,用于生成新的数据属性。
  • Watch: 适用于在数据变化时执行副作用,如异步操作、昂贵的计算、DOM 操作等。它是异步或同步的,主要用于观察数据的变化并执行其他任务。

简单来说,如果你需要根据现有数据生成一个新数据并显示或使用,用 Computed;如果你需要在数据变化时执行某个操作(比如网络请求、日志记录等),用 Watch。

9. 组件系统 (The Component System)

组件是 Vue.js 最强大的功能之一。组件可以扩展 HTML 元素,封装可重用的代码。在大型应用中,组件系统是必不可少的。

组件是拥有预定义选项的 Vue 实例。一个应用可以被组织成一个嵌套的组件树:

根实例 (Root)
├── Header
├── Sidebar
└── Main
├── PostList
│ ├── PostItem
│ └── PostItem
└── Paginator

9.1 定义和注册组件

你可以使用 Vue.component() 方法全局注册一个组件:

javascript
// 定义一个名为 button-counter 的新组件
Vue.component('button-counter', {
data: function () {
return {
count: 0
}
},
template: '<button @click="count++">你点击了我 {{ count }} 次</button>'
})

这里的 data 必须是一个函数,这样每个组件实例都会有自己独立的数据副本,而不是共享同一个数据对象。template 定义了组件的 HTML 结构。

全局注册的组件可以在任何 Vue 实例或组件的模板中使用:

“`html



“`

每个 <button-counter> 都是一个独立的组件实例,拥有自己的 count 数据。点击一个按钮不会影响其他按钮的计数。

除了全局注册,你也可以局部注册组件(通常在组件内部的 components 选项中注册)。这使得组件只在你需要的地方可用,避免了全局命名冲突,并且通常是更推荐的做法,尤其是在使用构建工具和单文件组件时。

9.2 通过 Props 向子组件传递数据

组件通常需要父子组件之间的数据传递。父组件可以使用 props 向子组件传递数据。子组件需要在 props 选项中声明它接受的 props:

javascript
Vue.component('blog-post', {
props: ['title'], // 声明接受一个名为 title 的 prop
template: '<h3>{{ title }}</h3>'
})

然后,在父组件的模板中,通过 v-bind 将数据传递给子组件:

“`html


“`

Props 是单向数据流:父组件的属性变化会传递到子组件,但子组件不能直接修改父组件传递下来的 prop 值。如果子组件需要修改数据,应该通过事件通知父组件。

9.3 通过事件向父组件通信

子组件可以通过触发事件来与父组件进行通信。子组件可以使用 $emit 方法触发一个自定义事件:

javascript
Vue.component('custom-button', {
template: '<button @click="handleClick">点击我</button>',
methods: {
handleClick: function() {
// 触发一个名为 'button-clicked' 的自定义事件
this.$emit('button-clicked');
}
}
});

父组件则可以使用 v-on (或 @)监听这个自定义事件:

“`html

总点击次数: {{ totalClicks }}



“`

在上面的例子中,每当一个 custom-button 被点击时,它会触发 button-clicked 事件。父组件监听这个事件,并调用 incrementTotal 方法来更新 totalClicks 数据。

Prop down, event up (单向数据流和事件通信) 是 Vue 组件通信的基本原则。

10. 生命周期钩子 (Lifecycle Hooks)

每个 Vue 实例在创建时都经历一系列初始化步骤。例如,它需要设置数据侦听、编译模板、将实例挂载到 DOM 并在数据变化时更新 DOM。同时,它也会运行一些叫做生命周期钩子的函数,让开发者有机会在特定阶段运行自己的代码。

最常用的生命周期钩子包括:

  • beforeCreate: 实例刚在内存中被创建出来,此时,还没有初始化 data 和 event。
  • created: 实例已经创建完成,datamethods 已经初始化,但 DOM 还没有生成。可以在这里进行数据初始化、异步请求等。
  • beforeMount: 在挂载之前调用:相关的 render 函数首次被调用。模板已经编译好,但尚未挂载到页面上。
  • mounted: 实例已经挂载到 DOM 上,此时可以通过 this.$el 访问到真实的 DOM 元素。可以在这里进行 DOM 操作、集成第三方库等。
  • beforeUpdate: 数据更新时调用,发生在虚拟 DOM 重新渲染和打补丁之前。可以在这里访问更新前的 DOM。
  • updated: 虚拟 DOM 重新渲染和打补丁之后调用。组件的 DOM 已经更新。可以在这里进行 DOM 操作,但要注意避免死循环。
  • beforeDestroy: 实例销毁之前调用。此时实例仍然完全可用。可以在这里进行清理工作,如清除定时器、解绑事件监听器等。
  • destroyed: 实例销毁之后调用。Vue 实例的所有东西都会解除绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。

这是一个简单的示例,展示了 createdmounted 钩子:

“`html

{{ message }}

“`

理解生命周期钩子对于在正确的时间执行逻辑(例如数据加载、DOM 操作、清理资源)至关重要。

11. 响应式原理概述 (Reactivity Overview)

Vue 最引人注目的特性之一是其非侵入性的响应式系统。当 Vue 实例被创建时,它会遍历 data 对象的所有属性,并使用 Object.defineProperty(在 Vue 2 中)将它们转换为 getter/setter。

当这些属性被访问时,getter 会被调用,Vue 会“记住”哪个组件或指令正在使用这个数据。这被称为“依赖收集”。当属性被设置时,setter 会被调用,Vue 会通知所有“记住”的依赖,触发视图的更新。

“`javascript
var obj = {};
var value = ‘hello’;

Object.defineProperty(obj, ‘message’, {
get: function() {
console.log(‘getter 调用’);
return value;
},
set: function(newValue) {
console.log(‘setter 调用:’, newValue);
value = newValue;
// 在 Vue 内部,这里会通知依赖进行更新
}
});

console.log(obj.message); // 输出 “getter 调用” 和 “hello”
obj.message = ‘world’; // 输出 “setter 调用: world”
console.log(obj.message); // 输出 “getter 调用” 和 “world”
“`

这就是 Vue 响应式系统的基本工作原理。它使得你只需要修改数据,Vue 会自动处理视图的更新。

注意: 由于 Object.defineProperty 的限制,Vue 2 在侦测数组和对象的变更时有一些注意事项,例如直接通过索引修改数组项 (arr[index] = newValue) 或直接给对象添加新属性 (obj.newProp = value) 可能不是响应式的。Vue 提供了一些变通方法,如 Vue.set(object, propertyName, value)Vue.delete(object, propertyName) 或使用数组变异方法(push, pop, shift, unshift, splice, sort, reverse)。理解这一点在开发中非常重要。

12. 总结与下一步

恭喜你!你已经了解了 Vue.js 2 的大部分核心概念:

  • 如何创建 Vue 实例并管理数据 (el, data)。
  • 如何使用模板语法绑定数据和表达式 ({{ }}, v-bind)。
  • 如何使用常用指令控制 DOM (v-if, v-for, v-on, v-model)。
  • 如何使用计算属性处理复杂逻辑和缓存 (computed)。
  • 如何使用侦听器响应数据变化并执行副作用 (watch)。
  • 如何使用组件构建可复用的 UI 模块 (Vue.component, props, $emit)。
  • 如何利用生命周期钩子在特定阶段执行代码 (created, mounted, etc.)。
  • 对 Vue 的响应式原理有了初步了解。

这只是 Vue.js 丰富世界的冰山一角。在掌握了这些基础之后,你可以继续深入学习:

  • 单文件组件 (Single-File Components – SFCs): 使用 .vue 文件将模板、脚本和样式封装在一起,这是 Vue 开发中最常见的组织方式。
  • Vue CLI: 官方提供的命令行工具,用于快速搭建现代化的 Vue 项目。
  • Vue Router: 官方路由管理器,用于构建单页应用。
  • Vuex: 官方状态管理模式,用于管理大型应用中的共享状态。
  • Mixins, Custom Directives, Plugins, Render Functions… 更多高级特性。

Vue.js 凭借其易学易用的特性和强大的功能,是现代前端开发中一个优秀的框架选择。希望本文能为你打开 Vue 世界的大门,并激发你进一步探索和学习的兴趣!祝你 Vue 之旅愉快!


发表评论

您的邮箱地址不会被公开。 必填项已用 * 标注

滚动至顶部