vue组件高级(上)

2022-10-26 17:35:17 浏览数 (3)

1. watch侦听器

wach侦听器允许开发者监视数据的变化,从而针对数据的变化做特定的操作。例如,监视用户名的变化并发起请求,判断用户名是否可用。

1.1 基本语法

开发者需要在watch节点下,定义自己的侦听器:

代码语言:javascript复制
export default{
    data(){
        return { username:'' }
    },
watch:{
    username(newVal,oldVal){
        console.log(newVal,oldVal)
        },
    },
}

1.2 检测用户名是否可用

代码语言:javascript复制
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选项:

代码语言:javascript复制
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选项:

代码语言:javascript复制
  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侦听器:

代码语言:javascript复制
 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框架为组件内置了不同时刻的生命周期函数,生命周期函数回伴随着组件的运行而自动调用。

  1. 当组件在内存中被 创建完毕之后,会自动调用 created函数。
  2. 当组件被成功的 渲染到页面上之后,会自动调用 mounted函数。
  3. 当组件被 销毁完毕之后,会自动调用 unmounted函数

2.2 监听组件的更新

当组件的data数据更新之后,vue会自动重新渲染组件的DOM结构,从而保证View视图展示的数据和Model数据源保持一致。

当组件被重新渲染完毕之后,会自动调用updated生命周期函数。

2.3完整的生命周期函数

生命周期函数

执行时机

所属阶段

执行次数

应用场景

beforeCreate

在内存中开始创建组件之前

创建阶段

唯一一次

-

created

组件在内存中创建完毕周

创建阶段

唯一一次

-

beforeMount

在把组件初次渲染到页面之前

创建阶段

唯一一次

-

mounted

组件初次在页面中渲染完毕之后

创建阶段

唯一一次

操作DOM元素

beforeUpdate

在组件被重新渲染之前

运行阶段

0或多次

-

updated

组件在页面中被重新渲染完毕后

运行阶段

0或多次

-

beforeUnmount

在组件被销毁之前

销毁阶段

唯一一次

-

unmount

组件被销毁后(页面和内存)

销毁阶段

唯一一次

-

3. 组件之间的数据共享

3.1组件之间的关系

在项目开发中,组件之间的关系分为如下3种:

  1. 父子关系
  2. 兄弟关系
  3. 后代关系

3.2 父子组件之间的数据共享

父子组件之间的数据共享又分为:

  1. 父 -> 子共享数据
  2. 子 -> 父共享数据
  3. 父 <-> 子双向数据同步

3.3.1 父组件向子组件共享数据

父组件通过v-bind属性绑定向子组件共享数据:

代码语言:javascript复制
    <MyTest :msg="message" :user="userinfo"></MyTest>
代码语言:javascript复制
data(){
    return{
        message:'hello vue',
        userinfo:{name:'zs'age:20},
    }
}

同时,子组件需要使用props接收数据:

代码语言:javascript复制
//子组件
<template>
    <h3>测试父子传值 </h3>
    <p> {{msg}} </p>
    <p> {{user}} </p>
</template>

<script>
export default{
    props:['msg','user'],
}
</script>

3.3.2 子组件向父组件共享数据

子组件通过自定义事件的方式向父组件共享数据:

代码语言:javascript复制
//子组件
export default{
    emits:['nchange'],//1.声明自定义事件
    data(){return {n:0}},
    methods:{
        addN(){
            this.n  
            //2.数据变化时,触发自定义的事件
            this.$emit('nchange',this.n)
        }
    }
}
代码语言:javascript复制
//父组件
//1.监听子组件的自定义事件 nchange
<MyTest @nchange="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

代码语言:javascript复制
const bus = mitt() 
export defult bus

在数据的接收方和发送方共享EventBus对象

导入并得到EventBus实例对象

代码语言:javascript复制
import bus from './eventBus.js'

调用EventBus的on()方法,声明自定义事件,通过事件回调接收数据

代码语言:javascript复制
bus.on('自定义事件',(data)=>{})

3.4.1 具体步骤

1. 安装mitt依赖包

在项目中运行如下的命令,安装mitt依赖包

代码语言:javascript复制
npm install mitt@2.1.0
2. 创建公共的EventBus模块

在项目中创建公共的eventBus模块:

代码语言:javascript复制
//eventBus.js
//导入mitt包
import mitt from 'mitt'
//创建EventBus的实例对象
const bus = mitt()

//将EventBus的实例对象共享出去
export default bus
3. 在数据接收方自定义事件

在数据接收方,调用 bus.on('事件名称',事件处理函数)方法注册一个自定义事件:

代码语言:javascript复制
//导入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('事件名称',要发送的数据)方法触发自定义事件:

代码语言:javascript复制
//导入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 方法,对其子孙组件共享数据:

代码语言:javascript复制
export default{
    data(){
        return{
            color:'red'//定义父组件要向子孙组件共享的数据
        }
    },
    provide(){//provide函数return的对象中,包含了要向子孙组件共享的数据
        return{
            color:this.color,
        }
    },
}

3.4.2 子孙节点通过inject接收数据

子孙节点可以使用inject数组,接收父级节点向下共享的数据:

代码语言:javascript复制
export default{
    inject:['color'],
}

3.4.3 父节点对外共享响应式的数据

父节点使用provide向下共享数据时,可以结合computed函数向下共享响应式的数据。

代码语言:javascript复制
import {computed} from 'vue' //从vue中按需导入computed函数

export default{
    data(){
        return{color:'red'}
    },
    provide(){
        return{
            color:computed(()=>this.color),
        }
    },
}

3.4.4 子孙节点使用响应式的数据

如果父级节点共享的是响应式的数据,则子孙节点必须以.value的形式使用。

代码语言:javascript复制
<template>
<h5>子孙组件--- {{color.value}} </h5>
</template>

<script>
export default{
    //接收响应式color数据,并在页面上使用
    inject:['color'],
}
</script>

3.5 vuex

vuex 是终极的组件之间的数据共享方案,在企业级的vue项目开发中,vuex可以让组件之间的数据共享变得更高效、清晰、且易于维护。

Vue3.x中全局配置axios

在实际项目开发中,几乎每个组件都会用到axios发起数据请求,此时会遇到如下两个问题:

  1. 每个组件中都需要导入axios(代码臃肿)
  2. 每次发请求都需要填写完整的请求路径(不利于后期的维护)

配置方式

在main.js入口文件中,通过 app.config.globalProperties全局挂载axios

代码语言:javascript复制
//为axios配置请求的根路径
axios.defaults.baseURL='http://api.com'

//将axios挂载为app的全局自定义属性之后
//每个组件可以通过this直接访问到全局挂载的自定义属性
app.config.globalProperties.$http = axios

在组件中发起axios请求:

代码语言:javascript复制
this.$http.get('/users')

0 人点赞