@@ -28,7 +28,7 @@ theme: smartblue
28
28
等等
29
29
```
30
30
31
- ## 文档
31
+ ## 2. 文档
32
32
33
33
[ Taro 文档 - API 说明] ( https://docs.taro.zone/docs/apis/about/desc )
34
34
@@ -50,7 +50,7 @@ Taro.request(url).then(function (res) {
50
50
51
51
我们先来看 ` tarojs/taro ` 的代码。
52
52
53
- ## tarojs/taro
53
+ ## 3. tarojs/taro
54
54
55
55
``` ts
56
56
// packages/taro/index.js
@@ -65,7 +65,12 @@ module.exports = taro
65
65
module .exports .default = module .exports
66
66
```
67
67
68
- ## src/program.ts
68
+ ` hooks ` 在上篇文章[ Taro 4.0 已正式发布 - 5.高手都在用的发布订阅机制 Events 在 Taro 中是如何实现的?] ( https://juejin.cn/post/7403915119448915977#heading-20 ) 讲过。
69
+ 简单来说就是 ` tap ` 是注册事件,` call ` 是触发事件。其中 ` mergeReconciler ` 函数中注册` initNativeApi ` 函数。
70
+
71
+ 这时我们需要来寻找 ` initNativeApi ` 函数在哪里实现的。可以在Taro源码中根据 ` initNativeApi ` 关键字搜索。或者之前的第三篇文章 [ 3. taro build] ( https://juejin.cn/post/7403193330271682612 ) 。我们知道端平台插件的代码在 ` @tarojs/plugin-platform-weapp ` 包中,路径是 ` packages/taro-platform-weapp/src/program.ts ` 。
72
+
73
+ ## 4. new Weapp 端平台插件
69
74
70
75
``` ts
71
76
// packages/taro-platform-weapp/src/program.ts
@@ -85,7 +90,11 @@ export default class Weapp extends TaroPlatformBase {
85
90
}
86
91
```
87
92
88
- ## src/runtime.ts
93
+ ` runtimePath ` 路径:` @tarojs/plugin-platform-weapp/dist/runtime ` 。
94
+
95
+ 对应的运行时路径 ` packages/taro-platform-weapp/src/runtime.ts ` 。
96
+
97
+ ## 5. 运行时 src/runtime.ts
89
98
90
99
``` ts
91
100
// packages/taro-platform-weapp/src/runtime.ts
@@ -97,7 +106,12 @@ mergeReconciler(hostConfig)
97
106
mergeInternalComponents (components )
98
107
```
99
108
100
- ## mergeReconciler
109
+ - 使用 mergeReconciler 函数把自定义的 hostConfig 合并到全局 [ Reconciler] ( https://docs.taro.zone/docs/platform-plugin/reconciler ) 中。
110
+ - 使用 mergeInternalComponents 函数把自定义组件信息 [ components.ts] ( https://docs.taro.zone/docs/platform-plugin/platform-mini#31-%E7%BC%96%E5%86%99-componentsts ) 合并到全局 internalComponents 组件信息对象中。
111
+
112
+ 我们来看下 ` mergeReconciler ` 函数的实现。
113
+
114
+ ## 6. mergeReconciler 函数
101
115
102
116
``` ts
103
117
// packages/shared/src/utils.ts
@@ -109,14 +123,11 @@ export function mergeReconciler (hostConfig, hooksForTest?) {
109
123
obj .tap (key , hostConfig [key ])
110
124
})
111
125
}
112
-
113
126
```
114
127
115
- ``` ts
116
- // packages/shared/src/utils.ts
117
- ```
128
+ ` obj.tap(key, hostConfig[key]) ` 是注册事件,在 ` call ` 调用。
118
129
119
- ## hostConfig
130
+ ## 7. hostConfig
120
131
121
132
``` ts
122
133
// packages/taro-platform-weapp/src/runtime-utils.ts
@@ -139,25 +150,19 @@ export const hostConfig = {
139
150
return config
140
151
},
141
152
transferHydrateData (data , element , componentsAlias ) {
142
- if (element .isTransferElement ) {
143
- const pages = getCurrentPages ()
144
- const page = pages [pages .length - 1 ]
145
- data [Shortcuts .NodeName ] = element .dataName
146
- page .setData ({
147
- [toCamelCase (data .nn )]: data
148
- })
149
- return {
150
- sid: element .sid ,
151
- [Shortcuts .Text ]: ' ' ,
152
- [Shortcuts .NodeName ]: componentsAlias [' #text' ]?._num || ' 8'
153
- }
154
- }
153
+ // 省略若干代码
155
154
},
156
155
}
157
156
158
157
```
159
158
160
- ## initNativeApi 初始化原始 api
159
+ 我们接着来看 ` initNativeApi ` 函数。
160
+
161
+ ## 8. initNativeApi 初始化原始 api
162
+
163
+ ``` ts
164
+ // packages/taro-platform-weapp/src/apis.ts
165
+ ```
161
166
162
167
``` ts
163
168
// packages/taro-platform-weapp/src/apis.ts
@@ -198,7 +203,9 @@ export function initNativeApi (taro) {
198
203
199
204
```
200
205
201
- ## processApis 处理 apis
206
+ ` initNativeApi ` 函数中调用了 ` processApis ` 函数,把 ` wx ` 的 api 转换成 ` taro ` 的 api。我们接着来看 ` processApis ` 函数的具体实现。
207
+
208
+ ## 9. processApis 处理 apis
202
209
203
210
``` ts
204
211
// packages/shared/src/native-apis.ts
@@ -209,15 +216,21 @@ const needPromiseApis = new Set<string>([
209
216
' chooseAddress' , ' chooseImage' , ' chooseLocation' , ' downloadFile' ,' getLocation' , ' navigateBack' , ' navigateTo' , ' openDocument' , ' openLocation' , ' reLaunch' , ' redirectTo' , ' scanCode' , ' showModal' , ' showToast' , ' switchTab' , ' uploadFile' ,
210
217
])
211
218
219
+ // processApis 参数对象
212
220
interface IProcessApisIOptions {
213
221
// 不需要 promisify 的 api
214
222
noPromiseApis? : Set <string >
215
- // 希望 promisify 的 api
223
+ // 需要 promisify 的 api
216
224
needPromiseApis? : Set <string >
225
+ // handleSyncApis 磨平差异
217
226
handleSyncApis? : (key : string , global : IObject , args : any []) => any
227
+ // 改变 key 或 option 字段,如需要把支付宝标准的字段对齐微信标准的字段
218
228
transformMeta? : (key : string , options : IObject ) => { key: string , options: IObject }
229
+ // 修改 apis
219
230
modifyApis? : (apis : Set <string >) => void
231
+ // 修改返回结果
220
232
modifyAsyncResult? : (key : string , res ) => void
233
+ // 是否只 promisify,只在 plugin-inject 端使用
221
234
isOnlyPromisify? : boolean
222
235
[propName : string ]: any
223
236
}
@@ -227,6 +240,9 @@ function processApis (taro, global, config: IProcessApisIOptions = {}) {
227
240
}
228
241
```
229
242
243
+ 是否只 ` promisify ` ,只在 ` @tarojs/plugin-inject ` 插件使用
244
+ > 可以为小程序平台注入公共的组件、API 等逻辑
245
+
230
246
``` ts
231
247
// packages/shared/src/native-apis.ts
232
248
function processApis (taro , global , config : IProcessApisIOptions = {}) {
@@ -266,7 +282,18 @@ function processApis (taro, global, config: IProcessApisIOptions = {}) {
266
282
267
283
```
268
284
269
- ### apis.forEach 需要 promisify 的 api 逻辑
285
+ ### 9.1 apis.forEach 需要 promisify 的 api 逻辑
286
+
287
+ ` nonsupport ` 函数
288
+
289
+ ``` ts
290
+ // packages/shared/src/utils.ts
291
+ export function nonsupport (api ) {
292
+ return function () {
293
+ console .warn (` 小程序暂不支持 ${api } ` )
294
+ }
295
+ }
296
+ ```
270
297
271
298
``` js
272
299
// packages/shared/src/native-apis.ts
@@ -303,43 +330,12 @@ apis.forEach(key => {
303
330
304
331
// Promise 化
305
332
const p: any = new Promise ((resolve , reject ) => {
306
- obj .success = res => {
307
- config .modifyAsyncResult ? .(key, res)
308
- options .success ? .(res)
309
- if (key === ' connectSocket' ) {
310
- resolve (
311
- Promise .resolve ().then (() => task ? Object .assign (task, res) : res)
312
- )
313
- } else {
314
- resolve (res)
315
- }
316
- }
317
- obj .fail = res => {
318
- options .fail ? .(res)
319
- reject (res)
320
- }
321
- obj .complete = res => {
322
- options .complete ? .(res)
323
- }
324
- if (args .length ) {
325
- task = global [key](obj, ... args)
326
- } else {
327
- task = global [key](obj)
328
- }
333
+ // 省略...,拆开在下方
329
334
})
330
335
331
336
// 给 promise 对象挂载属性
332
337
if ([' uploadFile' , ' downloadFile' ].includes (key)) {
333
- equipTaskMethodsIntoPromise (task, p)
334
- p .progress = cb => {
335
- task? .onProgressUpdate (cb)
336
- return p
337
- }
338
- p .abort = cb => {
339
- cb? .()
340
- task? .abort ()
341
- return p
342
- }
338
+ // 省略实现...
343
339
}
344
340
return p
345
341
}
@@ -349,46 +345,90 @@ apis.forEach(key => {
349
345
})
350
346
```
351
347
348
+ ` promisify ` 具体实现
349
+
352
350
``` ts
353
- // packages/shared/src/utils.ts
354
- export function nonsupport (api ) {
355
- return function () {
356
- console .warn (` 小程序暂不支持 ${ api} ` )
357
- }
351
+ // Promise 化
352
+ const p: any = new Promise ((resolve , reject ) => {
353
+ obj .success = res => {
354
+ config .modifyAsyncResult ?.(key , res )
355
+ options .success ?.(res )
356
+ if (key === ' connectSocket' ) {
357
+ resolve (
358
+ Promise .resolve ().then (() => task ? Object .assign (task , res ) : res )
359
+ )
360
+ } else {
361
+ resolve (res )
362
+ }
363
+ }
364
+ obj .fail = res => {
365
+ options .fail ?.(res )
366
+ reject (res )
367
+ }
368
+ obj .complete = res => {
369
+ options .complete ?.(res )
370
+ }
371
+ if (args .length ) {
372
+ task = global [key ](obj , ... args )
373
+ } else {
374
+ task = global [key ](obj )
375
+ }
376
+ })
377
+ ```
378
+
379
+ ``` ts
380
+ // 给 promise 对象挂载属性
381
+ if ([' uploadFile' , ' downloadFile' ].includes (key )) {
382
+ // 省略实现...
383
+ equipTaskMethodsIntoPromise (task , p )
384
+ p .progress = cb => {
385
+ task ?.onProgressUpdate (cb )
386
+ return p
387
+ }
388
+ p .abort = cb => {
389
+ cb ?.()
390
+ task ?.abort ()
391
+ return p
392
+ }
358
393
}
394
+
359
395
```
360
396
361
- ### apis.forEach 不需要 promisify 的 api 逻辑
397
+ ### 9.2 apis.forEach 不需要 promisify 的 api 逻辑
362
398
363
399
``` ts
364
400
// packages/shared/src/native-apis.ts
365
- let platformKey = key
366
-
367
- // 改变 key 或 option 字段,如需要把支付宝标准的字段对齐微信标准的字段
368
- if (config .transformMeta ) {
369
- platformKey = config .transformMeta (key, {}).key
370
- }
401
+ if (_needPromiseApis .has (key )) {
402
+ // 省略,上方
403
+ } else {
404
+ let platformKey = key
405
+ // 改变 key 或 option 字段,如需要把支付宝标准的字段对齐微信标准的字段
406
+ if (config .transformMeta ) {
407
+ platformKey = config .transformMeta (key , {}).key
408
+ }
371
409
372
- // API 不存在
373
- if (! global .hasOwnProperty (platformKey)) {
374
- taro[key] = nonsupport (key)
375
- return
376
- }
377
- if (isFunction (global [key])) {
378
- taro[key] = (... args ) => {
379
- if (config .handleSyncApis ) {
380
- return config .handleSyncApis (key, global , args)
381
- } else {
382
- return global [platformKey].apply (global , args)
410
+ // API 不存在
411
+ if (! global .hasOwnProperty (platformKey )) {
412
+ taro [key ] = nonsupport (key )
413
+ return
414
+ }
415
+ if (isFunction (global [key ])) {
416
+ taro [key ] = (... args ) => {
417
+ if (config .handleSyncApis ) {
418
+ return config .handleSyncApis (key , global , args )
419
+ } else {
420
+ return global [platformKey ].apply (global , args )
421
+ }
383
422
}
423
+ } else {
424
+ // 属性类型
425
+ taro [key ] = global [platformKey ]
384
426
}
385
- } else {
386
- // 属性类型
387
- taro[key] = global [platformKey]
388
427
}
428
+
389
429
```
390
430
391
- ## 总结
431
+ ## 10. 总结
392
432
393
433
## links
394
434
0 commit comments