feat(computed): 添加计算属性功能实现
- 实现了 ComputedRefImpl 类来管理计算属性 - 添加了 computed 函数用于创建计算属性 - 在 ReactiveEffect 中添加 computed 属性引用 - 将 computed 导出到 reactivity 和 vue 主包 - 添加了 isFunction 工具函数判断函数类型 - 创建了计算属性的 HTML 示例文件进行演示
This commit is contained in:
30
packages/reactivity/src/computed.ts
Normal file
30
packages/reactivity/src/computed.ts
Normal 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
|
||||
}
|
||||
@@ -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实例
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
export { reactive } from './reactive'
|
||||
export { effect } from './effect'
|
||||
export { ref } from './ref'
|
||||
export { computed } from './computed'
|
||||
|
||||
@@ -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'
|
||||
}
|
||||
|
||||
26
packages/vue/examples/reactivity/computed.html
Normal file
26
packages/vue/examples/reactivity/computed.html
Normal 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>
|
||||
@@ -1 +1 @@
|
||||
export { reactive, effect, ref } from '@vue/reactivity'
|
||||
export { reactive, effect, ref, computed } from '@vue/reactivity'
|
||||
|
||||
Reference in New Issue
Block a user