一、简介
Vue.js是一个流行的JavaScript框架,用于构建用户界面和单页应用程序(SPA)。自2014年由前Google工程师尤雨溪发布以来,Vue迅速获得了广泛的关注和使用,特别是在前端开发领域。
核心特性
- 响应式数据绑定:Vue最显著的特点之一是其响应式系统。当Vue实例的数据对象发生变化时,视图会自动更新。这使得状态管理变得简单直观。
- 组件系统:Vue的另一个关键特性是组件系统。组件是可重用的Vue实例,完全具备与新实例相同的选项,如数据、计算属性、方法等。这种组件化使得构建大型应用变得更加高效和模块化。
- 虚拟DOM:Vue使用虚拟DOM(Document Object Model)来提升性能和效率。这意味着当视图发生变化时,Vue会先在虚拟DOM上进行变更,然后高效地将这些变更应用到实际的DOM上。
- 指令系统:Vue提供了一套丰富的指令(如v-bind, v-model, v-on等),使得HTML模板的编写变得更加直观和方便。
设计哲学
Vue的设计哲学是渐进式的。你可以只在一个小项目中引入Vue来处理交互式部分,而不必重构整个项目。随着项目的发展,你可以逐渐探索Vue的更多特性,如组件系统、Vuex(状态管理)、Vue Router(路由管理)等。这种渐进式的特性使得Vue既适合小型项目,也适合大型、复杂的单页应用。
社区和生态系统
Vue享有一个活跃且快速增长的社区。Vue的生态系统包括但不限于:
- Vuex:官方状态管理库。
- Vue Router:官方路由库。
- Nuxt.js:用于服务器端渲染的框架。
- Vuetify、Quasar等:提供现成UI组件的库。
学习曲线
Vue被广泛认为是最易于学习的前端框架之一。其简洁的API设计、清晰的文档以及渐进式的特性使得初学者可以轻松上手。
应用场景
Vue可以用于构建各种Web应用,从小型项目(如动态表单、小型网站)到大型企业级应用(如电子商务网站、后台系统)。它的灵活性和模块化使其适应各种不同的开发需求。
总的来说,Vue以其易用性、灵活性和强大的功能,成为了现代Web开发中最受欢迎的框架之一。无论是对于初学者还是有经验的开发者,Vue都是一个值得考虑的优秀选择。
二、模型架构
Vue.js 的架构可以从几个关键部分来理解:其响应式系统、组件结构、以及与此相关的模块(如Vuex和Vue Router)。下面详细介绍这些构成部分:
1. 响应式系统
Vue 的核心是一个响应式系统,它基于 MVVM(Model-View-ViewModel)模式:
- Model:代表应用数据,通常是纯JavaScript对象。
- View:是由Vue模板构成的DOM表现。
- ViewModel:是Vue实例,它是一个连接视图和数据的中介。在ViewModel中,Vue实例通过一些特殊的属性和函数来观察数据的变化,并自动更新DOM。
当数据变化时,Vue会自动更新视图,这是通过依赖跟踪和一个发布者-订阅者模式实现的。每个组件实例都对应一个watcher实例,它会在组件渲染过程中把属性记录为依赖,当依赖项的setter被调用时,通知watcher重新计算,从而使其关联的组件重新渲染。
2. 组件系统
Vue的另一个关键特点是组件系统。Vue应用由嵌套的、可复用的组件树组成:
- 组件(Component):是Vue最强大的功能之一。每个组件都是一个拥有预定义选项的Vue实例。组件可以包含自己的模板、数据、方法、生命周期钩子等。
- Props:组件可以接受外部传递的数据,这些数据称为props。
- 事件(Events):组件之间可以通过事件进行通信,子组件可以发射事件让父组件监听和响应。
- 插槽(Slots):用于父子组件内容的分发。
3. Vue Router
对于单页应用(SPA),Vue Router 提供了前端路由的功能。它允许你构建一个单页应用的导航系统,而无需页面重新加载。Vue Router 与 Vue.js 核心深度集成,使得构建单页应用变得更加容易。
4. Vuex
Vuex 是 Vue 的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。Vuex 非常适合处理多个组件共享状态的场景。
5. 服务端渲染(SSR)
Vue.js 也支持服务端渲染,这对于SEO和首次加载性能特别重要。通过SSR,可以在服务器端执行Vue组件的渲染,生成并发送静态HTML到客户端,实现更快的首次内容绘制。
总结
Vue的架构提供了一个简单但强大的模式,用于构建用户界面。通过响应式数据绑定和组件系统,开发者可以轻松创建高效的、维护性好的应用程序。同时,Vue的生态系统(包括Vue Router和Vuex)提供了构建复杂应用程序所需的所有工具和功能。这些特性,加上其渐进式的本质,使Vue成为了现代Web应用开发的一个非常受欢迎的选择。
三、 响应式系统
核心概念
- 响应式数据: Vue 中的数据(例如,在
data
对象中定义的数据)是响应式的。这意味着当这些数据改变时,视图将自动更新。 - 依赖跟踪: 当组件渲染时,系统会记录哪些数据被读取。之后,当这些数据改变时,系统知道需要重新渲染哪些组件。
- 虚拟DOM (VDOM): Vue 使用虚拟DOM来提高渲染效率。当状态改变时,Vue 会先在虚拟DOM上进行改变,然后比较新旧虚拟DOM的差异,并将差异应用于实际的DOM上。
实现细节
- 响应式属性: 在 Vue 2.x 中,这是通过 Object.defineProperty 实现的。Vue 3.x 则使用了 ES6 的 Proxy 特性来提供更好的性能和更多的语言特性支持。
- 依赖收集: 当组件进行渲染时,它会读取所需的数据属性,这些属性会收集当前组件作为依赖。如果这些属性的值发生变化,依赖的组件会被重新渲染。
- 异步更新队列: Vue 在数据变化后并不会立即更新DOM,而是把这个更新任务放入到一个异步队列中。在下一个事件循环中,Vue 会清空队列并执行必要的DOM更新。这种方式可以有效地批量处理数据变化,避免不必要的重复渲染。
ES6的 Proxy
特性
这是一个非常强大和灵活的功能,它允许你创建一个对象的代理(proxy),从而可以拦截和自定义对象的基本操作,例如属性查找、赋值、枚举、函数调用等。
基本概念
Proxy
对象用于定义基本操作的自定义行为(如属性查找、赋值、枚举、函数调用等)。它包含两个参数:
- 目标对象 (
target
): 被Proxy
包裹的原始对象。 - 处理器对象 (
handler
): 一个定义了多种“陷阱”(trap)的对象,这些陷阱对应于基本操作。
代码示例
let target = {
name: "target"
};
let handler = {
get: function(obj, prop) {
if (prop in obj) {
return obj[prop];
} else {
return `Property ${prop} not found`;
}
},
set: function(obj, prop, value) {
if (prop === 'age' && !Number.isInteger(value)) {
throw new TypeError('Age must be an integer');
}
obj[prop] = value;
return true;
}
};
let proxy = new Proxy(target, handler);
console.log(proxy.name); // 输出: target
console.log(proxy.age); // 输出: Property age not found
proxy.age = 30; // 正常赋值
console.log(proxy.age); // 输出: 30
proxy.age = 'thirty'; // 抛出错误: TypeError: Age must be an integer
在这个例子中,proxy
是 target
对象的一个代理。通过 handler
对象,我们定义了对 target
对象的 get
和 set
操作的自定义行为。
主要特性
- 拦截和定制行为: Proxy 可以拦截对象上的几乎所有操作,包括属性访问、赋值、函数调用、原型链操作等。
- 验证: 可以用于验证属性值。
- 观察对象: 用于观察对象属性的读写。
- 虚拟对象: 可以创建完全虚拟的对象,这些对象的属性和行为可以完全自定义。
- 反射 (Reflect): ES6 同时引入了
Reflect
对象,它提供了一系列与 Proxy 陷阱函数相对应的方法。这使得在处理器对象内部可以方便地执行默认行为。
使用场景
- 调试: 在属性访问或函数调用时添加日志记录。
- 数据绑定和观察者模式: 自动观察数据变化。
- 数据验证和格式化。
- API 包装和适配。
- 性能优化: 惰性求值或条件加载。
Proxy
特性为 JavaScript 带来了前所未有的操作对象的灵活性和控制力,使得可以在底层操作上实现高级、定制的行为。
VUE和JS的事件循环
Vue.js 和 JavaScript 的事件循环是两个相互关联但又有所不同的概念。我将首先解释 JavaScript 的事件循环,然后讨论 Vue.js 是如何在这个框架内工作的。
JavaScript 事件循环
JavaScript 事件循环是 JavaScript 引擎处理异步操作的机制。它允许 JavaScript 代码执行时,同时处理异步事件(如点击、定时器、HTTP 请求等)。其工作原理如下:
- 调用栈(Call Stack):
-
- 当一个函数被调用时,它被添加到调用栈中。
- 当函数执行完成,它会从调用栈中弹出。
- 事件队列(Event Queue):
-
- 当一个异步事件发生并准备好被处理时,它的回调函数被添加到事件队列中。
- 事件循环(Event Loop):
-
- 事件循环的工作是检查调用栈并确定是否为空。
- 如果调用栈为空,事件循环会从事件队列中取出第一个事件,并将其对应的回调放入调用栈,开始执行。
- 这个过程是循环进行的,因此称为“事件循环”。
Vue.js 和事件循环
Vue.js 是一个构建用户界面的渐进式框架,它在 JavaScript 的事件循环之上提供了响应式数据绑定和组件系统。Vue.js 如何与事件循环交互:
- 响应式系统:
-
- Vue.js 使用响应式系统自动追踪依赖并在数据变化时更新视图。
- 当数据变化时,视图的更新并不是立即执行的,而是被放入一个异步队列中。这就是 Vue.js 的异步更新机制。
- 异步更新队列:
-
- Vue.js 有自己的内部队列来管理异步更新。
- 当数据变化时,组件不会立即重新渲染。相反,Vue 将需要更新的组件标记为“脏的”并放入异步队列。
- 在下一个事件循环中,Vue 清空队列,并只执行必要的组件更新。这种机制可以避免不必要的重复渲染,并提高性能。
- 与 JavaScript 事件循环的集成:
-
- Vue.js 的异步更新队列利用 JavaScript 的事件循环。
- 它通常使用
Promise.then
、MutationObserver
或setTimeout
来延迟队列的处理到下一个事件循环中。
总结
Vue.js 在 JavaScript 的事件循环基础上构建了自己的响应式系统和异步更新机制。通过将组件的更新推迟到下一个事件循环,Vue 可以优化性能并避免不必要的渲染,同时保持界面的响应性和数据的一致性。这种机制允许 Vue.js 高效地管理数据变化和界面更新,同时充分利用 JavaScript 异步处理的能力。
四、 组件系统
4.1 组件定义
Vue 组件定义是 Vue.js 中一个重要的概念,它允许你创建可重用的代码块,具有自己的模板、逻辑和样式。Vue 组件可以被视为自定义元素,它们扩展了 HTML 的能力。下面详细介绍 Vue 组件的定义方式:
单文件组件(.vue 文件)
在 Vue.js 中,最常见的组件定义方式是使用单文件组件(SFC)。这种方式将模板、脚本和样式封装在一个 .vue
文件中。
- 模板部分(Template):
-
- 使用 HTML 编写。
- 可以包含其他组件、数据绑定和指令。
- 脚本部分(Script):
-
- 用于定义组件的逻辑,如数据、方法、生命周期钩子等。
- 通过
export default
导出一个 Vue 组件对象。
- 样式部分(Style):
-
- 可以包含 CSS 用于样式化组件。
- 支持预处理器如 SCSS。
<template>
<div>{{ message }}</div>
</template>
<script>
export default {
data() {
return {
message: 'Hello, Vue!'
}
}
}
</script>
<style>
div {
color: red;
}
</style>
JavaScript 对象
在 Vue.js 中,除了使用单文件组件(.vue
文件)定义组件外,还可以直接在 JavaScript 文件中定义组件。这种方式不依赖于 .vue
文件,而是利用纯 JavaScript 来创建组件。有两种主要的方法:使用 Vue.extend
方法或者直接定义一个对象。
1. 使用 Vue.extend
方法
Vue.extend
是一种构造器,它创建一个“扩展实例构造器”,允许你定义一个预设选项的 Vue 组件。这个方法返回一个“扩展实例构造器”,也就是一个“子类”,这个子类继承自 Vue。
var MyComponent = Vue.extend({
// 选项对象
template: '<div>{{ message }}</div>',
data() {
return {
message: 'Hello, Vue!'
};
}
});
// 创建 MyComponent 实例
new MyComponent().$mount('#app');
在这个例子中,Vue.extend
创建了一个新的组件构造器 MyComponent
。然后,你可以像使用普通 Vue 实例一样使用这个构造器来创建组件实例。
2. 直接定义一个对象
另一种方式是直接定义一个对象,然后通过 Vue.component
方法全局注册这个组件。这种方式简洁直观,适用于较小的应用或是功能。
Vue.component('my-component', {
// 选项对象
template: '<div>{{ message }}</div>',
data() {
return {
message: 'Hello, Vue!'
};
}
});
在这个例子中,Vue.component
方法用于全局注册组件。它接受两个参数:组件的名字(在这里是 'my-component'
)和一个选项对象,这个对象定义了组件的行为和模板。
4.2 组件属性
1、data
Vue 组件的 data
属性是其中一个核心概念,用于声明组件的响应式状态。这个属性在组件内部定义了可以被模板和组件的逻辑所使用的数据。
基本概念
- 类型:在组件中,
data
必须是一个函数,这样每个实例都可以维护一份数据的独立拷贝,避免数据在组件间共享。 - 作用:定义组件的状态。任何在
data
中声明的属性都是响应式的,意味着当这些属性的值改变时,Vue 将自动更新 DOM。 - 访问方式:在组件的模板、计算属性、方法、生命周期钩子和监视器中,可以通过
this
关键字访问data
属性中的数据。
定义方式
在定义组件时,data
属性必须被声明为一个返回对象的函数。这个对象包含了组件的状态。
Vue.component('my-component', {
data() {
return {
counter: 0,
message: 'Hello Vue!'
};
}
});
在这个例子中,data
函数返回一个对象,该对象包含 counter
和 message
两个属性。
使用场景
- 局部状态管理:当你需要存储组件特有的状态时,例如用户输入、计时器状态或任何其他只与该组件相关的数据。
- 响应式数据:Vue 的响应式系统会自动追踪
data
属性中数据的变化,并在数据变化时更新视图。 - 组件实例间独立:由于
data
是一个函数,每个组件实例可以维持一份独立的数据副本,这样同一组件的不同实例之间的数据不会相互影响。
注意事项
- 初始化时声明:为了确保数据是响应式的,需要在组件的
data
中初始化所有需要的属性。 - 直接修改数组和对象:Vue 不能检测到对象属性的添加或删除。当需要修改对象或数组时,应使用 Vue.set 或以新对象替换旧对象。
- 数据的非响应性:如果在
data
定义后添加新的属性到对象上,这些新属性不会是响应式的。应该在初始的data
函数中预先声明它们。
data
属性是 Vue 组件中管理和维护状态的基础,合理利用它可以让组件的状态管理更加清晰和高效。
2、父子组件通信方式
props
在 Vue.js 中,props
是用于接收来自父组件数据的自定义属性。在单文件组件(.vue 文件)中,props
的使用是组件间通信的关键部分。以下是如何在单文件组件中使用 props
的详细步骤和方法。
步骤 1: 定义 Props
在子组件中,首先需要定义 props
。这可以通过数组语法或对象语法来完成。
数组语法
<template>
<!-- 使用 props -->
<div>{{ title }}</div>
</template>
<script>
export default {
props: ['title']
}
</script>
对象语法(推荐)
对象语法允许提供详细的配置,如类型检查、默认值和必需性。
<template>
<div>{{ title }}</div>
</template>
<script>
export default {
props: {
title: {
type: String,
required: true,
default: 'Default Title'
}
}
}
</script>
步骤 2: 在父组件中传递 Props
在父组件中,你需要将数据作为属性传递给子组件。
<template>
<my-component title="Hello Vue!"></my-component>
</template>
<script>
import MyComponent from './MyComponent.vue';
export default {
components: {
MyComponent
}
}
</script>
步骤 3: 在子组件中使用 Props
在子组件中,你可以像使用普通数据一样使用 props
。
<template>
<div>{{ title }}</div>
</template>
<script>
export default {
props: ['title']
}
</script>
高级使用
Props 验证
可以对 props
进行详细的验证,以确保传入的数据类型正确,并且符合预期。
<script>
export default {
props: {
age: {
type: Number,
required: true,
validator: value => {
return value > 0;
}
}
}
}
</script>
使用 Props 初始化数据
有时,你可能需要基于 props
的值来初始化组件的局部状态。
<script>
export default {
props: ['initialCounter'],
data() {
return {
counter: this.initialCounter
};
}
}
</script>
注意事项
- 不要直接修改 Props:Vue 强烈建议不要直接修改
props
的值。如果需要,可以将props
的值赋给data
属性或计算属性进行处理。 - Props 的单向数据流:
props
的更新只能从父组件流向子组件。这有助于预防子组件无意间改变父组件的状态,从而导致应用的数据流难以理解和维护。
props
的正确使用是创建可维护和高效 Vue 应用的关键之一,它确保了组件间清晰和灵活的数据流动。
自定义事件
在 Vue.js 中,自定义事件是组件间通信的重要机制,尤其是从子组件向父组件传递信息。在单文件组件中使用自定义事件包括在子组件中触发事件和在父组件中监听这些事件。以下是使用自定义事件的详细步骤和方法。
步骤 1: 子组件中触发事件
在子组件中,你可以使用 this.$emit
方法来触发一个事件。这个方法接受事件名作为第一个参数,随后的参数是传递给监听器的数据。
子组件(ChildComponent.vue)
<template>
<button @click="handleClick">Click me</button>
</template>
<script>
export default {
methods: {
handleClick() {
// 触发自定义事件,发送信息给父组件
this.$emit('custom-event', 'some data');
}
}
}
</script>
步骤 2: 父组件中监听事件
在父组件中,你可以使用 v-on
或简写 @
来监听子组件触发的事件。
父组件(ParentComponent.vue)
<template>
<child-component @custom-event="handleCustomEvent"></child-component>
</template>
<script>
import ChildComponent from './ChildComponent.vue';
export default {
components: {
ChildComponent
},
methods: {
handleCustomEvent(data) {
console.log('Event received:', data);
// 处理事件和数据
}
}
}
</script>
进阶使用
使用 .native
监听原生事件
如果你需要在父组件中监听子组件根元素的原生事件,可以使用 .native
修饰符。
<child-component @click.native="handleClick"></child-component>
使用 v-model
实现双向绑定
Vue 允许使用 v-model
在自定义组件上实现双向绑定。这实际上是 value
属性和 input
事件的语法糖。
<!-- 子组件 -->
<template>
<input :value="value" @input="updateValue">
</template>
<script>
export default {
props: ['value'],
methods: {
updateValue(event) {
this.$emit('input', event.target.value);
}
}
}
</script>
<!-- 父组件 -->
<template>
<child-component v-model="inputValue"></child-component>
</template>
<script>
import ChildComponent from './ChildComponent.vue';
export default {
components: {
ChildComponent
},
data() {
return {
inputValue: 'initial value'
};
}
}
</script>
注意事项
- 避免与原生 DOM 事件冲突:自定义事件名不应与原生 DOM 事件(如
click
、mouseover
等)冲突,以防止混淆。 - 命名约定:建议使用 kebab-case(短横线分隔命名)来命名自定义事件。
自定义事件是 Vue 组件间沟通的强大工具,它允许子组件以一种松耦合的方式向父组件发送消息,有助于保持组件的封装性和可重用性。
插槽
Vue 的插槽(Slots)是一种用于组件模板的内容分发机制,允许开发者将内容从父组件插入到子组件的指定位置。这在单文件组件(.vue 文件)中特别有用,因为它提供了一种灵活的方式来创建可复用和可配置的组件。以下是在单文件组件中使用插槽的方法和步骤。
默认插槽
默认插槽是最简单的插槽类型,用于分发父组件中未指定插槽的内容。
子组件 (ChildComponent.vue)
<template>
<div>
<h2>Title</h2>
<slot></slot> <!-- 默认插槽 -->
</div>
</template>
<script>
export default {
// 组件逻辑
}
</script>
在这里,<slot></slot>
标签定义了一个默认插槽。
父组件 (ParentComponent.vue)
<template>
<child-component>
<p>This will go into the default slot.</p>
</child-component>
</template>
<script>
import ChildComponent from './ChildComponent.vue';
export default {
components: {
ChildComponent
}
}
</script>
具名插槽
具名插槽允许你为不同的插槽指定不同的内容。
子组件 (ChildComponent.vue)
<template>
<div>
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot> <!-- 默认插槽 -->
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
</template>
父组件 (ParentComponent.vue)
<template>
<child-component>
<template v-slot:header>
<h1>Header Content</h1>
</template>
<p>Main Content</p> <!-- 默认插槽内容 -->
<template v-slot:footer>
<p>Footer Content</p>
</template>
</child-component>
</template>
作用域插槽
Vue 的作用域插槽是一种强大的功能,允许子组件传递数据到它的插槽内容中,这些内容定义在父组件里。作用域插槽特别适用于创建可复用的组件模板,它们需要根据父组件的数据来定制内容。以下是在单文件组件中使用作用域插槽的方法和步骤。
子组件:定义作用域插槽
在子组件中,你定义一个插槽,并决定哪些数据要传递给这个插槽。这是通过在 <slot>
标签中使用 v-bind
或简写 :
来实现的。
子组件 (ChildComponent.vue)
<template>
<ul>
<li v-for="item in items" :key="item.id">
<!-- 定义作用域插槽,并传递 item 数据 -->
<slot name="item" :item="item">
{{ item.defaultText }} <!-- 默认内容 -->
</slot>
</li>
</ul>
</template>
<script>
export default {
data() {
return {
items: [
{ id: 1, text: 'Item 1', defaultText: 'Default 1' },
{ id: 2, text: 'Item 2', defaultText: 'Default 2' }
// 更多 items...
]
};
}
}
</script>
这里,子组件为每个 item
定义了一个作用域插槽,将 item
对象作为属性传递给插槽。
父组件:使用作用域插槽
父组件接收子组件传递的数据,并决定如何显示这些数据。
父组件 (ParentComponent.vue)
<template>
<child-component>
<!-- 使用作用域插槽 -->
<template v-slot:item="slotProps">
<span>{{ slotProps.item.text }}</span>
</template>
</child-component>
</template>
<script>
import ChildComponent from './ChildComponent.vue';
export default {
components: {
ChildComponent
}
}
</script>
在这个例子中,父组件使用 v-slot:item="slotProps"
来接收从子组件传递过来的 item
数据。slotProps
是一个对象,它包含了所有传递给该插槽的属性。在这里,它包含了子组件中的 item
对象。
使用场景
作用域插槽非常适合以下场景:
- 创建可复用的列表组件,其中列表项的内容需要根据父组件的数据定制。
- 构建一个组件,其部分 UI 结构和行为由父组件控制,但数据来自子组件。
- 实现高度可定制的组件接口。
注意事项
- 在作用域插槽中,插槽内容仍然在父组件的作用域内编译,因此可以访问父组件中的数据和方法。
- 默认插槽内容是可选的。如果父组件没有提供对应插槽的内容,将显示子组件中定义的默认内容。
- 作用域插槽增强了组件间的合作能力,同时保持了组件的封装性和可重用性。
作用域插槽是 Vue.js 中一项强大的功能,提供了一种灵活的方式来创建具有动态内容的组件,同时保持了组件的清晰界限和可维护性。
插槽使用的注意事项
- 插槽内容是在父组件作用域内编译的,因此父组件的数据和方法可以在插槽内容中使用。
- 插槽可以是可选的;如果父组件没有提供内容,子组件的插槽会被显示默认内容。
- 作用域插槽允许子组件将数据作为插槽的“范围”提供给父组件,这对于创建高度动态的组件特别有用。
Vue 的插槽系统提供了一种强大的机制,用于构建灵活且可重用的组件,它允许开发者更好地控制内容的布局和组合。
3、methods
Vue.js 中的 methods
属性是用于在 Vue 实例中定义方法的地方。这些方法可以用于响应事件、计算数据或任何其他逻辑。在单文件组件(.vue 文件)中使用 methods
属性是非常直接和常见的做法。以下是在单文件组件中使用 methods
属性的方法和步骤。
定义 Methods
在单文件组件中,methods
属性是一个对象,其中的每个属性都是一个方法。这些方法可以在组件的模板中被调用,或者在其他方法、计算属性和生命周期钩子中被使用。
示例:子组件 (MyComponent.vue)
<template>
<div>
<button @click="incrementCount">Increment</button>
<p>Count: {{ count }}</p>
</div>
</template>
<script>
export default {
data() {
return {
count: 0
};
},
methods: {
incrementCount() {
this.count += 1;
}
}
}
</script>
在这个示例中:
incrementCount
方法被定义在methods
对象内。- 当按钮被点击时,
@click
指令调用incrementCount
方法。 incrementCount
方法更新count
数据属性的值。
调用 Methods
在 Vue 组件中,你可以通过 this
关键字调用 methods
中定义的方法。
在模板中调用
可以在 Vue 模板的指令中直接调用方法,如上面示例中的 @click="incrementCount"
。
在 JavaScript 代码中调用
你也可以在组件的其他方法、计算属性或生命周期钩子中调用这些方法。
export default {
methods: {
methodOne() {
// 逻辑...
},
methodTwo() {
this.methodOne();
}
}
}
Methods 使用场景
- 事件处理:响应用户输入,如点击按钮、提交表单等。
- 复杂计算:执行比计算属性更复杂的逻辑操作。
- 重用逻辑:封装可在多处调用的代码块。
注意事项
- 避免过度使用:对于依赖组件数据并用于渲染结果的逻辑,优先考虑使用计算属性。
- 访问组件数据和方法:在
methods
中,可以通过this
访问组件的数据和其他方法。 - 响应性:
methods
中的方法不是响应式的,它们不会像计算属性那样自动重新计算。它们仅在被调用时执行。
methods
属性在 Vue 组件中提供了一个强大的工具,可以用于处理用户交互、执行计算或其他逻辑操作,从而增加了组件的交互性和功能性。
4、computed
Vue.js 中的 computed
属性是用来声明计算属性的地方。计算属性是基于响应式依赖进行缓存的数据属性。与方法相比,计算属性只在相关响应式依赖发生改变时才会重新求值,这使得它们非常适合执行更复杂的逻辑,同时保持高效性。在单文件组件(.vue 文件)中使用 computed
属性是常见且有益的做法。以下是在单文件组件中使用 computed
属性的方法和步骤。
定义计算属性
在单文件组件中,computed
属性是一个对象,其中的每个属性都是一个计算属性。这些属性看起来像常规的数据属性,但实际上它们的值是由一个函数计算得来的。
示例:子组件 (MyComponent.vue)
<template>
<div>
<p>Original message: "{{ message }}"</p>
<p>Reversed message: "{{ reversedMessage }}"</p>
</div>
</template>
<script>
export default {
data() {
return {
message: 'Hello Vue!'
};
},
computed: {
reversedMessage() {
return this.message.split('').reverse().join('');
}
}
}
</script>
在这个示例中:
reversedMessage
是一个计算属性,它依赖于data
中的message
属性。- 每当
message
的值发生变化时,reversedMessage
会自动更新。
使用计算属性
计算属性可以像常规的数据属性一样在模板中被使用。它们通常用于模板表达式和数据绑定。
在模板中使用
在 Vue 模板中,直接引用计算属性名即可。
<p>{{ reversedMessage }}</p>
在 JavaScript 代码中使用
在组件的其他方法或计算属性中,你可以通过 this
关键字来引用计算属性。
computed: {
anotherComputedProp() {
return this.reversedMessage + ' some other data';
}
}
计算属性的使用场景
- 复杂逻辑:当模板中的表达式过于复杂时,可以使用计算属性来简化模板。
- 性能优化:计算属性会缓存结果,只有当依赖的响应式数据发生变化时,它们才会重新计算。
- 数据格式化:在显示之前格式化或计算数据。
注意事项
- 依赖的响应性:计算属性的响应性完全取决于它们所依赖的数据属性。如果依赖的数据不是响应式的,计算属性也不会更新。
- 不要改变响应式数据:避免在计算属性中改变其依赖的响应式数据,这可能导致不可预测的结果。
- 计算属性默认只有 getter:如果需要,你也可以提供一个 setter。
computed
属性提供了一种声明式的方法来描述数据的依赖关系和计算逻辑,是 Vue 组件设计中的一个重要工具。
5、watch
Vue.js 中的 watch
属性是一个非常有用的功能,用于观察和响应 Vue 实例上数据对象的变化。当你需要在数据变化时执行异步或开销较大的操作时,watch
是最合适的选择。在单文件组件(.vue 文件)中使用 watch
属性可以让你轻松地追踪数据的变化并作出相应的反应。以下是在单文件组件中使用 watch
属性的方法和步骤。
定义 Watchers
在单文件组件中,watch
属性是一个对象,其中的每个属性对应一个要观察的数据属性。你可以为每个属性指定一个函数,当被观察的属性变化时,该函数将被调用。
示例:子组件 (MyComponent.vue)
<template>
<div>
<input v-model="message" placeholder="Edit me">
<p>The message is: {{ message }}</p>
</div>
</template>
<script>
export default {
data() {
return {
message: ''
};
},
watch: {
message(newVal, oldVal) {
console.log(`The new message is: ${newVal}`);
}
}
}
</script>
在这个示例中:
message
是一个数据属性,通过v-model
在输入框中被绑定。watch
对象包含一个message
函数,每当message
数据变化时,这个函数就会被调用。
Watcher 函数参数
Watcher 函数默认接收两个参数:
newVal
:变化后的值。oldVal
:变化前的值。
使用场景
- 异步操作:如在数据变化时从服务器获取数据。
- 复杂逻辑:当需要执行比计算属性更复杂的响应逻辑时。
- 监听路由变化:如在 Vue Router 中监听
$route
的变化。
高级特性
深度观察
使用 deep
选项可以观察对象内部值的变化。
watch: {
someObject: {
handler(newVal, oldVal) {
// 处理逻辑
},
deep: true
}
}
立即触发
使用 immediate
选项可以在监听开始后立即触发回调。
watch: {
someData: {
handler(newVal, oldVal) {
// 处理逻辑
},
immediate: true
}
}
注意事项
- 避免过度使用:
watch
可能会引起性能问题,特别是在观察复杂数据结构时。只在必要时使用。 - 清理工作:如果你在 watcher 中设置了定时器或执行了其他副作用操作,请确保在组件销毁时清理它们。
watch
属性提供了一种强大的方式来响应数据的变化,它在处理异步操作、复杂逻辑或依赖于外部数据源的情况下尤其有用。
6、template
-
- 类型:字符串。
- 作用:定义组件的 HTML 模板。
- 使用:在单文件组件(.vue 文件)中通常用
<template>
标签,也可以在 JavaScript 中定义为字符串。
7、mixins
Vue.js 的 mixins
属性提供了一种灵活的方式来复用组件逻辑。Mixin 是一个包含选项对象的 JavaScript 对象,这些选项可以包含任何组件选项。当组件使用 mixin 时,所有 mixin 的选项将被“混合”进入组件本身的选项。这在单文件组件中特别有用,因为它允许开发者共享和重用代码,减少重复和增加可维护性。以下是在单文件组件中使用 mixins
属性的方法和步骤。
定义 Mixin
首先,你需要定义一个 mixin。这通常是一个单独的 JavaScript 文件,包含可在多个组件间共享的属性、方法、生命周期钩子等。
示例:创建一个 Mixin (myMixin.js)
export default {
data() {
return {
mixinMessage: 'Hello from mixin!'
};
},
created() {
console.log('Mixin hook called');
},
methods: {
mixinMethod() {
console.log('Mixin method called');
}
}
};
这个 mixin 定义了一个数据属性 mixinMessage
、一个生命周期钩子 created
和一个方法 mixinMethod
。
使用 Mixin
在组件中使用 mixin,只需要在组件的选项对象中添加一个 mixins
属性,并引入 mixin。
示例:在组件中使用 Mixin (MyComponent.vue)
<template>
<div>
<p>{{ mixinMessage }}</p>
<button @click="mixinMethod">Call Mixin Method</button>
</div>
</template>
<script>
import myMixin from './myMixin';
export default {
mixins: [myMixin],
created() {
console.log('Component hook called');
}
};
</script>
在这个组件中,我们引入并使用了 myMixin
。这使得 MyComponent
组件获得了 mixin 中的数据、方法和生命周期钩子。
Mixins 的合并规则
- 数据对象:在组件和 mixins 中的数据对象将被合并。如果发生冲突,组件数据将具有优先权。
- 钩子函数:如果同一生命周期钩子在组件和 mixins 中都有定义,它们将被合并为一个数组,且 mixins 中的钩子将首先被调用。
- 方法、组件、指令等:如果发生冲突,组件自身的选项将具有优先权。
使用场景和注意事项
- 复用代码:对于跨组件共享的逻辑、数据和方法,mixins 是一个好的解决方案。
- 注意冲突:在使用 mixins 时要注意属性、方法和生命周期钩子的命名冲突。
- 可维护性:虽然 mixins 可以增加复用性,但过度使用或不当使用可能会让组件之间的关系变得复杂,影响可维护性。
mixins
提供了一种强大的方式来扩展 Vue 组件的功能,但应谨慎使用,以保持代码的清晰和可维护性。
8、directives
Vue.js 中的 directives
属性允许你自定义指令,这是一种强大的机制,用于直接操作 DOM 元素。在单文件组件中使用自定义指令可以帮助你封装对 DOM 的底层操作,从而增加代码的可复用性和可维护性。以下是在单文件组件中使用 directives
属性的方法和步骤。
常用指令
在 Vue.js 中,指令是一种特殊的特性,带有 v-
前缀。它们用于为 HTML 元素添加特殊的行为或者操作,比如动态绑定数据、监听事件、条件渲染等。以下是 Vue.js 中常用的一些指令:
- v-model:用于实现表单元素与 Vue 实例中数据的双向绑定,可以同时监听输入事件和修改数据。
<input v-model="message">
- v-bind:用于动态绑定 HTML 元素的属性,可以动态地设置属性的值。
<div v-bind:class="{ active: isActive }"></div>
或者使用简写形式 :
:
<div :class="{ active: isActive }"></div>
- v-on:用于监听 HTML 元素的事件,当触发指定的事件时,执行相应的方法。
<button v-on:click="handleClick">Click me</button>
或者使用简写形式 @
:
<button @click="handleClick">Click me</button>
- v-if / v-else-if / v-else:用于条件性地渲染元素,根据表达式的值决定是否渲染元素。
<div v-if="isShow">Hello, Vue!</div>
- v-for:用于循环渲染列表中的元素,根据数据源动态生成多个相同结构的元素。
<ul>
<li v-for="(item, index) in items" :key="index">{{ item }}</li>
</ul>
- v-show:与
v-if
类似,用于根据表达式的值来显示或隐藏元素,但是它是通过 CSS 的display
属性来控制元素的显示与隐藏,而不是直接从 DOM 中移除元素。
<div v-show="isShow">Hello, Vue!</div>
- v-text:用于将元素的
textContent
设置为指定的值,替代插值语法{{ }}
。
<p v-text="message"></p>
- v-html:用于将元素的
innerHTML
设置为指定的 HTML 字符串,用于渲染富文本内容。
<div v-html="htmlContent"></div>
这些是 Vue.js 中常用的一些指令,通过使用它们,可以实现 Vue 应用中的各种动态交互效果和功能。
定义自定义指令
自定义指令通常在 Vue 组件的 directives
选项中定义,它是一个包含指令定义的对象。
示例:定义一个自定义指令 (MyComponent.vue)
<template>
<div v-my-directive="color">Colored text</div>
</template>
<script>
export default {
directives: {
myDirective: {
// 钩子函数,当绑定元素插入到 DOM 中时调用
inserted(el, binding) {
el.style.color = binding.value;
}
}
}
}
</script>
在这个例子中:
- 定义了一个名为
v-my-directive
的自定义指令。 - 当元素被插入到 DOM 中时,
inserted
钩子函数被调用。 el
参数是绑定元素的 DOM 对象。binding
对象包含了指令的详细信息,如传递给指令的值(在这里是color
)。
使用自定义指令
在同一个组件或注册了该自定义指令的其他组件中,可以像使用内置指令一样使用自定义指令。
<template>
<div v-my-directive="'red'">This text will be red</div>
</template>
自定义指令的钩子函数
自定义指令提供了几个钩子函数,你可以根据需要使用它们:
bind
: 只调用一次,当指令第一次绑定到元素时调用。inserted
: 被绑定元素插入父节点时调用。update
: 所在组件的 VNode 更新时调用,但可能在其子 VNode 更新之前调用。componentUpdated
: 所在组件的 VNode 及其子 VNode 全部更新后调用。unbind
: 只调用一次,当指令与元素解绑时调用。
使用场景和注意事项
- DOM 操作:当需要进行底层 DOM 操作时,自定义指令是一个好选择。
- 封装逻辑:可以将复杂的 DOM 操作逻辑封装在自定义指令中,使得代码更加整洁和可维护。
- 重用性:自定义指令可以在不同的组件中重用。
自定义指令是 Vue.js 提供的一种强大且灵活的方式,用于封装和复用 DOM 操作的逻辑。正确使用时,它们可以帮助你编写更清晰、更有组织的代码。
9、filters
Vue 3.x 已经不再支持 filters
属性,这是从 Vue 2.x 版本中移除的。在 Vue 2.x 中,filters
属性用于定义文本格式化过滤器,可以用于模板中的文本转换和格式化。尽管 Vue 3.x 不再支持它,我仍可以向你展示在 Vue 2.x 中如何使用 filters
属性,以及在 Vue 3.x 中的替代方案。
Vue 2.x 中的 Filters 使用方法
定义 Filter
在单文件组件中,你可以在组件的 filters
选项内定义局部过滤器。
<template>
<p>{{ message | capitalize }}</p>
</template>
<script>
export default {
data() {
return {
message: 'hello world'
};
},
filters: {
capitalize(value) {
if (!value) return '';
value = value.toString();
return value.charAt(0).toUpperCase() + value.slice(1);
}
}
}
</script>
在这个例子中,定义了一个 capitalize
过滤器,它将输入文本的首字母转换为大写。
在模板中使用 Filter
你可以在双花括号插值和 v-bind
表达式中使用过滤器。
{{ message | capitalize }}
Vue 3.x 的替代方案
在 Vue 3.x 中,你可以使用计算属性或方法来替代过滤器的功能。
使用计算属性
计算属性可以用于处理和返回转换后的数据。
<template>
<p>{{ capitalizedMessage }}</p>
</template>
<script>
export default {
data() {
return {
message: 'hello world'
};
},
computed: {
capitalizedMessage() {
if (!this.message) return '';
return this.message.charAt(0).toUpperCase() + this.message.slice(1);
}
}
}
</script>
使用方法
你也可以定义一个方法来实现相同的功能。
<template>
<p>{{ capitalize(message) }}</p>
</template>
<script>
export default {
data() {
return {
message: 'hello world'
};
},
methods: {
capitalize(value) {
if (!value) return '';
return value.charAt(0).toUpperCase() + value.slice(1);
}
}
}
</script>
虽然 Vue 3.x 移除了 filters
,但计算属性和方法提供了更多的灵活性和功能性,使得在处理和展示数据时更加方便。
10、extends
Vue.js 的 extends
选项允许你扩展另一个组件。这是一种构建可复用组件的强大方法,尤其是当你希望创建一个基于现有组件但带有额外功能或覆写某些行为的组件时。在单文件组件中使用 extends
可以使代码更加模块化和可维护。以下是在单文件组件中使用 extends
属性的方法和步骤。
定义要扩展的基础组件
首先,你需要一个基础组件,它定义了一些基本的数据、方法、生命周期钩子等。
基础组件 (BaseComponent.vue)
<template>
<div>
<h2>{{ title }}</h2>
<p>{{ message }}</p>
</div>
</template>
<script>
export default {
data() {
return {
title: 'Base Title',
message: 'Message from Base Component'
};
},
methods: {
displayMessage() {
console.log(this.message);
}
}
}
</script>
使用 extends 创建扩展组件
接下来,你可以创建一个新的组件,它通过 extends
选项扩展了基础组件。
扩展组件 (ExtendedComponent.vue)
<template>
<div>
<h2>{{ title }}</h2>
<button @click="displayMessage">Display Message</button>
</div>
</template>
<script>
import BaseComponent from './BaseComponent.vue';
export default {
extends: BaseComponent,
data() {
return {
title: 'Extended Title' // 覆写基础组件的数据
};
},
methods: {
displayMessage() {
console.log('This is from the extended component.');
console.log(this.message); // 调用继承自基础组件的数据
}
}
}
</script>
在这个例子中:
- 通过
extends: BaseComponent
,扩展组件继承了BaseComponent
的所有选项(数据、方法等)。 title
数据属性在扩展组件中被覆写,而message
保持不变。displayMessage
方法在扩展组件中被覆写,但仍然可以访问继承自基础组件的message
数据。
extends 的使用场景
- 代码复用:当多个组件有共同的基础功能时,可以将这些功能放在一个基础组件中,然后通过
extends
来扩展这个基础组件。 - 组件继承:在扩展现有组件的同时,还可以添加新的功能或覆写某些行为。
注意事项
- 合并规则:类似于
mixins
,extends
也遵循特定的合并规则。例如,生命周期钩子函数将被合并到一个数组中,而数据对象将进行适当的合并和覆写。 - 可维护性:虽然
extends
可以帮助减少代码重复,但过度使用可能会使组件关系变得复杂,影响代码的可读性和可维护性。
使用 extends
是 Vue 中代码复用和组件继承的一种有效方式,它能够帮助开发者构建可维护且模块化的大型应用。
11、provide / inject
Vue.js 中的 provide
和 inject
选项一起使用,为组件树提供了一种依赖注入的机制。这对于在深层嵌套的组件之间共享数据非常有用,特别是在构建大型应用时。通过这种方式,祖先组件可以作为其所有子孙组件的依赖提供者。以下是在单文件组件中使用 provide
和 inject
属性的方法和步骤。
祖先组件:使用 provide 提供数据
provide
选项允许你定义要提供给后代组件的数据或方法。
祖先组件 (AncestorComponent.vue)
<template>
<div>
<child-component></child-component>
</div>
</template>
<script>
import ChildComponent from './ChildComponent.vue';
export default {
components: {
ChildComponent
},
provide() {
return {
sharedData: 'Shared Data'
};
}
}
</script>
在这个例子中,祖先组件提供了一个名为 sharedData
的数据。
后代组件:使用 inject 接收数据
inject
选项允许子孙组件从其祖先组件接收指定的数据或方法。
后代组件 (ChildComponent.vue)
<template>
<div>{{ sharedData }}</div>
</template>
<script>
export default {
inject: ['sharedData']
}
</script>
在这个例子中,后代组件接收了从其祖先组件提供的 sharedData
数据。
使用场景
- 跨组件通信:当你需要在深层嵌套的组件间共享数据时,
provide
和inject
是有用的工具。 - 高阶插件/组件库:用于构建需要在多个组件间共享状态或逻辑的高阶插件或组件库。
注意事项
- 响应性:如果你想要提供的数据是响应式的,请确保它是 Vue 的响应式对象。你可以使用 Vue 的响应式系统函数,如
Vue.observable
(Vue 2.x)或reactive
(Vue 3.x)来实现。 - 不是反应式通信:
provide
和inject
绑定并不是可响应的。这意味着如果你提供的是一个非响应式对象,那么更改这个对象的属性不会触发子孙组件的更新。 - 使用场景:虽然
provide
和inject
提供了一种跨组件通信的方式,但它们并不应被滥用。对于大多数场景,更好的选择是使用 Vuex 或类似的状态管理库。
provide
和 inject
提供了一种高级的、用于在组件树中传递数据的方式,使得跨多层组件的通信变得更加简洁。
12、el
Vue.js 中的 el
属性用于指定当前 Vue 实例所控制的 DOM 元素。在单文件组件(SFC)的上下文中,通常不直接使用 el
属性,因为组件被设计为可重用和可组合的,而不是绑定到特定的 DOM 元素上。但是,了解它的基本使用方法仍然很重要。
在传统 Vue 实例中的使用
在非单文件组件的环境中,你会这样使用 el
属性:
new Vue({
el: '#app',
data: {
message: 'Hello Vue!'
}
});
这段代码会告诉 Vue 实例将其挂载到 ID 为 app
的 DOM 元素上。这意味着 Vue 实例的所有数据和方法都将在这个元素及其子元素中可用。
在单文件组件中的替代方案
在单文件组件中,通常不使用 el
属性,因为组件本身代表了要渲染的模板。你会这样创建一个单文件组件:
<template>
<div>
{{ message }}
</div>
</template>
<script>
export default {
data() {
return {
message: 'Hello Vue!'
};
}
}
</script>
这个组件可以被导入到主 Vue 实例或其他组件中,如下所示:
import MyComponent from './MyComponent.vue';
new Vue({
el: '#app',
components: {
MyComponent
}
});
这里,Vue 实例使用 el
属性指定了要挂载的元素,而单文件组件则作为可复用的部分被导入和使用,而不需要关心具体挂载到哪个 DOM 元素上。
13、name
Vue.js 中的 name
属性在单文件组件(SFC)中非常有用。它主要用于组件的标识,这在多个方面非常有用,比如递归组件、Vue 开发者工具中的调试,以及在某些高级功能中,比如组件的缓存和动态组件。
在单文件组件中的使用
在单文件组件中,name
属性通常在 <script>
部分声明,如下所示:
<template>
<div>
<!-- 组件模板内容 -->
</div>
</template>
<script>
export default {
name: 'MyComponent',
// 其他选项如 data, methods, computed 等
}
</script>
name
属性的优势和用途
- 递归组件: 如果一个组件需要在其模板中递归调用自身,
name
属性是必需的。这是因为组件需要一个名字来引用自己。 - 开发者工具: 在 Vue Devtools 中,具有
name
属性的组件更容易识别和调试。没有name
属性的组件将显示为匿名组件,这可能使调试变得困难。 - keep-alive: 当使用
<keep-alive>
组件时,可以利用include
和exclude
属性来缓存或排除特定的组件。这些属性通常使用组件的name
值来引用组件。 - 动态组件: 在使用
<component :is="...">
的动态组件时,name
属性可以用来确定哪个组件应该被加载和渲染。
注意事项
name
属性的值应该是唯一的,特别是在一个大型项目中,避免使用重复的组件名。- Vue.js 并不强制要求所有单文件组件都必须有
name
属性,尤其是在不需要上述功能的情况下。
4.3 组件注册
在 Vue.js 中,组件注册是一种将自定义组件添加到 Vue 应用的方法,使它们可以在应用的任何部分重复使用。Vue 提供了两种组件注册方式:全局注册和局部注册。理解这两种方法及其适用情景对于构建高效、可维护的 Vue 应用至关重要。
全局注册
全局注册的组件可以在任何新创建的 Vue 根实例及其子组件中使用,无需再次导入或注册。
如何进行全局注册:
// 首先,导入 Vue 和 组件
import Vue from 'vue';
import MyComponent from './MyComponent.vue';
// 使用 Vue.component 方法进行全局注册
Vue.component('my-component', MyComponent);
// 现在 MyComponent 可以在任何 Vue 实例中使用
new Vue({
el: '#app'
});
在这种情况下,<my-component>
可以在任何 Vue 实例的模板中使用,包括根实例或任何子组件。
优点:
- 简化组件的重用,不需要在每个使用它的地方重新导入和注册。
缺点:
- 可能增加初始载入时间,因为所有全局注册的组件都会被包含在最终构建的文件中,不论它们是否被使用。
- 不利于模块化和代码分割。
局部注册
局部注册的组件只能在注册它们的组件内使用。这是一种更模块化的方法。
如何进行局部注册:
<template>
<div>
<my-component></my-component>
</div>
</template>
<script>
import MyComponent from './MyComponent.vue';
export default {
components: {
'my-component': MyComponent
}
}
</script>
在这个例子中,MyComponent
只在导入并注册它的组件内部可用。
优点:
- 有助于减少最终构建的文件大小,因为只包括必要的组件。
- 提高代码的可维护性和可读性,因为清晰地显示了每个组件所依赖的子组件。
缺点:
- 如果在多个地方使用相同的组件,需要在每个地方单独导入和注册。
小结
- 使用全局注册可以简化大型应用中多次使用的组件的使用,但可能会影响性能。
- 局部注册更适合于只在少数几个地方使用的组件,有助于保持代码的模块化和清晰。
五、Vue Router
Vue Router 是 Vue.js 的官方路由管理器。它与 Vue.js 核心深度集成,使得在单页应用中构建复杂的路由系统变得简单。Vue Router 提供的功能包括嵌套路由/视图、模块化的、基于组件的路由配置、路由参数、查询、通配符等。
基础概念
1. 安装和初始化
在开始使用 Vue Router 之前,需要先进行安装,并在 Vue 应用中初始化它:
import Vue from 'vue';
import VueRouter from 'vue-router';
Vue.use(VueRouter);
// 定义路由配置
const routes = [
{ path: '/', component: HomeComponent },
{ path: '/about', component: AboutComponent }
];
// 创建 router 实例
const router = new VueRouter({
routes // (缩写)相当于 routes: routes
});
// 创建和挂载根实例
new Vue({
router,
// ...其他选项
}).$mount('#app')
2. 路由配置
路由配置是一个路由数组,每个路由映射到一个组件。你可以定义任意多的路由,并在每个路由上配置多种选项:
const routes = [
{ path: '/user/:id', component: UserComponent }
];
3. 路由视图
<router-view>
组件是一个路由出口,渲染当前路由匹配到的组件:
<template>
<div id="app">
<router-view></router-view>
</div>
</template>
4. 导航链接
<router-link>
组件用于用户导航。to
属性指定目标路由的链接,类似于 HTML 的 <a>
标签:
<router-link to="/about">About</router-link>
5、使用路由
在组件中,可以使用 <router-link> 和 <router-view> 组件来实现路由的导航和视图显示:
<template>
<div>
<router-link to="/">Home</router-link>
<router-link to="/about">About</router-link>
<router-view></router-view>
</div>
</template>
- <router-link> 类似于 HTML 的 <a> 标签,用于导航到不同的路由。
- <router-view> 是显示当前路由对应组件的占位符。
进阶特性
1.动态路由和路由参数
Vue Router 允许使用动态路由参数。这意味着,可以基于 URL 中的参数来动态渲染组件:
{
path: '/user/:id',
component: User
}
在这个路由中,:id 是一个动态参数。访问 /user/1 时,User 组件会被渲染,并且可以通过 this.$route.params.id 访问到 id 的值。
2. 嵌套路由
可以通过配置子路由数组来构建嵌套路由:
const routes = [
{
path: '/user/:id',
component: UserComponent,
children: [
{
path: 'profile',
component: UserProfile
},
{
path: 'posts',
component: UserPosts
}
]
}
];
3. 编程式导航
除了使用 <router-link>
创建导航链接,还可以使用 JavaScript 来导航,例如 router.push
:
router.push('/about');
4. 命名路由
可以给路由设置一个名字,使得路由更易管理:
{ path: '/user/:id', name: 'user', component: UserComponent }
5.路由守卫
路由守卫是 Vue Router 的重要特性,允许在路由发生变化时执行逻辑(例如,检查用户是否登录):
router.beforeEach((to, from, next) => {
// 检查用户是否登录
if (to.name !== 'Login' && !isAuthenticated) next({ name: 'Login' })
else next()
});
在这个例子中,beforeEach 是一个全局守卫,检查用户是否登录,如果没有登录并试图访问非登录页面,用户将被重定向到登录页。
总结
Vue Router 是构建单页应用的重要工具,提供了多种路由配置和导航方法,以适应不同的应用需求。它的灵活性和集成度使得在 Vue 应用中管理路由变得简单高效。
六、Vuex
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式和库。它用于集中管理应用的所有组件的状态,并以一种可预测的方式来实现变更。在大型应用中,它非常有用,因为它帮助你更好地组织和维护数据。
安装 Vuex
如果你正在使用 Vue CLI 或类似的构建工具,可以通过 npm 或 yarn 来安装 Vuex:
npm install vuex@next
确保安装的是与 Vue 3 兼容的 Vuex 版本(例如 Vuex 4)。
创建一个 Vuex Store
Vuex 的核心是 store(仓库)。Store 包含了应用的状态(state)和改变状态的方法(mutations, actions)。
// store/index.js
import { createStore } from 'vuex';
export default createStore({
state: {
count: 0
},
mutations: {
increment(state) {
state.count++;
}
},
actions: {
increment(context) {
context.commit('increment');
}
},
getters: {
doubleCount: state => state.count * 2
}
});
在这个例子中,创建了一个包含单一状态 count
的 store。还有一个 increment
mutation 来改变状态,一个 increment
action 来提交(commit)这个 mutation,以及一个 doubleCount
getter。
在 Vue 应用中引入 Vuex Store
// main.js
import { createApp } from 'vue';
import App from './App.vue';
import store from './store';
createApp(App)
.use(store)
.mount('#app');
在 Vue 应用的主入口文件中,导入 store 并通过 use
方法将其添加到 Vue 应用实例。
在组件中使用 Vuex Store
在 Vue 组件中,可以通过 this.$store
访问 Vuex store。
<template>
<div>
{{ $store.state.count }}
<button @click="increment">Increment</button>
</div>
</template>
<script>
export default {
methods: {
increment() {
this.$store.dispatch('increment');
}
}
};
</script>
在这个组件中,使用 this.$store.state.count
来访问 Vuex store 中的 count
状态,使用 this.$store.dispatch('increment')
来触发 action。
模块化 Vuex Store
对于大型应用,您可能需要将 Vuex store 分成多个模块:
// store/modules/myModule.js
export default {
state: { /* ... */ },
mutations: { /* ... */ },
actions: { /* ... */ },
getters: { /* ... */ }
}
// store/index.js
import myModule from './modules/myModule';
export default createStore({
modules: {
myModule
}
});
这样,每个模块都可以有自己的状态、突变、操作和获取器。
总结
Vuex 提供了一种机制来集中管理应用的状态,并通过严格的规则确保状态以可预测的方式改变。这对于大型应用尤其重要,因为它帮助维护代码的组织和可维护性。