第四章 计算属性和帧听器

Vue2计算属性和侦听器

computed

  • 依赖多个变量计算出一个变量,且具有缓存机制,依赖值不变的情况下,会复用计算值。

  • computed中不能进行异步操作

watch

  • 通常监听一个变量的变化,而去做一些事
  • watvh中可异步操作

简单记就是:一般情况下computed的多对一,watch一对多

computed

获取的计算属性的值为return后面的值

<template>
  <div>
    <h1>总价为:{{ total }}</h1>
    <h1>总价为:{{ total2 }}</h1>
  </div>
</template>

<script>
import axios from 'axios'

export default {
  data() {
    return {
      goods: [
        { id: 1, price: 1, nums: 1 },
        { id: 1, price: 2, nums: 2 },
        { id: 1, price: 3, nums: 3 }
      ]
    }
  },

  computed: {
    // 1.computed格式1
    total() {
      let res = this.goods.reduce((pre, cur) => {
        return pre + cur.price * cur.nums
      }, 0)

      return res
    },
	
    // 2.computed格式2
    total2: {

      // 使用total2这个属性时,调用get函数
      get() {
        let res = this.goods.reduce((pre, cur) => {
          return pre + cur.price * cur.nums
        }, 0)

        return res
      },

      // 修改total2这个属性值时,调用set函数
      set(newVal) {
        console.log('total2被赋值修改了',newVal);
      }
    }
  }
}
</script>
<style lang="less"></style>

给计算属性传参:以返回函数的形式接收参数。

<template>
  <div>
    <h1>{{ total(arr1) }}</h1>
    <h1>{{ total(arr2) }}</h1>
  </div>
</template>

<script>
export default {
  data() {
    return {
      arr1: [1, 2, 3],
      arr2: [4, 5, 6]
    }
  },

  computed: {
    total(arr) {
      return function (arr) {
        let res = arr.reduce((pre, cur) => {
          return pre + cur
        }, 0)
        return res
      }
    }
  }
}
</script>
<style lang="less"></style>

watch

<template>
  <div>
    <h1>{{ name }}</h1>
    <button @click="name = 'CCC'">改变姓名</button>
    <h1>{{ age }}</h1>
    <button @click="age++">改变年龄</button>

  </div>
</template>

<script>

export default {
  data() {
    return {
      name: 'cjc',
      age: 999
    }
  },

  watch: {
    // 方式1
    name(newVal, oldVal) {
      console.log(newVal, oldVal);
    },

    // 方式2
    age: {
      handler(newVal, oldVal) {
        console.log(newVal, oldVal);
      },
      // Vue实例初始化的时候立即调用watch的监听回调函数
      immediate: true,
      // 深度监听
      deep: true
    }
  }
}
</script>
<style lang="less"></style>

监听对象某个属性

// 监听某个属性
"infos.a": {
    handler(newVal, oldVal) {
        console.log(newVal, oldVal);
    }
}

排除某些属性的监听

mounted() {
    Object.keys(this.params)
      .filter((_) => !["c", "d"].includes(_)) // 排除对c,d属性的监听
      .forEach((_) => {
        this.$watch((vm) => vm.params[_], handler, {
          deep: true,
        });
      });
  },
data() {
    return {
      params: {
        a: 1,
        b: 2,
        c: 3,
        d: 4
      },
    };
  },
watch: {
    params: {
      deep: true,
      handler() {
        this.getList;
      },
    },
  }

Vue3计算属性和侦听器

computed

基本用法

  1. 多对一
  2. 有缓存(响应式数据没发生变化时,使用缓存的数据)
  3. 不能异步代码
<template>
  <div>
    <h1>总价为:{{ total }}</h1>
    <h1>总价为:{{ total2 }}</h1>
  </div>
</template>

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

const goods = reactive([
  { id: 1, price: 1, nums: 1 },
  { id: 1, price: 2, nums: 2 },
  { id: 1, price: 3, nums: 3 }
])

// 1.computed格式1 传入回调函数,只支持getter
const total = computed(() => {
  return goods.reduce((pre, cur) => {
    return pre + cur.price * cur.nums
  }, 0)
})

// 2.computed格式2 传入对象,支持getter、setter
const total2 = computed({
  get() {
    return goods.reduce((pre, cur) => {
      return pre + cur.price * cur.nums
    }, 0)
  },
  set(newVal) {
    console.log('total2被赋值修改了', newVal);
  }
})

total2.value++
</script>

<style scoped></style>

购物车

在这里插入图片描述
筛选后的总价:
在这里插入图片描述

