1. watch侦听器
wach侦听器允许开发者监视数据的变化,从而针对数据的变化做特定的操作。例如,监视用户名的变化并发起请求,判断用户名是否可用。
1.1 基本语法
开发者需要在watch节点下,定义自己的侦听器:
export default{ | |
data(){ | |
return { username:'' } | |
}, | |
watch:{ | |
username(newVal,oldVal){ | |
console.log(newVal,oldVal) | |
}, | |
}, | |
} |
1.2 检测用户名是否可用
import axios from 'axios' | |
export default{ | |
data(){ | |
return {username:''} | |
}, | |
watch:{ | |
async username(newVal,oldVal){ | |
const {data:res} =await axios.get('https://www.abv,com/api/${newVal}') | |
console.log(res) | |
} | |
} | |
} |
1.3 immediate选项
默认情况下,组件在初次加载完毕后不会调用watch侦听器,如果想让watch侦听器立即被调用,则需要使用 immediate
选项:
watch: { | |
// 1.监听username的变化 | |
username: { | |
// 2.handler属性是固定写法,当username变化时,调用handler | |
async handler(newVal, oldVal) { | |
const { data: res } = await axios.get('https://www.abv,com/api/${newVal}'); | |
console.log(res); | |
}, | |
//3.表示组件加载完毕后立即调用一次当前的watch侦听器 | |
immediate: true, | |
}, | |
}, |
1.4 deep选项
当watch侦听的是一个对象,如果对象中的属性值发生了变化,则无法被监听到,此时需要用到deep选项:
data() { | |
return { | |
info: { username: 'admin' }, //info中包含username属性 | |
}; | |
}, | |
watch: { | |
// 直接监听info对象的变化 | |
info: { | |
async handler(newVal, oldVal) { | |
const { data: res } = await axios.get('https://www.abv,com/api/${newVal.username}'); | |
console.log(res); | |
}, | |
deep: true, //需要使用deep选项,否则username的值无法被监听到 | |
}, | |
}, |
1.5 监听对象单个属性的变化
如果只想监听对象中单个属性的变化,则可以按照如下的方式定义watch侦听器:
data() { | |
return { | |
info: { username: 'admin', password: '' }, //info中包含username属性 | |
}; | |
}, | |
watch: { | |
'info.username': { | |
//只想监听info.username属性值的变化 | |
async handler(newVal, oldVal) { | |
const { data: res } = await axios.get('https://www.abv,com/api/${newVal}'); | |
console.log(res); | |
}, | |
}, | |
}, |
1.6 计算属性 VS 侦听器
计算属性和侦听器侧重的应用场景不同:
- 计算属性侧重于监听多个值的变化,最终计算并返回一个新值
- 侦听器侧重于监听单个数据的变化,最终执行特定的业务处理,不需要有任何返回值
2. 组件的生命周期
组件的生命周期指的是:组件从创建->运行(渲染)->销毁的整个过程,强调的是一个时间段。
开始 —> import导入组件 —> components注册组件 —> 以标签形式使用组件 —> 在内存中创建组件的实例对象 —> 把创建的组件实例渲染到页面上 —> 组件切换时销毁需要被隐藏的组件 —> 结束
2.1 监听组件的不同时刻
vue框架为组件内置了不同时刻的生命周期函数,生命周期函数回伴随着组件的运行而自动调用。
- 当组件在内存中被
创建
完毕之后,会自动调用created
函数。 - 当组件被成功的
渲染
到页面上之后,会自动调用mounted
函数。 - 当组件被
销毁
完毕之后,会自动调用unmounted
函数
2.2 监听组件的更新
当组件的data数据更新之后,vue会自动重新渲染组件的DOM结构,从而保证View视图展示的数据和Model数据源保持一致。
当组件被重新渲染完毕之后,会自动调用updated生命周期函数。
2.3完整的生命周期函数
3. 组件之间的数据共享
3.1组件之间的关系
在项目开发中,组件之间的关系分为如下3种:
- 父子关系
- 兄弟关系
- 后代关系
3.2 父子组件之间的数据共享
父子组件之间的数据共享又分为:
- 父 -> 子共享数据
- 子 -> 父共享数据
- 父 <-> 子双向数据同步
3.3.1 父组件向子组件共享数据
父组件通过v-bind属性绑定向子组件共享数据:
<MyTest :msg="message" :user="userinfo"></MyTest> | |
data(){ | |
return{ | |
message:'hello vue', | |
userinfo:{name:'zs'age:20}, | |
} | |
} |
同时,子组件需要使用props接收数据:
//子组件 | |
<template> | |
<h3>测试父子传值 </h3> | |
<p> {{msg}} </p> | |
<p> {{user}} </p> | |
</template> | |
<script> | |
export default{ | |
props:['msg','user'], | |
} | |
</script> |
3.3.2 子组件向父组件共享数据
子组件通过自定义事件的方式向父组件共享数据:
//子组件 | |
export default{ | |
emits:['nchange'],//1.声明自定义事件 | |
data(){return {n:0}}, | |
methods:{ | |
addN(){ | |
this.n++ | |
//2.数据变化时,触发自定义的事件 | |
this.$emit('nchange',this.n) | |
} | |
} | |
} | |
//父组件 | |
//1.监听子组件的自定义事件 nchange | |
<MyTest ="getn"></MyTest> | |
export default{ | |
data(){return{nFormSon:0}}, | |
methods:{ | |
getn(n){//1.通过形参,接收子组件传递过来的数据 | |
this.nFromSon=n | |
} | |
} | |
} |
3.3.3 父子组件之间数据的双向同步
父组件在使用子组件期间,可以使用v-model指令维护组件内外数据的双向同步:
3.3 兄弟组件之间的数据共享
兄弟组件之间实现数据共享的方案是EventBus。可以借助于第三方的包mitt来创建eventBus对象,从而实现兄弟组件之间的数据共享。
创建EventBus
const bus = mitt() | |
export defult bus |
在数据的接收方和发送方共享EventBus对象
导入并得到EventBus实例对象
import bus from './eventBus.js'
调用EventBus的on()方法,声明自定义事件,通过事件回调接收数据
bus.on('自定义事件',(data)=>{})
3.4.1 具体步骤
1. 安装mitt依赖包
在项目中运行如下的命令,安装mitt依赖包
npm install mitt@2.1.0
2. 创建公共的EventBus模块
在项目中创建公共的eventBus模块:
//eventBus.js | |
//导入mitt包 | |
import mitt from 'mitt' | |
//创建EventBus的实例对象 | |
const bus = mitt() | |
//将EventBus的实例对象共享出去 | |
export default bus |
3. 在数据接收方自定义事件
在数据接收方,调用 bus.on('事件名称',事件处理函数)
方法注册一个自定义事件:
//导入eventBus.js模块,得到共享的bus对象 | |
import bus from './eventBus.js' | |
export default{ | |
data(){return {count:0}}, | |
created(){ | |
//调用bus.on()方法注册一个自定义事件,通过处理函数的形参接收数据 | |
bus.on('countChange',(count)=>{ | |
this.count = count | |
} | |
} | |
} |
4. 在数据发送方触发事件
在数据发送方,调用bus.emit('事件名称',要发送的数据)方法触发自定义事件:
//导入eventBus.js模块,得到共享的bus对象 | |
import bus from './eventBus.js' | |
export default{ | |
data(){return{count:0}}, | |
methods:{ | |
addCount(){ | |
this.count++ | |
bus.emit('countChange',this.count)//调用bus.emit()方法触发自定义事件,并发送数据 | |
} | |
} | |
} |
3.4 后代关系组件之间的数据共享
后代关系组件之间共享数据,指的是父节点的组件向其子孙组件共享数据。
此时组件之间的嵌套关系比较复杂,可以使用provide和inject实现后代关系组件之间的数据共享。
3.4.1 父节点通过provide共享数据
父节点的组件可以通过 provide 方法,对其子孙组件共享数据:
export default{ | |
data(){ | |
return{ | |
color:'red'//定义父组件要向子孙组件共享的数据 | |
} | |
}, | |
provide(){//provide函数return的对象中,包含了要向子孙组件共享的数据 | |
return{ | |
color:this.color, | |
} | |
}, | |
} |
3.4.2 子孙节点通过inject接收数据
子孙节点可以使用inject数组,接收父级节点向下共享的数据:
export default{ | |
inject:['color'], | |
} |
3.4.3 父节点对外共享响应式的数据
父节点使用provide向下共享数据时,可以结合computed函数向下共享响应式的数据。
import {computed} from 'vue' //从vue中按需导入computed函数 | |
export default{ | |
data(){ | |
return{color:'red'} | |
}, | |
provide(){ | |
return{ | |
color:computed(()=>this.color), | |
} | |
}, | |
} |
3.4.4 子孙节点使用响应式的数据
如果父级节点共享的是响应式的数据,则子孙节点必须以.value的形式使用。
<template> | |
<h5>子孙组件--- {{color.value}} </h5> | |
</template> | |
<script> | |
export default{ | |
//接收响应式color数据,并在页面上使用 | |
inject:['color'], | |
} | |
</script> |
3.5 vuex
vuex 是终极的组件之间的数据共享方案,在企业级的vue项目开发中,vuex可以让组件之间的数据共享变得更高效、清晰、且易于维护。
Vue3.x中全局配置axios
在实际项目开发中,几乎每个组件都会用到axios发起数据请求,此时会遇到如下两个问题:
- 每个组件中都需要导入axios(代码臃肿)
- 每次发请求都需要填写完整的请求路径(不利于后期的维护)
配置方式
在main.js入口文件中,通过 app.config.globalProperties
全局挂载axios
//为axios配置请求的根路径 | |
axios.defaults.baseURL='http://api.com' | |
//将axios挂载为app的全局自定义属性之后 | |
//每个组件可以通过this直接访问到全局挂载的自定义属性 | |
app.config.globalProperties.$http = axios |
在组件中发起axios请求:
this.$http.get('/users')