Vue生命周期:
紧跟前文,目标学习Vue2.0——3.0: 懂个锤子Vue、WebPack5.0、WebPack高级进阶 涉及的技术栈…
当然既然学习框架的了,HTML+CSS+JS三件套必须的就不说了: JavaScript 快速入门
Vue.js 的生命周期是指从组件实例创建到销毁的整个过程:
这个过程分为四个阶段:创建——挂载——更新——销毁
每个阶段都有相应的生命周期钩子函数;
创建阶段: 准备数据)
-
beforeCreate: 在实例初始化之后,进行数据侦听和事件/侦听器的配置之前同步调用;
在这个阶段,数据是获取不到的,并且真实dom元素也是没有渲染出来的
-
created: 实例创建完成后立即调用,这一步实例已完成对选项的处理;
意味着:数据侦听、计算属性、方法、事件/侦听器的回调函数,已被配置完毕,但,挂载阶段还没开始;
此阶段,可以访问到数据了:但是页面中真实DOM还没有渲染出来;
钩子函数:可以进行相关初始化事件的绑定、发送请求操作;
挂载阶段: 渲染模板)
-
beforeMount: 在挂载开始之前被调用:相关的 render 函数首次被调用;
DOM即将渲染出来,与created钩子函数用法基本一致,可以进行相关初始化事件的绑定、发送ajax操作
-
mounted: 实例被挂载后调用,
el
被新创建的vm.$e
替换,如果根实例挂载到了一个元素上,vm.$el
也在元素内;数据挂载完毕,真实dom元素已经渲染完成了,钩子函数内部可以做一些实例化相关的操作
更新阶段: 修改数据 → 更新视图)
-
beforeUpdate: 在数据发生改变后,DOM被更新之前被调用,适合在现有 DOM 将要被更新之前访问它;
钩子函数不会立即执行: 当组件挂载完毕的时候,数据发生改变的时候,立马执行;
钩子函数获取DOM的内容是更新之前的内容:
.innerHTML
-
updated: 在数据发生改变后、虚拟DOM重新渲染、更新完毕之后被调用,适合执行依赖于 DOM 的操作;
数据发现改变之后生成新的虚拟DOM,与之前的虚拟DOM进行比对,差异之后,就会进行真实DOM渲染;
updated钩子函数内,可以获取:diff算法更新之后的DOM内容;
销毁阶段: 注销Vue实例,清理资源占用
-
beforeDestory: 实例销毁之前调用,在这一步,实例仍然可用;
组件销毁的时候触发:钩子函数,可以做一些善后操作、清除一些初始化事件、定时器相关的东西;
-
destoryed: 实例销毁后调用:对应 Vue 实例的所有指令都被解绑、事件监听器被移除、所有的子实例也都被销毁
-
注意: 卸载之后页面还存在,因为卸载并不会清理DOM,但此时VUE实例已经无法操作了;
-
销毁操作: 有很多种通常是:
关闭浏览器
、调用: Vue实例.$destroy();
生命周期钩子Demo
<body>
<div id="app">
<h3>{
{ title }}</h3>
<div>
<button @click="count--">-</button>
<span>{
{ count }}</span>
<button @click="count++">+</button>
</div>
</div>
<script>
const app = new Vue({
el: '#app',
data: {
count: 100,
title: '计数器'
},
//创建阶段: 准备数据)
beforeCreate () {
console.log('beforeCreate 响应式数据准备好之前', this.count)
},
created () {
console.log('created 响应式数据准备好之后', this.count);
//this.数据名 获取请求回来的数据,函数内可以开始发送始化渲染的请求了;
},
//挂载阶段: 渲染模板)
beforeMount () {
console.log('beforeMount 模板渲染之前', document.querySelector('h3').innerHTML) },
mounted () {
console.log('mounted 模板渲染之后', document.querySelector('h3').innerHTML) },
//更新阶段: 修改数据 → 更新视图)
beforeUpdate () {
console.log('beforeUpdate 数据修改了',this.count,',视图还没更新', document.querySelector('span').innerHTML) },
updated () {
console.log('updated 数据修改了',this.count,',视图已经更新', document.querySelector('span').innerHTML) },
//卸载阶段: 注销Vue实例,清理资源占用
beforeDestroy () {
console.log('beforeDestroy, 卸载前')
console.log('清除掉一些Vue以外的资源占用,定时器,延时器...')
},
destroyed () {
console.log('destroyed卸载后: Vue实例失去活性,完全丧失功能,但并不会清理DOM')
}
})
</script>
</body>
生命周期钩子函数案例:
介绍最常用的钩子函数: created
、mounted
处于创建和挂载阶段、一般来说页面加载过程中执行、定义的操作;
updated
: 属于使用过程中执行的钩子函数,update更多会被计算属性、watcher
取而代之;
distroyed
: Vue实例销毁后调用,通常用于对资源的回收操作;
created应用:
Vue实例创建完成后调用,适合在此阶段进行数据初始化和网络请求,
注意事项:data
、methods
数据已经可用,但 DOM 还未生成,不能进行 DOM 操作;
Demo案例: 在created
中将 message
的值从 'Hello, Vue!'
修改为 'Hello, World!
,定义一个初始化请求数据;
//因为内部涉及到异步操作,所以为了稳定执行顺序需要 async\await
async created () {
console.log('created: 组件实例已创建');
//发送请求获取数据,更新到 list 中,用于页面渲染 v-for
const res = await axios.get('http://127.0.0.1:3000/news/list');
this.list = res.data.data.newsList;
//在 created 钩子中进行数据初始化
this.newsTitle = 'M新闻';
},
mounted应用:
Vue实例挂载到 DOM 上后调用,适合在此阶段进行依赖于 DOM 的操作,如获取 DOM 元素、发起异步请求等;
Demo案例: 在 mounted
钩子中使用 this.$nextTick
确保 DOM 已经完全渲染,然后将 <h1>
元素的颜色设置为蓝色
mounted() {
console.log('mounted: 组件已挂载到 DOM');
// 在 mounted 钩子中进行 DOM 操作
this.$nextTick(() => {
const h1Element = this.$el.querySelector('h1');
h1Element.style.color = 'blue';
});
}
小黑记账清单:
文档学习借鉴于黑马,但为了接口稳定,本人自己使用Express搭建了后端环境:
原黑马接口文档: https://www.apifox.cn/apidoc/shared-24459455-ebb1-4fdc-8df8-0aff8dc317a8/api-53371058
<body>
<div id="app">
<div class="contain">
<!-- 左侧列表 -->
<div class="list-box">
<!-- 添加资产 -->
<form class="my-form">
<input type="text" class="form-control" placeholder="消费名称" />
<input type="text" class="form-control" placeholder="消费价格" />
<button 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>
<td>1</td>
<td>帽子</td>
<td>99.00</td>
<td><a href="javascript:;">删除</a></td>
</tr>
<tr>
<td>2</td>
<td>大衣</td>
<td class="red">199.00</td>
<td><a href="javascript:;">删除</a></td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="4">消费总计: 298.00</td>
</tr>
</tfoot>
</table>
</div>
<!-- 右侧图表 -->
<div class="echarts-box" id="main"></div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/echarts.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
/**
* 接口文档地址:学习借鉴于黑马,但为了接口稳定,本人自己使用Express搭建了后端环境;
* https://www.apifox.cn/apidoc/shared-24459455-ebb1-4fdc-8df8-0aff8dc317a8/api-53371058
*
* 功能需求:
* 1. 基本渲染
* 2. 添加功能
* 3. 删除功能
* 4. 饼图渲染
*/
const app = new Vue({
el: '#app',
data: {
},
})
</script>
</body>
页面渲染:
页面渲染: 窗口打开立刻发送请求获取数据 created
,拿到数据,存到data
的响应式数据中,
结合数据,进行渲染 v-for
,消费统计 —> 计算属性computed
请求接口: http://127.0.0.1:3000/goodsBill/goodsBillList
<!-- ....省略部分代码 -->
<body>
<div id="app">
<div class="contain">
<!-- 左侧列表 -->
<div class="list-box">
<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>{
{item.price}}</td>
<td><a href="javascript:;">删除</a></td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="4">消费总计: {
{ totalPrice.toFixed(2) }}</td>
</tr>
</tfoot>
</table>
</div>
</div>
</div>
<script>
/**
* 接口文档地址:学习借鉴于黑马,但为了接口稳定,本人自己使用Express搭建了后端环境;
* https://www.apifox.cn/apidoc/shared-24459455-ebb1-4fdc-8df8-0aff8dc317a8/api-53371058 */
const app = new Vue({
el: '#app',
data: {
list:[],
},
computed: {
totalPrice () {
return this.list.reduce((sum, item) => sum + item.price, 0) }
},
async created () {
const res = await axios.get('http://127.0.0.1:3000/goodsBill/goodsBillList');
this.list = res.data.data
}
})
</script>
</body>
</html>
新增商品账单:
新增商品账单: 收集表单数据v-model (Vue优点直接获取数据
,使用指令修饰符处理数据,
Vue实例中定义新增函数methods:{ add(){ ... } }
,并添加按钮注册点击事件:对输入的内容做非空判断,发送请求;
请求成功后,对文本框内容进行清空,并重新渲染列表数据,所以就需要重新请求goodsBillList
,为了方便也可以定义函数;
优化:created中页面加载过程中的请求,调用:methods
,created阶段:可以访问到数据、函数;
调用接口: http://127.0.0.1:3000/goodsBill/addgoodsBill
、{ 'name':'汪汪雪饼','price':5 }
<!-- ....省略部分代码 -->
<body>
<div id="app">
<div class="contain">
<!-- 左侧列表 -->
<div class="list-box">
<!-- 添加资产 -->
<form class="my-form">
<input type="text" class="form-control" placeholder="消费名称" v-model.trim="name" />
<input type="text" class="form-control" placeholder="消费价格" v-model.number="price" />
<button type="button" class="btn btn-primary" @click="add" >添加账单</button>
</form>
<!-- ....省略部分代码 -->
</div>
</div>
</div>
<script>
/**
* 接口文档地址:学习借鉴于黑马,但为了接口稳定,本人自己使用Express搭建了后端环境;
* https://www.apifox.cn/apidoc/shared-24459455-ebb1-4fdc-8df8-0aff8dc317a8/api-53371058 */
const app = new Vue({
el: '#app',
data: {
list:[],
name: '',
price: ''
},
computed: {
totalPrice () {
return this.list.reduce((sum, item) => sum + item.price, 0) }
},
async created () {
// const res = await axios.get('http://127.0.0.1:3000/goodsBill/goodsBillList');
// this.list = res.data.data
// 优化:created阶段:可以访问到数据、函数, 但是页面中真实DOM还没有渲染出来;
// 所以可以调用methods中的请求接口函数,实现页面渲染,优化代码结构;
this.getList(); //渲染数据;
},
methods: {
//页面渲染:
async getList(){
const res = await axios.get('http://127.0.0.1:3000/goodsBill/goodsBillList');
this.list = res.data.data;
},
//新增商品账单:
async add(){
// 验证数据非空\发送添加请求\重新渲染数据;
if (!this.name) {
return alert('请输入消费名称'); }
if (typeof this.price !== 'number') {
return alert('请输入正确的消费价格') }
const res = await axios.post('http://127.0.0.1:3000/goodsBill/addgoodsBill', {
//发送添加请求
name: this.name,
price: this.price
})
this.getList(); //重新渲染数据;
//置空数据
this.name = ''
this.price = ''
},
//删除商品账单:
async del (id) {
}
}
})
</script>
</body>
</html>
删除商品账单:
删除商品账单: 注册点击事件,获取当前行的id
,根据id
发送删除请求,重新渲染列表
调用接口: DELTE http://127.0.0.1:3000/goodsBill/delgoodsBill/:id
商品账单饼图渲染:
前端领域图形渲染:一定离不开的三方依赖:Apache ECharts 内置了丰富的图形组件,轻松的进行数据展示;
引入Echarts依赖: https://cdn.jsdelivr.net/npm/[email protected]/dist/echarts.min.js
创建一个容器用于展示组件、mounted
函数中DOM已经渲染完成,在其中初始化图形;
在每次数据修改之后,更新图形中的数据,重新渲染图形;
<!-- ....省略部分代码 -->
<body>
<div id="app">
<div class="contain">
<!-- 左侧列表 -->
<!-- 右侧图表: 创建一个容器用于展示组件-->
<div class="echarts-box" id="main"></div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/echarts.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
/**
* 接口文档地址:学习借鉴于黑马,但为了接口稳定,本人自己使用Express搭建了后端环境;
* https://www.apifox.cn/apidoc/shared-24459455-ebb1-4fdc-8df8-0aff8dc317a8/api-53371058 */
const app = new Vue({
el: '#app',
data: {
list:[],
name: '',
price: ''
},
mounted(){
//`mounted`函数中DOM已经渲染完成,在其中初始化图形;
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('http://127.0.0.1:3000/goodsBill/goodsBillList');
this.list = res.data.data;
//在每次数据修改之后,更新图形中的数据,重新渲染图形;
this.myChart.setOption({
series: [
{
data: this.list.map(item => ({
value: item.price, name: item.name}))
}
]
})
}
}
})
</script>
</body>
</html>
代码GZH回复: Vue生命周期