feat(computed): 添加计算属性功能实现

- 实现了 ComputedRefImpl 类来管理计算属性
- 添加了 computed 函数用于创建计算属性
- 在 ReactiveEffect 中添加 computed 属性引用
- 将 computed 导出到 reactivity 和 vue 主包
- 添加了 isFunction 工具函数判断函数类型
- 创建了计算属性的 HTML 示例文件进行演示
This commit is contained in:
dj
2026-02-08 15:19:49 +08:00
parent c0853b353d
commit 4c60486511
6 changed files with 64 additions and 1 deletions

View File

@@ -0,0 +1,30 @@
import { isFunction } from '@vue/shared'
import { Dep } from './dep'
import { ReactiveEffect } from './effect'
import { trackRefValue } from './ref'
export class ComputedRefImpl<T> {
public dep?: Dep = undefined
private _value!: T
public readonly effect: ReactiveEffect<T>
public readonly __v_isRef = true
constructor(getter) {
this.effect = new ReactiveEffect(getter)
this.effect.computed = this
}
get value() {
trackRefValue(this) //触发依赖
this._value = this.effect.run()
return this._value
}
}
export function computed(getterOrOptions) {
let getter
const onlyGetter = isFunction(getterOrOptions)
if (onlyGetter) {
getter = getterOrOptions
}
const cRef = new ComputedRefImpl(getter)
return cRef
}

View File

@@ -1,5 +1,6 @@
import { createDep, Dep } from './dep'
import { isArray } from '@vue/shared'
import { ComputedRefImpl } from './computed'
type KeyToDepMap = Map<any, Dep>
/**
@@ -19,6 +20,7 @@ export function effect<T = any>(fn: () => T) {
export let activeEffect: ReactiveEffect | undefined
export class ReactiveEffect<T = any> {
computed?: ComputedRefImpl<T>
constructor(public fn: () => T) {}
run() {
//当前被激活的effect实例

View File

@@ -1,3 +1,4 @@
export { reactive } from './reactive'
export { effect } from './effect'
export { ref } from './ref'
export { computed } from './computed'

View File

@@ -9,3 +9,7 @@ export const isObject = (val: unknown) =>
*/
export const hasChanged = (value: any, oldValue: any): boolean =>
!Object.is(value, oldValue)
export const isFunction = (val: unknown): val is Function => {
return typeof val === 'function'
}

View File

@@ -0,0 +1,26 @@
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Document</title>
<script src="../../dist/vue.js"></script>
</head>
<body>
<div id="app"></div>
</body>
<script>
const { reactive,effect,computed } = Vue
const obj=reactive({
name:'张三'
})
const computedObj= computed(()=>{
return '姓名:'+obj.name
})
effect(()=>{
document.querySelector('#app').innerText=computedObj.value
})
setTimeout(()=>{
obj.name='李四'
},2000)
</script>
</html>

View File

@@ -1 +1 @@
export { reactive, effect, ref } from '@vue/reactivity'
export { reactive, effect, ref, computed } from '@vue/reactivity'