初学Vue(全家桶)-第19天(vue3):计算属性、监视属性、vue3生命周期

初学vue

1、vue3中计算属性computed的基本使用

功能和vue2中的一样,只是写法上有些许区别,但vue3目前仍可以使用vue2中的写法,不过不推荐。
vue3中计算属性的使用具体看例子,不赘述了

<template>
  姓:<input type="text" v-model="person.firstName">
  <br>
  名:<input type="text" v-model="person.lastName">
  <br>
  <span>全名:{{person.fullName}}</span>
  <br>
  直接修改计算属性计算出的全名:<br>
  <input type="text" v-model="person.fullName">
</template>

<script>
    // 引入计算属性的组合API
    import {reactive,computed} from "vue"
    export default {
        name:"ComputedTest",
        setup(){
            // 定义一个数据(对象类型)
            let person = reactive({
                firstName:"张",
                lastName:"三"
            })

            // 计算属性
            // 简写形式(这样就没有考虑计算属性被修改的情况
            // person.fullName = computed(()=>{
            //     return person.firstName + "-" + person.lastName
            // })
            
            // 完整写法(这样可以对计算属性进行读写操作
            person.fullName = computed({
                get(){
                    return person.firstName + "-" + person.lastName
                },
                set(value){
                    const nameArr = value.split("-") // 按照”-“拆分全名
                    person.firstName = nameArr[0]
                    person.lastName = nameArr[1]
                }
            })
            return {
                person
            }
        },
    }
</script>

请添加图片描述

2、vue3中监视属性watch的基本使用

2.1 监视ref定义的数据

vue3中watch和vue2中的使用方式很相似。

<template>
  <h2>当前求和为:{{sum}}</h2>
  <button @click="sum++">点我加1</button>
  <hr>
  <h2>当前的信息为:{{msg}}</h2>
  <button @click="msg+='!'">添加感叹号</button>
</template>

<script>
// 引入ref的组合API
import {ref,watch} from "vue"
export default {
    name:"WatchTest01",
    setup(){
      let sum = ref(0)
      let msg = ref("你好呀")
      // 情况一:监视ref所定义的一个响应式数据
      watch(sum,(newValue,oldValue)=>{
        console.log("sum变了",newValue,oldValue)
      })

      // 传入第三个参数{immediate:true},用于页面刷新后立即监视
      // watch(sum,(newValue,oldValue)=>{
      //   console.log("sum变了",newValue,oldValue)
      // },{immediate:true})

      // 情况二:监视ref所定义的多个响应式数据
      watch([sum,msg],(newValue,oldValue)=>{
        console.log("sum或msg变了",newValue,oldValue);
      })

      // 返回一个对象
      return {
        sum,
        msg
      }
    }
}
</script>
<style>

</style>

请添加图片描述

关于watch监视ref定义的数据是否要用到.value的问题:
(1)当ref定义的是一个基本数据类型时,如下:

<h2>当前求和为:{{sum}}</h2>
<button @click="sum++">点我加1</button>
----------------------------------------------------------
let sum = ref(0)

watch(sum,(newValue,oldValue)=>{
	console.log("sum的值改变了",newValue,oldValue)
})

分析:watch这里第一个参数必须是sum而不能是sum.value,因为ref中定义的是一个基本类型数据,如果用sum.value的话,就相当于直接监视0这个数字,而使用sum的话就是在监视sum这个结构,打印出sum,console.log(sum),可以看到结果是一个refImpl对象,而这个对象下就包括value值,所以要监视整个sum。
(2)当ref定义的是一个引用数据类型时,如下:

