Web前端开发篇(3)---vue3的计算属性computed&监视watch

1 计算属性 - computed

 计算属性与方法的区别是,计算属性有缓存,方法无缓存。即每次调用方法都会重新执行一次,而计算属性会缓存结果。注:计算属性是只读的,可以根据依赖的响应式数据改变,而无法给计算属性重新赋值:

<template>
  <div class="person">
    姓:<input type="text" v-model="firstName"> <br>
    名:<input type="text" v-model="lastName"> <br>
    全名:<span>{{fullName}}</span> <br>
  </div>

</template>

<script setup lang="ts">
import {computed, ref} from "vue";

  // 数据
  let firstName = ref("zhang")
  let lastName = ref("san")
  // 计算属性(只读)
  let fullName = computed(()=>{
    return firstName.value + lastName.value
  })
  // 方法

</script>

理论上,computed为只读属性,但是也有其他办法,可以间接修改。其实就是将计算属性的get和set方法暴露,在set方法中添加修改逻辑,也只是去修改计算属性依赖的响应式数据,从而引起的计算属性的变化,changeFullName方法中的赋值也只是为了去调用set方法,从头到尾也没有直接修改计算属性fullName:

<template>
  <div class="person">
    姓:<input type="text" v-model="firstName"> <br>
    名:<input type="text" v-model="lastName"> <br>
    全名:<span>{{fullName}}</span> <br>
    <button @click="changeFullName">修改全名</button>
  </div>

</template>

<script setup lang="ts">
import {computed, ref} from "vue";

  // 数据
  let firstName = ref("zhang")
  let lastName = ref("san")
  // 计算属性(只读)
  // let fullName = computed(()=>{
  //   return firstName.value + lastName.value
  // })
  // 计算属性(可读可写)
  let fullName = computed({
    get(){
      return firstName.value + lastName.value
    },
    set(val){
      firstName.value = "li"
      lastName.value = "si"
    }
  })
  // 方法
  function changeFullName(){
    // 从此只是为了去调用fullName的set函数,真正的修改逻辑都在set中
    fullName.value = "lisi"
  }
</script>

2 监视watch

vue3的watch只能监视以下四种数据:

  • ref定义的数据
  • reactive定义的数据
  • 函数返回一个值(getter函数)
  • 一个包含上述内容的数组

(1)监视ref定义的基本类型数据

注:监视的是ref定义的数据,不是ref的value 

<template>
  <div>
    <p>{{num}}</p>
    <button @click="addNum">增加</button>
  </div>
</template>

<script setup lang="ts">
import {ref, watch} from 'vue';
  // 属性
  let num = ref(0)
  // 方法
  function addNum(){
    num.value += 1
  }
  // 监视
  watch(num, (newValue, oldValue)=>{
    console.log(newValue, oldValue)
  })
</script>

加上停止监视的逻辑:

  // 监视
  const stopWatch = watch(num, (newValue, oldValue)=>{
    console.log(newValue, oldValue)
    if(newValue >= 10){
      stopWatch()
    }
  })

(2)监视ref定义的对象类型数据

下面这样的写法只是监视了对象整体,当对象某个数值,比如name、age发生变化时,并不会调用watch。只有当整体发生变化使,比如person.value = {name: "李四", age: 20},才会调用watch:

  // 属性
  let person = ref({name: "张三", age: 18})

  // 监视
  watch(person, (newValue, oldValue)=>{
    console.log(newValue, oldValue)
  })

若想要监视对象内部属性的变化,需要手动开启深度监视。但是如果修改对象的某个值,newValue和oldValue相同,因为它们是同一个对象。只有修改整个对象才会产生新旧数据:

  // 属性
  let person = ref({name: "张三", age: 18})  

  // 监视
  watch(person, (newValue, oldValue)=>{
    console.log(newValue, oldValue)
  },{deep: true})

若想要在初始化时立即执行一次watch,则需要另一个参数:

  // 监视
  watch(person, (newValue, oldValue)=>{
    console.log(newValue, oldValue)
  },{deep: true, immediate: true})

