vue3.0中的computed写法
作者:Akimoto Hiroshi
vue3.0 computed写法
用computed计算属性之前别忘了引入
使用完毕别忘了导出
computed里面还有两个方法:get和set
- get方法:
结果:
get方法是读取数据时候调用的,监测到数据变化以后就自动执行:
结果:
点击以后:
说明get在程序运行时自动调用,后面监测到数据变化就再次调用
我们改一下代码:
点击前结果:
点击后结果:
所以我们能得出: 点击button以后,执行到plusOne.value = 2
时候,相当于调用了:
// 其中参数val就是修改的值2 set: val => { console.log('executing function set') return count.value = val - 1 }
所以现在count的值为2-1=1,这样的值改变引起set方法的注意,被监测到了,所以继续执行:
get: () => { console.log('executing function get') return count.value + 1 }
这样count的值变成1+1 = 2
所以最后显示2
vue3.0 computed的使用及其注意点
为什么使用
当我们不想在template的html元素上写很长的js逻辑时,我们就会想使用计算属性computed
使用
computed
传入一个 getter 函数,返回一个默认不可手动修改的 ref 对象。
取自官网:https://vue3js.cn/reactivity/computed.html#computed
const count = ref(1) const plusOne = computed(() => count.value + 1) console.log(plusOne.value) // 2 plusOne.value++ // 错误! // 或者传入一个拥有 get 和 set 函数的对象,创建一个可手动修改的计算状态。 const count = ref(1) const plusOne = computed({ get: () => count.value + 1, set: (val) => { count.value = val - 1 }, }) plusOne.value = 1 console.log(count.value) // 0 // 更多文档: https://vue3js.cn/vue-composition-api/#computed
正文
计算属性,可能会依赖其他 reactive 的值,同时会延迟和缓存计算值
export function computed<T>( getterOrOptions: ComputedGetter<T> | WritableComputedOptions<T> ) { let getter: ComputedGetter<T> let setter: ComputedSetter<T> // 如果传入是 function 说明是只读 computed if (isFunction(getterOrOptions)) { getter = getterOrOptions setter = __DEV__ ? () => { console.warn('Write operation failed: computed value is readonly') } : NOOP } else { // 不是方法说明是自定义的 getter setter getter = getterOrOptions.get setter = getterOrOptions.set } let dirty = true let value: T let computed: ComputedRef<T> // 创建 effect, 我们在看 effect 源码时知道了传入 lazy 代表不会立即执行,computed 表明 computed 上游依赖改变的时候,会优先 trigger runner effect, scheduler 表示 effect trigger 的时候会调用 scheduler 而不是直接调用 effect const runner = effect(getter, { lazy: true, // mark effect as computed so that it gets priority during trigger computed: true, scheduler: () => { // 在触发更新时把dirty置为true, 不会立即更新 if (!dirty) { dirty = true trigger(computed, TriggerOpTypes.SET, 'value') } } }) // 构造一个 computed 返回 computed = { __v_isRef: true, // expose effect so computed can be stopped effect: runner, get value() { // dirty为ture, get操作时,执行effect获取最新值 // if (dirty) { value = runner() dirty = false } // dirty为false, 表示值未更新,直接返回 track(computed, TrackOpTypes.GET, 'value') return value }, set value(newValue: T) { setter(newValue) } } as any return computed }
注意事项
如果存在计算属性依赖其他异步或者props传进的属性,再通过state.xxx获取最新属性值进行判断,那么就必须写在getter回调里,例如:
const haveFile = computed(() => state.jobInfo.fileName ? state.jobInfo.fileName.includes('http') : false); const permitProduct = computed(() => !state.isPower || state.isDqcFinish); const permitDownl = computed(() => !state.isPower || !haveFile.value);
我们可以看到permitProduct 和permitDownl 都依赖state.isPower这个变量值,且该变量写在watch监听中,随时可能改变,因此,我们console.log写在permitDownl 变量的下一行,可能看不到最新结果的打印:
const haveFile = computed(() => state.jobInfo.fileName ? state.jobInfo.fileName.includes('http') : false); const permitProduct = computed(() => !state.isPower || state.isDqcFinish); const permitDownl = computed(() => !state.isPower || !haveFile.value); console.log('state.isPower ===>', state.isPower);
正确的做法,应该是写在getter回调里:
const haveFile = computed(() => state.jobInfo.fileName ? state.jobInfo.fileName.includes('http') : false); const permitProduct = computed(() => !state.isPower || state.isDqcFinish); const permitDownl = computed(() => { console.log('state.isPower ===>', state.isPower); // 此时可以获得最新值 return !state.isPower || !haveFile.value; });
并且要注意的一点是,如果当前计算属性依赖其他计算属性,例如上面所写的permitDownl 依赖于 haveFile,这时,写法就必须是haveFile.value而非haveFile
计算属性获取值在非template区域,而是在js区域内,则必须使用propname.value去获取值!
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。