简介:Vue.js是一款轻量级前端JavaScript框架,专注于视图层,易于上手且功能强大,适合构建用户界面。本课程为“Vue.js全套视频教程”的第一讲“课程简介”,专为初学者设计,帮助掌握Vue的核心概念与基础语法。内容涵盖Vue.js介绍、安装配置、基本语法、指令使用、组件开发、生命周期钩子、响应式原理、模板语法、Vuex状态管理及实战小项目等。通过本课程学习,学员可打下扎实的Vue基础,为后续学习Vue路由、动画、服务端渲染等内容做好准备。
1. Vue.js介绍与核心特性
Vue.js 是一款用于构建用户界面的渐进式 JavaScript 框架,由尤雨溪于2014年发布。它以轻量、高效、易上手著称,适用于从简单页面增强到复杂单页应用(SPA)的开发。其核心库专注于视图层,易于与其他库或项目集成。
1.1 Vue.js的基本概念
Vue.js 采用声明式编程模型,开发者无需手动操作 DOM,只需关注数据状态的变化,视图会自动更新。其核心思想是“数据驱动视图”,通过 Vue 构造函数创建实例,绑定数据对象与模板,实现响应式更新。例如:
new Vue({
el: '#app',
data: {
message: 'Hello Vue!'
}
})
上述代码中, el
指定挂载点, data
定义响应式数据,当 message
变化时,视图自动更新。
1.2 Vue.js在现代前端开发中的地位
随着前端工程化的发展,Vue.js 凭借其简洁的 API 和渐进式架构,成为主流框架之一。它在中小型项目中尤为受欢迎,也支持通过 Vue Router、Vuex、Vue CLI 等生态工具构建大型应用。相比 React 和 Angular:
- React :更偏向于“视图层”库,灵活性高但需搭配其他工具(如 Redux、React Router)。
- Angular :功能全面但学习曲线陡峭,适合企业级应用。
- Vue :兼具灵活性与易用性,适合快速开发和团队协作。
1.3 Vue.js的核心特性
1.3.1 响应式数据绑定
Vue 的核心机制是响应式数据绑定,通过 Object.defineProperty(Vue 2)或 Proxy(Vue 3)实现数据监听,当数据变化时,视图自动更新。
1.3.2 组件化架构
组件是 Vue 应用的基本构建单元,支持复用、嵌套与通信。通过组件化开发,可以实现模块化、可维护的前端架构。
1.3.3 指令系统
Vue 提供一系列内置指令(如 v-if、v-for、v-on、v-model),用于操作 DOM 的行为与属性。同时也支持自定义指令,扩展模板语法。
1.3.4 模板语法
Vue 使用基于 HTML 的模板语法,允许开发者将 DOM 与 Vue 实例中的数据进行绑定。例如:
<div id="app">{{ message }}</div>
模板中的 {{ message }}
是文本插值,会自动渲染为 data
中的值。
1.4 Vue.js与其他框架对比
特性 | Vue.js | React | Angular |
---|---|---|---|
学习曲线 | 平缓 | 中等 | 陡峭 |
数据绑定 | 双向绑定(v-model) | 单向绑定 | 双向绑定 |
渐进式架构 | ✅ | ✅ | ❌ |
模板语法 | 类HTML | JSX | 类HTML |
社区活跃度 | 高 | 高 | 中 |
生态工具 | Vue Router、Vuex | React Router、Redux | Angular CLI、Material |
通过对比可以看出,Vue.js 在易用性、灵活性与生态支持方面具备显著优势,特别适合中型项目和快速开发场景。
2. Vue.js安装与环境配置
在开始使用 Vue.js 构建前端应用之前,必须正确安装并配置开发环境。这一章节将详细介绍如何引入 Vue.js、搭建本地开发环境以及运行和调试项目。通过本章内容,开发者将掌握从零开始搭建 Vue.js 项目的完整流程,并具备开发 Vue 应用所需的基本工具链。
2.1 Vue.js的引入方式
在开发 Vue 应用时,引入 Vue.js 的方式决定了项目的结构和开发方式。常见的引入方式包括 CDN 引入和通过 NPM 安装模块化引入。开发者应根据项目需求选择合适的方式。
2.1.1 CDN引入
CDN(Content Delivery Network)引入方式适合快速上手或构建小型项目,无需安装构建工具即可直接在 HTML 文件中引入 Vue.js。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vue CDN 引入示例</title>
<script src="https://cdn.jsdelivr.net/npm/vue@3"></script>
</head>
<body>
<div id="app">
{{ message }}
</div>
<script>
const { createApp } = Vue;
createApp({
data() {
return {
message: 'Hello Vue via CDN!'
};
}
}).mount('#app');
</script>
</body>
</html>
代码解析
- 第 8 行:使用
<script>
标签引入 Vue.js 的 CDN 地址。 - 第 14 行:定义
message
数据属性,初始值为字符串'Hello Vue via CDN!'
。 - 第 15 行:通过
createApp
创建 Vue 应用实例,并使用mount
方法将应用挂载到#app
元素上。 - 优点:无需本地构建工具,快速启动项目。
- 缺点:不适用于大型项目或需要模块化开发的场景。
适用场景
适用于教学演示、原型设计、静态页面增强等小型项目。
2.1.2 NPM安装与模块化引入
对于需要模块化开发、使用构建工具(如 Webpack 或 Vite)的中大型项目,推荐使用 NPM 安装 Vue.js,并通过模块化方式引入。
安装步骤
- 确保已安装 Node.js 和 npm(可通过
node -v
和npm -v
验证)。 - 创建项目目录并进入:
bash mkdir my-vue-project cd my-vue-project
- 初始化 npm 项目:
bash npm init -y
- 安装 Vue.js:
bash npm install vue@next
示例代码
// main.js
import { createApp } from 'vue';
import App from './App.vue';
const app = createApp(App);
app.mount('#app');
<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vue NPM 引入示例</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="./main.js"></script>
</body>
</html>
<!-- App.vue -->
<template>
<div>
{{ message }}
</div>
</template>
<script>
export default {
data() {
return {
message: 'Hello Vue via NPM!'
};
}
};
</script>
代码解析
- 第 1 行:使用
import
引入 Vue 的createApp
方法。 - 第 2 行:引入
App.vue
组件。 - 第 4 行:创建 Vue 应用实例。
- 第 5 行:将组件挂载到
#app
元素。 - 第 14 行:定义模板并绑定
message
数据属性。
优势
- 支持模块化开发,便于组件复用。
- 可集成构建工具(如 Webpack、Vite)进行打包、压缩、热更新等。
- 更适合大型项目或团队协作开发。
2.2 开发环境搭建
为了高效开发 Vue 应用,需要搭建一个支持热更新、调试、代码压缩等特性的开发环境。
2.2.1 Node.js与npm的安装配置
Node.js 是构建现代前端项目的基础,npm 是其默认的包管理器。
安装步骤
- 前往 Node.js 官网 下载并安装 LTS 版本。
- 安装完成后,验证安装是否成功:
bash node -v npm -v
配置 npm 镜像(可选)
国内用户可使用淘宝镜像加速安装:
npm install -g cnpm --registry=https://registry.npmmirror.com
2.2.2 使用Vue CLI创建项目
Vue CLI 是官方提供的命令行工具,可快速生成 Vue 项目脚手架。
安装 Vue CLI
npm install -g @vue/cli
创建项目
vue create my-vue-app
选择配置项后,CLI 会自动创建项目结构。
项目目录结构
my-vue-app/
├── node_modules/
├── public/
├── src/
│ ├── assets/
│ ├── components/
│ ├── App.vue
│ └── main.js
├── package.json
└── README.md
目录说明
目录/文件 | 作用说明 |
---|---|
node_modules | 存放项目依赖包 |
public | 存放静态资源,如图片、robots.txt 等 |
src | 源码目录,包含 Vue 组件和入口文件 |
App.vue | 根组件 |
main.js | 入口 JavaScript 文件 |
package.json | 包管理配置文件 |
2.2.3 项目结构解析与开发工具配置(如VS Code)
使用 VS Code 可以提高开发效率,推荐安装以下插件:
- Vetur :提供 Vue 单文件组件语法高亮、智能补全、格式化等功能。
- ESLint :用于代码规范检查。
- Prettier :自动格式化代码。
VS Code 配置步骤
- 安装 VS Code:https://code.visualstudio.com/
- 安装插件:
- 打开 VS Code,点击左侧扩展图标,搜索并安装 Vetur、ESLint、Prettier。 - 配置保存时自动格式化:
- 打开File > Preferences > Settings
。
- 搜索format on save
,勾选Editor: Format On Save
。
示例:配置 ESLint 与 Prettier 联合使用
- 安装依赖:
bash npm install eslint prettier eslint-config-prettier eslint-plugin-vue eslint-plugin-vuejs-accessibility --save-dev
- 创建
.eslintrc.js
文件:
js module.exports = { root: true, env: { browser: true, es2021: true }, extends: [ 'eslint:recommended', 'plugin:vue/vue3-recommended', 'plugin:@typescript-eslint/recommended', 'prettier' ], parserOptions: { ecmaVersion: 'latest', sourceType: 'module' }, plugins: ['vue', '@typescript-eslint'], rules: { // 自定义规则 } };
2.3 运行与调试Vue项目
2.3.1 启动本地开发服务器
Vue CLI 创建的项目默认支持热更新开发服务器。
启动命令
cd my-vue-app
npm run serve
执行后,终端会输出本地开发服务器地址,例如:
App running at:
- Local: http://localhost:8080/
- Network: http://192.168.1.5:8080/
项目运行流程图
graph TD
A[项目目录] --> B[运行 npm run serve]
B --> C[Webpack Dev Server 启动]
C --> D[编译 Vue 文件]
D --> E[生成内存中的打包文件]
E --> F[浏览器访问本地服务器]
F --> G[实时更新页面]
2.3.2 基本调试技巧与Chrome开发者工具使用
Chrome 开发者工具(DevTools)是调试 Vue 项目的核心工具。
常用调试功能
- Elements 面板 :查看和修改 DOM 结构。
- Console 面板 :查看 JavaScript 错误、打印日志。
- Sources 面板 :设置断点、单步调试代码。
- Network 面板 :监控网络请求、查看资源加载情况。
- Vue Devtools 插件 :专门用于调试 Vue 应用的状态、组件结构等。
使用 Vue Devtools 调试
- 安装 Vue Devtools 浏览器插件。
- 打开项目页面,点击 Devtools 插件图标。
- 在 Vue 面板中查看组件树、响应式数据、事件等信息。
示例:调试组件数据
在 App.vue
中添加调试代码:
<template>
<div>
<p>{{ message }}</p>
<button @click="changeMessage">Change Message</button>
</div>
</template>
<script>
export default {
data() {
return {
message: 'Initial Message'
};
},
methods: {
changeMessage() {
console.log('Button clicked');
this.message = 'Message Changed!';
}
}
};
</script>
在浏览器中点击按钮后,可以在 Console 面板中看到 'Button clicked'
输出,验证事件是否被正确触发。
本章从 Vue.js 的引入方式讲起,逐步引导读者完成开发环境的搭建与项目运行调试。通过 CDN 和 NPM 的对比,帮助开发者根据项目需求选择合适的引入方式;通过 Vue CLI 的使用和 VS Code 的配置,构建起完整的开发环境;最后介绍了如何使用 Chrome DevTools 和 Vue Devtools 进行调试,为后续章节的组件开发与数据绑定打下坚实基础。
3. Vue实例与数据绑定
在 Vue.js 中, Vue 实例 是整个应用的基石。每个 Vue 应用都从一个 Vue 实例开始,它负责将数据绑定到 DOM,并处理用户交互与视图更新之间的关系。理解 Vue 实例的创建方式及其配置项是掌握 Vue.js 的关键一步。本章将深入讲解 Vue 实例的构成、核心配置项(如 el
、 data
、 methods
和生命周期钩子),并结合数据绑定机制,帮助开发者构建响应式、可交互的前端应用。
3.1 Vue实例的创建与配置
Vue 实例是 Vue.js 应用的核心对象。通过 new Vue()
创建的实例会接管一个 DOM 元素,并与数据模型建立绑定关系。理解实例的创建过程和配置选项是掌握 Vue 开发的第一步。
3.1.1 el与data选项的作用
在创建 Vue 实例时,最常用的两个配置项是 el
和 data
。
-
el
:指定 Vue 实例挂载的目标 DOM 元素。该元素及其子元素将被 Vue 实例接管,成为数据绑定和指令作用的范围。 -
data
:用于存储 Vue 实例的数据模型。这些数据是响应式的,一旦发生变化,视图会自动更新。
new Vue({
el: '#app',
data: {
message: 'Hello Vue.js!'
}
});
对应的 HTML:
<div id="app">
<p>{{ message }}</p>
</div>
逻辑分析:
-
el: '#app'
:表示 Vue 实例将挂载在 id 为app
的 DOM 元素上。 -
data
对象中的message
属性被绑定到视图中,使用双大括号语法{{ message }}
进行插值。 - 当
message
的值发生变化时,页面中对应的<p>
元素内容会自动更新。
参数说明:
配置项 | 说明 |
---|---|
el | DOM 元素的选择器,通常是 #id 或 tagName |
data | 一个对象,包含 Vue 实例中可响应的数据属性 |
3.1.2 methods与生命周期钩子的初步使用
除了 el
和 data
, methods
和生命周期钩子函数也是 Vue 实例的重要配置项。
-
methods
:定义 Vue 实例的方法,这些方法可以在模板中通过事件绑定调用。 - 生命周期钩子(Lifecycle Hooks) :Vue 实例在创建、更新和销毁过程中会触发一系列钩子函数,开发者可以在此执行初始化、清理等操作。
示例代码:
new Vue({
el: '#app',
data: {
count: 0
},
methods: {
increment() {
this.count++;
}
},
created() {
console.log('Vue instance created');
},
mounted() {
console.log('Vue instance mounted to DOM');
}
});
对应的 HTML:
<div id="app">
<p>点击次数:{{ count }}</p>
<button @click="increment">点击增加</button>
</div>
逻辑分析:
-
methods
中定义了increment
方法,当按钮被点击时,count
的值会增加。 -
created
和mounted
是 Vue 实例的两个生命周期钩子:
-created
:实例创建完成后调用,此时数据已初始化,但尚未挂载 DOM。
-mounted
:实例挂载完成后调用,此时 DOM 已渲染完毕。
生命周期钩子列表:
钩子函数 | 触发时机 |
---|---|
beforeCreate | 实例初始化之前 |
created | 实例创建完成后 |
beforeMount | 挂载前 |
mounted | 挂载完成后 |
beforeUpdate | 数据更新前 |
updated | 数据更新完成后 |
beforeUnmount | 实例销毁前 |
unmounted | 实例销毁后 |
3.2 数据绑定机制
Vue 的一大核心特性是 响应式数据绑定 。数据模型的变化会自动更新视图,反之亦然。Vue 使用 Object.defineProperty 或 Proxy (Vue 3)实现数据的响应式更新。
3.2.1 单向绑定与双向绑定原理
Vue 支持两种数据绑定方式:
- 单向绑定 :数据模型 → 视图,即数据变化自动更新视图。
- 双向绑定 :数据模型 ↔ 视图,即数据变化更新视图,视图变化也更新数据。
单向绑定示例:
<div id="app">
<p>{{ message }}</p>
</div>
new Vue({
el: '#app',
data: {
message: 'Hello Vue'
}
});
此时,修改 message
的值,页面内容会自动更新。
双向绑定示例(使用 v-model
):
<div id="app">
<input v-model="message">
<p>输入内容:{{ message }}</p>
</div>
new Vue({
el: '#app',
data: {
message: ''
}
});
逻辑分析:
-
v-model
是 Vue 提供的语法糖,用于实现双向绑定。 - 其本质是同时使用
:value
(绑定数据到输入框)和@input
(监听输入事件更新数据)。 - 当用户在输入框中输入内容时,
message
的值会自动更新,并同步到<p>
标签中。
3.2.2 数据响应式更新机制详解
Vue 通过 数据劫持 + 发布订阅模式 实现数据的响应式更新。
数据劫持流程图(使用 mermaid):
graph TD
A[Vue实例创建] --> B[数据对象劫持]
B --> C{是否为对象或数组}
C -->|是| D[递归劫持]
C -->|否| E[使用Object.defineProperty或Proxy]
E --> F[设置getter/setter]
F --> G[数据变化通知Dep]
G --> H[通知Watcher]
H --> I[更新视图]
响应式原理简要说明:
- 数据劫持 :Vue 在初始化时会对
data
中的每个属性进行处理,使用Object.defineProperty
(Vue 2)或Proxy
(Vue 3)将其转换为响应式属性。 - 依赖收集 :当模板中使用到某个数据时,Vue 会记录该数据的依赖关系(即哪个视图依赖于该数据)。
- 派发更新 :当数据发生变化时,Vue 会通知所有依赖该数据的视图进行更新。
3.3 实践:实现一个简单的数据绑定示例
为了加深对 Vue 实例和数据绑定的理解,我们来实现一个简单的示例: 用户输入内容并实时显示在页面上 。
3.3.1 数据驱动视图更新
在这个示例中,我们将使用 Vue 的响应式数据绑定机制,实现一个输入框与显示区域的同步更新。
<div id="app">
<input v-model="inputText">
<p>你输入的内容是:{{ inputText }}</p>
</div>
new Vue({
el: '#app',
data: {
inputText: ''
}
});
逻辑分析:
- 使用
v-model
绑定inputText
到<input>
输入框。 - 页面中的
<p>
标签显示inputText
的值。 - 当用户在输入框中输入内容时,
inputText
的值会被更新,触发视图重新渲染。
3.3.2 绑定用户输入与视图同步
我们可以进一步扩展功能,比如在用户输入时对内容进行过滤或转换。
<div id="app">
<input v-model="rawInput">
<p>处理后的内容:{{ processedInput }}</p>
</div>
new Vue({
el: '#app',
data: {
rawInput: ''
},
computed: {
processedInput() {
return this.rawInput.toUpperCase();
}
}
});
逻辑分析:
- 使用
v-model
绑定原始输入值rawInput
。 - 定义了一个计算属性
processedInput
,将输入内容转换为大写。 - 当用户输入内容变化时,
processedInput
会自动更新,并反映在视图中。
计算属性 vs 方法:
对比项 | 方法 | 计算属性 |
---|---|---|
是否缓存结果 | 否 | 是 |
调用方式 | 方法调用(需加括号) | 属性访问(无需括号) |
性能 | 每次渲染都执行 | 依赖数据未变时不重复执行 |
总结
本章围绕 Vue 实例展开,详细讲解了 el
、 data
、 methods
、生命周期钩子等关键配置项的使用方式,并深入剖析了 Vue 的数据绑定机制(包括单向绑定与双向绑定)。最后通过一个实际案例演示了如何利用 Vue 的响应式系统实现数据与视图的同步更新。这些内容为后续章节中组件通信、指令系统、计算属性等高级特性的学习打下了坚实基础。
4. 指令系统(v-if、v-for、v-on、v-model等)
Vue.js 的指令系统是其核心特性之一,它提供了一种简洁而强大的方式来操作 DOM 元素。通过指令,开发者可以将数据绑定到视图中,实现条件渲染、循环渲染、事件监听、表单双向绑定等常见功能。在本章中,我们将系统性地学习 Vue 指令的分类、使用方法,以及在实际项目中的应用场景。
4.1 指令的基本概念与作用
4.1.1 什么是自定义指令
在 Vue 中,指令是一种带有 v-
前缀的特殊属性,它被用于直接操作 DOM 或响应数据变化。Vue 提供了丰富的内置指令,如 v-if
、 v-for
、 v-on
、 v-model
等。除此之外,Vue 也允许开发者自定义指令,以满足特定需求。
自定义指令通常用于以下场景:
- 直接访问 DOM 元素(如聚焦、滚动、动画)
- 实现全局的 UI 行为(如权限控制、水印)
- 与第三方库集成(如 jQuery 插件)
示例:创建一个自定义指令用于自动聚焦输入框
<input type="text" v-focus>
// main.js
const app = createApp(App)
app.directive('focus', {
mounted(el) {
el.focus()
}
})
app.mount('#app')
代码逻辑分析:
-
v-focus
是我们自定义的指令名。 -
app.directive('focus', { ... })
注册了该指令。 -
mounted(el)
是指令的生命周期钩子之一,el
是绑定的 DOM 元素。 - 在页面加载后,输入框会自动获得焦点。
参数说明:
钩子函数 | 说明 |
---|---|
beforeMount | 在绑定元素的父组件挂载之前调用 |
mounted | 在绑定元素的父组件挂载之后调用 |
beforeUpdate | 在包含组件的 VNode 更新之前调用 |
updated | 在包含组件的 VNode 及其子组件的 VNode 更新之后调用 |
beforeUnmount | 在指令与元素解绑之前调用(仅在 Vue 3 中) |
unmounted | 在指令与元素解绑之后调用 |
4.1.2 内置指令分类与使用场景
Vue 的内置指令可以分为以下几类:
类型 | 指令示例 | 功能说明 |
---|---|---|
条件渲染 | v-if , v-show | 控制元素是否显示 |
列表渲染 | v-for | 遍历数组或对象生成 DOM 元素 |
事件绑定 | v-on | 监听 DOM 事件 |
表单绑定 | v-model | 实现双向数据绑定 |
属性绑定 | v-bind 或 : | 动态绑定 HTML 属性 |
文本渲染 | v-text , v-html | 渲染文本内容或 HTML 片段 |
示例:使用 v-html
动态插入 HTML 内容
<div v-html="rawHtml"></div>
const app = createApp({
data() {
return {
rawHtml: '<strong>这是一段富文本内容</strong>'
}
}
})
逻辑分析:
-
v-html
会将字符串解析为 HTML 并插入到 DOM 中。 - 不推荐用于用户输入内容,避免 XSS 攻击。
4.2 常用指令详解
4.2.1 条件渲染:v-if、v-show
Vue 提供了两种条件渲染的方式: v-if
和 v-show
。
使用示例:
<h2 v-if="isVisible">我是条件显示的内容(v-if)</h2>
<h2 v-show="isVisible">我是条件显示的内容(v-show)</h2>
<button @click="toggle">切换显示</button>
const app = createApp({
data() {
return {
isVisible: true
}
},
methods: {
toggle() {
this.isVisible = !this.isVisible
}
}
})
对比分析:
特性 | v-if | v-show |
---|---|---|
渲染方式 | 条件为假时不渲染,不生成 DOM 节点 | 始终渲染,通过 CSS 控制显示 |
性能 | 切换频繁时性能较差 | 切换频繁时性能较好 |
适用场景 | 条件不常变化的场景 | 频繁切换显示的场景 |
流程图对比:
graph TD
A[v-if 条件判断] --> B{条件为真?}
B -->|是| C[渲染 DOM]
B -->|否| D[不渲染 DOM]
E[v-show 条件判断] --> F{条件为真?}
F -->|是| G[设置 display: block]
F -->|否| H[设置 display: none]
4.2.2 列表渲染:v-for
v-for
是 Vue 中最常用的循环指令,它允许我们基于数组或对象的迭代来渲染列表。
示例:使用 v-for
渲染任务列表
<ul>
<li v-for="task in tasks" :key="task.id">
{{ task.name }}
</li>
</ul>
const app = createApp({
data() {
return {
tasks: [
{ id: 1, name: '学习 Vue' },
{ id: 2, name: '写博客' },
{ id: 3, name: '发布文章' }
]
}
}
})
参数说明:
参数名 | 说明 |
---|---|
item | 当前迭代的元素 |
index | 当前索引(可选) |
array | 当前遍历的数组(可选) |
注意事项:
- 始终使用
:key
提供一个唯一标识符,帮助 Vue 优化虚拟 DOM 的 diff 算法。 - 不要使用
index
作为key
,除非数据顺序不会变化。
4.2.3 事件绑定:v-on
v-on
指令用于监听 DOM 事件,并在触发时执行相应的 JavaScript 行为。
示例:点击按钮触发事件
<button v-on:click="sayHello">点击我</button>
<!-- 简写 -->
<button @click="sayHello">点击我</button>
const app = createApp({
methods: {
sayHello() {
alert('Hello Vue!')
}
}
})
参数说明:
参数名 | 说明 |
---|---|
$event | 事件对象,可传入方法中进行处理 |
修饰符 | 如 .preventDefault 、 .stopPropagation 等 |
示例:阻止默认事件
<form @submit.prevent="handleSubmit">
<button type="submit">提交</button>
</form>
const app = createApp({
methods: {
handleSubmit() {
console.log('表单提交成功')
}
}
})
4.2.4 表单输入绑定:v-model
v-model
是 Vue 中实现表单输入双向绑定的核心指令。它会自动将用户输入的值同步到数据模型中。
示例:使用 v-model
绑定输入框
<input type="text" v-model="message">
<p>你输入的是:{{ message }}</p>
const app = createApp({
data() {
return {
message: ''
}
}
})
支持的表单元素:
元素类型 | 支持情况 |
---|---|
input[type=text] | ✅ |
input[type=checkbox] | ✅ |
input[type=radio] | ✅ |
select | ✅ |
textarea | ✅ |
高级用法: .lazy
、 .number
、 .trim
修饰符
<!-- 输入时不立即更新,失去焦点后更新 -->
<input v-model.lazy="message">
<!-- 自动将输入值转为数字 -->
<input v-model.number="age">
<!-- 自动去除首尾空格 -->
<input v-model.trim="username">
4.3 实战应用
4.3.1 构建动态表单验证
在实际开发中,我们常常需要对用户输入进行验证。结合 v-model
、 v-if
和 methods
,我们可以轻松实现一个动态表单验证系统。
示例:邮箱验证表单
<form @submit.prevent="submitForm">
<input type="text" v-model="email" placeholder="请输入邮箱">
<p v-if="emailError" class="error">{{ emailError }}</p>
<button type="submit">提交</button>
</form>
const app = createApp({
data() {
return {
email: '',
emailError: ''
}
},
methods: {
submitForm() {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
if (!this.email) {
this.emailError = '邮箱不能为空'
} else if (!emailRegex.test(this.email)) {
this.emailError = '邮箱格式不正确'
} else {
this.emailError = ''
alert('提交成功!')
}
}
}
})
功能说明:
- 使用
v-model
同步用户输入。 - 使用
v-if
动态显示错误信息。 - 使用正则表达式进行邮箱格式验证。
4.3.2 实现一个待办事项列表(Todo List)
示例:实现一个简单的待办事项管理功能
<div id="app">
<input v-model="newTask" @keyup.enter="addTask" placeholder="输入任务">
<button @click="addTask">添加</button>
<ul>
<li v-for="task in tasks" :key="task.id">
<input type="checkbox" v-model="task.completed">
<span :class="{ completed: task.completed }">{{ task.text }}</span>
<button @click="removeTask(task)">删除</button>
</li>
</ul>
</div>
const app = createApp({
data() {
return {
newTask: '',
tasks: []
}
},
methods: {
addTask() {
if (this.newTask.trim()) {
this.tasks.push({
id: Date.now(),
text: this.newTask,
completed: false
})
this.newTask = ''
}
},
removeTask(task) {
this.tasks = this.tasks.filter(t => t.id !== task.id)
}
}
})
样式建议(可选):
.completed {
text-decoration: line-through;
color: gray;
}
功能说明:
- 使用
v-model
绑定输入框。 - 使用
v-for
动态生成任务列表。 - 使用
v-model
控制任务完成状态。 - 实现任务添加与删除功能。
通过本章的学习,我们掌握了 Vue 指令的基本概念、常用指令的使用方式以及在实际开发中的典型应用场景。这些指令是构建交互式用户界面的基础,熟练掌握它们将大大提升 Vue 应用的开发效率和质量。在后续章节中,我们将进一步深入 Vue 的计算属性、侦听器以及组件化开发等内容,进一步提升开发能力。
5. 计算属性与侦听器
计算属性和侦听器是 Vue.js 中实现数据响应式和逻辑处理的两个核心机制。它们分别适用于不同场景下的数据处理需求: 计算属性 用于处理基于已有数据派生出的新数据,具有缓存机制,适用于高频读取但低频更新的数据; 侦听器 则更适合处理异步操作或需要执行复杂逻辑的场景,例如监听某个数据变化后进行 API 请求、深度监听对象变化等。
本章将从基本用法出发,深入剖析它们的内部机制,并结合实战案例展示其在实际项目中的应用。
5.1 计算属性的基本用法
5.1.1 与methods的区别
在 Vue 中, methods
和 computed
都可以用于封装逻辑,但它们在执行时机和性能表现上存在显著差异。
methods
的执行时机
methods
是 Vue 实例中的方法集合,它们在每次触发响应式更新时都会重新执行。即使返回的结果没有变化,只要模板中引用了该方法,它就会被调用。
<template>
<div>
<p>Full Name: {{ fullName() }}</p>
</div>
</template>
<script>
export default {
data() {
return {
firstName: 'John',
lastName: 'Doe'
}
},
methods: {
fullName() {
return `${this.firstName} ${this.lastName}`;
}
}
}
</script>
在这个例子中,每当 firstName
或 lastName
发生变化, fullName()
方法都会重新执行。
computed
的执行时机
computed
属性基于其依赖的响应式数据进行缓存。只有当依赖的数据发生变化时,它才会重新求值。
<template>
<div>
<p>Full Name: {{ fullName }}</p>
</div>
</template>
<script>
export default {
data() {
return {
firstName: 'John',
lastName: 'Doe'
}
},
computed: {
fullName() {
return `${this.firstName} ${this.lastName}`;
}
}
}
</script>
逻辑分析:
-
fullName
依赖于firstName
和lastName
。 - 当这两个属性未发生变化时,多次访问
fullName
不会重新计算,而是返回缓存值。 - 只有当其中一个依赖项发生变化时,
fullName
才会重新计算。
对比总结:
特性 | methods | computed |
---|---|---|
是否缓存 | 否 | 是 |
触发频率 | 每次模板更新都会执行 | 仅当依赖变化时才执行 |
适用场景 | 不依赖缓存、需要动态计算的逻辑 | 基于依赖数据的复杂派生逻辑 |
5.1.2 缓存机制与性能优化
Vue 的计算属性之所以高效,是因为它具备缓存机制。Vue 会追踪其依赖项,只有当依赖发生变化时才会重新计算。
缓存机制的实现原理
Vue 的响应式系统会记录 computed
属性的依赖关系。当依赖项未发生变化时,直接返回缓存结果;当依赖项变化后,重新计算并缓存新值。
性能优化示例:
假设我们有一个列表,需要根据输入框内容进行过滤:
<template>
<div>
<input v-model="searchQuery" placeholder="Search..." />
<ul>
<li v-for="item in filteredItems" :key="item.id">{{ item.name }}</li>
</ul>
</div>
</template>
<script>
export default {
data() {
return {
searchQuery: '',
items: [
{ id: 1, name: 'Apple' },
{ id: 2, name: 'Banana' },
{ id: 3, name: 'Cherry' },
{ id: 4, name: 'Date' }
]
}
},
computed: {
filteredItems() {
return this.items.filter(item => {
return item.name.toLowerCase().includes(this.searchQuery.toLowerCase());
});
}
}
}
</script>
逐行逻辑分析:
-
filteredItems
是一个计算属性,依赖于items
和searchQuery
。 - 每次
searchQuery
或items
发生变化时,filteredItems
会重新计算。 - 没有使用
methods
,避免了每次渲染都执行过滤逻辑,提升性能。
性能优化建议:
- 尽可能将基于响应式数据的复杂逻辑封装到
computed
中。 - 避免在
methods
中重复执行相同的逻辑。 - 对大型数据集进行操作时,优先使用
computed
。
5.2 侦听器(watch)的使用
5.2.1 异步操作与复杂逻辑处理
watch
主要用于观察某个数据的变化,并在其变化时执行相应的操作。与 computed
不同, watch
更适合执行异步操作或复杂逻辑,比如发送请求、修改多个状态、处理对象或数组的变化等。
示例:监听搜索输入并发送请求
<template>
<div>
<input v-model="searchTerm" placeholder="Search..." />
<p v-if="loading">Loading...</p>
<ul v-else>
<li v-for="result in results" :key="result.id">{{ result.name }}</li>
</ul>
</div>
</template>
<script>
export default {
data() {
return {
searchTerm: '',
results: [],
loading: false
}
},
watch: {
searchTerm(newVal) {
if (newVal.length < 2) return;
this.loading = true;
// 模拟异步请求
setTimeout(() => {
this.results = [
{ id: 1, name: 'Result 1 for ' + newVal },
{ id: 2, name: 'Result 2 for ' + newVal }
];
this.loading = false;
}, 500);
}
}
}
</script>
逐行逻辑分析:
- 当
searchTerm
变化时,触发watch
回调。 - 设置
loading
为true
,显示加载状态。 - 使用
setTimeout
模拟网络请求,获取搜索结果。 - 请求完成后更新
results
并关闭加载状态。
适用场景总结:
- 处理异步操作(如 API 请求)
- 当数据变化时需要执行副作用(如通知、日志、修改其他状态)
- 处理对象或数组深层变化(需启用
deep
选项)
5.2.2 deep
与 immediate
选项解析
Vue 的 watch
提供了两个高级选项: deep
和 immediate
,用于控制监听行为。
deep: true
—— 深度监听对象
默认情况下,Vue 不会监听对象内部的变化。使用 deep: true
可以开启深度监听。
watch: {
user: {
handler(newVal) {
console.log('User changed:', newVal);
},
deep: true
}
}
说明:
-
user
是一个对象。 - 设置
deep: true
后,即使对象内部某个属性发生变化,也能触发监听器。
immediate: true
—— 立即执行回调
immediate: true
会在 watch
初始化时立即执行一次回调。
watch: {
searchTerm: {
handler(newVal) {
console.log('Current value:', newVal);
},
immediate: true
}
}
说明:
- 初始化时,
searchTerm
的初始值为空字符串,也会触发一次handler
。 - 这在组件加载时需要立即执行某些逻辑时非常有用。
deep
与 immediate
组合使用示例:
watch: {
formData: {
handler(newVal) {
console.log('Form data changed:', newVal);
},
deep: true,
immediate: true
}
}
应用场景:
- 表单数据对象监听
- 初始化时需要根据表单数据做初始化操作
- 数据结构复杂,需要深度监听
5.3 实战:实现动态数据处理
5.3.1 实时搜索与过滤功能
在前端开发中,实时搜索与过滤是一个常见的需求。我们可以结合 computed
和 watch
来实现一个高性能的搜索功能。
示例:结合 computed
与 watch
实现搜索功能
<template>
<div>
<input v-model="searchText" placeholder="Search items..." />
<ul>
<li v-for="item in filteredList" :key="item.id">{{ item.name }}</li>
</ul>
</div>
</template>
<script>
export default {
data() {
return {
searchText: '',
items: [
{ id: 1, name: 'Apple' },
{ id: 2, name: 'Banana' },
{ id: 3, name: 'Cherry' },
{ id: 4, name: 'Date' }
],
filteredList: []
}
},
watch: {
searchText(newVal) {
this.filterList(newVal);
}
},
methods: {
filterList(query) {
this.filteredList = this.items.filter(item =>
item.name.toLowerCase().includes(query.toLowerCase())
);
}
}
}
</script>
逻辑分析:
- 使用
watch
监听searchText
变化。 - 在
watch
中调用filterList
方法进行过滤。 - 将结果存入
filteredList
,供模板渲染使用。
性能对比:
实现方式 | 是否缓存 | 性能表现 |
---|---|---|
全部使用 computed | 是 | 更优 |
使用 watch + methods | 否 | 更灵活但需手动控制 |
建议:
- 如果搜索逻辑简单,优先使用
computed
。 - 如果涉及异步请求或更复杂的处理逻辑,可结合
watch
使用。
5.3.2 数据变化驱动的复杂状态更新
在一些复杂场景中,我们需要监听某个数据变化来更新多个状态,甚至触发其他组件的状态变化。
示例:监听用户角色变化,更新权限状态
<template>
<div>
<select v-model="userRole">
<option value="admin">Admin</option>
<option value="editor">Editor</option>
<option value="viewer">Viewer</option>
</select>
<p v-if="canEdit">You can edit content.</p>
<p v-if="canDelete">You can delete content.</p>
</div>
</template>
<script>
export default {
data() {
return {
userRole: 'viewer',
canEdit: false,
canDelete: false
}
},
watch: {
userRole(newRole) {
this.canEdit = newRole === 'admin' || newRole === 'editor';
this.canDelete = newRole === 'admin';
}
}
}
</script>
逻辑分析:
- 使用
watch
监听userRole
的变化。 - 根据不同的角色设置
canEdit
和canDelete
权限。 - 模板中通过
v-if
控制显示对应权限的提示。
扩展讨论:
- 如果权限逻辑复杂,可以将其封装为一个权限服务模块。
- 在大型项目中,建议使用 Vuex 或 Pinia 进行全局状态管理。
- 可结合
deep
监听对象结构变化,实现更灵活的状态控制。
总结(隐含在上下文中)
本章通过从基础用法到高级特性的讲解,系统性地介绍了 Vue.js 中的 计算属性 和 侦听器 。计算属性适合处理依赖数据的派生逻辑,具有缓存机制,适用于高性能场景;侦听器则适用于监听数据变化并执行副作用,尤其适合处理异步任务和复杂逻辑。通过多个实战案例,我们展示了如何在实际开发中合理使用它们来提升代码的可维护性和性能表现。
下一章将继续深入 Vue 的组件化开发体系,探讨组件通信机制及其在项目中的实际应用。
6. 组件化开发与组件通信
组件化开发是Vue.js中最核心、最具优势的特性之一。它通过将UI拆分为独立、可复用的组件,极大地提升了代码的可维护性和开发效率。本章将深入探讨组件化开发的基本概念、组件创建方式、父子组件之间的数据通信机制,以及非父子组件的通信策略,帮助开发者构建更加模块化和结构清晰的Vue应用。
6.1 组件的基本概念与创建
6.1.1 什么是组件化开发
组件化开发是一种将用户界面拆分为多个独立、可复用、可组合的模块的开发方式。每个组件拥有自己的模板、逻辑和样式,可以在不同的上下文中重复使用,降低代码耦合度,提高项目可维护性。
在Vue中,组件本质上是一个带有名字的Vue实例,它可以接收输入(props),并返回输出(渲染的HTML)。
6.1.2 组件的注册与使用
Vue组件分为全局组件和局部组件。全局组件在整个应用中都可以使用,局部组件仅在注册的父组件中可用。
全局组件注册示例:
// main.js
import Vue from 'vue'
import App from './App.vue'
// 定义一个全局组件
Vue.component('my-button', {
template: `<button @click="onClick">点击我</button>`,
methods: {
onClick() {
alert('按钮被点击了!')
}
}
})
new Vue({
render: h => h(App)
}).$mount('#app')
局部组件注册示例:
<!-- ParentComponent.vue -->
<template>
<div>
<my-button />
</div>
</template>
<script>
import MyButton from './MyButton.vue'
export default {
components: {
MyButton
}
}
</script>
通过组件注册机制,开发者可以轻松实现组件的模块化复用。
6.2 父子组件通信
6.2.1 props传递数据
在父子组件通信中,父组件通过 props
向子组件传递数据。props是子组件接收外部数据的接口,具有单向数据流的特性。
示例:父组件传递title给子组件
<!-- ParentComponent.vue -->
<template>
<child-component :title="pageTitle" />
</template>
<script>
import ChildComponent from './ChildComponent.vue'
export default {
components: { ChildComponent },
data() {
return {
pageTitle: '这是子组件的标题'
}
}
}
</script>
<!-- ChildComponent.vue -->
<template>
<h1>{{ title }}</h1>
</template>
<script>
export default {
props: ['title']
}
</script>
也可以为props指定类型、默认值等:
props: {
title: {
type: String,
required: true,
default: '默认标题'
}
}
6.2.2 自定义事件($emit)
子组件通过自定义事件将数据传递给父组件,使用 $emit
方法触发事件并传递参数。
示例:子组件向父组件传值
<!-- ChildComponent.vue -->
<template>
<button @click="sendToParent">发送数据</button>
</template>
<script>
export default {
methods: {
sendToParent() {
this.$emit('data-sent', 'Hello Parent!')
}
}
}
</script>
<!-- ParentComponent.vue -->
<template>
<child-component @data-sent="handleData" />
</template>
<script>
export default {
methods: {
handleData(msg) {
console.log('接收到子组件数据:', msg)
}
}
}
</script>
通过props和$emit的配合,可以实现父子组件之间的双向数据流动。
6.3 非父子组件通信
6.3.1 使用事件总线(Event Bus)
当组件之间没有直接父子关系时,可以使用事件总线进行通信。事件总线是一个独立的Vue实例,用于在不同组件之间发送和监听事件。
创建事件总线:
// event-bus.js
import Vue from 'vue'
export const EventBus = new Vue()
组件A发送事件:
<!-- ComponentA.vue -->
<script>
import { EventBus } from './event-bus'
export default {
methods: {
sendData() {
EventBus.$emit('message', '来自组件A的消息')
}
}
}
</script>
组件B监听事件:
<!-- ComponentB.vue -->
<script>
import { EventBus } from './event-bus'
export default {
created() {
EventBus.$on('message', (msg) => {
console.log('接收到消息:', msg)
})
}
}
</script>
虽然事件总线实现简单,但在大型项目中容易导致事件混乱,建议结合Vuex使用。
6.3.2 Vuex状态管理基础
Vuex是Vue官方推荐的状态管理模式,适用于管理全局状态。它通过单一状态树、Mutations、Actions和Getters实现组件间的状态共享。
Vuex基本结构:
// store.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
count: 0
},
mutations: {
increment(state) {
state.count++
}
},
actions: {
incrementAsync({ commit }) {
setTimeout(() => {
commit('increment')
}, 1000)
}
},
getters: {
doubleCount(state) {
return state.count * 2
}
}
})
在组件中使用:
<template>
<div>
<p>当前计数:{{ count }}</p>
<p>双倍计数:{{ doubleCount }}</p>
<button @click="increment">增加</button>
<button @click="incrementAsync">异步增加</button>
</div>
</template>
<script>
import { mapState, mapActions, mapGetters } from 'vuex'
export default {
computed: {
...mapState(['count']),
...mapGetters(['doubleCount'])
},
methods: {
...mapActions(['increment', 'incrementAsync'])
}
}
</script>
Vuex通过集中式管理,使得组件通信更加清晰、可维护。
6.4 实战:构建可复用组件库
6.4.1 实现可配置的按钮组件
我们可以创建一个通用的按钮组件,支持传入文本、类型、禁用状态等属性。
<!-- MyButton.vue -->
<template>
<button
:class="['my-button', type]"
:disabled="disabled"
@click="$emit('click')"
>
{{ label }}
</button>
</template>
<script>
export default {
props: {
label: {
type: String,
required: true
},
type: {
type: String,
default: 'default',
validator: value => ['default', 'primary', 'danger'].includes(value)
},
disabled: {
type: Boolean,
default: false
}
}
}
</script>
<style scoped>
.my-button {
padding: 10px 20px;
border-radius: 4px;
border: none;
cursor: pointer;
margin: 5px;
}
.my-button.default {
background-color: #f0f0f0;
color: #333;
}
.my-button.primary {
background-color: #42b983;
color: white;
}
.my-button.danger {
background-color: #e74c3c;
color: white;
}
</style>
使用方式:
<template>
<my-button label="提交" type="primary" @click="handleSubmit" />
</template>
6.4.2 封装通用的表单组件
我们可以创建一个通用的表单输入组件,支持动态绑定值和事件。
<!-- MyInput.vue -->
<template>
<div class="my-input">
<label v-if="label">{{ label }}</label>
<input
:type="type"
:value="value"
@input="$emit('input', $event.target.value)"
:placeholder="placeholder"
/>
</div>
</template>
<script>
export default {
props: {
label: String,
type: {
type: String,
default: 'text'
},
value: [String, Number],
placeholder: String
}
}
</script>
使用方式:
<template>
<div>
<my-input label="用户名:" v-model="username" placeholder="请输入用户名" />
<p>当前用户名:{{ username }}</p>
</div>
</template>
<script>
export default {
data() {
return {
username: ''
}
}
}
</script>
通过上述封装,我们可以构建出一个可复用的组件库,提升开发效率和代码质量。
简介:Vue.js是一款轻量级前端JavaScript框架,专注于视图层,易于上手且功能强大,适合构建用户界面。本课程为“Vue.js全套视频教程”的第一讲“课程简介”,专为初学者设计,帮助掌握Vue的核心概念与基础语法。内容涵盖Vue.js介绍、安装配置、基本语法、指令使用、组件开发、生命周期钩子、响应式原理、模板语法、Vuex状态管理及实战小项目等。通过本课程学习,学员可打下扎实的Vue基础,为后续学习Vue路由、动画、服务端渲染等内容做好准备。