Skip to content

Commit

Permalink
first cimmit
Browse files Browse the repository at this point in the history
  • Loading branch information
jindy committed Jun 2, 2022
0 parents commit 0b29f82
Show file tree
Hide file tree
Showing 17 changed files with 620 additions and 0 deletions.
27 changes: 27 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
node_modules
.DS_Store
dist
dist-ssr
.zip

# local env files
# .env.local
# .env.*.local
*.local

# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
yarn.lock

# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

6 changes: 6 additions & 0 deletions babel.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module.exports = {
presets: [
['@babel/preset-env', {targets: {node: 'current'}}],
'@babel/preset-typescript',
],
};
4 changes: 4 additions & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
module.exports = {
preset: 'ts-jest',
testEnvironment: 'node',
};
19 changes: 19 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"name": "guide-mini-vue",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"scripts": {
"test": "jest"
},
"devDependencies": {
"@babel/core": "^7.18.0",
"@babel/preset-env": "^7.18.0",
"@babel/preset-typescript": "^7.17.12",
"@types/jest": "^27.5.1",
"babel-jest": "^28.1.0",
"jest": "^28.1.0",
"ts-jest": "^28.0.3",
"typescript": "^4.7.2"
}
}
63 changes: 63 additions & 0 deletions src/reactivity/baseHandles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { extend, isObject } from "../shared"
import { track, trigger } from "./effect"
import { reactive, ReactiveFlags, readonly } from "./reactive"

const get = createGetter()
const set = createSetter()
const readonlyGet = createGetter(true)
const shallowReadonlyGet = createGetter(true, true)

function createGetter(isReadonly = false, isShallow = false) {
return function get(target, key) {
if (key === ReactiveFlags.IS_REACTIVE) {
return !isReadonly
} else if (key === ReactiveFlags.IS_READONLY) {
return isReadonly
}

const res = Reflect.get(target, key)

if (isShallow) {
return res
}

if (isObject(res)) {
return isReadonly ? readonly(res) : reactive(res)
}

if (!isReadonly) {
// TODO 依赖收集
track(target, key)
}

return res
}
}

function createSetter() {
return function set(target, key, value) {
const res = Reflect.set(target, key, value)

// TODO 触发依赖
trigger(target, key)

return res
}
}

export const mutableHandles = {
get,
set,
}

export const readonlyHandles = {
get: readonlyGet,
set(target, key, value) {
console.warn(`key:${key}set 失败,因为target是readonly:${target}`)
return true
},
}

export const shallowReadonlyHandles = extend({}, readonlyHandles, {
get: shallowReadonlyGet,
})
110 changes: 110 additions & 0 deletions src/reactivity/effect.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import { extend } from "../shared"

class ReactiveEffect {
private _fn: any
deps = []
active = true
onStop?: () => void
public scheduler: Function | undefined
constructor(fn, scheduler?: Function) {
this._fn = fn
this.scheduler = scheduler
}
run() {
if (!this.active) {
return this._fn()
}

shouldTrack = true
activeEffect = this

const result = this._fn()
shouldTrack = false
activeEffect = undefined

return result
}
stop() {
// this.deps.forEach((dep: any) => dep.delete(this))
if (this.active) {
if (this.onStop) {
this.onStop()
}
cleanupEffect(this)
this.active = false
}
}
}

function cleanupEffect(effect) {
effect.deps.forEach((dep: any) => {
dep.delete(effect)
})
}

const targetMap = new Map()
export function track(target, key) {
if (!isTracking()) {
return
}
// target => key => dep
let depsMap = targetMap.get(target)
if (!depsMap) {
depsMap = new Map()
targetMap.set(target, depsMap)
}
let dep = depsMap.get(key)
if (!dep) {
dep = new Set()
depsMap.set(key, dep)
}
trackEffect(dep)
}

export function trackEffect(dep) {
if (dep.has(activeEffect)) return
dep.add(activeEffect)
activeEffect.deps.push(dep)
}

export function trigger(target, key) {
let depsMap = targetMap.get(target)
let dep = depsMap.get(key)
triggerEffect(dep)
}

export function triggerEffect(dep) {
for (const effect of dep) {
if (effect.scheduler) {
effect.scheduler()
} else {
effect.run()
}
}
}

let activeEffect,
shouldTrack = false
export function effect(fn, options: any = {}) {
const _effect = new ReactiveEffect(fn, options.scheduler)
// _effect.onStop = options.onStop
// options
// Object.assign(_effect, options)
// extend
extend(_effect, options)

_effect.run()

const runner: any = _effect.run.bind(_effect)

runner.effect = _effect
return runner
}

export function stop(runner) {
runner.effect.stop()
}

export function isTracking() {
return shouldTrack && activeEffect != undefined
}
3 changes: 3 additions & 0 deletions src/reactivity/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export function add(a, b) {
return a + b
}
38 changes: 38 additions & 0 deletions src/reactivity/reactive.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import {
mutableHandles,
readonlyHandles,
shallowReadonlyHandles,
} from "../reactivity/baseHandles"

export const enum ReactiveFlags {
IS_REACTIVE = "__v_isReactive",
IS_READONLY = "__v_isReadonly",
}

export function reactive(raw) {
return createActiveObject(raw, mutableHandles)
}

export function readonly(raw) {
return createActiveObject(raw, readonlyHandles)
}

export function shallowReadonly(raw) {
return createActiveObject(raw, shallowReadonlyHandles)
}

export function isReactive(value): Boolean {
return !!value[ReactiveFlags.IS_REACTIVE]
}

export function isReadonly(value): Boolean {
return !!value[ReactiveFlags.IS_READONLY]
}

export function isProxy(value): Boolean {
return isReactive(value) || isReadonly(value)
}

function createActiveObject(raw: any, baseHandles) {
return new Proxy(raw, baseHandles)
}
31 changes: 31 additions & 0 deletions src/reactivity/ref.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { hasChange } from "./../shared/index"
import { isTracking, trackEffect, triggerEffect } from "./effect"

class RefImpl {
private _value: any
public dep
constructor(value) {
this._value = value
this.dep = new Set()
}
get value() {
trackRefValue(this)
return this._value
}
set value(newValue) {
if (hasChange(newValue, this._value)) {
this._value = newValue
triggerEffect(this.dep)
}
}
}

function trackRefValue(ref) {
if (isTracking()) {
trackEffect(ref.dep)
}
}

export function ref(value) {
return new RefImpl(value)
}
Loading

0 comments on commit 0b29f82

Please sign in to comment.