vue3中计算属性与监听的使用(setup函数和setup语法糖两版)

2,240 阅读3分钟

一、计算属性

  • 计算属性可以帮我们将数据转换成需要展示的数据格式,不必在模板中编写大量的表达式进行处理。
  • computed()方法可以传一个函数将结果return出去

setup函数版本

<template>
  <div class="box">
    <button @click="num++">添加</button>
    <div>单价:{{ price }}¥</div>
    <div>数量:{{ num }}¥</div>
    <div>总价:{{ total }}</div>
  </div>
</template>
<script>
// 引入
import {  reactive, toRefs,computed } from 'vue';
export default {
  setup() {
    const data = reactive({
      num: 0,
      price: 10
    })
    // 引入后可直接使用computed()
    // 必须有返回值,通过定义变量接收
    const total = computed(() => {
      // 计算处理总价并return出去
      return data.num * data.price + '¥'
    })
    // 需要将变量返回出去,否则页面无法使用
    return {
      ...toRefs(data),
      total
    }
  },
}
</script>
<style scoped lang="scss"></style>

setup语法糖版本

<template>
  <div class="box">
    <button @click="data.num++">添加</button>
    <div>单价:{{ data.price }}</div>
    <div>数量:{{ data.num }}</div>
    <div>总价:{{ total }}</div>
  </div>
</template>
<script setup>
// 引入
import { reactive,computed } from 'vue';
const data = reactive({
  num: 0,
  price: 10
})
// 引入后可直接使用computed()
// 必须有返回值,通过定义变量接收,页面可直接使用变量
const total = computed(() => {
  return data.num * data.price
})
</script>
<style scoped lang="scss"></style>

修改计算属性

  • 计算属性的值默认为只读
  • computed()方法也可以传一个对象,实现这个对象的get和set方法,以此实现对计算属性的使用和修改
  • 此处演示setup语法糖版本,setup函数同理,不做过多演示
<template>
  <div class="box">
    <button @click="data.num++">添加</button>
    <div>单价:{{ data.price }}</div>
    <div>数量:{{ data.num }}</div>
    <div>总价:{{ total }}</div>
    <button @click="handleTotal">添加10个</button>
  </div>
</template>
<script setup>
// 引入
import { reactive, computed, } from 'vue';
const data = reactive({
  num: 0,
  price: 10
})
// 引入后可直接使用computed()
// 必须有返回值,通过定义变量接收,页面可直接使用变量
const total = computed({
  // get返回计算属性结果
  get: () => {
    return data.num * data.price
  },
  // set可使用传入参数
  set: (value) => {
    console.log(value)
    return data.num = value
  }
})
// 通过事件修改计算属性结果
const handleTotal = () => {
  total.value = data.num + 10
}
</script>
<style scoped lang="scss"></style>

二、监听(侦听器)

  • watch用来监听数据的响应式变化.获取数据变化前后的值
  • 可通过不同方式分别对单个数据、多个数据、数据某个属性、首次监听等多个场景进行不同的逻辑处理
  • watch(),第一个参数为监听源,第二个参数为监听回调
  • 在监听回调中有两个参数,第一个为新值,第二个为旧值

普通监听

<template>
  <div class="box">
    <div><input type="text" placeholder="请输入" v-model="name"></div>
    <div><input type="text" placeholder="请输入" v-model="age"></div>
    <button @click="sexChange">变性别</button>
    <button @click="hobbyChange">改爱好</button>
  </div>
</template>
<script setup>
// 引入
import { ref, reactive,watch } from 'vue';
const data = reactive({
      sex: '男',
      tel:15612345678,
      hobby: ['吃', '喝', '玩', '乐']
})
const name = ref('张三')
const age = ref('18')
const sexChange=()=>{
  data.sex=='男'?data.sex='女':data.sex='男'
}
const hobbyChange=()=>{
  data.hobby.pop()
}
// 引入监听后通过watch(),第一个参数为监听源,第二个参数为监听回调
// 在监听回调中有两个参数,第一个为新值,第二个为旧值
watch(name, (newData, oldData) => {
  console.log(newData, oldData);
})
</script>
<style scoped lang="scss"></style>

监听多个

  • 当有多个数据需要同时监听时,可以通过数组的方式进行监听
  • newDataoldData此时也为数组
watch([name,age], (newData, oldData) => {
  // 返回的数据是数组
  console.log(newData, oldData);
})

首次监听

  • 通过添加immediate属性,开启监听源的首次监听
watch(name, (newData, oldData) => {
  console.log(newData, oldData);
}, {
  //开启首次监听
  immediate: true
})

监听proxy数据

  • 当监听值为proxy对象时,oldValue值出现异常,此时与newValue相同
watch(data, (newData, oldData) => {
  //新旧值相同,oldValue无法正确获取
  console.log(newData, oldData);
})

监听proxy数据的某个属性

  • 需要将监听值写成函数返回形式,vue3无法直接监听对象的某个属性变化
watch(()=>data.sex, (newData, oldData) => {
  console.log(newData, oldData);
})

监听proxy数据的某些属性

watch([()=>data.tel,()=>data.sex], (newData, oldData) => {
  console.log(newData, oldData);
})

深度监听

  • 当监听proxy对象的属性为复杂数据类型时,需要开启deep深度监听
watch(()=>data.hobby, (newData, oldData) => {
  //新旧值相同,oldValue无法正确获取
  console.log(newData, oldData);
},{
  deep:true
})

路由监听

// 引入路由vue-router中的useRouter
import { useRouter } from 'vue-router'
const router = useRouter()
watch(() => router.currentRoute.value.path,(toPath) => {
      //要执行的方法
      const query = router.currentRoute.value.query;
      console.log('路由发生变化');
},{immediate: true,deep: true})

注意:

1、如果定义了reactive的数据,想去使用watch监听数据改变,则无法正确获取旧值,并且deep属性配置无效,自动强制开启了深层次监听。

2、如果使用 ref 初始化一个对象或者数组类型的数据,会被自动转成reactive的实现方式,生成proxy代理对象。也会变得无法正确取旧值。

3、用任何方式生成的数据,如果接收的变量是一个proxy代理对象,就都会导致watch这个对象时,watch回调里无法正确获取旧值。

4、本质是newvalue和oldvalue是指向同一个对象,所以才会产生2者相同的情况,我们可以通过计算属性,将响应式对象转换为ComputedRef的响应式字符串,之后监听这个字符串,将解包后的旧值新值转为对象形式即可