一、Vue生命周期
生命周期是什么?
二、钩子函数
Vue框架内置函数,随着组件的生命周期阶段,自动执行!
场景:组件创建完毕后,可以在created生命周期函数中发起Ajax请求,从而初始化data数据
分为 四大阶段 8个方法
例如 before Create 初始化之前 created 初始化之后
阶段 | 方法名 | 方法名 |
初始化 | beforeCreate 初始化之前 | created 初始化之后 |
挂载 | beforeMount | mounted |
更新 | beforeUpdate | updated |
销毁 | beforeDestroy | destroyed |
1、如何知道Vue生命周期到达了什么阶段?
使用钩子函数
2、钩子函数有哪些?
初始化 / 挂载 / 更新 / 销毁
对应的方法有哪些
初始化 beforeCreate created
挂载 beforeMount mounted
更新 beforeUpdate updated
销毁 befoteDestroy destroyed
三、四大阶段
重点:
①new Vue() vue实例化组件
②Init Events & Lifecycle 初始化事件 和 生命周期函数
③beforeCreate 生命周期枸杞函数被执行
④created 生命周期钩子函数被执行
⑤Init injections&reactivity - Vue内部添加data 和 methods 等
⑥has el opition? 是否有 el 选项 检查挂载到哪里
没有 调用 $mount()方法
有 继续检查template选项
3.1初始化 beforeCreate() 和 created初始化之后
<script>
export default {
data(){
return {
msg: "hello, Vue"
}
},
// 一. 初始化
// new Vue()以后, vue内部给实例对象添加了一些属性和方法, data和methods初始化"之前"
beforeCreate(){
console.log("beforeCreate -- 执行");
console.log(this.msg); // undefined
},
// data和methods初始化以后
// 场景: 网络请求, 注册全局事件
created(){
console.log("created -- 执行");
console.log(this.msg); // hello, Vue
this.timer = setInterval(() => {
console.log("哈哈哈"); //所有函数执行完了再执行
}, 1000)
}
}
</script>
Vue实例从创建到编译模板执行了那些钩子函数?
beforeCreate/created
created 函数触发能获取到data?
能获取到data 但是不能获取真实的DOM
3.2挂载阶段 beforeMount 挂载之前 mounted 挂载之后
①template选项检查
有 - 编译template返回render渲染函数
无 – 编译el选项对应标签作为template(要渲染的模板)
②.虚拟DOM挂载成真实DOM之前
③.beforeMount – 生命周期钩子函数被执行
④.Create … – 把虚拟DOM和渲染的数据一并挂到真实DOM上
⑤.真实DOM挂载完毕
⑥.mounted – 生命周期钩子函数被执行
<script>
export default {
data(){
return {
msg: "hello, Vue"
}
},
// 一. 初始化
// new Vue()以后, vue内部给实例对象添加了一些属性和方法, data和methods初始化"之前"
beforeCreate(){
console.log("beforeCreate -- 执行");
console.log(this.msg); // undefined
},
// data和methods初始化以后
// 场景: 网络请求, 注册全局事件
created(){
console.log("created -- 执行");
console.log(this.msg); // hello, Vue
this.timer = setInterval(() => {
console.log("哈哈哈");
}, 1000)
}
}
</script>
在Vue实例从创建到显示都经历了那些钩子函数?
beforeCreate / created / before Mount / mounted
在 ceated 函数里面 能获取真实的DOM吗?
不能获取真实的DOM
在什么钩子函数可以获取真实的DOM
mounted
3.3更新阶段
①当data里数据改变,更新DOM之前
②beforeUpdate 生命周期钩子函数被执行
③Virtual DOM .... 虚拟DOM 重新渲染 打补丁到真实DOM
④updated - 生命周期钩子函数被执行
⑤当有data数据改变 - 重复这个循环
准备ul+li循环, 按钮添加元素, 触发data改变->导致更新周期开始
<template>
<div>
<p>学习生命周期 - 看控制台打印</p>
<p id="myP">{{ msg }}</p>
<ul id="myUL">
<li v-for="(val, index) in arr" :key="index">
{{ val }}
</li>
</ul>
<button @click="arr.push(1000)">点击末尾加值</button>
</div>
</template>
<script>
export default {
data(){
return {
msg: "hello, Vue",
arr: [5, 8, 2, 1]
}
},
// ...省略其他代码
// 三. 更新
// 前提: data数据改变才执行
// 更新之前
beforeUpdate(){
console.log("beforeUpdate -- 执行");
console.log(document.querySelectorAll("#myUL>li")[4]); // undefined
},
// 更新之后
// 场景: 获取更新后的真实DOM
updated(){
console.log("updated -- 执行");
console.log(document.querySelectorAll("#myUL>li")[4]); // li
}
}
</script>
什么时候执行updated 钩子函数
当数据发生变化 并更新页面后。
在哪里可以获取到更新后的DOM
在updated钩子函数里
3.4销毁阶段 beforeDestroy destroy
重点
①.当$destroy()被调用 – 比如组件DOM被移除(例v-if)
②.beforeDestroy – 生命周期钩子函数被执行
③.拆卸数据监视器、子组件和事件侦听器
④.实例销毁后, 最后触发一个钩子函数
⑤.destroyed – 生命周期钩子函数被执行
<script>
export default {
// ...省略其他代码
// 四. 销毁
// 前提: v-if="false" 销毁Vue实例
// 场景: 移除全局事件, 移除当前组件, 计时器, 定时器, eventBus移除事件$off方法
beforeDestroy(){
// console.log('beforeDestroy -- 执行');
clearInterval(this.timer) // 哈哈输出结束
},
destroyed(){
// console.log("destroyed -- 执行");
}
}
</script>
<Life v-if="show"></Life>
<button @click="show = false">销毁组件</button>
<script>
data(){
return {
show: true
}
},
</script>
小结:
一般在beforeDestroy / destroyed 里做什么?
手动消除计时器 / 定时器/ 全局事件
四、axios基本使用 -发布书籍 案例
axios 是一个专门用于发送ajax请求的库
1、官网: axios中文网|axios API 中文文档 | axios
2、特点
支持客户端发送Ajax请求
支持服务端Node.js发送请求
支持Promise相关用法
支持请求和响应的拦截器功能
自动转换JSON数据
axios 底层还是原生js实现, 内部通过Promise封装的
小结
1、什么是ajax?
一种前端异步请求后端的技术
2、ajax原理?
浏览器window接口的XMLHttpRequest
3、axios是什么?
基于原生ajax+Promise技术封装通用于前后端的请求库
案例:
获取所有图书信息
功能: 点击调用后台接口, 拿到所有数据 – 打印到控制台
接口: 参考预习资料.md – 接口文档
引入: 下载axios, 引入后才能使用
<template>
<div>
<div> Axios的使用 </div>
<div>
书名:<input type="text" v-model="bookname" /> <br />
作者:<input type="text" v-model="author" /><br />
出版社:<input type="text" v-model="publisher" /><br />
<button @click="submitBook()">提交图书</button>
</div>
</div>
</template>
<script>
//1、下载包npm install axios
//2、引入包import 变量 from "包名"
//3、使用axios
///api/getbooks
import axios from 'axios';
export default {
data() {
return {
bookname: '', //书名
author: '', //作者
publisher: '', //出版社
id: 189
};
},
async created() {
//axios.get(url,参数)
//axios原地会返回一个promise,也就是可以通过then和catch来捕获成功和失败的结果
//配置请求的基地址(接口请求的地址都是统一的,一个项目里面会有多个接口请求,所以统一地址统一配置)
axios.defaults.baseURL = 'http://ajax-api.itheima.net';
//不带参数的 get请求
// axios
// .get('/api/books')
// .then(res => {
// console.log(res);
// })
// .catch(() => {});
try {
//异步的请求会有返回值
//async和awsit一块使用
let data = await axios.get('/api/books');
console.log(data);
} catch (error) {
console.log(error);
}
//不带参数的 get请求
//直接使用axios方法,传入配置对象(url,请求方式,请求参数,、、、)
axios({
url: '/api/books',
method: 'get'
}).then(res => {
console.log(res);
});
//带参数的 get请求
axios({
// url: `/api/books/${this.id}`,
url: '/api/books/209',
method: 'get'
}).then(res => {
console.log(res);
});
},
methods: {
async submitBook() {
// 带参数的 post请求
// axios({
// url: '/api/books',
// method: 'post',
// data: {
// //过去的写法,拿input的值,元素.value
// bookname: this.bookname,
// author: this.author,
// publisher: this.publisher
// }
// }).then(res => {
// console.log(res);
// });
try {
let obj = {
url: '/api/books',
method: 'post',
data: {
//过去的写法,拿input的值,元素.value
bookname: this.bookname,
author: this.author,
publisher: this.publisher
}
};
let data = await axios(obj);
console.log(data);
} catch (error) {}
}
}
};
</script>
<style scoped></style>
小结
1、axios如何发起一次get请求?
在method选项配置为true / 也可以默认不写
2、axios函数调用原地结果是什么?
是一个Promise对象
3、如何拿到Promise里ajax的成功或失败的结果?
then() / catch()
五、$ref和$nextTick的使用
5.1$ref 获取原生dom元素
目前有两种获取方式 一个是通过ID 另一个通过ref 属性获取
真实的dom只有在 mounted 挂载之后才能获取到
①目标标签 - 添加 id / ref
②通过 id、ref属性获取
什么时候 用ref 什么时候用refs?
单个标签的时候使用 ref
多个标签的时候使用refs
<h1 id="h" ref="myH">获取原生</h1>
<h1 id="h2" ref="myHs">获取原生dom</h1>
mounted(){
console.log(document.getElementByID("h"))//h1
console.log(this.$refs)//myH myHS
console.log(this.$refs.myH); //myH
console.log(this.$refs.myHs); //myHs
}
5.1.1ref 组件对象
通过ref属性获取组件对象
1、创建Demo组件, 写一个方法
2、App.vue使用Demo组件, 给ref属性-名字随意
3、恰当时机, 通过ref属性 获取组件对象, 可调用组件对象里方法等
路径:components/Child/Demo.vue
<template>
<div>
<p>我是Demo组件</p>
</div>
</template>
<script>
export default {
methods: {
fn(){
console.log("demo组件内的方法被调用了");
}
}
}
</script>
More.vue - 获取组件对象 - 调用组件方法
<template>
<div>
<p>1. 获取原生DOM元素</p>
<h1 id="h" ref="myH">我是一个孤独可怜又能吃的h1</h1>
<p>2. 获取组件对象 - 可调用组件内一切</p>
<Demo ref="de"></Demo>
</div>
</template>
<script>
// 目标: 获取组件对象
// 1. 创建组件/引入组件/注册组件/使用组件
// 2. 组件起别名ref
// 3. 恰当时机, 获取组件对象
import Demo from './Child/Demo'
export default {
mounted(){
console.log(document.getElementById("h")); // h1
console.log(this.$refs.myH); // h1
let demoObj = this.$refs.de;
demoObj.fn()
},
components: {
Demo
}
}
</script>
小结
1、如何获取组件对象呢?
目标组件添加ref属性
this.$refs.名字 获取组件对象
2、拿到组件对象能做什么?
调用组件里的属性/方法
5.2nextTick基础使用
目标:点击改data,获取原生DOM内容
1、创建标签显示数据
2、点击+1,马上获取原生DOM内容
原因: Vue更新DOM是异步的
目标:等DOM更新后, 触发此方法里函数体执行
1、语法: this.$nextTick(函数体)
<template>
<div>
<p>1. 获取原生DOM元素</p>
<h1 id="h" ref="myH">我是一个孤独可怜又能吃的h1</h1>
<p>2. 获取组件对象 - 可调用组件内一切</p>
<Demo ref="de"></Demo>
<p>3. vue更新DOM是异步的</p>
<p ref="myP">{{ count }}</p>
<button @click="btn">点击count+1, 马上提取p标签内容</button>
</div>
</template>
<script>
// 目标: 获取组件对象
// 1. 创建组件/引入组件/注册组件/使用组件
// 2. 组件起别名ref
// 3. 恰当时机, 获取组件对象
import Demo from './Child/Demo'
export default {
mounted(){
console.log(document.getElementById("h")); // h1
console.log(this.$refs.myH); // h1
let demoObj = this.$refs.de;
demoObj.fn()
},
components: {
Demo
},
data(){
return {
count: 0
}
},
methods: {
///写法1
btn(){
this.count++; // vue监测数据更新, 开启一个DOM更新队列(异步任务)
console.log(this.$refs.myP.innerHTML); // 0
// 原因: Vue更新DOM异步
// 解决: this.$nextTick()
// 过程: DOM更新完会挨个触发$nextTick里的函数体
this.$nextTick(() => {
console.log(this.$refs.myP.innerHTML); // 1
})
}
///写法2 通过 async await promis 函数的异步同步
async btn(){
this.count++; // vue监测数据更新, 开启一个DOM更新队列(异步任务)
console.log(this.$refs.myP.innerHTML); // 0
await this.$nextTick()
this.$refs.myP.innerHTML
}
}
}
</script>
5.3nextTick使用场景
点击按钮自身隐藏, 出现输入框并马上处于激活状态
效果演示:
<template>
<div>
<input ref="myInp" type="text" placeholder="这是一个输入框" v-if="isShow">
<button v-else @click="btn">点击我进行搜索</button>
</div>
</template>
<script>
// 目标: 点按钮(消失) - 输入框出现并聚焦
// 1. 获取到输入框
// 2. 输入框调用事件方法focus()达到聚焦行为
export default {
data(){
return {
isShow: false
}
},
methods: {
async btn(){
this.isShow = true;
// this.$refs.myInp.focus()
// 原因: data变化更新DOM是异步的
// 输入框还没有挂载到真实DOM上
// 解决:
// this.$nextTick(() => {
// this.$refs.myInp.focus()
// })
// 扩展: await取代回调函数
// $nextTick()原地返回Promise对象
await this.$nextTick()
this.$refs.myInp.focus()
}
}
}
</script>