Vue基础入门到实战3(生命周期+工程化开发+组件化开发)

1 Vue生命周期

1.1 简介

思考:什么时候可以发送初始化渲染请求?(越早越好)什么时候可以开始操作dom?(至少dom得渲染出来)

Vue生命周期:就是一个Vue实例从创建 到 销毁 的整个过程。

生命周期四个阶段:① 创建 ② 挂载 ③ 更新 ④ 销毁

1.创建阶段:创建响应式数据;

2.挂载阶段:渲染模板;

3.更新阶段:修改数据,更新视图;

4.销毁阶段:销毁Vue实例。

68206593781

1.2 Vue生命周期钩子

Vue生命周期过程中,会 自动运行一些函数,被称为【生命周期钩子】→ 让开发者可以在【特定阶段】运行 自己的代码

68206604029

1
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
<div id="app">
<h3>{{ title }}</h3>
<div>
<button @click="count--">-</button>
<span>{{ count }}</span>
<button @click="count++">+</button>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
count: 100,
title: '计数器'
},
// 1. 创建阶段(准备数据)
beforeCreate () {
console.log('beforeCreate 响应式数据准备好之前', this.count)
},
created () {
console.log('created 响应式数据准备好之后', this.count)
// this.数据名 = 请求回来的数据
// 可以开始发送初始化渲染的请求了
},

// 2. 挂载阶段(渲染模板)
beforeMount () {
console.log('beforeMount 模板渲染之前', document.querySelector('h3').innerHTML)
},
mounted () {
console.log('mounted 模板渲染之后', document.querySelector('h3').innerHTML)
// 可以开始操作dom了
},

// 3. 更新阶段(修改数据 → 更新视图)
beforeUpdate () {
console.log('beforeUpdate 数据修改了,视图还没更新', document.querySelector('span').innerHTML)
},
updated () {
console.log('updated 数据修改了,视图已经更新', document.querySelector('span').innerHTML)
},

// 4. 卸载阶段
beforeDestroy () {
console.log('beforeDestroy, 卸载前')
console.log('清除掉一些Vue以外的资源占用,定时器,延时器...')
},
destroyed () {
console.log('destroyed,卸载后')
}
})
</script>

1.3 生命周期钩子小案例

在created中发送数据

1
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
<style>
* {
margin: 0;
padding: 0;
list-style: none;
}
.news {
display: flex;
height: 120px;
width: 600px;
margin: 0 auto;
padding: 20px 0;
cursor: pointer;
}
.news .left {
flex: 1;
display: flex;
flex-direction: column;
justify-content: space-between;
padding-right: 10px;
}
.news .left .title {
font-size: 20px;
}
.news .left .info {
color: #999999;
}
.news .left .info span {
margin-right: 20px;
}
.news .right {
width: 160px;
height: 120px;
}
.news .right img {
width: 100%;
height: 100%;
object-fit: cover;
}
</style>

<div id="app">
<ul>
<li v-for="(item, index) in list" :key="item.id" class="news">
<div class="left">
<div class="title">{{ item.title }}</div>
<div class="info">
<span>{{ item.source }}</span>
<span>{{ item.time }}</span>
</div>
</div>
<div class="right">
<img :src="item.img" alt="">
</div>
</li>
</ul>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script>
// 接口地址:http://hmajax.itheima.net/api/news
// 请求方式:get
const app = new Vue({
el: '#app',
data: {
list: []
},
async created(){
// 1. 发送请求获取数据
const res = await axios.get('http://hmajax.itheima.net/api/news')
// 2. 更新到 list 中,用于页面渲染 v-for
this.list = res.data.data
}
})
</script>

1.4 案例-小黑记账清单

1.4.1 需求图示

68207197208

1.4.2 需求分析

1.基本渲染

2.添加功能

3.删除功能

4.饼图渲染

1.4.3 思路分析

1.基本渲染

  • 立刻发送请求获取数据 created
  • 拿到数据,存到data的响应式数据中
  • 结合数据,进行渲染 v-for
  • 消费统计 —> 计算属性

2.添加功能

  • 收集表单数据 v-model,使用指令修饰符处理数据
  • 给添加按钮注册点击事件,对输入的内容做非空判断,发送请求
  • 请求成功后,对文本框内容进行清空
  • 重新渲染列表

3.删除功能

  • 注册点击事件,获取当前行的id
  • 根据id发送删除请求
  • 需要重新渲染

