- 该文章是在学习 小满vue3 课程的随堂记录
- 示例均采用
,且包含
typescript
的基础用法
本篇文章主要学习 computed
的 基本使用方式
、简单购物车实战
、源码理解
computed 支持两种定义方式:选项式
、函数式
对象格式
,对象内部有 get
、set
函数可读可写
<div class="">
firstName: <input type="text" v-model="firstName" />
<br />
lastName: <input type="text" v-model="lastName" />
<br />
fullName: {{ fullName }}
<br />
<button @click="change">设置fullNamebutton>
div>
import { ref, reactive, computed } from "vue";
const firstName = ref<string>("张");
const lastName = ref<string>("三");
const fullName = computed({
// get 函数用于获取
get() {
return firstName.value + "-" + lastName.value;
},
// set 函数用于设置
set(newVal) {
// 数组的解构赋值
[firstName.value, lastName.value] = newVal.split("-");
},
});
const change = () => {
fullName.value = "李-四";
};
只读
,只能获取 不能修改<div class="">
firstName: <input type="text" v-model="firstName" />
<br />
lastName: <input type="text" v-model="lastName" />
<br />
fullName2: {{ fullName2 }}
div>
const fullName2 = computed(() => {
return firstName.value + "***" + lastName.value;
});
// 这里修改会报错:Cannot assign to 'value' because it is a read-only property
// fullName2.value = "王-五";
设计一个购物车,可以实现简单的 商品数量增减
、单种商品总价
、总计价格
、购物车搜索
功能
效果如图:
<div>
<input
type="text"
v-model="keyword"
placeholder="computed购物车案例——搜索"
style="width: 400px"
/>
<br />
<table
border
width="500"
cellspacing="0"
cellpadding="0"
style="margin-top: 10px"
>
<thead>
<tr>
<th>物品名称th>
<th>物品单价th>
<th>物品数量th>
<th>物品总价th>
<th>操作th>
tr>
thead>
<tbody>
<tr v-for="(item, index) in searchData" :key="index">
<td>{{ item.name }}td>
<td>{{ item.price }}td>
<td>
<button @click="item.num > 1 ? item.num-- : null">-button>
{{ item.num }}
<button @click="item.num < 99 ? item.num++ : null">+button>
td>
<td>{{ item.num * item.price }}td>
<td>
<button @click="del(index)">删除button>
td>
tr>
tbody>
<tfoot>
<tr>
<td>总价:{{ total }}td>
tr>
tfoot>
table>
div>
const keyword = ref<string>("");
interface Data {
name: string;
price: number;
num: number;
}
// 原始数组
const data = reactive<Data[]>([
{
name: "小满的绿帽子",
price: 100,
num: 1,
},
{
name: "小满的红衣服",
price: 200,
num: 1,
},
{
name: "小满的黑袜子",
price: 300,
num: 1,
},
]);
// 总价
const total = computed(() => {
return data.reduce((pre, cur) => {
return pre + cur.num * cur.price;
}, 0);
});
// 删除
const del = (index: number) => {
data.splice(index, 1);
};
// 搜索数组
const searchData = computed(() => {
return data.filter((item) => item.name.includes(keyword.value));
});
源码学习记录:
/**
*
* computed()
*
* 1、如果 computed 的第一个参数是函数,说明是只读的传入形式,将参数赋值给 getter, setter为空或在开发环境抛出警告
*
* 2、否则则为选项式传参,直接去第一个参数里面读 get 和 set 并赋值
*
*
* ComputedRefImpl
*
* 1、这个类是创建 computed 的核心函数
*
* 2、_dirty:是否是脏的,是否需要重新计算(脏值检测原理!!),默认是 true(如果值没有发生变化,就会使用缓存中的值)
*
* 3、get value() 的写法,可以看出,内部是劫持了 value 属性 (ref)
*
* - toRaw 先将 this 脱离 proxy 代理
* - _dirty 若为 true,则需要重新计算
*
* - _dirty 设置为 false(下次不需要再走进来)
* - self.effect.run() 读取 return出来值的操作(根据依赖变化后计算出的新值)
*
*
* - _cacheable 若为 false,即缓存不可用,那肯定也是要走进重新计算的
* - 否则直接返回现有的值
*
* 4、构造函数 中的 ReactiveEffect,源码中搜索 class ReactiveEffect
*
* - ReactiveEffect(fn, scheduler, scope)
* - 跟上一章学习的 effect 是一样的,对其进行扩展,支持了调度(scheduler)
* - effect(() => { 依赖函数 })
*
* 5、调度函数又是在哪里调用的? trigger -> triggerEffect 函数中调用
* - 也就是说 当依赖发生变化时,才会调用 scheduler
*
* 6、new ReactiveEffect 传入的 scheduler 函数体中会将 _dirty 置为 true(即依赖发生变化时,_dirty置为true)
* 然后在 get value() 时,走进的就是 run(),即重新获取不读缓存
*
* 7、依赖未改变时,_dirty 一直是 false,再次访问就会取老的值,不会重新获取
*
*/