(3)监视reactive定义的对象类型数据

reactive修改整个对象的方法:

  // 方法
  function changePerson(){
    Object.assign(person, {name: "李四", age: 20})
  }

  // 监视
  watch(person, (newValue, oldValue)=>{
    console.log(newValue, oldValue)
  })

watch监视reactive定义的对象类型数据,是默认开启深度监听的,且无法关闭。

(4)监视ref或reactive定义的对象类型数据中的某个属性

  // 属性
  let person = reactive({
    name: "张三", 
    age: 18, 
    car: {c1: "宝马", c2: "奥迪"}
  })

如果我就想监视person中的name基本类型属性,修改其他属性时,不执行监视name的watch:

  // 监视
  // 正确写法1:
  watch(()=>{return person.name}, (newValue, oldValue)=>{
    console.log("名字发生了变化", newValue, oldValue)
  })
  // 正确写法2:
  watch(()=> person.name, (newValue, oldValue)=>{
    console.log("名字发生了变化", newValue, oldValue)
  })
  
  // 错误写法1:这样监视的是整体
  watch(person, (newValue, oldValue)=>{
    console.log("名字发生了变化", newValue, oldValue)
  })
  // 错误写法2:报错
  watch(person.person, (newValue, oldValue)=>{
    console.log("名字发生了变化", newValue, oldValue)
  })

如果我就想监视person中的car对象类型属性,监视整体以及某个属性的变化:

  //正确写法:可以监视整体发生变化,可以监视某个属性
  watch(()=> person.car, (newValue, oldValue)=>{
    console.log("车发生了变化", newValue, oldValue)
  },{deep: true})  


  //错误写法:只能监视整体变化,不会监视某个属性变化
  watch(()=> person.car, (newValue, oldValue)=>{
    console.log("车发生了变化", newValue, oldValue)
  }) 
  //错误写法2:只能监视某个属性的变化,不会监视整体发生变化
  watch(person.car, (newValue, oldValue)=>{
    console.log("车发生了变化", newValue, oldValue)
  })

(5)监视上述多个数据

  // 监视
  watch([()=> person.name, ()=> person.car], (newValue, oldValue)=>{
    console.log(newValue, oldValue)
  }, {deep: true})

3 watchEffect

watch和watchEffect的区别:watch需要明确指出要监视哪几个数据,watchEffect不需要。当初始化时,watchEffect就会执行一次。现在模拟一个场景:判断某个人的年龄是否成年。

watch写法:

  // 监视
  watch([()=>person.name, ()=>person.age], (value)=>{
    let [name, age] = value
    if(age >= 18){
      console.log(name,"成年了!")
    }
  })

watchEffect写法:

  watchEffect(()=>{
    if(person.age >= 18){
      console.log(person.name, "成年了!")
    }
  })

4 自定义接口和类型

自定义接口文件:

// 定义一个接口,用于限制person对象的具体属性
export interface PersonInter{
    id:string,
    name:string,
    age:number
}

// 定义一个自定义类型
export type Persons = Array<PersonInter>

引用并使用:

<template>
</template>

<script setup lang="ts">
  import {type PersonInter,type Persons} from "@/types";

  let person:PersonInter = {id:"qwer1234", name:"张三", age:45}
  let personList:Persons = [
    {id:"qwer1234", name:"张三", age:45},
    {id:"qwer1234", name:"张三", age:45},
    {id:"qwer1234", name:"张三", age:45}
  ]
</script>

变成响应式对象数据,两种写法:

  //写法1
  let personList:Persons = reactive([
    {id:"qwer1234", name:"张三", age:45},
    {id:"qwer1234", name:"张三", age:45},
    {id:"qwer1234", name:"张三", age:45}
  ])

  //写法2
  let personList = reactive<Persons>([
    {id:"qwer1234", name:"张三", age:45},
    {id:"qwer1234", name:"张三", age:45},
    {id:"qwer1234", name:"张三", age:45}
  ])
  • 7
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值