4.饼图渲染

  • 初始化一个饼图 echarts.init(dom) mounted钩子中渲染
  • 根据数据试试更新饼图 echarts.setOptions({…})

1.4.4 代码准备

1
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<!-- CSS only -->
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css"
/>
<style>
.red {
color: red !important;
}
.search {
width: 300px;
margin: 20px 0;
}
.my-form {
display: flex;
margin: 20px 0;
}
.my-form input {
flex: 1;
margin-right: 20px;
}
.table > :not(:first-child) {
border-top: none;
}
.contain {
display: flex;
padding: 10px;
}
.list-box {
flex: 1;
padding: 0 30px;
}
.list-box a {
text-decoration: none;
}
.echarts-box {
width: 600px;
height: 400px;
padding: 30px;
margin: 0 auto;
border: 1px solid #ccc;
}
tfoot {
font-weight: bold;
}
@media screen and (max-width: 1000px) {
.contain {
flex-wrap: wrap;
}
.list-box {
width: 100%;
}
.echarts-box {
margin-top: 30px;
}
}
</style>
</head>
<body>
<div id="app">
<div class="contain">
<!-- 左侧列表 -->
<div class="list-box">
<!-- 添加资产 -->
<form class="my-form">
<input
v-model="name"
type="text"
class="form-control"
placeholder="消费名称"
/>
<input
v-model.number="price"
type="text"
class="form-control"
placeholder="消费价格"
/>
<button @click="add" type="button" class="btn btn-primary">
添加账单
</button>
</form>

<table class="table table-hover">
<thead>
<tr>
<th>编号</th>
<th>消费名称</th>
<th>消费价格</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr v-for="(item, index) in list" :key="item.id">
<td>{{ index+1 }}</td>
<td>{{ item.name }}</td>
<td :class="{red:item.price>500}">
{{ item.price.toFixed(2) }}
</td>
<td><a @click="del(item.id)" href="javascript:;">删除</a></td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="4">消费总计: {{ totalPrice.toFixed(2) }}</td>
</tr>
</tfoot>
</table>
</div>

<!-- 右侧图表 -->
<div class="echarts-box" id="main"></div>
</div>
</div>
<script src="../echarts.min.js"></script>
<script src="../vue.js"></script>
<script src="../axios.js"></script>
<script>
/**
* 接口文档地址:
* https://www.apifox.cn/apidoc/shared-24459455-ebb1-4fdc-8df8-0aff8dc317a8/api-53371058
*
* 功能需求:
* 1. 基本渲染
* 2. 添加功能
* (1) 收集表单数据 v-model
* (2) 给添加按钮注册点击事件,发送添加请求
* (3) 需要重新渲染
* 3. 删除功能
* 4. 饼图渲染
* (1) 初始化一个饼图 echarts.init(dom) mounted钩子实现
* (2) 根据数据实时更新饼图 echarts.setOption({ ... })
*/
const app = new Vue({
el: "#app",
data: {
list: [],
name: "",
price: "",
},
computed: {
totalPrice() {
return this.list.reduce((sum, item) => sum + item.price, 0);
},
},
async created() {
this.getList();
},
mounted() {
// 初始化
this.myChart = echarts.init(document.querySelector("#main"));
this.myChart.setOption({
// 大标题
title: {
text: "消费账单列表",
left: "center",
},
// 提示框
tooltip: {
trigger: "item",
},
// 图例
legend: {
orient: "vertical",
left: "left",
},
// 数据项
series: [
{
name: "消费账单",
type: "pie",
radius: "50%", // 半径
data: [
// { value: 1048, name: '球鞋' },
// { value: 735, name: '防晒霜' }
],
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: "rgba(0, 0, 0, 0.5)",
},
},
},
],
});
},
methods: {
async getList() {
const res = await axios.get(
"https://applet-base-api-t.itheima.net/bill",
{
params: {
creator: "小美",
},
}
);
console.log(res.data.data);
this.list = res.data.data;
// 每次获取数据的时候,顺便更新饼图
this.myChart.setOption({
// 数据项
series: [
{
data: this.list.map((item) => ({
value: item.price,
name: item.name,
})),
},
],
});
},
async add() {
if (this.name === "") {
alert("物品名称不能为空");
return;
}
if (typeof this.price !== "number") {
alert("价格必须为数字");
return;
}
const res = await axios.post(
"https://applet-base-api-t.itheima.net/bill",
{
creator: "小美",
name: this.name,
price: this.price,
}
);
console.log(res.data.data);
// 重新拉数据
this.getList();
this.name = "";
this.price = "";
},
async del(id) {
const res = await axios.delete(
`https://applet-base-api-t.itheima.net/bill/${id}`
);
this.getList();
},
},
});
</script>
</body>
</html>

