Vue3计算属性
Posted monana6
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Vue3计算属性相关的知识,希望对你有一定的参考价值。
计算属性
// 1. 响应式数据
const data = reactive( count: 0 );
// 2. 计算属性
const plusOne = computed(() => data.count + 1);
// 3. 依赖收集
effect(() => console.log(plusOne.value));
// 4. 触发上面的effect重新执行
data.count++;
为什么data.count
的改变能间接触发访问了计算属性的 effect 的重新执行呢?
首先看一下简化版本的computed
的代码
export function computed(getter)
let dirty = true;
let value: T;
// 这里还是利用了effect做依赖收集
const runner = effect(getter,
// 这里保证初始化的时候不去执行getter
lazy: true, //表示effect函数返回的runner并不会立即执行,懒加载
computed: true, // 表示这是一个computed effect,用于trigger阶段的优先级排序
// 调度执行顺序的实现
scheduler: () =>
// 在触发更新时 只是把dirty置为true
// 而不去立刻计算值 所以计算属性有lazy的特性
dirty = true;
,
);
return
get value()
if (dirty)
// 在真正的去获取计算属性的value的时候
// 依据dirty的值决定去不去重新执行getter 获取最新值
value = runner();
dirty = false;
// 这里是关键 后续讲解
trackChildRun(runner);
return value;
,
set value(newValue: T)
setter(newValue);
,
;
首先要知道,effect 函数会立即开始执行,再执行之前,先把
effect自身
变成全局的activeEffect
,以供响应式数据收集依赖。并且
activeEffect
的记录是用的栈的方式,随着函数的开始进行入栈,随着函数的结束出栈。这样就可以维护嵌套的effect关系。
先起几个别名便于讲解
// 计算effect
const plusOne =computed(() => data.count + 1);
// 日志effect
effect(() => console.log(plusOne.value));
从依赖关系来看,
日志effect
读取了计算effect
计算effect
读取了响应式属性count
所以更新的顺序也应该是:
count改变` -> `计算effect更新` -> `日志effect更新
解读
当日志effect开始执行的时候,此时的activeEffect
是日志effect,此时的 effectStack
是[ 日志 effect ]
执行日志effect读取了plusOne.value,进而触发了
get value()
if (dirty)
// 在真正的去获取计算属性的value的时候
// 依据dirty的值决定去不去重新执行getter 获取最新值
value = runner()
dirty = false
// 这里是关键 后续讲解
trackChildRun(runner)
return value
,
首先进入了求值过程:value = runner(),runner 其实就是计算effect,它是对于用户传入的 getter 函数的包装
进入runner()函数之后,此时的activeEffect就是计算effect,此时的 `effectStack` 是[ 日志 effect, 计算 effect]
runner 所包裹的() => data.count + 1
也就是计算effect
会去读取count
,因为是由 effect 包裹的函数,所以触发了响应式数据的get
拦截:
此时count
会收集计算effect
作为自己的依赖。
并且计算effect
会收集count
的依赖集合,保存在自己身上。(通过effect.deps
属性)
dep.add(activeEffect);
activeEffect.deps.push(dep);
也就是形成了一个双向收集的关系,于是计算effect有了count的所有依赖,count
也存了计算effect
的依赖。
然后在 runner 运行结束后,计算effect
出栈了,此时activeEffect
变成了栈顶的日志effect
此时activeEffect
是日志 effect,此时的effectStack
是[ 日志 effect ]
接下来进入关键的步骤:`trackChildRun()`
trackChildRun(runner);
function trackChildRun(childRunner: ReactiveEffect)
for (let i = 0; i < childRunner.deps.length; i++)
const dep = childRunner.deps[i];
dep.add(activeEffect);
这个runner
就是计算effect
,它的deps
上此时挂着count
的依赖集合,
在trackChildRun
中,它把当前的 activeEffect 也就是日志effect
也加入到了count
的依赖集合中。
此时count
的依赖集合是这样的:[ 计算effect, 日志effect ]
这样下次count
更新的时候,会把两个 effect 都重新触发,而由于触发的顺序是先触发computed effect
后触发普通effect
,因此就完成了
- 计算 effect 的 dirty 置为 true,标志着下次读取需要重新求值。
- 日志 effect 读取计算 effect 的 value,获得最新的值并打印出来。
Vue_(组件)计算属性
Vue计算属性中文文档 传送门
Vue计算属性:更强大的属性声明方式,可以对定义的属性进行逻辑处理与数据监视;
注意:模板内的表达式非常便利,但是设计它们的初衷是用于简单运算的。在模板中放入太多的逻辑会让模板过重且难以维护
Learn
一、计算属性的基本使用
二、计算属性的getter和setter
三、计算属性与方法的区别【重点】 传送门
项目结构
【每个demo下方都存有html源码】
一、计算属性的基本使用
计算属性computed中对<input>组件中msg信息进行事件监听
data:{ msg:‘Hello Gary!!‘ }, computed : { msg1 : function(){ return this.msg.toUpperCase(); } }
<div> <input type="text" v-model="msg" /><br /> 原样文本显示:<h1>{{msg}}</h1><br /> 大写文本显示:<h1>{{msg.toUpperCase()}}</h1><br /> 计算属性文本显示:<h1>{{msg1}}</h1><br /> </div>
两种方法使原文本显示数据小写全部转换为大写
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Gary</title> <script type="text/javascript" src="../js/vue.js"></script> <script> window.onload= ()=>{ new Vue({ el:‘div‘, data:{ msg:‘Hello Gary!!‘ }, computed : { msg1 : function(){ return this.msg.toUpperCase(); } } }); } </script> </head> <body> <div> <input type="text" v-model="msg" /><br /> 原样文本显示:<h1>{{msg}}</h1><br /> 大写文本显示:<h1>{{msg.toUpperCase()}}</h1><br /> 计算属性文本显示:<h1>{{msg1}}</h1><br /> </div> </body> </html>
二、计算属性的getter和setter
需求:需要计算属性文本要比原样文本数字大10
计算属性computed中对<input>组件中对num1数字信息进行事件监听
data:{ num:0 }, computed : { num1: function(){ return parseInt(this.num) + 10; } }
<div> <input type="text" v-model="num" /><br /> 原样文本显示:<h1>{{num}}</h1><br /> <input type="text" v-model="num1" /><br /> 计算属性文本显示:<h1>{{num1}}</h1><br /> </div>
发现只能正向从原样显示去修改计算属性中num1的数值,如果要从计算属性去修改原样文本显示,需要设置计算属性的get和set方法
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Gary</title> <script type="text/javascript" src="../js/vue.js"></script> <script> window.onload= ()=>{ new Vue({ el:‘div‘, data:{ num:0 }, computed : { num1: function(){ return parseInt(this.num) + 10; } } }); } </script> </head> <body> <div> <input type="text" v-model="num" /><br /> 原样文本显示:<h1>{{num}}</h1><br /> <input type="text" v-model="num1" /><br /> 计算属性文本显示:<h1>{{num1}}</h1><br /> </div> </body> </html>
给计算属性显示设置get和set方法
data:{ num:0 }, computed : { num1 : { get : function(){ return parseInt(this.num) + 10; }, set : function(value){ this.num = value; } } }
注意:set方法中是this.num=value,num1的值去监听num值的变化
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Gary</title> <script type="text/javascript" src="../js/vue.js"></script> <script> window.onload= ()=>{ new Vue({ el:‘div‘, data:{ num:0 }, computed : { num1 : { get : function(){ return parseInt(this.num) + 10; }, set : function(value){ this.num = value; } } } }); } </script> </head> <body> <div> <input type="text" v-model="num" /><br /> 原样文本显示:<h1>{{num}}</h1><br /> <input type="text" v-model="num1" /><br /> 计算属性文本显示:<h1>{{num1}}</h1><br /> </div> </body> </html>
三、计算属性与方法的区别
计算属性有缓存机制,方法没有
只要计算属性内相关依赖的值不发生改变,多次调用计算属性可以从缓存中获取值,不必重复计算
方法每次调用都要重新执行一遍
小写转化成大写计算属性写法
data : { msg : ‘Gary‘ }, computed : { msg1 : function(){ console.log("执行计算属性computed"); return this.msg.toUpperCase(); }
小写转化成大写方法写法
data : { msg : ‘Gary‘ }, methods : { upperCase(){ console.log("执行方法methods"); return this.msg.toUpperCase(); },
添加个<button>组件去展示输入文本中转化成大写后的内容,用来查看计算属性与方法区别
<div> <input type="text" v-model="msg" /><br /> 原样显示:<h1>{{msg}}</h1><br /> 计算属性显示:<h1>{{msg1}}</h1><br /> 方法显示:<h1>{{upperCase()}}</h1><br /> <button @click="show">show</button> </div>
show(){ console.log("计算属性展示文本中的内容 :" + this.msg1); console.log("方法调用展示文本中的内容 :" + this.upperCase()); }
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Gary</title> <script type="text/javascript" src="../js/vue.js" ></script> <script> window.onload = () => { new Vue({ el : ‘div‘, data : { msg : ‘Gary‘ }, computed : { msg1 : function(){ console.log("执行计算属性computed"); return this.msg.toUpperCase(); } }, methods : { upperCase(){ console.log("执行方法methods"); return this.msg.toUpperCase(); }, show(){ console.log("计算属性展示文本中的内容 :" + this.msg1); console.log("方法调用展示文本中的内容 :" + this.upperCase()); } } }); } </script> </head> <body> <div> <input type="text" v-model="msg" /><br /> 原样显示:<h1>{{msg}}</h1><br /> 计算属性显示:<h1>{{msg1}}</h1><br /> 方法显示:<h1>{{upperCase()}}</h1><br /> <button @click="show">show</button> </div> </body> </html>
以上是关于Vue3计算属性的主要内容,如果未能解决你的问题,请参考以下文章