1
+ // 给一个obj定义一个响应式的属性
2
+ function defineReactive ( obj , key , val ) {
3
+ // 递归
4
+ // val如果是个对象,就需要递归处理
5
+ observe ( val ) ;
6
+
7
+ // 创建Dep实例
8
+ const dep = new Dep ( )
9
+
10
+ Object . defineProperty ( obj , key , {
11
+ get ( ) {
12
+ console . log ( "get" , key ) ;
13
+ // 依赖关系收集
14
+ Dep . target && dep . addDep ( Dep . target )
15
+ return val ;
16
+ } ,
17
+ set ( newVal ) {
18
+ if ( newVal !== val ) {
19
+ console . log ( "set" , key ) ;
20
+ val = newVal ;
21
+ // 新值如果是对象,仍然需要递归遍历处理
22
+ observe ( newVal ) ;
23
+ // update()
24
+ dep . notify ( )
25
+ }
26
+ } ,
27
+ } ) ;
28
+ }
29
+
30
+ // 遍历响应式处理
31
+ function observe ( obj ) {
32
+ if ( typeof obj !== "object" || obj == null ) {
33
+ return obj ;
34
+ }
35
+
36
+ new Observer ( obj ) ;
37
+ }
38
+
39
+ // 能够将传入对象中的所有key代理到指定对象上
40
+ function proxy ( vm ) {
41
+ Object . keys ( vm . $data ) . forEach ( ( key ) => {
42
+ Object . defineProperty ( vm , key , {
43
+ get ( ) {
44
+ return vm . $data [ key ] ;
45
+ } ,
46
+ set ( v ) {
47
+ vm . $data [ key ] = v ;
48
+ } ,
49
+ } ) ;
50
+ } ) ;
51
+ }
52
+
53
+ class Observer {
54
+ constructor ( obj ) {
55
+ // 判断传入obj类型,做相应处理
56
+ if ( Array . isArray ( obj ) ) {
57
+ // todo
58
+ } else {
59
+ this . walk ( obj ) ;
60
+ }
61
+ }
62
+
63
+ walk ( obj ) {
64
+ Object . keys ( obj ) . forEach ( ( key ) => defineReactive ( obj , key , obj [ key ] ) ) ;
65
+ }
66
+ }
67
+
68
+ class KVue {
69
+ constructor ( options ) {
70
+ // 0.保存选项
71
+ this . $options = options ;
72
+ this . $data = options . data ;
73
+
74
+ // 1.对data做响应式处理
75
+ observe ( options . data ) ;
76
+
77
+ // 2.代理
78
+ proxy ( this ) ;
79
+
80
+ // 3.编译
81
+ new Compile ( options . el , this ) ;
82
+ }
83
+ }
84
+
85
+ class Compile {
86
+ constructor ( el , vm ) {
87
+ this . $vm = vm ;
88
+ this . $el = document . querySelector ( el ) ;
89
+
90
+ if ( this . $el ) {
91
+ this . compile ( this . $el ) ;
92
+ }
93
+ }
94
+
95
+ // 遍历node,判断节点类型,做不同处理
96
+ compile ( node ) {
97
+ const childNodes = node . childNodes ;
98
+
99
+ Array . from ( childNodes ) . forEach ( ( n ) => {
100
+ // 判断类型
101
+ if ( this . isElement ( n ) ) {
102
+ // console.log('编译元素', n.nodeName);
103
+ this . compileElement ( n ) ;
104
+ // 递归
105
+ if ( n . childNodes . length > 0 ) {
106
+ this . compile ( n ) ;
107
+ }
108
+ } else if ( this . isInter ( n ) ) {
109
+ // 动态插值表达式
110
+ // console.log('编译文本', n.textContent);
111
+ this . compileText ( n ) ;
112
+ }
113
+ } ) ;
114
+ }
115
+
116
+ isElement ( n ) {
117
+ return n . nodeType === 1 ;
118
+ }
119
+
120
+ // 形如{{ooxx}}
121
+ isInter ( n ) {
122
+ return n . nodeType === 3 && / \{ \{ ( .* ) \} \} / . test ( n . textContent ) ;
123
+ }
124
+
125
+ // 编译插值文本 {{ooxx}}
126
+ compileText ( n ) {
127
+ // 获取表达式
128
+ // n.textContent = this.$vm[RegExp.$1];
129
+ this . update ( n , RegExp . $1 , "text" ) ;
130
+ }
131
+
132
+ // 编译元素:遍历它的所有特性,看是否k-开头指令,或者@事件
133
+ compileElement ( n ) {
134
+ const attrs = n . attributes ;
135
+ Array . from ( attrs ) . forEach ( ( attr ) => {
136
+ // k-text="xxx"
137
+ // name = k-text,value = xxx
138
+ const attrName = attr . name ;
139
+ const exp = attr . value ;
140
+ // 指令
141
+ if ( this . isDir ( attrName ) ) {
142
+ // 执行特定指令处理函数
143
+ const dir = attrName . substring ( 2 ) ;
144
+ this [ dir ] && this [ dir ] ( n , exp ) ;
145
+ }
146
+ } ) ;
147
+ }
148
+
149
+ update ( node , exp , dir ) {
150
+ // 1.init
151
+ const fn = this [ dir + 'Updater' ]
152
+ fn && fn ( node , this . $vm [ exp ] )
153
+
154
+ // 2.update
155
+ new Watcher ( this . $vm , exp , val => {
156
+ fn && fn ( node , val )
157
+ } )
158
+ }
159
+
160
+ // k-text
161
+ text ( node , exp ) {
162
+ this . update ( node , exp , "text" ) ;
163
+ }
164
+
165
+ textUpdater ( node , val ) {
166
+ node . textContent = val ;
167
+ }
168
+
169
+ // k-html
170
+ html ( node , exp ) {
171
+ this . update ( node , exp , "html" ) ;
172
+ }
173
+
174
+ htmlUpdater ( node , val ) {
175
+ node . innerHTML = val ;
176
+ }
177
+
178
+ isDir ( attrName ) {
179
+ return attrName . startsWith ( "k-" ) ;
180
+ }
181
+ }
182
+
183
+ // 负责dom更新
184
+ class Watcher {
185
+ constructor ( vm , key , updater ) {
186
+ this . vm = vm ;
187
+ this . key = key ;
188
+ this . updater = updater ;
189
+
190
+ // 触发一下get
191
+ Dep . target = this
192
+ this . vm [ this . key ]
193
+ Dep . target = null
194
+ }
195
+
196
+ // 将来会被Dep调用
197
+ update ( ) {
198
+ this . updater . call ( this . vm , this . vm [ this . key ] ) ;
199
+ }
200
+ }
201
+
202
+ // 保存watcher实例的依赖类
203
+ class Dep {
204
+ constructor ( ) {
205
+ this . deps = [ ]
206
+ }
207
+ // 此处dep就是Watcher的实例
208
+ addDep ( dep ) {
209
+ // 创建依赖关系时调用
210
+ this . deps . push ( dep )
211
+ }
212
+ notify ( ) {
213
+ this . deps . forEach ( dep => dep . update ( ) )
214
+ }
215
+ }
0 commit comments