2 工程化开发和脚手架

2.1 开发Vue的两种方式

  • 核心包传统开发模式:基于html / css / js 文件,直接引入核心包,开发 Vue。
  • 工程化开发模式:基于构建工具(例如:webpack)的环境中开发Vue。

68209003907

工程化开发模式优点:

提高编码效率,比如使用 JS 新语法、Less/Sass、Typescript 等通过 webpack 都可以编译成浏览器识别的 ES3/ES5/CSS 等

工程化开发模式问题:

  • webpack 配置 不简单
  • 雷同 的基础配置
  • 缺乏 统一的标准

为了解决以上问题,所以我们需要一个工具,生成标准化的配置

2.2 脚手架Vue CLI

Vue CLI 是Vue官方提供的一个 全局命令工具。可以帮助我们 快速创建 一个开发Vue项目的 标准化基础架子。【集成了webpack配置】

好处

  1. 开箱即用,零配置
  2. 内置babel等工具
  3. 标准化的webpack配置

使用步骤

  1. 全局安装(只需安装一次即可) yarn global add @vue/cli 或者 npm i @vue/cli -g
  2. 查看 vue/cli 版本: vue --version
  3. 创建项目架子:vue create project-name(项目名不能使用中文)
  4. 启动项目:yarn serve 或者 npm run serve(命令不固定,找package.json)

2.3 项目目录介绍

68209214852

虽然脚手架中的文件有很多,目前咱们只需记住三个文件即可

  1. main.js 入口文件
  2. App.vue App根组件
  3. index.html 模板文件

2.4 运行流程

68209403287

3 组件化开发

组件化:一个页面可以拆分成一个个组件,每个组件有着自己独立的结构、样式、行为。

好处:便于维护,利于复用 → 提升开发效率。

组件分类:普通组件、根组件。

比如:下面这个页面,可以把所有的代码都写在一个页面中,但是这样显得代码比较混乱,难易维护。咱们可以按模块进行组件划分

68216885237

3.1 根组件 App.vue

3.1.1 根组件介绍

整个应用最上层的组件,包裹所有普通小组件

68216913168

3.1.2 组件是由三部分构成

  • 语法高亮插件

68216926426

  • 三部分构成

    • template:结构 (有且只能一个根元素)
    • script: js逻辑
    • style: 样式 (可支持less,需要装包)
  • 让组件支持less

    (1) style标签,lang=“less” 开启 less 功能

    (2) 装包: yarn add less less-loader -D 或者npm i less less-loader -D

3.2 普通组件的注册使用-局部注册

只能在注册的组件内使用。

步骤

  1. 创建.vue文件(三个组成部分)
  2. 在使用的组件内先导入再注册,最后使用

注意

组件名规范 —> 大驼峰命名法, 如 HmHeader

语法

使用方式:当成html标签使用即可 <组件名></组件名>

68222796681

1
2
3
4
5
6
7
8
9
10
11
12
// 导入需要注册的组件
import 组件对象 from '.vue文件路径'
import HmHeader from './components/HmHeader'

export default { // 局部注册
  components: {
   '组件名': 组件对象,
    HmHeader:HmHeaer,
// 名字相同可以简写
HmHeader
}
}

3.3 普通组件的注册使用-全局注册

全局注册的组件,在项目的任何组件中都能使用

步骤

  1. 创建 .vue 组件(三个组成部分)
  2. main.js 中进行全局注册

注意

组件名规范 —> 大驼峰命名法, 如 HmHeader

语法

当成 HTML 标签直接使用

<组件名></组件名>

main.js 中书写 Vue.component('组件名', 组件对象)

例:

1
2
3
// 导入需要全局注册的组件
import HmButton from './components/HmButton'
Vue.component('HmButton', HmButton)

Vue基础入门到实战3(生命周期+工程化开发+组件化开发)
https://fulequn.github.io/2024/06/Article202406051/
作者
Fulequn
发布于
2024年6月5日
许可协议