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