<h3>姓名:{{person.name}}</h3>
<h3>年龄:{{person.age}}</h3>
<h3>薪资:{{person.job.salary}}</h3>
<button @click="person.name += '!'">修改姓名</button>
<button @click="person.age += 1">增长年龄</button>
<button @click="person.job.salary += 3">涨薪</button>
-----------------------------------------------------------
let person = ref({
	name:"张三",
	age:18,
	job:{
		salary:20
	}
})
// 第一种方式实现监视到对象中的所有属性
watch(person.value,(newValue,oldValue)=>{
	console.log("person中的属性改变了”,newValue,oldValue)
})

// 第二种方式实现监视到对象中的所有属性
watch(person,(newValue,oldValue)=>{
	console.log("person中的属性改变了”,newValue,oldValue)
},{{deep:true}})

分析:如果这里不使用这两种方式来对对象进行监视,那么就无法起到监视效果。

  • 对于方式一,利用的是使用ref对引用类型进行定义时,底层会自动转换成reactive函数对对象进行定义,那么此时console.log(person)可以看到结果如下,person是一个refimpl对象
    在这里插入图片描述
  • 对于方式二,直接利用{{deep:true}}配置项进行深度监视,监视的时person.value,当person.value下面的数据发生改变时,深度监视到就会立即更新页面。

2.2 监视reactive定义的数据

<template>
    <h3>姓名:{{person.name}}</h3>
    <h3>年龄:{{person.age}}</h3>
    <h3>薪资:{{person.job.salary}}</h3>
    <button @click="person.name += '!'">修改姓名</button>
    <button @click="person.age += 1">增长年龄</button>
    <button @click="person.job.salary += 3">涨薪</button>
</template>

<script>
import {reactive,watch} from "vue"
export default {
    name:"WatchTest02",
    setup(){
        let person = reactive({
            name:"张三",
            age:18,
            job:{
                type:"前端工程师",
                salary:15
            }
        })

        // 监视reactive中的数据

        // 情况一:监视reactive所定义的一个响应式数据的全部属性
        // 1、此处无法正确的获取oldValue
        // 2、reactive的监视是强制深度监视,关不了
        /*
        watch(person,(newValue,oldValue)=>{
            console.log("person变化了",newValue,oldValue)
        },{deep:false}) // 此处的deep配置无效
        */
   
        // 情况二:监视reactive所定义的一个响应式数据中的某个属性
        /*
        watch(()=>person.name,(newValue,oldValue)=>{
            console.log("person变化了",newValue,oldValue)
        })
        */
        
        // 情况三:监视reactive所定义的一个响应式数据中的某些属性
        /*
        watch([()=>person.name,()=>person.age],(newValue,oldValue)=>{
            console.log("person中的name或age变化了",newValue,oldValue)
        })
        */

        // 情况四:监视reactive所定义的对象中的某个属性(如果这个属性依然是个对象),那么deep配置有效
        watch(()=>person.job,(newValue,oldValue)=>{
            console.log("person的job属性变化了",newValue,oldValue)
        },{deep:true}) // 此处deep配置有效

        return {
            person
        }
    }
}
</script>

2.3 watchEffect函数

  • watch的套路是既要指名监视的属性,也要指明监视的回调
  • watchEffect的套路是:不用指明监视哪个属性,监视的回调中用到哪个属性,那就监视哪个属性。
  • watchEffect有点像computed:
    • 区别在于computed注重的是计算出来的值(回调函数的返回值),所以必须要写返回值
    • 而watchEffect更注重的是过程(回调函数的函数体),所以不用写返回值。
<template>
    <h3>姓名:{{person.name}}</h3>
    <h3>年龄:{{person.age}}</h3>
    <h3>薪资:{{person.job.salary}}</h3>
    <button @click="person.name += '!'">修改姓名</button>
    <button @click="person.age += 1">增长年龄</button>
    <button @click="person.job.salary += 3">涨薪</button>
</template>

<script>
import {reactive,ref,watchEffect} from "vue"
export default {
    name:"WatchTest02",
    setup(){
        let sum = ref(0)
        let person = reactive({
            name:"张三",
            age:18,
            job:{
                type:"前端工程师",
                salary:15
            }
        })

        watchEffect(()=>{
            // watchEffect所指定的回调中用到的数据只要发生变化,则直接重新执行回调
            // 使用sum和person对象中的age
            const x1 = sum.value
            const x2 = person.age
            console.log("watchEffect配置的回调执行了!",x1,x2)
        })
        return {
            sum,
            person
        }
    }
}
</script>

请添加图片描述

可以看到只有在watchEffect中用到的对象才会被监视到,并且页面刷新时watchEffect就会自动执行一次

3、Vue3生命周期

在这里插入图片描述

和vue2的区别
(1)和vue2一样,主要是8个生命周期钩子,但有两个钩子又和vue2不一样,vue3将vue2中的beforeDestroy和destroyed换成了beforeUnmounte和unmounted
(2)在创建组件对象时,vue2是直接new Vue(),之后是走一步算一步,哪里需要挂载东西再挂载东西,例如会进行对象上是否有el的判断,没有则自动挂载上,;而vue3是Vue.create(option).mount(el),直接把需要的东西准备好,甚至提前把el直接挂载到对象上。

两种方式使用生命周期钩子

  • 第一种方式:通过配置项的形式使用生命周期钩子
setup(){
	...
},
beforeCreate(){......},
created(){......},
beforeMounted(){......},
mounted(){......},
beforeDestroy(){......},
destroyed(){......},
beforeUnmounted(){......},
unmounted(){......}
  • 第二种方式:通过组合式API的形式去使用生命周期钩子(也就是将生命周期钩子放到setup配置项中)
// 引入API
import {} from "vue"
--------------------
setup(){
	......
	onBeforeMounted(()=>{...})
	onMounted(()=>{...})
	onBeforeDestroy(()=>{...})
	onDestroyed(()=>{...})
	onBeforeUnmounted(()=>{...})
	onUnmounted(()=>{...})
}

注意点:
(1)原来vue2中的beforeDestroy和destroyed不能使用,取而代之的是beforeUnmounted和unmounted
(2)将生命周期钩子放到setup配置项中时,需要注意生命周期钩子的形式变了,并且不支持beforeCreate和created写入setup中,因为setup会在这两个钩子执行之前执行.
(3)如果同时使用了这两中方式,那么会有执行先后顺序问题,写在setup中的钩子的优先级会更高,例如:onBeforeMounted会比BeforeMounted先执行。(建议只是用其中一种方式)

4、自定义hook函数

  • 定义
    本质是一个函数,把setup函数中使用的CompositionAPI进行了封装,类似于vue2中的mixin。
  • 优势
    可以复用代码,让setup中的逻辑更加清楚易懂

例如,实现这么一个功能,鼠标点击屏幕,显示鼠标点击时的坐标。
请添加图片描述

如果只是一个人要用到这个功能,那么这个功能就可以直接写在组件中,如下:

<template>
  <h1>鼠标点击屏幕,显示鼠标点击时的坐标</h1>
  <h2>鼠标横坐标:{{point.x}}</h2>
  <h2>鼠标纵坐标:{{point.y}}</h2>
</template>

<script>
import { reactive,onMounted,onBeforeUnmount} from "vue"
export default {
    name:"HookTest",
    setup() {
        // 定义变量:表示点的坐标
        const point = reactive({
            x:0,
            y:0
        })

        // 定义函数:获取坐标
        function usePoint(event){
            point.x = event.pageX
            point.y = event.pageY
            console.log("横坐标:"+ point.x,"纵坐标:"+ point.y);
        }

        
        // 在onMounted钩子中给window绑定事件
        onMounted(() => {
            window.addEventListener("click",usePoint)
        })

        // 在onBeforeUnmount钩子中给window解绑事件
        onBeforeUnmount(()=>{
            window.removeEventListener("click",usePoint)
        })
        // 返回一个对象
        return {
            point
        }
    }
}
</script>

如果想要让这个功能做到随引随用,那么可以使用自定义hook函数进行封装,如下:

  • src/hooks/usePoint.js
import {reactive,onMounted,onBeforeUnmount} from "vue"
export default function usePoint(){
    // 定义变量:表示点的坐标
    const point = reactive({
        x:0,
        y:0
    })

    // 定义函数:获取坐标
    function usePoint(event){
        point.x = event.pageX
        point.y = event.pageY
        console.log("横坐标:"+ point.x,"纵坐标:"+ point.y);
    }

    // 在onMounted钩子中给window绑定事件
    onMounted(() => {
        window.addEventListener("click",usePoint)
    })

    // 在onBeforeUnmount钩子中给window解绑事件
    onBeforeUnmount(()=>{
        window.removeEventListener("click",usePoint)
    })

    // 返回一个获取到的对象
    return point
}

  • HookTest.vue
<template>
  <h1>鼠标点击屏幕,显示鼠标点击时的坐标</h1>
  <h2>鼠标横坐标:{{point.x}}</h2>
  <h2>鼠标纵坐标:{{point.y}}</h2>
</template>

<script>
// 引入hook函数
import usePoint from "../hooks/usePoint"
export default {
    name:"HookTest",
    setup() {
    	// 调用hook函数
        const point = usePoint() 
        // 接收usePoint()方法return过来的对象

        // 返回point对象
        return {
            point
        }
    }
}
</script>

通过hook函数,无论哪个组件想要使用这个功能,那么只需要引入并调用即可

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值