# 一.组件的生命周期
# 1.生命周期
Vue 的生命周期是指 Vue 实例从创建到销毁的整个过程中,按照特定的顺序执行的一系列钩子函数(也称为生命周期钩子)。这些钩子函数允许开发者在不同的阶段插入自定义的代码逻辑,以控制和管理 Vue 实例的行为。
生命周期(Life Cycle)是指一个组件从创建 -> 运行 -> 销毁的整个阶段,强调的是一个时间段。
# 2.生命周期函数
- 创建阶段
- 挂载阶段
- 更新阶段
- 卸载阶段
生命周期函数:是由 vue 框架提供的内置函数,会伴随着组件的生命周期,自动按次序执行。
注意:生命周期强调的是时间段,生命周期函数强调的是时间点。
Vue.js 是一种流行的 JavaScript 框架,提供了一些生命周期钩子函数,允许您在 Vue 组件的不同阶段执行自定义逻辑。下面是 Vue.js 2.x 版本的生命周期函数列表:
- beforeCreate:在 Vue 实例初始化之后,数据观测 (data observation) 和事件配置 (event/watcher setup) 之前被调用。
- created:在 Vue 实例创建完成后立即调用,可以访问已创建的实例,但无法进行 DOM 操作。
- beforeMount:在 Vue 实例挂载到 DOM 之前被调用。
- mounted:在 Vue 实例挂载到 DOM 后调用,可以进行 DOM 操作。这是大多数初始化工作的最佳时机。
- beforeUpdate:在响应式数据更新时调用,但在 DOM 重新渲染之前调用。
- updated:在 DOM 重新渲染后调用,可以执行依赖于 DOM 的操作。
- activated:在使用 keep-alive 组件包裹的组件激活时调用。
- deactivated:在使用 keep-alive 组件包裹的组件停用时调用。
- beforeDestroy:在 Vue 实例销毁之前调用,可以执行一些清理操作。
- destroyed:在 Vue 实例销毁后调用,所有的事件监听器会被移除,所有的子实例也会被销毁。
- errorCaptured:当子组件抛出错误时调用,可以用于错误处理和日志记录。
除了上述生命周期钩子函数之外,Vue 3.x 版本还引入了一些新的生命周期函数:
- beforeUnmount:在 Vue 实例卸载之前被调用,类似于 beforeDestroy。
- unmounted:在 Vue 实例卸载后调用,类似于 destroyed。
这些生命周期函数允许您在 Vue 组件的不同阶段执行代码,以处理数据的初始化、DOM 操作、清理和其他自定义逻辑。请注意,Vue 3.x 版本中的 beforeMount 和 mounted 钩子函数在 2.x 版本中分别为 beforeMount 和 mounted。
# 3.官网流程图
# 二.组件之间的数据共享
# 1.组件之间的关系
在项目开发中,组件之间的最常见的关系分为如下两种:
① 父子关系
② 兄弟关系
# 2.父子数据共享
父子组件之间的数据共享
父子组件之间的数据共享又分为:
① 父 -> 子共享数据
② 子 -> 父共享数据
# 3.父到子的数据
父组件向子组件共享数据需要使用自定义属性。示例代码如下:
在 Vue 中,父组件向子组件传递数据可以使用自定义属性来实现。您可以通过在子组件上定义 props 属性来接收来自父组件的数据。
以下是一个简单的示例:
在父组件中,使用 v-bind 指令将数据传递给子组件的 props 属性:
<template>
<div>
<child-component :message="parentMessage"></child-component>
</div>
</template>
<script>
import ChildComponent from "./ChildComponent.vue";
export default {
components: {
ChildComponent,
},
data() {
return {
parentMessage: "Hello from parent component",
};
},
};
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
在子组件中,通过 props 属性接收来自父组件的数据:
<template>
<div>
<p>{{ message }}</p>
</div>
</template>
<script>
export default {
props: ["message"],
};
</script>
2
3
4
5
6
7
8
9
10
11
在上述示例中,父组件通过 v-bind 指令将parentMessage
数据传递给子组件的message
属性。子组件通过 props 属性声明message
,然后就可以在子组件的模板中使用该属性。
注意:父组件向子组件传递的数据是单向的,子组件无法直接修改父组件的数据。如果需要修改父组件的数据,可以使用自定义事件或 Vuex 等状态管理工具来实现。
props写法:
# 4.子到父的数据
子组件向父组件共享数据使用自定义事件。示例代码如下:
在 Vue 中,子组件向父组件共享数据可以通过自定义事件来实现。以下是实现的基本步骤:
- 在父组件中定义一个数据属性或变量,用于接收子组件传递的数据。
- 在父组件中注册一个自定义事件,并定义一个方法来处理该事件。
- 在子组件中触发自定义事件,并将需要共享的数据作为事件的参数传递给父组件。
下面是一个简单的示例:
在父组件中:
<template>
<div>
<h2>父组件</h2>
<p>接收到的数据:{{ sharedData }}</p>
<child-component @custom-event="handleCustomEvent"></child-component>
</div>
</template>
<script>
import ChildComponent from "./ChildComponent.vue";
export default {
components: {
ChildComponent,
},
data() {
return {
sharedData: "",
};
},
methods: {
handleCustomEvent(data) {
this.sharedData = data;
},
},
};
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
在子组件中:
<template>
<div>
<h3>子组件</h3>
<button @click="emitCustomEvent">传递数据给父组件</button>
</div>
</template>
<script>
export default {
methods: {
emitCustomEvent() {
const data = "这是要传递的数据";
this.$emit("custom-event", data);
},
},
};
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
在上面的示例中,子组件中的按钮被点击时,触发了自定义事件custom-event
,并将数据'这是要传递的数据'
作为参数传递给父组件。
父组件中的handleCustomEvent
方法接收到子组件传递的数据,并将其赋值给父组件的sharedData
属性。父组件中的模板中可以直接使用sharedData
来显示接收到的数据。
通过这种方式,子组件就可以将数据通过自定义事件的方式传递给父组件,实现数据的共享和交互。
# 5.兄弟数据共享
在 Vue 2.x 中,如果要实现兄弟组件之间的数据共享,可以使用 EventBus(事件总线)作为一种简单而有效的方案。
EventBus 是一个 Vue 实例,可以用作中央事件管理器,用于在组件之间传递消息和共享数据。以下是使用 EventBus 进行兄弟组件之间数据共享的基本步骤:
- 创建一个 EventBus 实例,在 Vue 应用的某个地方,例如在 main.js 文件中:
// main.js
import Vue from "vue";
// 创建EventBus实例
export const eventBus = new Vue();
2
3
4
5
- 在发送数据的组件中,通过 EventBus 实例触发事件,并传递数据:
// ComponentA.vue
import { eventBus } from "./main.js";
export default {
methods: {
sendDataToSibling() {
const data = "这是要共享的数据";
eventBus.$emit("custom-event", data);
},
},
};
2
3
4
5
6
7
8
9
10
11
- 在接收数据的组件中,通过 EventBus 实例监听事件,并在事件处理程序中获取共享的数据:
// ComponentB.vue
import { eventBus } from "./main.js";
export default {
data() {
return {
sharedData: "",
};
},
mounted() {
eventBus.$on("custom-event", this.handleCustomEvent);
},
beforeDestroy() {
eventBus.$off("custom-event", this.handleCustomEvent);
},
methods: {
handleCustomEvent(data) {
this.sharedData = data;
},
},
};
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
在上面的示例中,ComponentA 组件通过eventBus.$emit
方法触发了名为custom-event
的事件,并传递了数据。ComponentB 组件通过eventBus.$on
方法监听了custom-event
事件,并在事件处理程序handleCustomEvent
中获取到共享的数据并更新组件的sharedData
属性。
通过 EventBus,兄弟组件之间可以进行数据的传递和共享,实现解耦和灵活的通信机制。但是需要注意,过度使用 EventBus 可能导致代码维护上的困难和混乱,因此在设计 Vue 应用时,需要慎重考虑使用 EventBus 的场景和频率。
# 6.EventBus 的使用步骤
① 创建 eventBus.js 模块,并向外共享一个 Vue 的实例对象
② 在数据发送方,调用 bus.$emit('事件名称', 要发送的数据) 方法触发自定义事件
③ 在数据接收方,调用 bus.$on('事件名称', 事件处理函数) 方法注册一个自定义事件
# 7.总结
# 三.ref 引用
# 1.什么是 ref 引用
ref 用来辅助开发者在不依赖于 jQuery 的情况下,获取 DOM 元素或组件的引用。每个 vue 的组件实例上,都包含一个 $refs 对象,里面存储着对应的 DOM 元素或组件的引用。默认情况下,组件的 $refs 指向一个空对象。
# 2.使用 ref 引用 DOM 元素
如果想要使用 ref 引用页面上的 DOM 元素,则可以按照如下的方式进行操作:
# 3.使用 ref 引用组件实例
如果想要使用 ref 引用页面上的组件实例,则可以按照如下的方式进行操作:
# 4.控制文本框和按钮的按需切换
通过布尔值 inputVisible 来控制组件中的文本框与按钮的按需切换。示例代码如下:
# 5.让文本框自动获得焦点
当文本框展示出来之后,如果希望它立即获得焦点,则可以为其添加 ref 引用,并调用原生 DOM 对象的
.focus() 方法即可。示例代码如下:
# 6.this.$nextTick(cb) 方法
组件的 $nextTick(cb) 方法,会把 cb 回调推迟到下一个 DOM 更新周期之后执行。通俗的理解是:等组件的
DOM 更新完成之后,再执行 cb 回调函数。从而能保证 cb 回调函数可以操作到最新的 DOM 元素。
# 四.数组函数使用
# 1.数组的 somo 方法
在 Vue.js 中,你可以使用 some
方法来检查数组中的元素是否满足某个条件。some
方法会遍历数组中的每个元素,如果有任何一个元素满足条件,则返回 true
,否则返回 false
。
下面是在 Vue.js 中使用 some
方法的示例:
<template>
<div>
<ul>
<li v-for="item in items" :key="item.id">
{{ item.name }}
</li>
</ul>
<p v-if="hasSpecialItem">数组中存在特殊项。</p>
<p v-else>数组中不存在特殊项。</p>
</div>
</template>
<script>
export default {
data() {
return {
items: [
{ id: 1, name: "Item 1" },
{ id: 2, name: "Item 2" },
{ id: 3, name: "Special Item" },
{ id: 4, name: "Item 4" },
],
};
},
computed: {
hasSpecialItem() {
return this.items.some((item) => item.name === "Special Item");
},
},
};
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
在上面的示例中,我们有一个名为 numbers
的数组,然后在计算属性 hasEvenNumber
中使用了 some
方法来检查数组中是否存在偶数。如果数组中有任何一个元素满足 number % 2 === 0
这个条件,那么 hasEvenNumber
的值就为 true
,否则为 false
。
你可以在 Vue.js 的计算属性、方法或生命周期钩子中使用 some
方法,具体取决于你的需求。只要将要处理的数组放在 Vue 组件的 data
选项中,就可以在组件的其他地方使用 some
方法来检查数组中的元素了。
# 2.数组的 every 方法
非常抱歉之前的回答有误。在 JavaScript 中,确实存在 every
方法用于检查数组中的所有元素是否都满足指定的条件。
以下是在 Vue.js 中使用 every
方法的示例:
data() {
return {
numbers: [1, 2, 3, 4, 5]
};
},
computed: {
allEven() {
return this.numbers.every(number => number % 2 === 0);
}
}
2
3
4
5
6
7
8
9
10
在上述示例中,我们有一个名为 numbers
的数组,并在计算属性 allEven
中使用了 every
方法来检查数组中的所有元素是否都是偶数。如果数组中的所有元素都满足 number % 2 === 0
这个条件,那么 allEven
的值就为 true
,否则为 false
。
请注意,every
方法是 JavaScript 数组的方法,Vue.js 并未提供 every
方法。在 Vue.js 中,你可以在计算属性、方法或生命周期钩子中使用 JavaScript 数组的方法来操作和处理数组。
# 3.数组的 reduce 方法
在 Vue.js 中,你可以使用 reduce
方法来对数组进行累积计算。reduce
方法接受一个回调函数和一个初始值作为参数,然后将数组中的每个元素依次传入回调函数进行计算,并返回最终的累积结果。
以下是在 Vue.js 中使用 reduce
方法的示例:
data() {
return {
numbers: [1, 2, 3, 4, 5]
};
},
computed: {
sum() {
return this.numbers.reduce((accumulator, currentValue) => accumulator + currentValue, 0);
}
}
2
3
4
5
6
7
8
9
10
在上面的示例中,我们有一个名为 numbers
的数组,并在计算属性 sum
中使用了 reduce
方法来计算数组元素的总和。回调函数接受两个参数 accumulator
和 currentValue
,分别表示累积值和当前值。初始值为 0
。在每次迭代中,回调函数将累积值和当前值相加,并将结果作为下一次迭代的累积值。最终,sum
的值将是数组中所有元素的总和。
你可以根据需求自定义回调函数的逻辑来进行不同的累积计算。reduce
方法还可以接受第二个可选参数,用于指定回调函数的初始值。
需要注意的是,reduce
方法是 JavaScript 数组的方法,不是 Vue.js 提供的特定功能。在 Vue.js 中,你可以在计算属性、方法或生命周期钩子中使用普通的 JavaScript 数组方法,以对数组进行操作和处理。
# 4.数组的 forEach 方法
forEach
是 JavaScript 中 Array 类型的一个方法,用于迭代数组的每个元素并执行指定的操作。它提供了一种简洁的方式来遍历数组,而无需使用传统的 for 循环。
forEach
方法接受一个回调函数作为参数,该回调函数会在数组的每个元素上被调用一次,可以通过回调函数来对每个元素进行处理或执行其他操作。回调函数接受三个参数:当前元素的值、当前元素的索引和被遍历的数组本身。
以下是 forEach
方法的语法:
array.forEach(callback(currentValue, index, array))
其中,array
是要遍历的数组,callback
是回调函数。
下面是一个示例,展示如何使用 forEach
遍历数组并打印每个元素的值:
const array = [1, 2, 3, 4, 5];
array.forEach(function(element) {
console.log(element);
});
2
3
4
在回调函数中,我们可以对每个元素进行自定义操作。例如,我们可以计算数组中所有元素的总和:
const array = [1, 2, 3, 4, 5];
let sum = 0;
array.forEach(function(element) {
sum += element;
});
console.log(sum); // 输出 15
2
3
4
5
6
需要注意的是,forEach
方法没有返回值,它仅用于迭代数组中的每个元素。如果想要返回一个新的数组,可以考虑使用其他方法,如 map
。另外,由于 forEach
方法无法中断循环,因此在需要中断或提前终止循环的情况下,可能需要使用传统的 for 循环或其他迭代方法。
使用Lambda表达式:
const array = [1, 2, 3, 4, 5];
// 使用 forEach 和 Lambda 表达式遍历数组
array.forEach((element) => {
console.log(element);
});
2
3
4
5
6
# 五.购物车案例
# 1.实现步骤
① 初始化项目基本结构
② 封装 MyHeader 组件
③ 基于 axios 请求商品列表数据( GET 请求,地址为 https://www.escook.cn/api/cart )
④ 封装 MyFooter 组件
⑤ 封装 MyGoods 组件
⑥ 封装 MyCounter 组件
# 2.总结
① 能够知道 vue 中常用的生命周期函数
- 创建阶段、运行阶段、销毁阶段
- created、mounted
② 能够知道如何实现组件之间的数据共享
- 父 -> 子(自定义属性)
- 子 -> 父(自定义事件)
- 兄弟组件(EventBus)
③ 能够知道如何使用 ref 引用 DOM 元素或组件
- 给元素或组件添加 ref="xxx" 的引用名称
- 通过 this.$refs.xxx 获取元素或组件的实例
- $nextTick() 函数的执行时机
# 3.指令顺序
- 先指令
- 再属性
- 最后事件
# 4.子向祖父传数据
使用 Event Bus 是一种在 Vue.js 中实现子组件向多级父组件传递数据的方法。Event Bus 是一个中央事件管理器,允许组件之间进行解耦的通信。以下是使用 Event Bus 实现子组件向多级父组件传递数据的步骤:
- 创建一个全局的 Event Bus 实例,通常可以在
main.js
中创建:
// main.js
import Vue from "vue";
export const eventBus = new Vue();
2
3
4
- 在需要传递数据的子组件中,使用 Event Bus 的
$emit
方法触发一个自定义事件,并将数据作为参数传递给该事件:
// ChildComponent.vue
import { eventBus } from "@/main.js";
export default {
methods: {
sendDataToParent() {
const data = "Hello from child";
eventBus.$emit("data-to-parent", data);
},
},
};
2
3
4
5
6
7
8
9
10
11
- 在多级父组件中,使用 Event Bus 的
$on
方法监听子组件触发的自定义事件,并在回调函数中处理传递的数据:
// ParentComponent.vue
import { eventBus } from "@/main.js";
export default {
created() {
eventBus.$on("data-to-parent", this.handleDataFromChild);
},
methods: {
handleDataFromChild(data) {
// 处理从子组件传递的数据
console.log(data);
},
},
};
2
3
4
5
6
7
8
9
10
11
12
13
14
在上述代码中,子组件使用 eventBus.$emit('data-to-parent', data)
触发了一个名为 data-to-parent
的自定义事件,并将数据 data
传递给该事件。多级父组件使用 eventBus.$on('data-to-parent', this.handleDataFromChild)
监听子组件触发的事件,并在 handleDataFromChild
方法中处理传递的数据。
通过 Event Bus,子组件可以向多级父组件传递数据,实现了跨层级的组件通信。需要注意的是,在适当的时机(如组件销毁)应该使用 eventBus.$off
方法取消事件监听,避免内存泄漏。
# 5.属性传递不封装
如果封装成一个对象,会在使用的地方,不知道对应的是哪个具体的字段,因为可能有多个对应一个