一、watch侦听器
定义:watch侦听器允许开发者监听数据的变化,从而针对数据的变化进行特定操作
export default {
name: 'MyWatch',
data() {
return {
username: 'admin',
}
},
// 需要在watch节点下,定义侦听器
watch: {
//监听userName的变化
username(newVal,oldVal){
console.log("变化后的新值", newVal);
console.log("变化前的旧值", oldVal);
}
},
}
immediate选项
作用:组件在初次加载完毕后不会调用watch监听器,immediate选项可以让watch监听器立即被调用
另username不在是一个方法了,而是指向一个对象
export default {
name: 'MyWatch',
data() {
return {
username: 'admin',
}
},
// 需要在watch节点下,定义侦听器
watch: {
//监听userName的变化
username: {
// handler属性是固定写法,当username变化时,调用handler
async handler(newVal, oldVal) {
const { data: res } = await axios.get('https://www.escook.cn/api/finduser/' + newVal)
console.log(res)
},
// 立即触发 watch 侦听器
immediate: true,
},
},
}
deep选项
作用:如果监听的是对象,对象中的属性值发生了变化,则无法被监听到,此时需要使用deep选项
export default {
name: 'MyWatch',
data() {
return {
info: {
username: 'zs',
age: 20,
},
}
},
watch: {
info: {
async handler(newVal) {
const { data: res } = await axios.get('https://www.escook.cn/api/finduser/' + newVal.username)
console.log(res)
},
deep: true,//需要使用deep节点,否则info中的username变化监听不到
},
},
}
仅需监听对象中一个属性的变化
export default {
name: 'MyWatch',
data() {
return {
info: {
username: 'zs',
age: 20,
},
}
},
watch: {
//仅监听info对象中username属性的变化
'info.username': {
async handler(newVal) {
const { data: res } = await axios.get('https://www.escook.cn/api/finduser/' + newVal)
console.log(res)
},
},
},
}
计算属性和侦听器的区别
计算属性侧重于监听多个值的变化,最终计算并返回一个新值
侦听器侧重于监听单个数据的变化,最终执行特定的业务处理,不需要有任何返回值
二、组件生命周期
组件的运行过程
- 在内存中创建组价的实例对象
- 把创建的组件实例渲染到页面上
- 当组件中data数据更新后,vue会重新渲染组件的DOM结构
- 组件切换时销毁需要被隐藏的组件
组件的声明周期:组件从创建到渲染到销毁的整个过程,强调的是一个时间段
组价的声明周期函数:监听组件运行的不同时刻,会伴随着组件的运行而自动调用
生命周期函数
生命周期函数 | 执行时机 | 所属阶段 | 执行次数 | 应用场景 |
beforeCreate | 开始创建组件之前 | 创建阶段 | 唯一1次 | |
created | 组件在内存中被创建完毕后调用 | 创建阶段 | 唯一1次 | 发ajax请求数据 |
beforeMount | 组件初次渲染之前 | 创建阶段 | 唯一1次 | |
mountde | 组件第一次被渲染到页面上后调用 | 创建阶段 | 唯一1次 | 操作DOM元素 |
beforeUpdate | 组件重新渲染之前 | 运行阶段 | 0或多次 | |
updated | 组件被重新渲染后调用 | 运行阶段 | 0或多次 | |
beforeUnmount | 组件被销毁之前 | 销毁阶段 | 唯一1次 | |
unmounted | 组件被销毁完毕后调用 | 销毁阶段 | 唯一1次 |
示例
export default {
name: 'LifeCycle',
data() {
return {
count: 0,
}
},
// 组件在内存中被创建完毕了
created() {
console.log('created: 组件在内存中被创建完毕了')
},
// 组件第一次被渲染到了页面上
mounted() {
console.log('mounted: 组件第一次被渲染到了页面上')
},
// 组件被重新渲染完毕了
updated() {
console.log('updated: 组件被重新渲染完毕了')
},
// 组件被销毁完毕了
unmounted() {
console.log('unmounted: 组件被销毁完毕了')
},
}
三、组件间的数据共享
1、父子组件之间的数据共享
父传子
父组件通过v-bind属性绑定像子组件传递数据,同时子组件通过props接收数据。
<!-- 父组件 -->
<template>
<div>
<h1>App 根组件 -- {{ count }}</h1>
<button type="button" class="btn btn-primary" @click="count += 1">+1</button>
<hr />
<!-- 3. 以v-bind的形式向子组件传递数据 -->
<my-son :num="count"></my-son>
</div>
</template>
<script>
// 1. 导入子组件
import MySon from './Son.vue'
export default {
name: 'MyApp',
data() {
return {
count: 0,
}
},
// 2. 注册子组件
components: {
MySon,
},
}
</script>
<!-- 子组件 -->
<template>
<div>
<h3>Son 子组件 --- {{ num }}</h3>
</div>
</template>
<script>
export default {
name: 'MySon',
// 子组件接收父组件传来的num值
props: ['num'],
}
</script>
子传父
子组件通过自定义事件的方式像父组件中共享数据
<!-- 子组件 -->
<template>
<div>
<h3>Son 子组件 --- {{ num }}</h3>
<button type="button" class="btn btn-danger" @click="add">+1</button>
</div>
</template>
<script>
export default {
name: 'MySon',
data(){
return{
num:0
}
}
// 1.通过emits节点声明自定义事件
emits: ['numchange'],
methods: {
add() {
//2.在合适的时机通过$emit方法触发自定义事件
this.$emit('numchange', this.num + 1)
},
},
}
</script>
<!-- 父组件 -->
<template>
<div>
<h1>App 根组件 -- {{ count }}</h1>
<!-- v-on监听子组件的自定义事件getNum -->
<my-son @numchange="getNum"></my-son>
</div>
</template>
<script>
import MySon from './Son.vue'
export default {
name: 'MyApp',
data() {
return {
count: 0,
}
},
methods: {
getNum(num) {
//通过形参接收子组件传来的数据
this.count = num
}
},
components: {
MySon,
},
}
</script>
父子双向数据同步
使用v-modal指令可维护父子组件的双向数据同步,在父组件中使用v-modal,在子组件中声明emits
<!-- 父组件 -->
<template>
<div>
<h1>App 根组件 -- {{ count }}</h1>
<button type="button" class="btn btn-primary" @click="count += 1">+1</button>
<hr />
<!-- 以v-bind的形式向子组件传递数据 -->
<my-son v-model:num="count"></my-son>
</div>
</template>
<script>
import MySon from './Son.vue'
export default {
name: 'MyApp',
data() {
return {
count: 0,
}
},
components: {
MySon,
},
}
</script>
<!-- 子组件 -->
<template>
<div>
<h3>Son 子组件 --- {{ num }}</h3>
<button type="button" class="btn btn-danger" @click="add">+1</button>
</div>
</template>
<script>
export default {
name: 'MySon',
// 子组件接收父组件传来的num值
props: ['num'],
//声明自定义事件,注意update固定写法
emits: ['update:num'],
methods: {
add() {
//触发自定义事件
this.$emit('update:num', this.num + 1)
},
},
}
</script>
2、兄弟组件之间的数据共享
兄弟组件之间通过EventBus实现数据共享
借助于第三方包mitt来创建eventBus对象
使用步骤
- 安装mitt包
- 创建EventBus
- export EventBus
数据发送方:
- 导入并得到EventBus实例对象
- 调用EventBus的emit()方法,向外发送数据
bus.emit('自定义事件', 要发送的数据)
数据接收方:
- 导入并得到EventBus实例对象
- 调用EventBus的on()方法,声明自定义事件,通过事件回调接收数据
bus.on('自定义事件', (data) => { })
示例:
1.安装依赖包
npm install mitt@版本号 -S
2.创建公共的eventBus模块
// eventBus.js
// 导入mitt包
import mitt from 'mitt'
// 创建EventBus实例对象
const bus = mitt()
// 将eventBus对象共享出去
export default bus
3.使用eventBus
父组件:App.vue
<template>
<div>
<h1>App 根组件</h1>
<hr />
<div class="brother-box">
<my-left></my-left>
<my-right></my-right>
</div>
</div>
</template>
<script>
import MyLeft from './Left.vue'
import MyRight from './Right.vue'
export default {
name: 'MyApp',
components: {
MyLeft,
MyRight,
},
}
</script>
数据接收方Right.vue
<template>
<div>
<h3>数据接收方 --- num 的值为:{{ num }}</h3>
</div>
</template>
<script>
// 导入并得到EventBus实例对象
import bus from './eventBus.js'
export default {
name: 'MyRight',
data() {
return {
num: 0,
}
},
created() {
// 调用EventBus的on()方法,声明自定义事件,通过事件回调接收数据
bus.on('countChange', count => {
this.num = count
})
},
}
</script>
数据发送方Left.vue
<template>
<div>
<h3>数据发送方 --- count 的值为:{{ count }}</h3>
<button type="button" class="btn btn-primary" @click="add">+1</button>
</div>
</template>
<script>
// 导入并得到EventBus实例对象
import bus from './eventBus.js'
export default {
name: 'MyLeft',
data() {
return {
count: 0,
}
},
methods: {
add() {
this.count++
// 调用EventBus的emit()方法,向外发送数据
bus.emit('countChange', this.count)
},
},
}
</script>
3、后代组件间的数据共享
父节点的组件向其子孙组件共享数据,可使用provide和inject实现后代关系组件之间的数据共享
提供数据使用provide,接收数据使用inject
使用步骤
- 父节点中通过provide方法,对其子孙组件共享数据
- 子孙节点中使用inject数组,接收父级节点向下共享的数据
- 父组件可结合computed函数共享响应式数据,子组件以.value的形式使用响应式数据
示例
父节点
<!-- 父组件 -->
<template>
<div>
<h1>App 根组件 -- {{ color }}</h1>
<hr />
<level-two></level-two>
</div>
</template>
<script>
import LevelTwo from './LevelTwo.vue'
//从vue中导入computed函数
import { computed } from 'vue'
export default {
name: 'MyApp',
data() {
return {
color: 'red',
count: 1,
}
},
provide() {
// provide函数return的对象中,包含了要向子孙组件中共享的数据
return {
color: this.color,
//调用computed函数,进行响应式数据共享
count: computed(() => this.count)
}
},
components: {
LevelTwo,
},
}
</script>
子节点
<template>
<div>
<h3>Level Two 二级组件</h3>
<hr />
<level-three></level-three>
</div>
</template>
<script>
import LevelThree from './LevelThree.vue'
export default {
name: 'LevelTwo',
components: {
LevelThree,
},
}
</script>
孙节点
<template>
<div>
<h5>Level Three 三级组件 --- {{ color }}</h5>
<!-- 响应式数据,必须以 .value 的形式进行使用 -->
<h5>Level Three 三级组件 --- {{ count.value }}</h5>
</div>
</template>
<script>
export default {
name: 'LevelThree',
// 子孙组件使用inject接收父级组件向下共享的数据
inject: ['color','count'],
}
</script>
四、全局配置axios
在main.js入口文件中,通过app.config.globalProperties全局挂载axios
步骤
- import安装axios包
- 在main.js入口文件中导入axios,并进行axios配置(根路径)
- 在main.js中将axios全局挂载至app上
- 在每个vue组件中,都可以通过this.$http发起get或post请求
示例
main.js中
import { createApp } from 'vue'
import App from './components/App.vue'
import './assets/css/bootstrap.css'
import './index.css'
import axios from 'axios'
const app = createApp(App)
// 为axios配置请求根路径
axios.defaults.baseURL = 'https://api.com'
// 将axios挂载为自定义属性后,每个组件可通过this直接访问的全局挂载的自定义属性
// $后的自定义属性名可自定义,此处为http
app.config.globalProperties.$http = axios
app.mount('#app')
发起post请求 PostInfo.vue
<template>
<div>
<h3>Post Info 组件</h3>
<hr />
<button type="button" class="btn btn-success" @click="postInfo">发起 POST 请求</button>
</div>
</template>
<script>
export default {
name: 'PostInfo',
methods: {
async postInfo() {
// 发起post请求this.$http.post(请求路径,请求数据)
const { data: res } = await this.$http.post('/api/post', { name: 'zs', age: 20 })
console.log(res)
},
},
}
</script>
发起get请求 GetInfo.vue
<template>
<div>
<h3>Get Info 组件</h3>
<hr />
<button type="button" class="btn btn-primary" @click="getInfo">发起 GET 请求</button>
</div>
</template>
<script>
export default {
name: 'GetInfo',
methods: {
async getInfo() {
// 发起get请求this.$http.get(请求路径,{params:{请求数据}}})
const { data: res } = await this.$http.get('/api/get', {
params: {
name: 'ls',
age: 33,
},
})
console.log(res)
},
},
}
</script>