文章目录
- 组件高级
- 一、watch 监听器
- 二、组件的生命周期
- 2.1 组件运行的过程
- 2.2 监听组件的不同时刻
- 2.3 监听组件的更新
- 2.4 主要生命周期函数
- 三、组件之间的数据共享
- 3.1 组件关系及数据共享
- 3.2 父子组件数据共享
- 3.3 兄弟组件数据共享
- 3.4 后代组件数据共享
- 3.5 vuex
- 四、全局配置 axios
组件高级
一、watch 监听器
1、监听器概念
watch 侦听器允许开发者监视数据的变化,从而针对数据的变化做特定的操作。例如,监视用户名的变化并发起请求,判断用户名是否可用。
2、基本语法
通过watch节点定义需要监听数据的函数,第一个参数是变化后的新值,第二个参数是变化之前的旧值:
<script>
export default{
data(){
return { username:''}
},
watch:{
username(newVal,oldVal) {
console.log(newVal, oldVal)
}
}
}
</script>
创建新的两个组件:
在MyWatch组件中声明数据项 username,并添加监听器检测值的变化,在页面中新增输入框,双向绑定 username,并且使用trim过滤前后空格:
我們設定初始 username 值为 admin,监听输入框中的数据值,每删除一个字符就会进行数据监听,控制台输出。
3、监测用户名是否可用
监听 username
的值变化,并使用 axios
发起 Ajax
请求,检测当前输入的用户名是否可用:
首先 npm install axios ,导入axios模块:
<script>
// 导入axios
import axios from 'axios'
export default {
name: 'MyWatch',
data() {
return {
username: 'admin',
}
},
watch: {
username(newVal,oldVal){
// 解构:重命名
async const { data:res} =await axios.get('https://www.escook.cn/api/finduser/${newVal}')
console.log(res)
}
},
}
</script>
通过控制台可以看出res是 Promise 对象属性(异步),我们通过解构将data数据提取出来,并且使用 await 、async 修饰,async 是“异步”的简写,而 await 可以认为是 async wait 的简写。所以应该很好理解 async 用于申明一个 function 是异步的,而 await 用于等待一个异步方法执行完成。
这部分服务器已经关闭了所以通过视屏讲解理解流程即可,最终效果类似是监听组件 username 的值,若为空则是用户名可用,若不为空存入第一次的值,此时用户名已被占用,再次修改用户名无效。
4、默认情况下,组件在初次加载完毕后不会调用 watch
侦听器(如下图所示没有输出内容)。如果想让 watch
侦听器立即被调用,则需要使用 immediate
选项。
<script>
import axios from 'axios'
export default {
name: 'MyWatch',
data() {
return {
username: 'admin',
}
},
watch: {
async username(newVal, oldVal) {
console.log("newVal:" + newVal, "oldVal" + oldVal)
// 解构:重命名
const {data:res} = axios.get("https://www.escook.cn/api/finduser/" + newVal)
console.log(res)
}
},
immediate:true // 组件加载完毕后立即调用一次当前的watch监听器
}
</script>
可以发现,程序一启动,控制台就输出了监听的信息:
5、当 watch 侦听的是一个对象,如果对象中的属性值发生了变化,则无法被监听到,此时需要使用 deep 选项
如果只想监听对象中单个属性的变化,则可以按照 watch:{ 对象.属性 {…}}
的方式定义 watch 侦听器:
6、计算属性 vs 侦听器
-
计算属性侧重于监听多个值的变化,最终计算并返回一个新值
-
侦听器侧重于监听单个数据的变化,最终执行特定的业务处理,不需要有任何返回值
返回顶部
二、组件的生命周期
2.1 组件运行的过程
-
组件的生命周期指的是:组件从
创建 -> 运行(渲染) -> 销毁
的整个过程,强调的是一个时间段。 -
官网解析
2.2 监听组件的不同时刻
vue 框架为组件内置了不同时刻的生命周期函数,生命周期函数会伴随着组件的运行而自动调用。例如:
① 当组件在内存中被创建完毕之后,会自动调用 created
函数
② 当组件被成功的渲染到页面上之后,会自动调用 mounted
函数
③ 当组件被销毁完毕之后,会自动调用 unmounted
函数
首先创建两个新的组件,并在 Vue 组件中将 LifeCycle 组件导入进去:
当我们创建几个基础生命周期函数后,启动vite创建程序,在控制台会出现 created、mounted 的自动调用:
通过定义新的组件button,动态修改参数 flag 的值,从而动态的改变 lifr-cycle 组件的创建、渲染与销毁,可以看到默认组件显示,当我们点击按钮后,组件消失,即被销毁,调用对应的 unmounted 函数,控制台输出信息:
<template>
<div>
<h1>App 根组件</h1>
<hr />
<!-- 3. 以标签形式使用组件,v-if 当flag为true的时候显示该组件 -->
<life-cycle v-if="flag"></life-cycle>
<!-- 按钮点击事件动态改变组件的创建与销毁 -->
<button @click="flag = !flag">Taggle</button>
</div>
</template>
<script>
// 1. import 导入组件
import LifeCycle from './LifeCycle.vue'
export default {
name: 'MyApp',
data() {
return {
flag: true,
}
},
// 2. components 注册组件
components: {
LifeCycle,
},
}
</script>
<style lang="less" scoped></style>
2.3 监听组件的更新
-
当组件的 data 数据更新之后,vue 会自动重新渲染组件的 DOM 结构,从而保证 View 视图展示的数据和 Model 数据源保持一致。
-
当组件被重新渲染完毕之后,会自动调用 updated 生命周期函数。
<template>
<div>
<h3>LifeCycle 组件 --- {{ count }}</h3>
<button class="btn btn-primary" type="button" @click="count+=1">Taggle</button>
</div>
</template>
<script>
export default {
name: 'LifeCycle',
data() {
return {
count: 0,
}
},
// 组件在内存中被创建完毕了
created() {
console.log('created: 组件在内存中被创建完毕了')
},
// 组件第一次被渲染到了页面上
mounted() {
console.log('mounted: 组件第一次被渲染到了页面上')
},
// 组件被重新渲染完毕了
updated() {
console.log('updated: 组件被重新渲染完毕了')
},
// 组件被销毁完毕了
unmounted() {
console.log('unmounted: 组件被销毁完毕了')
},
}
</script>
<style lang="less" scoped></style>
2.4 主要生命周期函数
注意:发起Ajax请求数据必须在created中,之所以不在 beforeCreate中是因为此时组件还未被创建,无法将数据挂载到data节点上(如下图所示,在控制台输出是count的值没有)!
返回顶部
三、组件之间的数据共享
这部分内容与props内容基本一致,可以参考!
3.1 组件关系及数据共享
在项目开发中,组件之间的关系分为如下 3 种:
-
父子关系
-
兄弟关系
-
后代关系
3.2 父子组件数据共享
父子组件之间的数据共享又分为:
-
父-> 子共享数据
-
子-> 父共享数据
-
父<-> 子双向数据同步
3.3 兄弟组件数据共享
兄弟组件之间实现数据共享的方案是 EventBus
。可以借助于第三方的包 mitt
来创建eventBus
对象,从而实现兄弟组件之间的数据共享。
安装 mitt 依赖包:npm install mitt@2.1.0
新建组件:Vue 、Left 、Right ,在Vue中导入Left、Right组件:
创建公共的 EventBus 模块:
// eventBus.js
// 导入 mitt 包
import mitt from 'mitt'
// 创建EventBus实例对象
const bus = mitt()
// 将 EventBus 对象共享出去
export default bus
在数据接收方自定义事件,调用 bus.on(‘事件名称’,事件处理函数) 方法注册一个自定义事件:
<template>
<div>
<h3>数据接收方 --- num 的值为:{{ num }}</h3>
</div>
</template>
<script>
// 导入bus实例对象
import bus from './eventBus.js'
export default {
name: 'MyRight',
data() {
return {
num: 0,
}
},
mounted(){
// 接收发送方数据
bus.on('countChange',(count)=>{
this.num = count
})
}
}
</script>
<style lang="less" scoped></style>
在数据发送方,调用bus.emit(‘事件名称’, 要发送的数据) 方法触发自定义事件。
<template>
<div>
<h3>数据发送方 --- count 的值为:{{ count }}</h3>
<button type="button" class="btn btn-primary" @click="add">+1</button>
</div>
</template>
<script>
// 导入bus实例对象
import bus from './eventBus.js'
export default {
name: 'MyLeft',
data() {
return {
count: 0,
}
},
methods: {
add() {
this.count++
// 发送方发送数据
bus.emit('countChange', this.count)
},
},
}
</script>
<style lang="less" scoped></style>
3.4 后代组件数据共享
后代关系组件之间共享数据,指的是父节点的组件向其子孙组件共享数据。此时组件之间的嵌套关系比较复杂,可以使用 provide
和 inject
实现后代关系组件之间的数据共享。
创建新的组件:App、LevelTwo、LevelThree,并将三个组件连级引入(App中导入LevelTwo组件,LevelTwo中导入LevelThree组件):
父节点的组件可以通过provide 方法,对其子孙组件共享数据:
<script>
import LevelTwo from './LevelTwo.vue'
export default {
name: 'MyApp',
data() {
return {
color: 'red',
}
},
provide() {
// 返回要共享的数据对象
return {
color: this.color,
}
},
components: {
LevelTwo,
},
}
</script>
子孙节点可以使用inject数组,接收父级节点向下共享的数据:
<template>
<div>
<h5>Level Three 三级组件 - {{ color }}</h5>
</div>
</template>
<script>
export default {
name: 'LevelThree',
inject: ['color'], // 接收数据
}
</script>
父节点对外共享响应式的数据
-
父节点使用
provide
向下共享数据时,可以结合computed
函数向下共享响应式的数据。<template> <div> <h1>App 根组件 -- {{ color }}</h1> <hr /> <level-two></level-two> </div> </template> <script> import LevelTwo from './LevelTwo.vue' import { computed } from 'vue' export default { name: 'MyApp', data() { return { color: 'red', } }, provide() { // 返回要共享的数据对象 return { color: computed(() => this.color), count: 1, } }, components: { LevelTwo, }, } </script> <style lang="less" scoped></style>
-
如果父级节点共享的是响应式的数据,则子孙节点必须以
.value
的形式进行使用<template> <div> <h5>Level Three 三级组件 --- {{ color.value }} --- {{ count }}</h5> </div> </template> <script> export default { name: 'LevelThree', inject: ['color', 'count'], } </script> <style lang="less" scoped></style>
**新增按钮,改变父组件中 color
的,可以观察到后代组件的 color
也跟着改变了: **
3.5 vuex
vuex 是终极的组件之间的数据共享方案。在企业级的 vue 项目开发中,vuex 可以让组件之间的数据共享变得高效、清晰、且易于维护。
从上图中我们可以看到,使用传统的组件之间的数据共享方式,在父与子、子与父、兄弟组件之间每有一个数据的传递就需要使用对应的方式进行传值,显得十分繁琐;而 vuex 方案则可以将这些所有类型的绑定事件进行统一的管理,简化了开发。
返回顶部
四、全局配置 axios
参考文章:【Vue】 Axios请求库
在实际项目开发中,几乎每个组件中都会用到 axios 发起数据请求。此时会遇到如下两个问题:
① 每个组件中都需要导入 axios(代码臃肿)
② 每次发请求都需要填写完整的请求路径(不利于后期的维护)
在 main.js
入口文件中,通过 app.config.globalProperties
全局挂载 axios
:
创建三个新的组件:Vue、GetInfo、PostInfo,GetInfo、PostInfo组件中分别创建按钮,实现get、post的请求方法:
返回顶部