<template>
  <div class="App">
    <input type="text" placeholder="输入商品名称" v-model="keyWord" />
    <table>
      <thead>
        <th>物品</th>
        <th>数量</th>
        <th>单价</th>
        <th>价格</th>
        <th>操作</th>
      </thead>
      <tbody>
        <tr v-for="(item, index) in searchGoods" :key="item.name">
          <td>{{ item.name }}</td>
          <td>
            <button @click="item.num > 1 ? item.num-- : num">-1</button>
            {{ item.num }}
            <button @click="item.num++">+1</button>
          </td>
          <td>{{ item.price }}</td>
          <td>{{ item.price * item.num }}</td>
          <td><button @click="handleDel(index)">删除</button></td>
        </tr>
      </tbody>
      <tfoot>
        <tr>
          <td colspan="5">所有物品总价{{ total }}</td>
        </tr>
        <tr>
          <td colspan="5">筛选后的总价{{ total2 }}</td>
        </tr>
      </tfoot>
    </table>
  </div>
</template>

<script setup lang="ts">
import { ref, reactive, computed } from "vue";
let goods = reactive([
  {
    name: "a",
    num: 1,
    price: 1,
  },
  {
    name: "b",
    num: 2,
    price: 2,
  },
  {
    name: "c",
    num: 3,
    price: 3,
  },
]);

// 总价
const total = computed(() => {
  return goods.reduce((pre, cur, index) => {
    return pre + cur.num * cur.price;
  }, 0);
});
const total2 = computed(() => {
  return searchGoods.value.reduce((pre, cur, index) => {
    return pre + cur.num * cur.price;
  }, 0);
});

// 删除
function handleDel(index) {
  goods.splice(index, 1);
}

// 搜索
const keyWord = ref<string>("");
const searchGoods = computed(() => {
  return goods.filter((item, index) => {
    return item.name.includes(keyWord.value);
  });
});
</script>

<style scoped>
th,
td {
  border: 1px solid #ccc;
}

td {
  text-align: center;
  padding: 10px;
}
</style>

给计算属性传参

给计算属性传参:以返回函数的形式接收参数。

<template>
  <div>
    <h1>{{ total(arr1) }}</h1>
    <h1>{{ total(arr2) }}</h1>

    <!-- <h1>总价为:{{ total2 }}</h1> -->
  </div>
</template>

<script setup>

import { ref, reactive, computed } from 'vue'

const arr1 = reactive([1, 2, 3])
const arr2 = reactive([1, 1, 1])

// 给计算属性传参:以返回函数的形式接收参数。
const total = computed((arr) => {
  return function (arr) {
    return arr.reduce((pre, cur) => {
      return pre + cur
    }, 0)
  }
})

</script>

<style scoped></style>

watch

基本使用

  1. 一对多
  2. 没有有缓存
  3. 能异步代码
<template>
  <div class="App">
    <!-- <input type="text" v-model="objRef.a.b.c" /> -->
    <div>姓名:<input type="text" v-model="name" /></div>
    <div>年龄:<input type="text" v-model="age" /></div>
    <div>objRef:<input type="text" v-model="objRef.a.b.c" /></div>
  </div>
</template>

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

// 1.监听多个数据源
const name = ref("cjc");
const age = ref(100);

watch(
  [name, age],
  (newArr, oldArr) => {
    console.log("newArr", newArr);
    console.log("oldArr", oldArr);
  },
  {
    deep: true,
  }
);

// 2.监听对象的某一属性
const objRef = ref({
  a: {
    b: {
      c: "c",
    },
  },
});

watch(
  () => objRef.value.a.b.c,
  (val, oldValue) => {
    console.log(val, oldValue);
  },
  {
    deep: true,
  }
);
</script>

watchEffect

基本用法

  1. 初始时自动调用一次回调函数
  2. 回调函数中用到几个监听几个,watchEffect 自动收集响应式数据的依赖
  3. 当依赖发生变化时,回调函数再次执行,执行过程中收集依赖
<template>
  <div class="App">
    {{ info.arr }}
    <button @click="info.arr.push('c')">添加arr</button>
    <button @click="info.name = 'cjc'">修改name</button>
    <button @click="stopWatch()">暂停监听</button>
  </div>
</template>

<script setup lang="ts">
import { ref, watchEffect } from "vue";
const info = ref({
  name: "CCC",
  age: 999,
  arr: ["a", "b"],
});

// watchEffect返回暂停监听器函数
const stopWatch = watchEffect((onCleanup) => {
  // 修改基本类型的值
  console.log(info.value.name);

  // 修改引用类型的值,不触发监听
  console.log(info.value.arr);
});
</script>

清除副作用

就是在触发监听之前会调用一个函数可以处理你的逻辑例如防抖

const stopWatch = watchEffect(
  (onCleanup) => {
    console.log(info.value.name);
    console.log(info.value.arr);

    onCleanup(() => {
      console.log("触发监听后最先执行的逻辑");
    });
  },
  {
    flush: "sync",
  }
);

副作用刷新时机 flush 一般使用post

  • pre 组件更新之前
  • sync 强制同步执行
  • post 组件更新之后
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值