@actview/core 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +163 -0
- package/README.zh.md +163 -0
- package/compile.d.ts +3 -0
- package/compile.d.ts.map +1 -0
- package/computed.d.ts +3 -0
- package/computed.d.ts.map +1 -0
- package/diff.d.ts +9 -0
- package/diff.d.ts.map +1 -0
- package/event.d.ts +8 -0
- package/event.d.ts.map +1 -0
- package/index.cjs +324 -0
- package/index.cjs.map +1 -0
- package/index.d.ts +8 -0
- package/index.d.ts.map +1 -0
- package/index.mjs +324 -0
- package/index.mjs.map +1 -0
- package/package.json +44 -0
- package/reactive.d.ts +5 -0
- package/reactive.d.ts.map +1 -0
- package/ref.d.ts +3 -0
- package/ref.d.ts.map +1 -0
- package/state.d.ts +4 -0
- package/state.d.ts.map +1 -0
- package/types/index.d.ts +16 -0
- package/types/index.d.ts.map +1 -0
- package/watch.d.ts +3 -0
- package/watch.d.ts.map +1 -0
- package/watchEffect.d.ts +6 -0
- package/watchEffect.d.ts.map +1 -0
package/README.md
ADDED
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
# @actview/core
|
|
2
|
+
|
|
3
|
+
The core reactive system for Actview, providing Vue-style reactive APIs.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @actview/core
|
|
9
|
+
# or
|
|
10
|
+
pnpm add @actview/core
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## API
|
|
14
|
+
|
|
15
|
+
### `ref<T>(value: T): Ref<T>`
|
|
16
|
+
|
|
17
|
+
Creates a reactive reference. Access and modify the value through `.value`.
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
import { ref } from '@actview/core'
|
|
21
|
+
|
|
22
|
+
const count = ref(0)
|
|
23
|
+
console.log(count.value) // 0
|
|
24
|
+
|
|
25
|
+
count.value++
|
|
26
|
+
console.log(count.value) // 1
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### `reactive<T>(value: T): T`
|
|
30
|
+
|
|
31
|
+
Creates a reactive object with deep reactivity support, including arrays.
|
|
32
|
+
|
|
33
|
+
```typescript
|
|
34
|
+
import { reactive } from '@actview/core'
|
|
35
|
+
|
|
36
|
+
const state = reactive({
|
|
37
|
+
name: 'Actview',
|
|
38
|
+
items: [1, 2, 3]
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
state.name = 'New Name' // triggers update
|
|
42
|
+
state.items.push(4) // triggers update
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### `computed<T>(getter: () => T): Ref<T>`
|
|
46
|
+
|
|
47
|
+
Creates a computed property that automatically recalculates when dependencies change.
|
|
48
|
+
|
|
49
|
+
```typescript
|
|
50
|
+
import { ref, computed } from '@actview/core'
|
|
51
|
+
|
|
52
|
+
const count = ref(1)
|
|
53
|
+
const double = computed(() => count.value * 2)
|
|
54
|
+
|
|
55
|
+
console.log(double.value) // 2
|
|
56
|
+
|
|
57
|
+
count.value = 5
|
|
58
|
+
console.log(double.value) // 10
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### `watch<T>(source, callback)`
|
|
62
|
+
|
|
63
|
+
Watches reactive data changes. Supports `ref`, `reactive` objects, or getter functions.
|
|
64
|
+
|
|
65
|
+
```typescript
|
|
66
|
+
import { ref, watch } from '@actview/core'
|
|
67
|
+
|
|
68
|
+
const count = ref(0)
|
|
69
|
+
|
|
70
|
+
// Watch a ref
|
|
71
|
+
watch(count, (newVal, oldVal) => {
|
|
72
|
+
console.log(`count changed: ${oldVal} -> ${newVal}`)
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
// Watch a getter function
|
|
76
|
+
watch(
|
|
77
|
+
() => count.value * 2,
|
|
78
|
+
(newVal, oldVal) => {
|
|
79
|
+
console.log(`double changed: ${oldVal} -> ${newVal}`)
|
|
80
|
+
}
|
|
81
|
+
)
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### `watchEffect(callback: () => void)`
|
|
85
|
+
|
|
86
|
+
Immediately executes the callback and automatically tracks dependencies. Re-executes when dependencies change.
|
|
87
|
+
|
|
88
|
+
```typescript
|
|
89
|
+
import { ref, watchEffect } from '@actview/core'
|
|
90
|
+
|
|
91
|
+
const count = ref(0)
|
|
92
|
+
|
|
93
|
+
watchEffect(() => {
|
|
94
|
+
console.log(`count is: ${count.value}`)
|
|
95
|
+
})
|
|
96
|
+
// Immediately outputs: count is: 0
|
|
97
|
+
|
|
98
|
+
count.value = 1
|
|
99
|
+
// Outputs: count is: 1
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### `compile(option: Option)`
|
|
103
|
+
|
|
104
|
+
Configuration-driven DOM binding. Automatically binds data and events through selectors.
|
|
105
|
+
|
|
106
|
+
```typescript
|
|
107
|
+
import { ref, compile } from '@actview/core'
|
|
108
|
+
|
|
109
|
+
const visible = ref(true)
|
|
110
|
+
const message = ref('Hello')
|
|
111
|
+
|
|
112
|
+
compile({
|
|
113
|
+
selector: '#app',
|
|
114
|
+
show: () => visible.value,
|
|
115
|
+
text: () => message.value,
|
|
116
|
+
listeners: [
|
|
117
|
+
{ type: 'click', callback: () => visible.value = !visible.value }
|
|
118
|
+
]
|
|
119
|
+
})
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
#### Option Properties
|
|
123
|
+
|
|
124
|
+
| Property | Type | Description |
|
|
125
|
+
|----------|------|-------------|
|
|
126
|
+
| `selector` | `string` | jQuery selector |
|
|
127
|
+
| `show` | `boolean \| () => boolean` | Controls element visibility |
|
|
128
|
+
| `text` | `string \| () => string` | Sets element text content |
|
|
129
|
+
| `render` | `() => string \| Node` | Custom render function (supports JSX) |
|
|
130
|
+
| `listeners` | `Listener[]` | Event listeners array |
|
|
131
|
+
|
|
132
|
+
## Type Definitions
|
|
133
|
+
|
|
134
|
+
```typescript
|
|
135
|
+
// Reactive reference
|
|
136
|
+
type Ref<T> = {
|
|
137
|
+
value: T
|
|
138
|
+
__isRef: true
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Event listener (type-safe)
|
|
142
|
+
type Listener<K extends keyof HTMLElementEventMap> = {
|
|
143
|
+
type: K
|
|
144
|
+
callback: (e: HTMLElementEventMap[K]) => void
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// compile options
|
|
148
|
+
type Option = {
|
|
149
|
+
selector: string
|
|
150
|
+
show?: boolean | (() => boolean)
|
|
151
|
+
text?: string | (() => string)
|
|
152
|
+
listeners?: Listener[]
|
|
153
|
+
render?: () => string | HTMLElement | Text | DocumentFragment
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## Dependencies
|
|
158
|
+
|
|
159
|
+
- `jquery` ^4.0.0
|
|
160
|
+
|
|
161
|
+
## License
|
|
162
|
+
|
|
163
|
+
MIT
|
package/README.zh.md
ADDED
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
# @actview/core
|
|
2
|
+
|
|
3
|
+
Actview 的核心响应式系统,提供 Vue 风格的响应式 API。
|
|
4
|
+
|
|
5
|
+
## 安装
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @actview/core
|
|
9
|
+
# 或
|
|
10
|
+
pnpm add @actview/core
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## API
|
|
14
|
+
|
|
15
|
+
### `ref<T>(value: T): Ref<T>`
|
|
16
|
+
|
|
17
|
+
创建一个响应式引用,通过 `.value` 访问和修改值。
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
import { ref } from '@actview/core'
|
|
21
|
+
|
|
22
|
+
const count = ref(0)
|
|
23
|
+
console.log(count.value) // 0
|
|
24
|
+
|
|
25
|
+
count.value++
|
|
26
|
+
console.log(count.value) // 1
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### `reactive<T>(value: T): T`
|
|
30
|
+
|
|
31
|
+
创建一个响应式对象,支持深层响应式和数组。
|
|
32
|
+
|
|
33
|
+
```typescript
|
|
34
|
+
import { reactive } from '@actview/core'
|
|
35
|
+
|
|
36
|
+
const state = reactive({
|
|
37
|
+
name: 'Actview',
|
|
38
|
+
items: [1, 2, 3]
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
state.name = 'New Name' // 触发更新
|
|
42
|
+
state.items.push(4) // 触发更新
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### `computed<T>(getter: () => T): Ref<T>`
|
|
46
|
+
|
|
47
|
+
创建一个计算属性,依赖变化时自动重新计算。
|
|
48
|
+
|
|
49
|
+
```typescript
|
|
50
|
+
import { ref, computed } from '@actview/core'
|
|
51
|
+
|
|
52
|
+
const count = ref(1)
|
|
53
|
+
const double = computed(() => count.value * 2)
|
|
54
|
+
|
|
55
|
+
console.log(double.value) // 2
|
|
56
|
+
|
|
57
|
+
count.value = 5
|
|
58
|
+
console.log(double.value) // 10
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### `watch<T>(source, callback)`
|
|
62
|
+
|
|
63
|
+
监听响应式数据变化,支持 `ref`、`reactive` 对象或 getter 函数。
|
|
64
|
+
|
|
65
|
+
```typescript
|
|
66
|
+
import { ref, watch } from '@actview/core'
|
|
67
|
+
|
|
68
|
+
const count = ref(0)
|
|
69
|
+
|
|
70
|
+
// 监听 ref
|
|
71
|
+
watch(count, (newVal, oldVal) => {
|
|
72
|
+
console.log(`count changed: ${oldVal} -> ${newVal}`)
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
// 监听 getter 函数
|
|
76
|
+
watch(
|
|
77
|
+
() => count.value * 2,
|
|
78
|
+
(newVal, oldVal) => {
|
|
79
|
+
console.log(`double changed: ${oldVal} -> ${newVal}`)
|
|
80
|
+
}
|
|
81
|
+
)
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### `watchEffect(callback: () => void)`
|
|
85
|
+
|
|
86
|
+
立即执行回调函数,并自动追踪依赖,依赖变化时重新执行。
|
|
87
|
+
|
|
88
|
+
```typescript
|
|
89
|
+
import { ref, watchEffect } from '@actview/core'
|
|
90
|
+
|
|
91
|
+
const count = ref(0)
|
|
92
|
+
|
|
93
|
+
watchEffect(() => {
|
|
94
|
+
console.log(`count is: ${count.value}`)
|
|
95
|
+
})
|
|
96
|
+
// 立即输出: count is: 0
|
|
97
|
+
|
|
98
|
+
count.value = 1
|
|
99
|
+
// 输出: count is: 1
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### `compile(option: Option)`
|
|
103
|
+
|
|
104
|
+
配置驱动的 DOM 绑定,通过选择器自动绑定数据和事件。
|
|
105
|
+
|
|
106
|
+
```typescript
|
|
107
|
+
import { ref, compile } from '@actview/core'
|
|
108
|
+
|
|
109
|
+
const visible = ref(true)
|
|
110
|
+
const message = ref('Hello')
|
|
111
|
+
|
|
112
|
+
compile({
|
|
113
|
+
selector: '#app',
|
|
114
|
+
show: () => visible.value,
|
|
115
|
+
text: () => message.value,
|
|
116
|
+
listeners: [
|
|
117
|
+
{ type: 'click', callback: () => visible.value = !visible.value }
|
|
118
|
+
]
|
|
119
|
+
})
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
#### Option 配置项
|
|
123
|
+
|
|
124
|
+
| 属性 | 类型 | 说明 |
|
|
125
|
+
|------|------|------|
|
|
126
|
+
| `selector` | `string` | jQuery 选择器 |
|
|
127
|
+
| `show` | `boolean \| () => boolean` | 控制元素显示/隐藏 |
|
|
128
|
+
| `text` | `string \| () => string` | 设置元素文本内容 |
|
|
129
|
+
| `render` | `() => string \| Node` | 自定义渲染函数(支持 JSX) |
|
|
130
|
+
| `listeners` | `Listener[]` | 事件监听器列表 |
|
|
131
|
+
|
|
132
|
+
## 类型定义
|
|
133
|
+
|
|
134
|
+
```typescript
|
|
135
|
+
// 响应式引用
|
|
136
|
+
type Ref<T> = {
|
|
137
|
+
value: T
|
|
138
|
+
__isRef: true
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// 事件监听器(类型安全)
|
|
142
|
+
type Listener<K extends keyof HTMLElementEventMap> = {
|
|
143
|
+
type: K
|
|
144
|
+
callback: (e: HTMLElementEventMap[K]) => void
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// compile 配置
|
|
148
|
+
type Option = {
|
|
149
|
+
selector: string
|
|
150
|
+
show?: boolean | (() => boolean)
|
|
151
|
+
text?: string | (() => string)
|
|
152
|
+
listeners?: Listener[]
|
|
153
|
+
render?: () => string | HTMLElement | Text | DocumentFragment
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## 依赖
|
|
158
|
+
|
|
159
|
+
- `jquery` ^4.0.0
|
|
160
|
+
|
|
161
|
+
## License
|
|
162
|
+
|
|
163
|
+
MIT
|
package/compile.d.ts
ADDED
package/compile.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compile.d.ts","sourceRoot":"","sources":["../compile.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAOjC,wBAAgB,OAAO,CAAC,MAAM,EAAE,MAAM,QA4ErC"}
|
package/computed.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"computed.d.ts","sourceRoot":"","sources":["../computed.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,SAAS,CAAA;AAI7B,wBAAgB,QAAQ,CAAC,CAAC,EAAE,UAAU,EAAE,MAAK,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAStD"}
|
package/diff.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 简单的 DOM Diff 算法
|
|
3
|
+
* @param oldNode 旧节点
|
|
4
|
+
* @param newNode 新节点
|
|
5
|
+
* @returns 实际更新后的节点(如果是替换操作,返回新节点;如果是属性更新,返回旧节点)
|
|
6
|
+
*/
|
|
7
|
+
export declare function diff(oldNode: Node, newNode: Node): Node;
|
|
8
|
+
export declare function diffChildren(parent: HTMLElement, oldList: (Node | undefined | null)[], newList: (Node | undefined | null)[]): void;
|
|
9
|
+
//# sourceMappingURL=diff.d.ts.map
|
package/diff.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diff.d.ts","sourceRoot":"","sources":["../diff.ts"],"names":[],"mappings":"AACA;;;;;GAKG;AACH,wBAAgB,IAAI,CAAC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,GAAG,IAAI,CAqCvD;AAsED,wBAAgB,YAAY,CAAC,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,CAAC,IAAI,GAAG,SAAS,GAAG,IAAI,CAAC,EAAE,EAAE,OAAO,EAAE,CAAC,IAAI,GAAG,SAAS,GAAG,IAAI,CAAC,EAAE,QAkB3H"}
|
package/event.d.ts
ADDED
package/event.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event.d.ts","sourceRoot":"","sources":["../event.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,SAAS,CAAC;AAE9B,qBAAa,QAAQ;IACnB,OAAO,CAAC,WAAW,CAAsC;IAGzD,SAAS,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,CAAC,EAAE,QAAQ,EAAE,MAAM,IAAI;IAQ7C,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,CAAC;CAItB;AAED,eAAO,MAAM,QAAQ,UAAiB,CAAC"}
|
package/index.cjs
ADDED
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
4
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
5
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
6
|
+
const $ = require("jquery");
|
|
7
|
+
class EventBus {
|
|
8
|
+
constructor() {
|
|
9
|
+
__publicField(this, "subscribers", /* @__PURE__ */ new Map());
|
|
10
|
+
}
|
|
11
|
+
// 订阅
|
|
12
|
+
subscribe(ref2, callback) {
|
|
13
|
+
var _a;
|
|
14
|
+
if (!this.subscribers.has(ref2)) {
|
|
15
|
+
this.subscribers.set(ref2, /* @__PURE__ */ new Set());
|
|
16
|
+
}
|
|
17
|
+
(_a = this.subscribers.get(ref2)) == null ? void 0 : _a.add(callback);
|
|
18
|
+
}
|
|
19
|
+
// 发布
|
|
20
|
+
publish(ref2) {
|
|
21
|
+
const callbacks = this.subscribers.get(ref2);
|
|
22
|
+
if (callbacks) callbacks.forEach((cb) => cb());
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
const eventBus = new EventBus();
|
|
26
|
+
let currentUpdateFn = null;
|
|
27
|
+
function setCurrentUpdateFn(fn) {
|
|
28
|
+
currentUpdateFn = fn;
|
|
29
|
+
}
|
|
30
|
+
function getCurrentUpdateFn() {
|
|
31
|
+
return currentUpdateFn;
|
|
32
|
+
}
|
|
33
|
+
function ref(value) {
|
|
34
|
+
const obj = { value, __isRef: true };
|
|
35
|
+
const state = new Proxy(obj, {
|
|
36
|
+
set: (target, key, value2) => {
|
|
37
|
+
if (key === "value") {
|
|
38
|
+
target[key] = value2;
|
|
39
|
+
eventBus.publish(state);
|
|
40
|
+
}
|
|
41
|
+
return true;
|
|
42
|
+
},
|
|
43
|
+
get: (target, key) => {
|
|
44
|
+
const currentUpdateFn2 = getCurrentUpdateFn();
|
|
45
|
+
if (key === "value" && currentUpdateFn2) {
|
|
46
|
+
eventBus.subscribe(state, currentUpdateFn2);
|
|
47
|
+
}
|
|
48
|
+
return target[key];
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
return state;
|
|
52
|
+
}
|
|
53
|
+
function computed(computedFn) {
|
|
54
|
+
const computedRef = ref(null);
|
|
55
|
+
const updateFn = () => {
|
|
56
|
+
computedRef.value = computedFn();
|
|
57
|
+
};
|
|
58
|
+
setCurrentUpdateFn(updateFn);
|
|
59
|
+
updateFn();
|
|
60
|
+
setCurrentUpdateFn(null);
|
|
61
|
+
return computedRef;
|
|
62
|
+
}
|
|
63
|
+
function watchEffect(callback) {
|
|
64
|
+
setCurrentUpdateFn(callback);
|
|
65
|
+
callback();
|
|
66
|
+
setCurrentUpdateFn(null);
|
|
67
|
+
}
|
|
68
|
+
const reactiveTriggerMap = /* @__PURE__ */ new WeakMap();
|
|
69
|
+
function getReactiveTriggerRef(target) {
|
|
70
|
+
if (target && typeof target === "object") return reactiveTriggerMap.get(target) ?? null;
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
function reactive(inittialValue) {
|
|
74
|
+
const triggerRef = { value: null, __isRef: true };
|
|
75
|
+
const createReactiveObject = (obj) => {
|
|
76
|
+
if (obj === null || typeof obj !== "object") return obj;
|
|
77
|
+
if (Array.isArray(obj)) {
|
|
78
|
+
return reactiveArray(obj);
|
|
79
|
+
}
|
|
80
|
+
const proxy = new Proxy(obj, {
|
|
81
|
+
get(target, key) {
|
|
82
|
+
const currentUpdateFn2 = getCurrentUpdateFn();
|
|
83
|
+
if (currentUpdateFn2) eventBus.subscribe(triggerRef, currentUpdateFn2);
|
|
84
|
+
const value = target[key];
|
|
85
|
+
if (value !== null && typeof value === "object") {
|
|
86
|
+
return createReactiveObject(value);
|
|
87
|
+
}
|
|
88
|
+
return value;
|
|
89
|
+
},
|
|
90
|
+
set(target, key, newValue) {
|
|
91
|
+
const oldValue = target[key];
|
|
92
|
+
if (oldValue !== newValue) {
|
|
93
|
+
target[key] = newValue;
|
|
94
|
+
eventBus.publish(triggerRef);
|
|
95
|
+
}
|
|
96
|
+
return true;
|
|
97
|
+
},
|
|
98
|
+
deleteProperty(target, key) {
|
|
99
|
+
const result = Reflect.deleteProperty(target, key);
|
|
100
|
+
eventBus.publish(triggerRef);
|
|
101
|
+
return result;
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
reactiveTriggerMap.set(proxy, triggerRef);
|
|
105
|
+
return proxy;
|
|
106
|
+
};
|
|
107
|
+
return createReactiveObject(inittialValue);
|
|
108
|
+
}
|
|
109
|
+
function reactiveArray(inittialValue) {
|
|
110
|
+
const arrayMethods = [
|
|
111
|
+
"push",
|
|
112
|
+
"pop",
|
|
113
|
+
"shift",
|
|
114
|
+
"unshift",
|
|
115
|
+
"splice",
|
|
116
|
+
"soft",
|
|
117
|
+
"reverse",
|
|
118
|
+
"fill",
|
|
119
|
+
"copyWithin"
|
|
120
|
+
];
|
|
121
|
+
const triggerRef = { value: null, __isRef: true };
|
|
122
|
+
if (Array.isArray(inittialValue)) {
|
|
123
|
+
const proxy = new Proxy(inittialValue.map((item) => reactive(item)), {
|
|
124
|
+
get(target, key) {
|
|
125
|
+
const value = target[key];
|
|
126
|
+
const currentUpdateFn2 = getCurrentUpdateFn();
|
|
127
|
+
if (currentUpdateFn2) eventBus.subscribe(triggerRef, currentUpdateFn2);
|
|
128
|
+
if (typeof key === "string" && arrayMethods.includes(key) && typeof value === "function") {
|
|
129
|
+
return function(...args) {
|
|
130
|
+
const result = value.apply(target, args);
|
|
131
|
+
eventBus.publish(triggerRef);
|
|
132
|
+
return result;
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
return value;
|
|
136
|
+
},
|
|
137
|
+
set(target, key, newValue) {
|
|
138
|
+
const result = Reflect.set(target, key, reactive(newValue));
|
|
139
|
+
if (typeof key === "string" && (!isNaN(Number(key)) || key === "length")) eventBus.publish(triggerRef);
|
|
140
|
+
return result;
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
reactiveTriggerMap.set(proxy, triggerRef);
|
|
144
|
+
return proxy;
|
|
145
|
+
}
|
|
146
|
+
return inittialValue;
|
|
147
|
+
}
|
|
148
|
+
function isRefLike(value) {
|
|
149
|
+
return !!value && typeof value === "object" && value.__isRef === true;
|
|
150
|
+
}
|
|
151
|
+
function watch(source, callback) {
|
|
152
|
+
if (typeof source === "function") {
|
|
153
|
+
const getter = source;
|
|
154
|
+
let oldValue;
|
|
155
|
+
const runGetter = () => {
|
|
156
|
+
setCurrentUpdateFn(job);
|
|
157
|
+
const value = getter();
|
|
158
|
+
setCurrentUpdateFn(null);
|
|
159
|
+
return value;
|
|
160
|
+
};
|
|
161
|
+
const job = () => {
|
|
162
|
+
const newValue = runGetter();
|
|
163
|
+
if (Object.is(newValue, oldValue)) return;
|
|
164
|
+
callback(newValue, oldValue);
|
|
165
|
+
oldValue = newValue;
|
|
166
|
+
};
|
|
167
|
+
oldValue = runGetter();
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
if (isRefLike(source)) {
|
|
171
|
+
const ref2 = source;
|
|
172
|
+
let oldValue = ref2.value;
|
|
173
|
+
eventBus.subscribe(
|
|
174
|
+
ref2,
|
|
175
|
+
() => {
|
|
176
|
+
const newValue = ref2.value;
|
|
177
|
+
if (Object.is(newValue, oldValue)) return;
|
|
178
|
+
callback(newValue, oldValue);
|
|
179
|
+
oldValue = newValue;
|
|
180
|
+
}
|
|
181
|
+
);
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
const triggerRef = getReactiveTriggerRef(source);
|
|
185
|
+
if (!triggerRef) {
|
|
186
|
+
throw new Error("watch 只能监控 ref、reactive 返回值,或 getter 函数");
|
|
187
|
+
}
|
|
188
|
+
let oldSnapshot = source;
|
|
189
|
+
eventBus.subscribe(triggerRef, () => {
|
|
190
|
+
const newSnapshot = source;
|
|
191
|
+
callback(newSnapshot, oldSnapshot);
|
|
192
|
+
oldSnapshot = newSnapshot;
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
function diff(oldNode, newNode) {
|
|
196
|
+
var _a;
|
|
197
|
+
if (oldNode.nodeType !== newNode.nodeType || oldNode.nodeName !== newNode.nodeName) {
|
|
198
|
+
(_a = oldNode.parentNode) == null ? void 0 : _a.replaceChild(newNode, oldNode);
|
|
199
|
+
return newNode;
|
|
200
|
+
}
|
|
201
|
+
if (oldNode.nodeType === Node.TEXT_NODE) {
|
|
202
|
+
if (oldNode.textContent !== newNode.textContent) {
|
|
203
|
+
oldNode.textContent = newNode.textContent;
|
|
204
|
+
}
|
|
205
|
+
return oldNode;
|
|
206
|
+
}
|
|
207
|
+
if (oldNode instanceof HTMLElement && newNode instanceof HTMLElement) {
|
|
208
|
+
updateAttributes(oldNode, newNode);
|
|
209
|
+
updateChildren(oldNode, newNode);
|
|
210
|
+
return oldNode;
|
|
211
|
+
}
|
|
212
|
+
if (oldNode instanceof DocumentFragment || newNode instanceof DocumentFragment) {
|
|
213
|
+
return newNode;
|
|
214
|
+
}
|
|
215
|
+
return oldNode;
|
|
216
|
+
}
|
|
217
|
+
function updateAttributes(oldNode, newNode) {
|
|
218
|
+
Array.from(oldNode.attributes).forEach((attr) => {
|
|
219
|
+
if (!newNode.hasAttribute(attr.name)) {
|
|
220
|
+
oldNode.removeAttribute(attr.name);
|
|
221
|
+
}
|
|
222
|
+
});
|
|
223
|
+
Array.from(newNode.attributes).forEach((attr) => {
|
|
224
|
+
if (oldNode.getAttribute(attr.name) !== attr.value) {
|
|
225
|
+
oldNode.setAttribute(attr.name, attr.value);
|
|
226
|
+
}
|
|
227
|
+
});
|
|
228
|
+
if ("value" in newNode && "value" in oldNode) {
|
|
229
|
+
const newValue = newNode.value;
|
|
230
|
+
const oldValue = oldNode.value;
|
|
231
|
+
const hasValueAttr = newNode.hasAttribute("value");
|
|
232
|
+
if (newValue !== oldValue) {
|
|
233
|
+
if (hasValueAttr || newValue !== "") {
|
|
234
|
+
oldNode.value = newValue;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
function updateChildren(oldParent, newParent) {
|
|
240
|
+
const oldChildren = Array.from(oldParent.childNodes);
|
|
241
|
+
const newChildren = Array.from(newParent.childNodes);
|
|
242
|
+
const maxLength = Math.max(oldChildren.length, newChildren.length);
|
|
243
|
+
for (let i = 0; i < maxLength; i++) {
|
|
244
|
+
const oldChild = oldChildren[i];
|
|
245
|
+
const newChild = newChildren[i];
|
|
246
|
+
if (!oldChild && newChild) {
|
|
247
|
+
oldParent.appendChild(newChild);
|
|
248
|
+
} else if (oldChild && !newChild) {
|
|
249
|
+
oldParent.removeChild(oldChild);
|
|
250
|
+
} else if (oldChild && newChild) {
|
|
251
|
+
diff(oldChild, newChild);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
function diffChildren(parent, oldList, newList) {
|
|
256
|
+
const maxLength = Math.max(oldList.length, newList.length);
|
|
257
|
+
for (let i = 0; i < maxLength; i++) {
|
|
258
|
+
const oldNode = oldList[i];
|
|
259
|
+
const newNode = newList[i];
|
|
260
|
+
if (!oldNode && newNode) {
|
|
261
|
+
parent.appendChild(newNode);
|
|
262
|
+
} else if (oldNode && !newNode) {
|
|
263
|
+
parent.removeChild(oldNode);
|
|
264
|
+
} else if (oldNode && newNode) {
|
|
265
|
+
diff(oldNode, newNode);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
function compile(option) {
|
|
270
|
+
const { selector, show, text, listeners, render } = option;
|
|
271
|
+
const element = $(selector);
|
|
272
|
+
const updateFn = () => {
|
|
273
|
+
const showValue = typeof show === "function" ? show() : show;
|
|
274
|
+
const textValue = typeof text === "function" ? text() : text;
|
|
275
|
+
if (textValue !== void 0) element.text(textValue);
|
|
276
|
+
showValue || showValue === void 0 ? element.show() : element.hide();
|
|
277
|
+
if (render && typeof render === "function") {
|
|
278
|
+
const lastRenderResult = element.data("__lastRenderResult");
|
|
279
|
+
const result = render();
|
|
280
|
+
if (typeof result === "string") {
|
|
281
|
+
element.empty();
|
|
282
|
+
element.text(result);
|
|
283
|
+
element.data("__lastRenderResult", null);
|
|
284
|
+
} else if (result instanceof Node) {
|
|
285
|
+
let currentNodes;
|
|
286
|
+
if (result instanceof DocumentFragment) {
|
|
287
|
+
currentNodes = Array.from(result.childNodes);
|
|
288
|
+
} else {
|
|
289
|
+
currentNodes = result;
|
|
290
|
+
}
|
|
291
|
+
if (lastRenderResult) {
|
|
292
|
+
if (!Array.isArray(lastRenderResult) && !Array.isArray(currentNodes) && lastRenderResult instanceof HTMLElement && currentNodes instanceof HTMLElement) {
|
|
293
|
+
const newDom = diff(lastRenderResult, currentNodes);
|
|
294
|
+
element.data("__lastRenderResult", newDom);
|
|
295
|
+
} else {
|
|
296
|
+
const oldList = Array.isArray(lastRenderResult) ? lastRenderResult : [lastRenderResult];
|
|
297
|
+
const newList = Array.isArray(currentNodes) ? currentNodes : [currentNodes];
|
|
298
|
+
diffChildren(element[0], oldList, newList);
|
|
299
|
+
element.data("__lastRenderResult", currentNodes);
|
|
300
|
+
}
|
|
301
|
+
} else {
|
|
302
|
+
element.empty();
|
|
303
|
+
element.append(result);
|
|
304
|
+
element.data("__lastRenderResult", currentNodes);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
};
|
|
309
|
+
setCurrentUpdateFn(updateFn);
|
|
310
|
+
updateFn();
|
|
311
|
+
setCurrentUpdateFn(null);
|
|
312
|
+
if (listeners && listeners.length > 0) {
|
|
313
|
+
listeners.forEach((listener) => {
|
|
314
|
+
element.on(listener.type, listener.callback);
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
exports.compile = compile;
|
|
319
|
+
exports.computed = computed;
|
|
320
|
+
exports.reactive = reactive;
|
|
321
|
+
exports.ref = ref;
|
|
322
|
+
exports.watch = watch;
|
|
323
|
+
exports.watchEffect = watchEffect;
|
|
324
|
+
//# sourceMappingURL=index.cjs.map
|
package/index.cjs.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":["../event.ts","../state.ts","../ref.ts","../computed.ts","../watchEffect.ts","../reactive.ts","../watch.ts","../diff.ts","../compile.ts"],"sourcesContent":["import { Ref } from \"./types\";\r\n\r\nexport class EventBus {\r\n private subscribers = new Map<Ref<any>, Set<()=>void>>();\r\n\r\n // 订阅\r\n subscribe(ref: Ref<any>, callback: () => void) {\r\n if (!this.subscribers.has(ref)) {\r\n this.subscribers.set(ref, new Set());\r\n }\r\n this.subscribers.get(ref)?.add(callback);\r\n }\r\n\r\n // 发布\r\n publish(ref: Ref<any>){\r\n const callbacks = this.subscribers.get(ref);\r\n if(callbacks) callbacks.forEach(cb=>cb())\r\n }\r\n}\r\n\r\nexport const eventBus = new EventBus();","export let currentUpdateFn: (() => void) | null = null;\r\n\r\nexport function setCurrentUpdateFn(fn: (() => void) | null) {\r\n currentUpdateFn = fn;\r\n}\r\n\r\nexport function getCurrentUpdateFn() {\r\n return currentUpdateFn;\r\n}\r\n","import { Ref } from \"./types\";\r\nimport { eventBus } from \"./event\";\r\nimport { getCurrentUpdateFn } from \"./state\";\r\nexport function ref<T>(value: T): Ref<T> {\r\n const obj = { value, __isRef: true };\r\n const state = new Proxy(obj, {\r\n set: (target, key, value) => {\r\n if (key === \"value\") {\r\n target[key] = value;\r\n eventBus.publish(state);\r\n }\r\n return true;\r\n },\r\n get: (target, key) => {\r\n const currentUpdateFn = getCurrentUpdateFn();\r\n if (key === \"value\" && currentUpdateFn) {\r\n eventBus.subscribe(state, currentUpdateFn);\r\n }\r\n return target[key as keyof typeof target];\r\n },\r\n }) as Ref<T>;\r\n return state;\r\n}","import { Ref } from \"./types\"\nimport { ref } from \"./ref\"\nimport { setCurrentUpdateFn } from \"./state\"\n\nexport function computed<T>(computedFn: ()=> T): Ref<T>{\n const computedRef = ref<T | null>(null)\n const updateFn = ()=> {\n computedRef.value = computedFn()\n }\n setCurrentUpdateFn(updateFn)\n updateFn()\n setCurrentUpdateFn(null)\n return computedRef as Ref<T>\n}\n","import { setCurrentUpdateFn } from \"./state\"\n\n/**\n * 监听响应式数据的变化,当数据变化时,调用回调函数\n * @param callback \n */\nexport function watchEffect(callback: () => void) {\n setCurrentUpdateFn(callback)\n callback()\n setCurrentUpdateFn(null)\n}","import { Ref } from \"./types\";\nimport { eventBus } from \"./event\";\nimport { getCurrentUpdateFn } from \"./state\";\n\nconst reactiveTriggerMap = new WeakMap<object, Ref<any>>()\n\nexport function getReactiveTriggerRef(target: unknown): Ref<any> | null {\n if(target && typeof target === 'object') return reactiveTriggerMap.get(target as object) ?? null\n return null\n}\n\nexport function reactive<T extends object>(inittialValue: T): T {\n const triggerRef = { value: null, __isRef: true as const } as Ref<any>\n\n const createReactiveObject = (obj: any): any=> {\n if(obj === null || typeof obj !== 'object') return obj\n \n // 如果是数组,递归处理每个元素\n if(Array.isArray(obj)){\n return reactiveArray(obj)\n }\n\n // 处理普通对象\n const proxy = new Proxy(obj, {\n get(target, key){\n const currentUpdateFn = getCurrentUpdateFn()\n if(currentUpdateFn) eventBus.subscribe(triggerRef, currentUpdateFn)\n \n const value = target[key]\n // 如果属性值是对象,递归代理\n if(value !== null && typeof value === 'object'){\n return createReactiveObject(value)\n }\n return value\n },\n set(target, key, newValue) {\n const oldValue = target[key]\n if(oldValue !== newValue) {\n target[key] = newValue\n eventBus.publish(triggerRef)\n }\n return true\n },\n deleteProperty(target, key){\n const result = Reflect.deleteProperty(target, key)\n eventBus.publish(triggerRef);\n return result;\n }\n \n })\n\n reactiveTriggerMap.set(proxy, triggerRef)\n return proxy\n }\n return createReactiveObject(inittialValue)\n}\n\n\nexport function reactiveArray<T extends object>(inittialValue: T): T {\n // 需要拦截的数组变更方法\n const arrayMethods = [\n 'push', 'pop', 'shift', 'unshift',\n 'splice', 'soft', 'reverse', 'fill',\n 'copyWithin'\n ]\n\n const triggerRef = {value: null, __isRef: true as const} as Ref<any>\n\n if(Array.isArray(inittialValue)){\n const proxy = new Proxy(inittialValue.map(item=>reactive(item)),{\n get(target, key){\n const value = target[key as keyof typeof target]\n const currentUpdateFn = getCurrentUpdateFn()\n if(currentUpdateFn) eventBus.subscribe(triggerRef,currentUpdateFn)\n \n if(typeof key === 'string' && arrayMethods.includes(key) && typeof value === 'function'){\n return function(...args: any[]){\n const result = (value as Function).apply(target, args);\n eventBus.publish(triggerRef);\n return result;\n }\n }\n\n return value;\n },\n set(target, key, newValue){\n const result = Reflect.set(target, key, reactive(newValue))\n if(typeof key === 'string' && (!isNaN(Number(key)) || key === 'length')) eventBus.publish(triggerRef)\n return result\n }\n }) as T\n reactiveTriggerMap.set(proxy as unknown as object, triggerRef)\n return proxy\n }\n return inittialValue\n}\n","import { Ref } from \"./types\";\nimport { eventBus } from \"./event\";\nimport { getReactiveTriggerRef } from \"./reactive\";\nimport { setCurrentUpdateFn } from \"./state\";\n\nfunction isRefLike<T = unknown>(value: unknown): value is Ref<T> {\n return !!value && typeof value === 'object' && (value as any).__isRef === true\n}\n\nexport function watch<T>(source: Ref<T> | (() => T) | object, callback: (newValue: T, oldValue: T) => void) {\n if(typeof source === 'function') {\n const getter = source as () => T\n let oldValue: T\n\n const runGetter = () => {\n setCurrentUpdateFn(job)\n const value = getter()\n setCurrentUpdateFn(null)\n return value\n }\n\n const job = () => {\n const newValue = runGetter()\n if(Object.is(newValue, oldValue)) return\n callback(newValue, oldValue)\n oldValue = newValue\n }\n\n oldValue = runGetter()\n return\n }\n\n if(isRefLike<T>(source)) {\n const ref = source as Ref<T>\n let oldValue = ref.value;\n\n eventBus.subscribe(\n ref,\n () => {\n const newValue = ref.value;\n if(Object.is(newValue, oldValue)) return\n callback(newValue, oldValue);\n oldValue = newValue;\n }\n );\n return\n }\n\n const triggerRef = getReactiveTriggerRef(source)\n if(!triggerRef) {\n throw new Error('watch 只能监控 ref、reactive 返回值,或 getter 函数')\n }\n\n let oldSnapshot = source as T\n eventBus.subscribe(triggerRef, () => {\n const newSnapshot = source as T\n callback(newSnapshot, oldSnapshot)\n oldSnapshot = newSnapshot\n })\n}\n","\n/**\n * 简单的 DOM Diff 算法\n * @param oldNode 旧节点\n * @param newNode 新节点\n * @returns 实际更新后的节点(如果是替换操作,返回新节点;如果是属性更新,返回旧节点)\n */\nexport function diff(oldNode: Node, newNode: Node): Node {\n // 1. 如果节点类型不同,直接替换\n if (oldNode.nodeType !== newNode.nodeType || oldNode.nodeName !== newNode.nodeName) {\n oldNode.parentNode?.replaceChild(newNode, oldNode);\n return newNode;\n }\n\n // 2. 文本节点处理\n if (oldNode.nodeType === Node.TEXT_NODE) {\n if (oldNode.textContent !== newNode.textContent) {\n oldNode.textContent = newNode.textContent;\n }\n return oldNode;\n }\n\n // 3. 元素节点处理\n if (oldNode instanceof HTMLElement && newNode instanceof HTMLElement) {\n // 3.1 更新属性\n updateAttributes(oldNode, newNode);\n\n // 3.2 更新子节点\n updateChildren(oldNode, newNode);\n \n return oldNode;\n }\n \n // DocumentFragment 处理(简单策略:直接把新内容插进去,不做精细 diff)\n if (oldNode instanceof DocumentFragment || newNode instanceof DocumentFragment) {\n // Fragment 比较特殊,插入后就消失了,这里无法复用 oldNode\n // 简单策略:如果父节点存在,用新 Fragment 替换旧位置的所有内容\n // 但由于 Fragment 插入后不可追踪,这里我们假设 compile.ts 里的用法场景:\n // 如果上次是 Fragment,这次也是 Fragment,我们很难直接 diff 它们(因为 Fragment 自身不留在 DOM 树上)\n // 所以对于 Fragment,建议在 compile 层直接全量替换,或者 diff 算法只处理 Element/Text\n return newNode;\n }\n\n return oldNode;\n}\n\nfunction updateAttributes(oldNode: HTMLElement, newNode: HTMLElement) {\n // 移除旧属性\n Array.from(oldNode.attributes).forEach(attr => {\n if (!newNode.hasAttribute(attr.name)) {\n oldNode.removeAttribute(attr.name);\n }\n });\n\n // 设置新属性\n Array.from(newNode.attributes).forEach(attr => {\n if (oldNode.getAttribute(attr.name) !== attr.value) {\n oldNode.setAttribute(attr.name, attr.value);\n }\n });\n \n // 特殊处理 value (input/textarea)\n // 只有当新节点显式设置了 value 属性(attribute)或者新节点的 value 属性(property)与默认空值不同时,才去同步 property\n // 这样可以避免“非受控组件”的用户输入被意外清空\n // 但对于受控组件(render 里 value={state}),如果 state 没变(render 出的 value 还是旧的),\n // 这里也会把用户输入重置回旧 state(符合 React 受控组件行为)。\n if ('value' in newNode && 'value' in oldNode) {\n const newValue = (newNode as any).value;\n const oldValue = (oldNode as any).value;\n \n // 只有当新值确实不同,且新节点似乎是有意设置了值时才更新\n // 简单的判断:如果新节点的 value 和它的 defaultValue (即 attribute) 一致,\n // 或者新节点有 value attribute,我们才认为它是受控的或者有明确初值的。\n // 如果新节点完全没设 value(attribute 是 null,property 是空串),可能是个“无辜”的非受控节点,\n // 这时如果旧节点有用户输入(oldValue != \"\"),我们尽量保留它。\n \n const hasValueAttr = newNode.hasAttribute('value');\n if (newValue !== oldValue) {\n // 如果新节点有显式的 value 属性,或者新节点的 value 属性不为空,强制同步\n if (hasValueAttr || newValue !== '') {\n (oldNode as any).value = newValue;\n }\n }\n }\n}\n\nfunction updateChildren(oldParent: HTMLElement, newParent: HTMLElement) {\n const oldChildren = Array.from(oldParent.childNodes);\n const newChildren = Array.from(newParent.childNodes);\n \n const maxLength = Math.max(oldChildren.length, newChildren.length);\n\n for (let i = 0; i < maxLength; i++) {\n const oldChild = oldChildren[i];\n const newChild = newChildren[i];\n\n if (!oldChild && newChild) {\n // 新增节点\n // 注意:这里需要 clone newChild,因为 appendChild 会移动节点\n // 但由于我们是在构建新的 vdom(这里其实是真实 dom),直接移过去也没问题,\n // 不过 diff 函数通常假设 newNode 是个模版。\n // 在当前框架下,newNode 是 render() 刚刚生成的新鲜 DOM,直接移动即可。\n oldParent.appendChild(newChild);\n } else if (oldChild && !newChild) {\n // 删除节点\n oldParent.removeChild(oldChild);\n } else if (oldChild && newChild) {\n // 递归 diff\n diff(oldChild, newChild);\n }\n }\n}\n\n\nexport function diffChildren(parent: HTMLElement, oldList: (Node | undefined | null)[], newList: (Node | undefined | null)[]) {\n const maxLength = Math.max(oldList.length, newList.length);\n \n for (let i = 0; i < maxLength; i++) {\n const oldNode = oldList[i];\n const newNode = newList[i];\n\n if (!oldNode && newNode) {\n // 新增\n parent.appendChild(newNode);\n } else if (oldNode && !newNode) {\n // 删除\n parent.removeChild(oldNode);\n } else if (oldNode && newNode) {\n // 对比更新\n diff(oldNode as Node, newNode);\n }\n }\n}","import { Option } from \"./types\";\r\nimport $ from \"jquery\";\r\nimport { setCurrentUpdateFn } from \"./state\";\r\n\r\n\r\nimport { diff, diffChildren } from \"./diff\";\r\n\r\nexport function compile(option: Option) {\r\n const { selector, show, text, listeners,render } = option;\r\n\r\n const element = $(selector);\r\n\r\n const updateFn = () => {\r\n const showValue = typeof show === \"function\" ? show() : show;\r\n const textValue = typeof text === \"function\" ? text() : text;\r\n if (textValue !== undefined) element.text(textValue);\r\n showValue || showValue === undefined ? element.show() : element.hide();\r\n if(render && typeof render === 'function'){\r\n // 获取上一次渲染的 DOM 结构(可能是单个 Node,也可能是 Node 列表)\r\n // 如果是 Fragment,我们需要追踪的是它的 childNodes 列表,而不是 Fragment 本身\r\n const lastRenderResult = element.data('__lastRenderResult') as Node | Node[] | undefined\r\n \r\n const result = render()\r\n \r\n if(typeof result === 'string') {\r\n element.empty()\r\n element.text(result)\r\n element.data('__lastRenderResult', null)\r\n } else if(result instanceof Node) {\r\n // 准备本次渲染的“追踪对象”\r\n // 如果是 Fragment,我们需要克隆一份它的子节点列表(因为 append 后 Fragment 就空了)\r\n let currentNodes: Node | Node[];\r\n if (result instanceof DocumentFragment) {\r\n currentNodes = Array.from(result.childNodes);\r\n } else {\r\n currentNodes = result;\r\n }\r\n\r\n if (lastRenderResult) {\r\n // 执行 Diff\r\n // 情况 1: 都是单个元素 (Element vs Element)\r\n if (!Array.isArray(lastRenderResult) && !Array.isArray(currentNodes) && \r\n lastRenderResult instanceof HTMLElement && currentNodes instanceof HTMLElement) {\r\n const newDom = diff(lastRenderResult, currentNodes)\r\n element.data('__lastRenderResult', newDom)\r\n } \r\n // 情况 2: 涉及列表/Fragment (List vs List / Element vs List / List vs Element)\r\n else {\r\n // 暂时降级:如果涉及 Fragment 列表 diff,逻辑比较复杂(需要类似 Vue 的列表 diff),\r\n // 这里为了稳健,如果检测到列表长度没变且 key 没变(这里没 key),可以尝试原地 patch?\r\n // 鉴于目前 diff 算法较弱,先保留“清空重绘”逻辑,但我们可以优化一下:\r\n // 如果是列表对列表,我们可以尝试一一对比?\r\n \r\n // 简单起见,我们对 Fragment 场景仍然做全量替换,以保证正确性。\r\n // 如果你想解决 input 失去焦点问题,必须在这里实现真正的列表 diff。\r\n // 也就是:diffArrays(oldChildren, newChildren, parent)\r\n \r\n // 下面尝试一个简单的列表 diff (无 key,按 index 对比)\r\n const oldList = Array.isArray(lastRenderResult) ? lastRenderResult : [lastRenderResult];\r\n const newList = Array.isArray(currentNodes) ? currentNodes : [currentNodes];\r\n \r\n diffChildren(element[0], oldList, newList);\r\n element.data('__lastRenderResult', currentNodes) // 注意:这里存的是新生成的节点引用\r\n }\r\n } else {\r\n // 首次渲染\r\n element.empty()\r\n element.append(result)\r\n element.data('__lastRenderResult', currentNodes)\r\n }\r\n }\r\n }\r\n };\r\n\r\n setCurrentUpdateFn(updateFn);\r\n updateFn();\r\n setCurrentUpdateFn(null);\r\n\r\n if (listeners && listeners.length > 0) {\r\n listeners.forEach((listener) => {\r\n element.on(listener.type, listener.callback);\r\n });\r\n }\r\n}\r\n\r\n\r\n"],"names":["ref","value","currentUpdateFn"],"mappings":"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"}
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { ref } from "./ref";
|
|
2
|
+
export { computed } from "./computed";
|
|
3
|
+
export { watchEffect } from "./watchEffect";
|
|
4
|
+
export { watch } from "./watch";
|
|
5
|
+
export { reactive } from "./reactive";
|
|
6
|
+
export { compile } from "./compile";
|
|
7
|
+
export * from './types';
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
package/index.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,OAAO,CAAA;AAC3B,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AACrC,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAC3C,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAA;AAC/B,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AACrC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,cAAc,SAAS,CAAA"}
|
package/index.mjs
ADDED
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
4
|
+
import $ from "jquery";
|
|
5
|
+
class EventBus {
|
|
6
|
+
constructor() {
|
|
7
|
+
__publicField(this, "subscribers", /* @__PURE__ */ new Map());
|
|
8
|
+
}
|
|
9
|
+
// 订阅
|
|
10
|
+
subscribe(ref2, callback) {
|
|
11
|
+
var _a;
|
|
12
|
+
if (!this.subscribers.has(ref2)) {
|
|
13
|
+
this.subscribers.set(ref2, /* @__PURE__ */ new Set());
|
|
14
|
+
}
|
|
15
|
+
(_a = this.subscribers.get(ref2)) == null ? void 0 : _a.add(callback);
|
|
16
|
+
}
|
|
17
|
+
// 发布
|
|
18
|
+
publish(ref2) {
|
|
19
|
+
const callbacks = this.subscribers.get(ref2);
|
|
20
|
+
if (callbacks) callbacks.forEach((cb) => cb());
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
const eventBus = new EventBus();
|
|
24
|
+
let currentUpdateFn = null;
|
|
25
|
+
function setCurrentUpdateFn(fn) {
|
|
26
|
+
currentUpdateFn = fn;
|
|
27
|
+
}
|
|
28
|
+
function getCurrentUpdateFn() {
|
|
29
|
+
return currentUpdateFn;
|
|
30
|
+
}
|
|
31
|
+
function ref(value) {
|
|
32
|
+
const obj = { value, __isRef: true };
|
|
33
|
+
const state = new Proxy(obj, {
|
|
34
|
+
set: (target, key, value2) => {
|
|
35
|
+
if (key === "value") {
|
|
36
|
+
target[key] = value2;
|
|
37
|
+
eventBus.publish(state);
|
|
38
|
+
}
|
|
39
|
+
return true;
|
|
40
|
+
},
|
|
41
|
+
get: (target, key) => {
|
|
42
|
+
const currentUpdateFn2 = getCurrentUpdateFn();
|
|
43
|
+
if (key === "value" && currentUpdateFn2) {
|
|
44
|
+
eventBus.subscribe(state, currentUpdateFn2);
|
|
45
|
+
}
|
|
46
|
+
return target[key];
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
return state;
|
|
50
|
+
}
|
|
51
|
+
function computed(computedFn) {
|
|
52
|
+
const computedRef = ref(null);
|
|
53
|
+
const updateFn = () => {
|
|
54
|
+
computedRef.value = computedFn();
|
|
55
|
+
};
|
|
56
|
+
setCurrentUpdateFn(updateFn);
|
|
57
|
+
updateFn();
|
|
58
|
+
setCurrentUpdateFn(null);
|
|
59
|
+
return computedRef;
|
|
60
|
+
}
|
|
61
|
+
function watchEffect(callback) {
|
|
62
|
+
setCurrentUpdateFn(callback);
|
|
63
|
+
callback();
|
|
64
|
+
setCurrentUpdateFn(null);
|
|
65
|
+
}
|
|
66
|
+
const reactiveTriggerMap = /* @__PURE__ */ new WeakMap();
|
|
67
|
+
function getReactiveTriggerRef(target) {
|
|
68
|
+
if (target && typeof target === "object") return reactiveTriggerMap.get(target) ?? null;
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
function reactive(inittialValue) {
|
|
72
|
+
const triggerRef = { value: null, __isRef: true };
|
|
73
|
+
const createReactiveObject = (obj) => {
|
|
74
|
+
if (obj === null || typeof obj !== "object") return obj;
|
|
75
|
+
if (Array.isArray(obj)) {
|
|
76
|
+
return reactiveArray(obj);
|
|
77
|
+
}
|
|
78
|
+
const proxy = new Proxy(obj, {
|
|
79
|
+
get(target, key) {
|
|
80
|
+
const currentUpdateFn2 = getCurrentUpdateFn();
|
|
81
|
+
if (currentUpdateFn2) eventBus.subscribe(triggerRef, currentUpdateFn2);
|
|
82
|
+
const value = target[key];
|
|
83
|
+
if (value !== null && typeof value === "object") {
|
|
84
|
+
return createReactiveObject(value);
|
|
85
|
+
}
|
|
86
|
+
return value;
|
|
87
|
+
},
|
|
88
|
+
set(target, key, newValue) {
|
|
89
|
+
const oldValue = target[key];
|
|
90
|
+
if (oldValue !== newValue) {
|
|
91
|
+
target[key] = newValue;
|
|
92
|
+
eventBus.publish(triggerRef);
|
|
93
|
+
}
|
|
94
|
+
return true;
|
|
95
|
+
},
|
|
96
|
+
deleteProperty(target, key) {
|
|
97
|
+
const result = Reflect.deleteProperty(target, key);
|
|
98
|
+
eventBus.publish(triggerRef);
|
|
99
|
+
return result;
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
reactiveTriggerMap.set(proxy, triggerRef);
|
|
103
|
+
return proxy;
|
|
104
|
+
};
|
|
105
|
+
return createReactiveObject(inittialValue);
|
|
106
|
+
}
|
|
107
|
+
function reactiveArray(inittialValue) {
|
|
108
|
+
const arrayMethods = [
|
|
109
|
+
"push",
|
|
110
|
+
"pop",
|
|
111
|
+
"shift",
|
|
112
|
+
"unshift",
|
|
113
|
+
"splice",
|
|
114
|
+
"soft",
|
|
115
|
+
"reverse",
|
|
116
|
+
"fill",
|
|
117
|
+
"copyWithin"
|
|
118
|
+
];
|
|
119
|
+
const triggerRef = { value: null, __isRef: true };
|
|
120
|
+
if (Array.isArray(inittialValue)) {
|
|
121
|
+
const proxy = new Proxy(inittialValue.map((item) => reactive(item)), {
|
|
122
|
+
get(target, key) {
|
|
123
|
+
const value = target[key];
|
|
124
|
+
const currentUpdateFn2 = getCurrentUpdateFn();
|
|
125
|
+
if (currentUpdateFn2) eventBus.subscribe(triggerRef, currentUpdateFn2);
|
|
126
|
+
if (typeof key === "string" && arrayMethods.includes(key) && typeof value === "function") {
|
|
127
|
+
return function(...args) {
|
|
128
|
+
const result = value.apply(target, args);
|
|
129
|
+
eventBus.publish(triggerRef);
|
|
130
|
+
return result;
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
return value;
|
|
134
|
+
},
|
|
135
|
+
set(target, key, newValue) {
|
|
136
|
+
const result = Reflect.set(target, key, reactive(newValue));
|
|
137
|
+
if (typeof key === "string" && (!isNaN(Number(key)) || key === "length")) eventBus.publish(triggerRef);
|
|
138
|
+
return result;
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
reactiveTriggerMap.set(proxy, triggerRef);
|
|
142
|
+
return proxy;
|
|
143
|
+
}
|
|
144
|
+
return inittialValue;
|
|
145
|
+
}
|
|
146
|
+
function isRefLike(value) {
|
|
147
|
+
return !!value && typeof value === "object" && value.__isRef === true;
|
|
148
|
+
}
|
|
149
|
+
function watch(source, callback) {
|
|
150
|
+
if (typeof source === "function") {
|
|
151
|
+
const getter = source;
|
|
152
|
+
let oldValue;
|
|
153
|
+
const runGetter = () => {
|
|
154
|
+
setCurrentUpdateFn(job);
|
|
155
|
+
const value = getter();
|
|
156
|
+
setCurrentUpdateFn(null);
|
|
157
|
+
return value;
|
|
158
|
+
};
|
|
159
|
+
const job = () => {
|
|
160
|
+
const newValue = runGetter();
|
|
161
|
+
if (Object.is(newValue, oldValue)) return;
|
|
162
|
+
callback(newValue, oldValue);
|
|
163
|
+
oldValue = newValue;
|
|
164
|
+
};
|
|
165
|
+
oldValue = runGetter();
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
if (isRefLike(source)) {
|
|
169
|
+
const ref2 = source;
|
|
170
|
+
let oldValue = ref2.value;
|
|
171
|
+
eventBus.subscribe(
|
|
172
|
+
ref2,
|
|
173
|
+
() => {
|
|
174
|
+
const newValue = ref2.value;
|
|
175
|
+
if (Object.is(newValue, oldValue)) return;
|
|
176
|
+
callback(newValue, oldValue);
|
|
177
|
+
oldValue = newValue;
|
|
178
|
+
}
|
|
179
|
+
);
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
const triggerRef = getReactiveTriggerRef(source);
|
|
183
|
+
if (!triggerRef) {
|
|
184
|
+
throw new Error("watch 只能监控 ref、reactive 返回值,或 getter 函数");
|
|
185
|
+
}
|
|
186
|
+
let oldSnapshot = source;
|
|
187
|
+
eventBus.subscribe(triggerRef, () => {
|
|
188
|
+
const newSnapshot = source;
|
|
189
|
+
callback(newSnapshot, oldSnapshot);
|
|
190
|
+
oldSnapshot = newSnapshot;
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
function diff(oldNode, newNode) {
|
|
194
|
+
var _a;
|
|
195
|
+
if (oldNode.nodeType !== newNode.nodeType || oldNode.nodeName !== newNode.nodeName) {
|
|
196
|
+
(_a = oldNode.parentNode) == null ? void 0 : _a.replaceChild(newNode, oldNode);
|
|
197
|
+
return newNode;
|
|
198
|
+
}
|
|
199
|
+
if (oldNode.nodeType === Node.TEXT_NODE) {
|
|
200
|
+
if (oldNode.textContent !== newNode.textContent) {
|
|
201
|
+
oldNode.textContent = newNode.textContent;
|
|
202
|
+
}
|
|
203
|
+
return oldNode;
|
|
204
|
+
}
|
|
205
|
+
if (oldNode instanceof HTMLElement && newNode instanceof HTMLElement) {
|
|
206
|
+
updateAttributes(oldNode, newNode);
|
|
207
|
+
updateChildren(oldNode, newNode);
|
|
208
|
+
return oldNode;
|
|
209
|
+
}
|
|
210
|
+
if (oldNode instanceof DocumentFragment || newNode instanceof DocumentFragment) {
|
|
211
|
+
return newNode;
|
|
212
|
+
}
|
|
213
|
+
return oldNode;
|
|
214
|
+
}
|
|
215
|
+
function updateAttributes(oldNode, newNode) {
|
|
216
|
+
Array.from(oldNode.attributes).forEach((attr) => {
|
|
217
|
+
if (!newNode.hasAttribute(attr.name)) {
|
|
218
|
+
oldNode.removeAttribute(attr.name);
|
|
219
|
+
}
|
|
220
|
+
});
|
|
221
|
+
Array.from(newNode.attributes).forEach((attr) => {
|
|
222
|
+
if (oldNode.getAttribute(attr.name) !== attr.value) {
|
|
223
|
+
oldNode.setAttribute(attr.name, attr.value);
|
|
224
|
+
}
|
|
225
|
+
});
|
|
226
|
+
if ("value" in newNode && "value" in oldNode) {
|
|
227
|
+
const newValue = newNode.value;
|
|
228
|
+
const oldValue = oldNode.value;
|
|
229
|
+
const hasValueAttr = newNode.hasAttribute("value");
|
|
230
|
+
if (newValue !== oldValue) {
|
|
231
|
+
if (hasValueAttr || newValue !== "") {
|
|
232
|
+
oldNode.value = newValue;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
function updateChildren(oldParent, newParent) {
|
|
238
|
+
const oldChildren = Array.from(oldParent.childNodes);
|
|
239
|
+
const newChildren = Array.from(newParent.childNodes);
|
|
240
|
+
const maxLength = Math.max(oldChildren.length, newChildren.length);
|
|
241
|
+
for (let i = 0; i < maxLength; i++) {
|
|
242
|
+
const oldChild = oldChildren[i];
|
|
243
|
+
const newChild = newChildren[i];
|
|
244
|
+
if (!oldChild && newChild) {
|
|
245
|
+
oldParent.appendChild(newChild);
|
|
246
|
+
} else if (oldChild && !newChild) {
|
|
247
|
+
oldParent.removeChild(oldChild);
|
|
248
|
+
} else if (oldChild && newChild) {
|
|
249
|
+
diff(oldChild, newChild);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
function diffChildren(parent, oldList, newList) {
|
|
254
|
+
const maxLength = Math.max(oldList.length, newList.length);
|
|
255
|
+
for (let i = 0; i < maxLength; i++) {
|
|
256
|
+
const oldNode = oldList[i];
|
|
257
|
+
const newNode = newList[i];
|
|
258
|
+
if (!oldNode && newNode) {
|
|
259
|
+
parent.appendChild(newNode);
|
|
260
|
+
} else if (oldNode && !newNode) {
|
|
261
|
+
parent.removeChild(oldNode);
|
|
262
|
+
} else if (oldNode && newNode) {
|
|
263
|
+
diff(oldNode, newNode);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
function compile(option) {
|
|
268
|
+
const { selector, show, text, listeners, render } = option;
|
|
269
|
+
const element = $(selector);
|
|
270
|
+
const updateFn = () => {
|
|
271
|
+
const showValue = typeof show === "function" ? show() : show;
|
|
272
|
+
const textValue = typeof text === "function" ? text() : text;
|
|
273
|
+
if (textValue !== void 0) element.text(textValue);
|
|
274
|
+
showValue || showValue === void 0 ? element.show() : element.hide();
|
|
275
|
+
if (render && typeof render === "function") {
|
|
276
|
+
const lastRenderResult = element.data("__lastRenderResult");
|
|
277
|
+
const result = render();
|
|
278
|
+
if (typeof result === "string") {
|
|
279
|
+
element.empty();
|
|
280
|
+
element.text(result);
|
|
281
|
+
element.data("__lastRenderResult", null);
|
|
282
|
+
} else if (result instanceof Node) {
|
|
283
|
+
let currentNodes;
|
|
284
|
+
if (result instanceof DocumentFragment) {
|
|
285
|
+
currentNodes = Array.from(result.childNodes);
|
|
286
|
+
} else {
|
|
287
|
+
currentNodes = result;
|
|
288
|
+
}
|
|
289
|
+
if (lastRenderResult) {
|
|
290
|
+
if (!Array.isArray(lastRenderResult) && !Array.isArray(currentNodes) && lastRenderResult instanceof HTMLElement && currentNodes instanceof HTMLElement) {
|
|
291
|
+
const newDom = diff(lastRenderResult, currentNodes);
|
|
292
|
+
element.data("__lastRenderResult", newDom);
|
|
293
|
+
} else {
|
|
294
|
+
const oldList = Array.isArray(lastRenderResult) ? lastRenderResult : [lastRenderResult];
|
|
295
|
+
const newList = Array.isArray(currentNodes) ? currentNodes : [currentNodes];
|
|
296
|
+
diffChildren(element[0], oldList, newList);
|
|
297
|
+
element.data("__lastRenderResult", currentNodes);
|
|
298
|
+
}
|
|
299
|
+
} else {
|
|
300
|
+
element.empty();
|
|
301
|
+
element.append(result);
|
|
302
|
+
element.data("__lastRenderResult", currentNodes);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
};
|
|
307
|
+
setCurrentUpdateFn(updateFn);
|
|
308
|
+
updateFn();
|
|
309
|
+
setCurrentUpdateFn(null);
|
|
310
|
+
if (listeners && listeners.length > 0) {
|
|
311
|
+
listeners.forEach((listener) => {
|
|
312
|
+
element.on(listener.type, listener.callback);
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
export {
|
|
317
|
+
compile,
|
|
318
|
+
computed,
|
|
319
|
+
reactive,
|
|
320
|
+
ref,
|
|
321
|
+
watch,
|
|
322
|
+
watchEffect
|
|
323
|
+
};
|
|
324
|
+
//# sourceMappingURL=index.mjs.map
|
package/index.mjs.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","sources":["../event.ts","../state.ts","../ref.ts","../computed.ts","../watchEffect.ts","../reactive.ts","../watch.ts","../diff.ts","../compile.ts"],"sourcesContent":["import { Ref } from \"./types\";\r\n\r\nexport class EventBus {\r\n private subscribers = new Map<Ref<any>, Set<()=>void>>();\r\n\r\n // 订阅\r\n subscribe(ref: Ref<any>, callback: () => void) {\r\n if (!this.subscribers.has(ref)) {\r\n this.subscribers.set(ref, new Set());\r\n }\r\n this.subscribers.get(ref)?.add(callback);\r\n }\r\n\r\n // 发布\r\n publish(ref: Ref<any>){\r\n const callbacks = this.subscribers.get(ref);\r\n if(callbacks) callbacks.forEach(cb=>cb())\r\n }\r\n}\r\n\r\nexport const eventBus = new EventBus();","export let currentUpdateFn: (() => void) | null = null;\r\n\r\nexport function setCurrentUpdateFn(fn: (() => void) | null) {\r\n currentUpdateFn = fn;\r\n}\r\n\r\nexport function getCurrentUpdateFn() {\r\n return currentUpdateFn;\r\n}\r\n","import { Ref } from \"./types\";\r\nimport { eventBus } from \"./event\";\r\nimport { getCurrentUpdateFn } from \"./state\";\r\nexport function ref<T>(value: T): Ref<T> {\r\n const obj = { value, __isRef: true };\r\n const state = new Proxy(obj, {\r\n set: (target, key, value) => {\r\n if (key === \"value\") {\r\n target[key] = value;\r\n eventBus.publish(state);\r\n }\r\n return true;\r\n },\r\n get: (target, key) => {\r\n const currentUpdateFn = getCurrentUpdateFn();\r\n if (key === \"value\" && currentUpdateFn) {\r\n eventBus.subscribe(state, currentUpdateFn);\r\n }\r\n return target[key as keyof typeof target];\r\n },\r\n }) as Ref<T>;\r\n return state;\r\n}","import { Ref } from \"./types\"\nimport { ref } from \"./ref\"\nimport { setCurrentUpdateFn } from \"./state\"\n\nexport function computed<T>(computedFn: ()=> T): Ref<T>{\n const computedRef = ref<T | null>(null)\n const updateFn = ()=> {\n computedRef.value = computedFn()\n }\n setCurrentUpdateFn(updateFn)\n updateFn()\n setCurrentUpdateFn(null)\n return computedRef as Ref<T>\n}\n","import { setCurrentUpdateFn } from \"./state\"\n\n/**\n * 监听响应式数据的变化,当数据变化时,调用回调函数\n * @param callback \n */\nexport function watchEffect(callback: () => void) {\n setCurrentUpdateFn(callback)\n callback()\n setCurrentUpdateFn(null)\n}","import { Ref } from \"./types\";\nimport { eventBus } from \"./event\";\nimport { getCurrentUpdateFn } from \"./state\";\n\nconst reactiveTriggerMap = new WeakMap<object, Ref<any>>()\n\nexport function getReactiveTriggerRef(target: unknown): Ref<any> | null {\n if(target && typeof target === 'object') return reactiveTriggerMap.get(target as object) ?? null\n return null\n}\n\nexport function reactive<T extends object>(inittialValue: T): T {\n const triggerRef = { value: null, __isRef: true as const } as Ref<any>\n\n const createReactiveObject = (obj: any): any=> {\n if(obj === null || typeof obj !== 'object') return obj\n \n // 如果是数组,递归处理每个元素\n if(Array.isArray(obj)){\n return reactiveArray(obj)\n }\n\n // 处理普通对象\n const proxy = new Proxy(obj, {\n get(target, key){\n const currentUpdateFn = getCurrentUpdateFn()\n if(currentUpdateFn) eventBus.subscribe(triggerRef, currentUpdateFn)\n \n const value = target[key]\n // 如果属性值是对象,递归代理\n if(value !== null && typeof value === 'object'){\n return createReactiveObject(value)\n }\n return value\n },\n set(target, key, newValue) {\n const oldValue = target[key]\n if(oldValue !== newValue) {\n target[key] = newValue\n eventBus.publish(triggerRef)\n }\n return true\n },\n deleteProperty(target, key){\n const result = Reflect.deleteProperty(target, key)\n eventBus.publish(triggerRef);\n return result;\n }\n \n })\n\n reactiveTriggerMap.set(proxy, triggerRef)\n return proxy\n }\n return createReactiveObject(inittialValue)\n}\n\n\nexport function reactiveArray<T extends object>(inittialValue: T): T {\n // 需要拦截的数组变更方法\n const arrayMethods = [\n 'push', 'pop', 'shift', 'unshift',\n 'splice', 'soft', 'reverse', 'fill',\n 'copyWithin'\n ]\n\n const triggerRef = {value: null, __isRef: true as const} as Ref<any>\n\n if(Array.isArray(inittialValue)){\n const proxy = new Proxy(inittialValue.map(item=>reactive(item)),{\n get(target, key){\n const value = target[key as keyof typeof target]\n const currentUpdateFn = getCurrentUpdateFn()\n if(currentUpdateFn) eventBus.subscribe(triggerRef,currentUpdateFn)\n \n if(typeof key === 'string' && arrayMethods.includes(key) && typeof value === 'function'){\n return function(...args: any[]){\n const result = (value as Function).apply(target, args);\n eventBus.publish(triggerRef);\n return result;\n }\n }\n\n return value;\n },\n set(target, key, newValue){\n const result = Reflect.set(target, key, reactive(newValue))\n if(typeof key === 'string' && (!isNaN(Number(key)) || key === 'length')) eventBus.publish(triggerRef)\n return result\n }\n }) as T\n reactiveTriggerMap.set(proxy as unknown as object, triggerRef)\n return proxy\n }\n return inittialValue\n}\n","import { Ref } from \"./types\";\nimport { eventBus } from \"./event\";\nimport { getReactiveTriggerRef } from \"./reactive\";\nimport { setCurrentUpdateFn } from \"./state\";\n\nfunction isRefLike<T = unknown>(value: unknown): value is Ref<T> {\n return !!value && typeof value === 'object' && (value as any).__isRef === true\n}\n\nexport function watch<T>(source: Ref<T> | (() => T) | object, callback: (newValue: T, oldValue: T) => void) {\n if(typeof source === 'function') {\n const getter = source as () => T\n let oldValue: T\n\n const runGetter = () => {\n setCurrentUpdateFn(job)\n const value = getter()\n setCurrentUpdateFn(null)\n return value\n }\n\n const job = () => {\n const newValue = runGetter()\n if(Object.is(newValue, oldValue)) return\n callback(newValue, oldValue)\n oldValue = newValue\n }\n\n oldValue = runGetter()\n return\n }\n\n if(isRefLike<T>(source)) {\n const ref = source as Ref<T>\n let oldValue = ref.value;\n\n eventBus.subscribe(\n ref,\n () => {\n const newValue = ref.value;\n if(Object.is(newValue, oldValue)) return\n callback(newValue, oldValue);\n oldValue = newValue;\n }\n );\n return\n }\n\n const triggerRef = getReactiveTriggerRef(source)\n if(!triggerRef) {\n throw new Error('watch 只能监控 ref、reactive 返回值,或 getter 函数')\n }\n\n let oldSnapshot = source as T\n eventBus.subscribe(triggerRef, () => {\n const newSnapshot = source as T\n callback(newSnapshot, oldSnapshot)\n oldSnapshot = newSnapshot\n })\n}\n","\n/**\n * 简单的 DOM Diff 算法\n * @param oldNode 旧节点\n * @param newNode 新节点\n * @returns 实际更新后的节点(如果是替换操作,返回新节点;如果是属性更新,返回旧节点)\n */\nexport function diff(oldNode: Node, newNode: Node): Node {\n // 1. 如果节点类型不同,直接替换\n if (oldNode.nodeType !== newNode.nodeType || oldNode.nodeName !== newNode.nodeName) {\n oldNode.parentNode?.replaceChild(newNode, oldNode);\n return newNode;\n }\n\n // 2. 文本节点处理\n if (oldNode.nodeType === Node.TEXT_NODE) {\n if (oldNode.textContent !== newNode.textContent) {\n oldNode.textContent = newNode.textContent;\n }\n return oldNode;\n }\n\n // 3. 元素节点处理\n if (oldNode instanceof HTMLElement && newNode instanceof HTMLElement) {\n // 3.1 更新属性\n updateAttributes(oldNode, newNode);\n\n // 3.2 更新子节点\n updateChildren(oldNode, newNode);\n \n return oldNode;\n }\n \n // DocumentFragment 处理(简单策略:直接把新内容插进去,不做精细 diff)\n if (oldNode instanceof DocumentFragment || newNode instanceof DocumentFragment) {\n // Fragment 比较特殊,插入后就消失了,这里无法复用 oldNode\n // 简单策略:如果父节点存在,用新 Fragment 替换旧位置的所有内容\n // 但由于 Fragment 插入后不可追踪,这里我们假设 compile.ts 里的用法场景:\n // 如果上次是 Fragment,这次也是 Fragment,我们很难直接 diff 它们(因为 Fragment 自身不留在 DOM 树上)\n // 所以对于 Fragment,建议在 compile 层直接全量替换,或者 diff 算法只处理 Element/Text\n return newNode;\n }\n\n return oldNode;\n}\n\nfunction updateAttributes(oldNode: HTMLElement, newNode: HTMLElement) {\n // 移除旧属性\n Array.from(oldNode.attributes).forEach(attr => {\n if (!newNode.hasAttribute(attr.name)) {\n oldNode.removeAttribute(attr.name);\n }\n });\n\n // 设置新属性\n Array.from(newNode.attributes).forEach(attr => {\n if (oldNode.getAttribute(attr.name) !== attr.value) {\n oldNode.setAttribute(attr.name, attr.value);\n }\n });\n \n // 特殊处理 value (input/textarea)\n // 只有当新节点显式设置了 value 属性(attribute)或者新节点的 value 属性(property)与默认空值不同时,才去同步 property\n // 这样可以避免“非受控组件”的用户输入被意外清空\n // 但对于受控组件(render 里 value={state}),如果 state 没变(render 出的 value 还是旧的),\n // 这里也会把用户输入重置回旧 state(符合 React 受控组件行为)。\n if ('value' in newNode && 'value' in oldNode) {\n const newValue = (newNode as any).value;\n const oldValue = (oldNode as any).value;\n \n // 只有当新值确实不同,且新节点似乎是有意设置了值时才更新\n // 简单的判断:如果新节点的 value 和它的 defaultValue (即 attribute) 一致,\n // 或者新节点有 value attribute,我们才认为它是受控的或者有明确初值的。\n // 如果新节点完全没设 value(attribute 是 null,property 是空串),可能是个“无辜”的非受控节点,\n // 这时如果旧节点有用户输入(oldValue != \"\"),我们尽量保留它。\n \n const hasValueAttr = newNode.hasAttribute('value');\n if (newValue !== oldValue) {\n // 如果新节点有显式的 value 属性,或者新节点的 value 属性不为空,强制同步\n if (hasValueAttr || newValue !== '') {\n (oldNode as any).value = newValue;\n }\n }\n }\n}\n\nfunction updateChildren(oldParent: HTMLElement, newParent: HTMLElement) {\n const oldChildren = Array.from(oldParent.childNodes);\n const newChildren = Array.from(newParent.childNodes);\n \n const maxLength = Math.max(oldChildren.length, newChildren.length);\n\n for (let i = 0; i < maxLength; i++) {\n const oldChild = oldChildren[i];\n const newChild = newChildren[i];\n\n if (!oldChild && newChild) {\n // 新增节点\n // 注意:这里需要 clone newChild,因为 appendChild 会移动节点\n // 但由于我们是在构建新的 vdom(这里其实是真实 dom),直接移过去也没问题,\n // 不过 diff 函数通常假设 newNode 是个模版。\n // 在当前框架下,newNode 是 render() 刚刚生成的新鲜 DOM,直接移动即可。\n oldParent.appendChild(newChild);\n } else if (oldChild && !newChild) {\n // 删除节点\n oldParent.removeChild(oldChild);\n } else if (oldChild && newChild) {\n // 递归 diff\n diff(oldChild, newChild);\n }\n }\n}\n\n\nexport function diffChildren(parent: HTMLElement, oldList: (Node | undefined | null)[], newList: (Node | undefined | null)[]) {\n const maxLength = Math.max(oldList.length, newList.length);\n \n for (let i = 0; i < maxLength; i++) {\n const oldNode = oldList[i];\n const newNode = newList[i];\n\n if (!oldNode && newNode) {\n // 新增\n parent.appendChild(newNode);\n } else if (oldNode && !newNode) {\n // 删除\n parent.removeChild(oldNode);\n } else if (oldNode && newNode) {\n // 对比更新\n diff(oldNode as Node, newNode);\n }\n }\n}","import { Option } from \"./types\";\r\nimport $ from \"jquery\";\r\nimport { setCurrentUpdateFn } from \"./state\";\r\n\r\n\r\nimport { diff, diffChildren } from \"./diff\";\r\n\r\nexport function compile(option: Option) {\r\n const { selector, show, text, listeners,render } = option;\r\n\r\n const element = $(selector);\r\n\r\n const updateFn = () => {\r\n const showValue = typeof show === \"function\" ? show() : show;\r\n const textValue = typeof text === \"function\" ? text() : text;\r\n if (textValue !== undefined) element.text(textValue);\r\n showValue || showValue === undefined ? element.show() : element.hide();\r\n if(render && typeof render === 'function'){\r\n // 获取上一次渲染的 DOM 结构(可能是单个 Node,也可能是 Node 列表)\r\n // 如果是 Fragment,我们需要追踪的是它的 childNodes 列表,而不是 Fragment 本身\r\n const lastRenderResult = element.data('__lastRenderResult') as Node | Node[] | undefined\r\n \r\n const result = render()\r\n \r\n if(typeof result === 'string') {\r\n element.empty()\r\n element.text(result)\r\n element.data('__lastRenderResult', null)\r\n } else if(result instanceof Node) {\r\n // 准备本次渲染的“追踪对象”\r\n // 如果是 Fragment,我们需要克隆一份它的子节点列表(因为 append 后 Fragment 就空了)\r\n let currentNodes: Node | Node[];\r\n if (result instanceof DocumentFragment) {\r\n currentNodes = Array.from(result.childNodes);\r\n } else {\r\n currentNodes = result;\r\n }\r\n\r\n if (lastRenderResult) {\r\n // 执行 Diff\r\n // 情况 1: 都是单个元素 (Element vs Element)\r\n if (!Array.isArray(lastRenderResult) && !Array.isArray(currentNodes) && \r\n lastRenderResult instanceof HTMLElement && currentNodes instanceof HTMLElement) {\r\n const newDom = diff(lastRenderResult, currentNodes)\r\n element.data('__lastRenderResult', newDom)\r\n } \r\n // 情况 2: 涉及列表/Fragment (List vs List / Element vs List / List vs Element)\r\n else {\r\n // 暂时降级:如果涉及 Fragment 列表 diff,逻辑比较复杂(需要类似 Vue 的列表 diff),\r\n // 这里为了稳健,如果检测到列表长度没变且 key 没变(这里没 key),可以尝试原地 patch?\r\n // 鉴于目前 diff 算法较弱,先保留“清空重绘”逻辑,但我们可以优化一下:\r\n // 如果是列表对列表,我们可以尝试一一对比?\r\n \r\n // 简单起见,我们对 Fragment 场景仍然做全量替换,以保证正确性。\r\n // 如果你想解决 input 失去焦点问题,必须在这里实现真正的列表 diff。\r\n // 也就是:diffArrays(oldChildren, newChildren, parent)\r\n \r\n // 下面尝试一个简单的列表 diff (无 key,按 index 对比)\r\n const oldList = Array.isArray(lastRenderResult) ? lastRenderResult : [lastRenderResult];\r\n const newList = Array.isArray(currentNodes) ? currentNodes : [currentNodes];\r\n \r\n diffChildren(element[0], oldList, newList);\r\n element.data('__lastRenderResult', currentNodes) // 注意:这里存的是新生成的节点引用\r\n }\r\n } else {\r\n // 首次渲染\r\n element.empty()\r\n element.append(result)\r\n element.data('__lastRenderResult', currentNodes)\r\n }\r\n }\r\n }\r\n };\r\n\r\n setCurrentUpdateFn(updateFn);\r\n updateFn();\r\n setCurrentUpdateFn(null);\r\n\r\n if (listeners && listeners.length > 0) {\r\n listeners.forEach((listener) => {\r\n element.on(listener.type, listener.callback);\r\n });\r\n }\r\n}\r\n\r\n\r\n"],"names":["ref","value","currentUpdateFn"],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@actview/core",
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"description": "Core reactive system for Actview - ref, reactive, computed, watch, compile",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./index.cjs",
|
|
7
|
+
"module": "./index.mjs",
|
|
8
|
+
"types": "./index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"import": {
|
|
12
|
+
"types": "./index.d.ts",
|
|
13
|
+
"default": "./index.mjs"
|
|
14
|
+
},
|
|
15
|
+
"require": {
|
|
16
|
+
"types": "./index.d.ts",
|
|
17
|
+
"default": "./index.cjs"
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"keywords": [
|
|
22
|
+
"actview",
|
|
23
|
+
"reactive",
|
|
24
|
+
"ref",
|
|
25
|
+
"computed",
|
|
26
|
+
"watch"
|
|
27
|
+
],
|
|
28
|
+
"author": "scliuyilin",
|
|
29
|
+
"license": "MIT",
|
|
30
|
+
"repository": {
|
|
31
|
+
"type": "git",
|
|
32
|
+
"url": ""
|
|
33
|
+
},
|
|
34
|
+
"homepage": "",
|
|
35
|
+
"bugs": {
|
|
36
|
+
"url": ""
|
|
37
|
+
},
|
|
38
|
+
"dependencies": {
|
|
39
|
+
"jquery": "^4.0.0"
|
|
40
|
+
},
|
|
41
|
+
"publishConfig": {
|
|
42
|
+
"access": "public"
|
|
43
|
+
}
|
|
44
|
+
}
|
package/reactive.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { Ref } from "./types";
|
|
2
|
+
export declare function getReactiveTriggerRef(target: unknown): Ref<any> | null;
|
|
3
|
+
export declare function reactive<T extends object>(inittialValue: T): T;
|
|
4
|
+
export declare function reactiveArray<T extends object>(inittialValue: T): T;
|
|
5
|
+
//# sourceMappingURL=reactive.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reactive.d.ts","sourceRoot":"","sources":["../reactive.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,SAAS,CAAC;AAM9B,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,OAAO,GAAG,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI,CAGtE;AAED,wBAAgB,QAAQ,CAAC,CAAC,SAAS,MAAM,EAAE,aAAa,EAAE,CAAC,GAAG,CAAC,CA4C9D;AAGD,wBAAgB,aAAa,CAAC,CAAC,SAAS,MAAM,EAAE,aAAa,EAAE,CAAC,GAAG,CAAC,CAqCnE"}
|
package/ref.d.ts
ADDED
package/ref.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ref.d.ts","sourceRoot":"","sources":["../ref.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,SAAS,CAAC;AAG9B,wBAAgB,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAmBvC"}
|
package/state.d.ts
ADDED
package/state.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../state.ts"],"names":[],"mappings":"AAAA,eAAO,IAAI,eAAe,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,IAAW,CAAC;AAEvD,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,IAAI,QAEzD;AAED,wBAAgB,kBAAkB,WANC,IAAI,SAQtC"}
|
package/types/index.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export type Ref<T> = {
|
|
2
|
+
value: T;
|
|
3
|
+
__isRef: true;
|
|
4
|
+
};
|
|
5
|
+
export type Listener<K extends keyof HTMLElementEventMap = keyof HTMLElementEventMap> = {
|
|
6
|
+
type: K;
|
|
7
|
+
callback: (e: HTMLElementEventMap[K]) => void;
|
|
8
|
+
};
|
|
9
|
+
export type Option = {
|
|
10
|
+
selector: string;
|
|
11
|
+
show?: boolean | (() => boolean);
|
|
12
|
+
text?: string | (() => string);
|
|
13
|
+
listeners?: Listener[];
|
|
14
|
+
render?: () => string | HTMLElement | Text | DocumentFragment;
|
|
15
|
+
};
|
|
16
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../types/index.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,GAAG,CAAC,CAAC,IAAI;IACjB,KAAK,EAAE,CAAC,CAAC;IACT,OAAO,EAAE,IAAI,CAAA;CAChB,CAAA;AAED,MAAM,MAAM,QAAQ,CAAC,CAAC,SAAS,MAAM,mBAAmB,GAAG,MAAM,mBAAmB,IAAI;IACpF,IAAI,EAAE,CAAC,CAAC;IACR,QAAQ,EAAE,CAAC,CAAC,EAAE,mBAAmB,CAAC,CAAC,CAAC,KAAK,IAAI,CAAA;CAChD,CAAA;AAED,MAAM,MAAM,MAAM,GAAG;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,OAAO,GAAG,CAAC,MAAM,OAAO,CAAC,CAAA;IAChC,IAAI,CAAC,EAAE,MAAM,GAAG,CAAC,MAAM,MAAM,CAAC,CAAA;IAC9B,SAAS,CAAC,EAAE,QAAQ,EAAE,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,MAAM,GAAG,WAAW,GAAG,IAAI,GAAG,gBAAgB,CAAC;CACjE,CAAA"}
|
package/watch.d.ts
ADDED
package/watch.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"watch.d.ts","sourceRoot":"","sources":["../watch.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,SAAS,CAAC;AAS9B,wBAAgB,KAAK,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,MAAM,EAAE,QAAQ,EAAE,CAAC,QAAQ,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,KAAK,IAAI,QAkDzG"}
|
package/watchEffect.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"watchEffect.d.ts","sourceRoot":"","sources":["../watchEffect.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,IAAI,QAI/C"}
|