-
Notifications
You must be signed in to change notification settings - Fork 0
/
search.xml
707 lines (335 loc) · 497 KB
/
search.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
<?xml version="1.0" encoding="utf-8"?>
<search>
<entry>
<title>算法-两个数组的交集</title>
<link href="/2020/11/08/%E7%AE%97%E6%B3%95-%E4%B8%A4%E4%B8%AA%E6%95%B0%E7%BB%84%E7%9A%84%E4%BA%A4%E9%9B%86/"/>
<url>/2020/11/08/%E7%AE%97%E6%B3%95-%E4%B8%A4%E4%B8%AA%E6%95%B0%E7%BB%84%E7%9A%84%E4%BA%A4%E9%9B%86/</url>
<content type="html"><![CDATA[<p>js求两个数组的交集<br><a id="more"></a></p><h2 id="题目"><a href="#题目" class="headerlink" title="题目"></a><strong>题目</strong></h2><p><img src="/img/leetcode/leetcode_array.png" alt="leetcode-array"></p><h2 id="我的思路"><a href="#我的思路" class="headerlink" title="我的思路"></a><strong>我的思路</strong></h2><ul><li><p>将数组nums1 转成map,然后数组2遍历,依次判断内部元素是否在nums1中,并且结果中不存在当前所遍历的nums2对象。代码如下:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @param {number[]} nums1</span></span><br><span class="line"><span class="comment"> * @param {number[]} nums2</span></span><br><span class="line"><span class="comment"> * @return {number[]}</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">var</span> intersection = <span class="function"><span class="keyword">function</span>(<span class="params">nums1, nums2</span>) </span>{</span><br><span class="line"> <span class="keyword">let</span> result = [];</span><br><span class="line"> <span class="keyword">let</span> originMap = {};</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i < nums1.length; i++) {</span><br><span class="line"> <span class="keyword">if</span> (originMap[nums1[i]]) {</span><br><span class="line"> originMap[nums1[i]] += <span class="number">1</span>;</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> originMap[nums1[i]] = <span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">let</span> j = <span class="number">0</span>; j < nums2.length; j++) {</span><br><span class="line"> <span class="keyword">if</span> (originMap[nums2[j]] && (!result.includes(nums2[j]))) {</span><br><span class="line"> result.push(nums2[j]);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> result;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li><li><p>结果<br><img src="/img/leetcode/leetcode-array-result.png" alt="leetcode-array-result"></p></li></ul><h2 id="以上执行用时还是很慢,想着如何优化"><a href="#以上执行用时还是很慢,想着如何优化" class="headerlink" title="以上执行用时还是很慢,想着如何优化"></a><strong>以上执行用时还是很慢,想着如何优化</strong></h2><ul><li>看题解,发现有个思路比较有趣, 貌似是3s</li><li><p>思路<br>1) 把第一个数组排序<br>2) 遍历第二个数组的值,判断是否在第一个数组中,这里使用的是二分法查找的数量</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">int</span>[] intersection(<span class="keyword">int</span> [] nums1, <span class="keyword">int</span> [] nums2) {</span><br><span class="line"> Array.sort(nums1);</span><br><span class="line"></span><br><span class="line"> Set(Integer) resSet = <span class="keyword">new</span> HashSet<>();</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i < nums2.length; i++) {</span><br><span class="line"> <span class="keyword">if</span> (binarySearch(nums1, nums2[i]);</span><br><span class="line"> resSet.add(nums2[i])</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">int</span> [] res = <span class="keyword">new</span> <span class="keyword">int</span>[resSet.size()];</span><br><span class="line"> <span class="keyword">int</span> k = <span class="number">0</span>; </span><br><span class="line"> <span class="keyword">for</span> (Integer num: resSet) {</span><br><span class="line"> res[k++] = num;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> res; </span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">boolean</span> <span class="title">binarySearch</span><span class="params">(<span class="keyword">int</span> [] nums, <span class="keyword">int</span> target)</span> </span>{</span><br><span class="line"> <span class="keyword">int</span> left = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">int</span> right = nums.length - <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">while</span>(left <= right) {</span><br><span class="line"> <span class="keyword">int</span> mid = left + (right - left) / <span class="number">2</span>;</span><br><span class="line"> <span class="keyword">int</span> midValue = nums[mid];</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (midValue === target) {</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (midValue > target) {</span><br><span class="line"> right = mid - <span class="number">1</span>;</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> left = mid + <span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li></ul>]]></content>
<tags>
<tag> 算法 数组 </tag>
</tags>
</entry>
<entry>
<title>H5页面适配iphoneX以上底部小黑条遮盖内容</title>
<link href="/2020/11/08/H5%E9%A1%B5%E9%9D%A2%E9%80%82%E9%85%8DiphoneX%E4%BB%A5%E4%B8%8A%E5%BA%95%E9%83%A8%E5%B0%8F%E9%BB%91%E6%9D%A1%E9%81%AE%E7%9B%96%E5%86%85%E5%AE%B9/"/>
<url>/2020/11/08/H5%E9%A1%B5%E9%9D%A2%E9%80%82%E9%85%8DiphoneX%E4%BB%A5%E4%B8%8A%E5%BA%95%E9%83%A8%E5%B0%8F%E9%BB%91%E6%9D%A1%E9%81%AE%E7%9B%96%E5%86%85%E5%AE%B9/</url>
<content type="html"><![CDATA[<p>H5页面适配iphoneX以上底部小黑条遮盖内容<br><a id="more"></a></p><h2 id="背景"><a href="#背景" class="headerlink" title="背景"></a><strong>背景</strong></h2><ul><li>iphone X 系列以上的H5 底部小黑条把内容遮盖</li></ul><h2 id="解决方案"><a href="#解决方案" class="headerlink" title="解决方案"></a><strong>解决方案</strong></h2><ul><li><p>增加 viewport属性, viewport-fit = “cover”</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><meta name=<span class="string">"viewport"</span> content=<span class="string">"width=device-width,initial-scale=1.0,maximum-scale=1.0,userscalable=0,viewport-fit=cover"</span>></span><br></pre></td></tr></table></figure></li><li><p>利用constant 函数,这个函数是ios11新增的css属性用于设定安全区域与边界的距离<br>1)safe-area-inset-left 安全区域与左右上下的距离<br>2)safe-area-inset-right<br>3) safe-area-inset-top<br>4) safe-area-inset-bottom</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">body{</span><br><span class="line"> padding-bottom: constant(safe-area-inset-bottom)</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li></ul><ul><li><p>对fixed元素的适配<br>1)fixed 元素完全吸底<br> i)通过增加内边距扩展高度</p> <figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">{</span><br><span class="line"> padding-bottom: constant(safe-area-inset-bottom)</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p> ii) 通过calc覆盖原来高度</p> <figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">{</span><br><span class="line"> height: calc(<span class="number">30</span>() + constant(safe-area-inset-bottom))</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p> iii) 新增空白元素</p> <figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">{</span><br><span class="line"> position: fixed;</span><br><span class="line"> bottom: <span class="number">0</span>;</span><br><span class="line"> height: constant(safe-area-inset-bottom);</span><br><span class="line"> width: <span class="number">100</span>%;</span><br><span class="line"> background: #fff;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li></ul><ul><li><p>fixed 元素不完全吸底</p><p>1) 通过外边距处理</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">{</span><br><span class="line"> margin-bottom:constant(safe-area-inset-bottom);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>2) 通过calc覆盖原来高度</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">{</span><br><span class="line"> height: calc(<span class="number">20</span>() + constant(safe-area-inset-bottom))</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li></ul>]]></content>
<tags>
<tag> 适配 </tag>
</tags>
</entry>
<entry>
<title>vue 图片压缩</title>
<link href="/2020/11/08/vue-%E5%9B%BE%E7%89%87%E5%8E%8B%E7%BC%A9/"/>
<url>/2020/11/08/vue-%E5%9B%BE%E7%89%87%E5%8E%8B%E7%BC%A9/</url>
<content type="html"><![CDATA[<p>基于强视觉项目进行的图片压缩优化<br><a id="more"></a></p><h2 id="背景"><a href="#背景" class="headerlink" title="背景"></a><strong>背景</strong></h2><ul><li>随着官网需求越来越大,打包越来越大,导致项目在C端的加载越来越慢,经一轮js和css压缩后,发现大批量的图<br>片没有压缩很好,故得上述情况<br><img src="/img/gzip/gzip_origin.png" alt="gzip_origin"></li></ul><h2 id="没有优化前"><a href="#没有优化前" class="headerlink" title="没有优化前"></a>没有优化前</h2><ul><li>21.2M</li></ul><h2 id="实现方式"><a href="#实现方式" class="headerlink" title="实现方式"></a>实现方式</h2><ul><li>网站压缩<br>1)推荐网站1:<a href="https://tinypng.com/" target="_blank" rel="noopener">tinypng</a>此网站可以批量压缩图片,当然一次性压太多,网站也会报错无法压缩成功,多试几次就好了,并且,这个网站的压缩图片可以反复压很多次<br>2) 推荐网站2:<a href="https://www.bejson.com/ui/compress_img/" target="_blank" rel="noopener">bejson</a> 该网站有点事自定义压缩体积,缺点是一次只能压一张图片<br>3) 效果:<br> i)经过一轮把所有图片在网站进行压缩以后,此时的大小为: 7.37M<br> <img src="/img/gzip/gzip_one.png" alt="gzip_one"></li><li><p>代码压缩<br>1) 引入 url-loader</p> <figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">npm install file-loader -D</span><br><span class="line">npm install url-loader -D</span><br></pre></td></tr></table></figure><p>2) vue.config.js 中配置如下:</p> <figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">chainWebpack: <span class="function">(<span class="params">config</span>) =></span> {</span><br><span class="line"> config.module</span><br><span class="line"> .rule(<span class="string">'images'</span>)</span><br><span class="line"> .test(<span class="regexp">/\.(png|jpe?g|gif|svg)(\?.*)?$/</span>)</span><br><span class="line"> .use(<span class="string">'url-loader'</span>)</span><br><span class="line"> .loader(<span class="string">'url-loader'</span>)</span><br><span class="line"> .options({ <span class="attr">bypassOnDebug</span>: <span class="literal">true</span> })</span><br><span class="line"> .end();</span><br><span class="line"> },</span><br></pre></td></tr></table></figure><p>3) 此时打包后大小为 4.6M</p><p> <img src="/img/gzip/gzip_end.png" alt="gzip_end"></p></li></ul><h2 id="感想与收获"><a href="#感想与收获" class="headerlink" title="感想与收获"></a>感想与收获</h2><ul><li>压缩成就感满满</li><li>关于url-loader 和file-loader的区别可以参看<br>1)<a href="https://www.webpackjs.com/loaders/file-loader/" target="_blank" rel="noopener">https://www.webpackjs.com/loaders/file-loader/</a><br>2) <a href="https://www.webpackjs.com/loaders/url-loader/" target="_blank" rel="noopener">https://www.webpackjs.com/loaders/url-loader/</a><br>3) <a href="https://blog.csdn.net/harmsworth2016/article/details/82055574" target="_blank" rel="noopener">https://blog.csdn.net/harmsworth2016/article/details/82055574</a><br>4) <a href="https://blog.csdn.net/dejing6575/article/details/101474194?utm_medium=distribute.pc_relevant_t0.none-task-blogBlogCommendFromMachineLearnPai2-1.channel_param&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blogBlogCommendFromMachineLearnPai2-1.channel_param" target="_blank" rel="noopener">https://blog.csdn.net/dejing6575/article/details/101474194?utm_medium=distribute.pc_relevant_t0.none-task-blogBlogCommendFromMachineLearnPai2-1.channel_param&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blogBlogCommendFromMachineLearnPai2-1.channel_param</a></li></ul>]]></content>
<tags>
<tag> vue 优化 </tag>
</tags>
</entry>
<entry>
<title>单页面应用打开耗时很慢</title>
<link href="/2020/11/06/%E5%8D%95%E9%A1%B5%E9%9D%A2%E5%BA%94%E7%94%A8%E6%89%93%E5%BC%80%E8%80%97%E6%97%B6%E5%BE%88%E6%85%A2/"/>
<url>/2020/11/06/%E5%8D%95%E9%A1%B5%E9%9D%A2%E5%BA%94%E7%94%A8%E6%89%93%E5%BC%80%E8%80%97%E6%97%B6%E5%BE%88%E6%85%A2/</url>
<content type="html"><![CDATA[<p>h5 单页面应用打开耗时很慢<br><a id="more"></a></p><h2 id="背景"><a href="#背景" class="headerlink" title="背景"></a><strong>背景</strong></h2><ul><li>最近vue单页面项目越做越大,发现首次加载耗时很慢,已经在一轮优化以后发现有时候耗时依旧很慢,尤其是h5的移动端页面</li></ul><h2 id="原因"><a href="#原因" class="headerlink" title="原因"></a><strong>原因</strong></h2><ul><li>移动端单页面应用使用懒加载,懒加载的请求会导致有时候请求过长就自动访问到根结点</li><li>谷歌字体请求耗时过长,查看network有时候会长达10s+</li></ul><h2 id="解决方案"><a href="#解决方案" class="headerlink" title="解决方案"></a>解决方案</h2><ul><li>懒加载的页面移除懒加载,在route.js中手动 import</li><li>谷歌字体优化<br>1) 查看请求是哪个urrl :我的项目中请求谷歌字体的url是<a href="https://fonts.googleapis.com/css?family=Open+Sans:400,400i,600" target="_blank" rel="noopener"></a><br><img src="/img/google/google-font.png" alt="google-font"><br>2) 然后把response 中的内容下载到本地,然后在main.js中 import 引入,如下<br> <img src="/img/google/google-css.png" alt="google-css"><br>3) 备注:担心谷歌会引入其他地址的字体,这边索性把两个地址的url的response都引入,请求地址如下<br> <a href="https://fonts.googleapis.com/css?family=Open+Sans:300,400,600,700" target="_blank" rel="noopener">https://fonts.googleapis.com/css?family=Open+Sans:300,400,600,700</a><br> <a href="https://fonts.googleapis.com/css?family=Roboto:400,300,500,700" target="_blank" rel="noopener">https://fonts.googleapis.com/css?family=Roboto:400,300,500,700</a></li></ul>]]></content>
<tags>
<tag> vue 单页面应用 请求耗时 </tag>
</tags>
</entry>
<entry>
<title>vue首屏白屏分析解决</title>
<link href="/2020/07/26/vue%E9%A6%96%E5%B1%8F%E7%99%BD%E5%B1%8F%E5%88%86%E6%9E%90%E8%A7%A3%E5%86%B3/"/>
<url>/2020/07/26/vue%E9%A6%96%E5%B1%8F%E7%99%BD%E5%B1%8F%E5%88%86%E6%9E%90%E8%A7%A3%E5%86%B3/</url>
<content type="html"><![CDATA[<p>vue 性能优化 白屏<br><a id="more"></a></p><h3 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h3><ul><li>需求:vue h5内嵌到app中,发现在app中显示h5时会出现首屏白屏,大概1-2s左右,但是在浏览器中没有白屏的知觉</li><li>参考文档:<a href="https://juejin.im/post/5bee7dd4e51d451f5b54cbb4" target="_blank" rel="noopener">https://juejin.im/post/5bee7dd4e51d451f5b54cbb4</a></li><li><p>分析:</p><ul><li><p>本地启动服务,在chrome浏览器控制台中分析如下,发现首屏白屏长达2200-400 = 1800ms,竟然有这么长的白屏时间<br><img src="/img/first-onload/01.png" alt=""><br><img src="/img/first-onload/02.png" alt=""><br>200ms左右时间在加载app.js,考虑是否可以路由懒加载</p></li><li><p>npm install webpack分析工具,然后在vue.config.js中配置,查看打包情况,如下</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm install webpack-bundle-analyzer - -save -dev</span><br></pre></td></tr></table></figure></li></ul><p>在vue.config.js中配置如下:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"> chainWebpack: <span class="function">(<span class="params">config</span>) =></span> {</span><br><span class="line"> <span class="comment">// 分析工具</span></span><br><span class="line"> <span class="keyword">if</span> (process.env.NODE_ENV == <span class="string">'production'</span>) {</span><br><span class="line"> <span class="keyword">if</span> (process.env.npm_config_report) {</span><br><span class="line"> config</span><br><span class="line"> .plugin(<span class="string">'webpack-bundle-analyzer'</span>)</span><br><span class="line"> .use(<span class="built_in">require</span>(<span class="string">'webpack-bundle-analyzer'</span>).BundleAnalyzerPlugin)</span><br><span class="line"> .end()</span><br><span class="line"> config.plugins.delete(<span class="string">'prefetch'</span>)</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>然后 npm run build – report<br><img src="/img/first-onload/03.png" alt=""><br><img src="/img/first-onload/04.png" alt=""><br><img src="/img/first-onload/05.png" alt=""><br><img src="/img/first-onload/06.png" alt=""></p></li></ul><ul><li>优化方案<ul><li>路由懒加载<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// lazy load</span></span><br><span class="line"><span class="keyword">const</span> Download = <span class="function"><span class="params">()</span> =></span> <span class="keyword">import</span>(<span class="string">'@/views/Download.vue'</span>);</span><br><span class="line"><span class="keyword">const</span> route = [</span><br><span class="line"> {</span><br><span class="line"> path: <span class="string">'/download'</span>,</span><br><span class="line"> name: <span class="string">'download'</span>,</span><br><span class="line"> component: Download</span><br><span class="line"> }</span><br><span class="line">];</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> route;</span><br></pre></td></tr></table></figure></li></ul></li></ul><pre><code>此时时间降低 到1200ms-400ms = 800ms,此时js.chunk.js压缩到 547.45k![](/img/first-onload/07.png)此时build包的情况![](/img/first-onload/08.png)![](/img/first-onload/09.png)- 利用webpack对超过10k以上的包进行gzip压缩- 对UI组件 antd-vue 进行按需加载![](/img/first-onload/10.png) - 进行以上分析以后,会发现,在FP与FCP阶段,还是有1s左右的首屏白屏,这里的解决方案是与UI和交互协调,引入骨架屏或者loading,这里在app加载之前引入loading,然后再APP创建的时候将这个loading移除即可,如下: public下index.html <figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br></pre></td><td class="code"><pre><span class="line"> <span class="meta"><!DOCTYPE html></span></span><br><span class="line">` <span class="tag"><<span class="name">html</span> <span class="attr">lang</span>=<span class="string">"en"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">head</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">meta</span> <span class="attr">charset</span>=<span class="string">"utf-8"</span> /></span></span><br><span class="line"> <span class="tag"><<span class="name">meta</span> <span class="attr">http-equiv</span>=<span class="string">"X-UA-Compatible"</span> <span class="attr">content</span>=<span class="string">"IE=edge"</span> /></span></span><br><span class="line"> <span class="tag"><<span class="name">meta</span> <span class="attr">name</span>=<span class="string">"viewport"</span> <span class="attr">content</span>=<span class="string">"width=device-width,initial-scale=1.0,user-scalable=0"</span> /></span></span><br><span class="line"> <span class="tag"><<span class="name">link</span> <span class="attr">rel</span>=<span class="string">"icon"</span> <span class="attr">href</span>=<span class="string">"<%= BASE_URL %>logo.ico"</span> /></span></span><br><span class="line"> <span class="tag"><<span class="name">link</span> <span class="attr">rel</span>=<span class="string">"icon"</span> <span class="attr">href</span>=<span class="string">"<%= BASE_URL %>logo.ico"</span> <span class="attr">rel</span>=<span class="string">"shortcut icon"</span> /></span></span><br><span class="line"> <span class="tag"><<span class="name">link</span> <span class="attr">rel</span>=<span class="string">"icon"</span> <span class="attr">href</span>=<span class="string">"<%= BASE_URL %>logo.ico"</span> <span class="attr">rel</span>=<span class="string">"Bookmark"</span> /></span></span><br><span class="line"> <span class="tag"><<span class="name">link</span> <span class="attr">rel</span>=<span class="string">"apple-touch-icon"</span> <span class="attr">sizes</span>=<span class="string">"152x152"</span> <span class="attr">href</span>=<span class="string">"<%= BASE_URL %>logo.png"</span> /></span></span><br><span class="line"> <span class="tag"><<span class="name">img</span> <span class="attr">id</span>=<span class="string">"shareImg"</span> <span class="attr">src</span>=<span class="string">"<%= BASE_URL %>sharelogo.jpg"</span> <span class="attr">width</span>=<span class="string">"0"</span> <span class="attr">height</span>=<span class="string">"0"</span> /></span></span><br><span class="line"> <span class="tag"><<span class="name">title</span>></span>iFLYBUDS<span class="tag"></<span class="name">title</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">script</span> <span class="attr">type</span>=<span class="string">"text/javascript"</span>></span><span class="undefined"></span></span><br><span class="line"><span class="javascript"> (<span class="function"><span class="keyword">function</span>(<span class="params">window, document</span>) </span>{</span></span><br><span class="line"><span class="javascript"> <span class="keyword">let</span> deviceWidth = <span class="built_in">document</span>.documentElement.clientWidth;</span></span><br><span class="line"><span class="javascript"> <span class="keyword">if</span> (<span class="built_in">window</span>.orientation == <span class="number">90</span> || <span class="built_in">window</span>.orientation == <span class="number">-90</span>) {</span></span><br><span class="line"><span class="javascript"> <span class="keyword">if</span> (deviceWidth > <span class="number">1334</span>)</span></span><br><span class="line"><span class="undefined"> deviceWidth = 1334;</span></span><br><span class="line"><span class="javascript"> <span class="built_in">document</span>.documentElement.style.fontSize = deviceWidth / <span class="number">13.34</span> + <span class="string">'px'</span>;</span></span><br><span class="line"><span class="javascript"> } <span class="keyword">else</span> {</span></span><br><span class="line"><span class="javascript"> <span class="keyword">if</span> (deviceWidth > <span class="number">750</span>)</span></span><br><span class="line"><span class="undefined"> deviceWidth = 750;</span></span><br><span class="line"><span class="javascript"> <span class="built_in">document</span>.documentElement.style.fontSize = deviceWidth / <span class="number">7.5</span> + <span class="string">'px'</span>;</span></span><br><span class="line"><span class="undefined"> }</span></span><br><span class="line"><span class="javascript"> })(<span class="built_in">window</span>, <span class="built_in">document</span>)</span></span><br><span class="line"><span class="undefined"> </span><span class="tag"></<span class="name">script</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">style</span> <span class="attr">type</span>=<span class="string">"text/css"</span>></span><span class="undefined"></span></span><br><span class="line"><span class="undefined"> #Loading {</span></span><br><span class="line"><span class="undefined"> width: 100vw;</span></span><br><span class="line"><span class="undefined"> height:100vh;</span></span><br><span class="line"><span class="undefined"> background: #1C1F29;</span></span><br><span class="line"><span class="undefined"> z-index: 1000;</span></span><br><span class="line"><span class="undefined"> margin-top: -18px;</span></span><br><span class="line"><span class="undefined"> }</span></span><br><span class="line"><span class="undefined"> .loader_inner {</span></span><br><span class="line"><span class="undefined"> display: flex;</span></span><br><span class="line"><span class="undefined"> flex-direction: column;</span></span><br><span class="line"><span class="undefined"> top: 50%;</span></span><br><span class="line"><span class="undefined"> left: 50%;</span></span><br><span class="line"><span class="undefined"> position: absolute;</span></span><br><span class="line"><span class="undefined"> -webkit-transform: translateY(-50%) translateX(-50%);</span></span><br><span class="line"><span class="undefined"> transform: translateY(-50%) translateX(-50%);</span></span><br><span class="line"><span class="undefined"> }</span></span><br><span class="line"><span class="undefined"> .loader_info {</span></span><br><span class="line"><span class="undefined"> width: 100%;</span></span><br><span class="line"><span class="undefined"> font-family: PingFang SC;</span></span><br><span class="line"><span class="undefined"> font-style: normal;</span></span><br><span class="line"><span class="undefined"> font-weight: normal;</span></span><br><span class="line"><span class="undefined"> font-size: 0.3rem;</span></span><br><span class="line"><span class="undefined"> line-height: 0.52rem;</span></span><br><span class="line"><span class="undefined"> text-align: center;</span></span><br><span class="line"><span class="undefined"> color: #A2A5B8;</span></span><br><span class="line"><span class="undefined"> }</span></span><br><span class="line"><span class="undefined"> .loader_inner_cicle {</span></span><br><span class="line"><span class="undefined"> position: relative;</span></span><br><span class="line"><span class="undefined"> width: 0.72rem;</span></span><br><span class="line"><span class="undefined"> height: 0.72rem;</span></span><br><span class="line"><span class="undefined"> margin: auto;</span></span><br><span class="line"><span class="undefined"> border:1px solid #fff;</span></span><br><span class="line"><span class="undefined"> }</span></span><br><span class="line"><span class="undefined"> #loader8 { </span></span><br><span class="line"><span class="undefined"> margin: auto;</span></span><br><span class="line"><span class="undefined"> float: left; </span></span><br><span class="line"><span class="undefined"> position: relative; </span></span><br><span class="line"><span class="undefined"> text-indent: -9999em; </span></span><br><span class="line"><span class="undefined"> border-top: 0.1rem solid #2e3043; </span></span><br><span class="line"><span class="undefined"> border-right: 0.1rem solid #2e3043; </span></span><br><span class="line"><span class="undefined"> border-bottom: 0.1rem solid #2e3043; </span></span><br><span class="line"><span class="undefined"> border-left: 0.1rem solid #80809e;</span></span><br><span class="line"><span class="undefined"> -webkit-animation: load8 2s infinite linear; </span></span><br><span class="line"><span class="undefined"> animation: load8 2s infinite linear; </span></span><br><span class="line"><span class="undefined"> } </span></span><br><span class="line"><span class="undefined"> #loader8, </span></span><br><span class="line"><span class="undefined"> #loader8:after { </span></span><br><span class="line"><span class="undefined"> border-radius: 50%; </span></span><br><span class="line"><span class="undefined"> width: 0.72rem; </span></span><br><span class="line"><span class="undefined"> height: 0.72rem; </span></span><br><span class="line"><span class="undefined"> } </span></span><br><span class="line"><span class="undefined"> @-webkit-keyframes load8 { </span></span><br><span class="line"><span class="undefined"> 0% { </span></span><br><span class="line"><span class="undefined"> -webkit-transform: rotate(0deg); </span></span><br><span class="line"><span class="undefined"> transform: rotate(0deg); </span></span><br><span class="line"><span class="undefined"> } </span></span><br><span class="line"><span class="undefined"> 100% { </span></span><br><span class="line"><span class="undefined"> -webkit-transform: rotate(360deg); </span></span><br><span class="line"><span class="undefined"> transform: rotate(360deg); </span></span><br><span class="line"><span class="undefined"> } </span></span><br><span class="line"><span class="undefined"> } </span></span><br><span class="line"><span class="undefined"> @keyframes load8 { </span></span><br><span class="line"><span class="undefined"> 0% { </span></span><br><span class="line"><span class="undefined"> -webkit-transform: rotate(0deg); </span></span><br><span class="line"><span class="undefined"> transform: rotate(0deg); </span></span><br><span class="line"><span class="undefined"> } </span></span><br><span class="line"><span class="undefined"> 100% { </span></span><br><span class="line"><span class="undefined"> -webkit-transform: rotate(360deg); </span></span><br><span class="line"><span class="undefined"> transform: rotate(360deg); </span></span><br><span class="line"><span class="undefined"> } </span></span><br><span class="line"><span class="undefined"> } </span></span><br><span class="line"><span class="undefined"> </span><span class="tag"></<span class="name">style</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">head</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">body</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">noscript</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">strong</span>></span>We're sorry but kuaidu-wx-pay doesn't work properly without JavaScript enabled. Please enable it to continue.<span class="tag"></<span class="name">strong</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">noscript</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">id</span>=<span class="string">"Loading"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"loader_inner"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">id</span>=<span class="string">"loader8"</span>></span><span class="tag"></<span class="name">div</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"loader_info"</span>></span>正在加载,请稍后<span class="tag"></<span class="name">div</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">div</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">div</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">id</span>=<span class="string">"app"</span>></span><span class="tag"></<span class="name">div</span>></span></span><br><span class="line"> <span class="comment"><!-- built files will be auto injected --></span></span><br><span class="line"> <span class="tag"></<span class="name">body</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">html</span>></span>`</span><br></pre></td></tr></table></figure> 然后在App创建之前将这个div移除,如下: App.vue <figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"> <template></span><br><span class="line"> <div id=<span class="string">"app"</span>></span><br><span class="line"> <router-view /></span><br><span class="line"> <<span class="regexp">/div></span></span><br><span class="line"><span class="regexp"> </</span>template></span><br><span class="line"> <script ></span><br><span class="line"> <span class="keyword">export</span> <span class="keyword">default</span> {</span><br><span class="line"> data () {</span><br><span class="line"> <span class="keyword">return</span> {}</span><br><span class="line"> },</span><br><span class="line"> created() {</span><br><span class="line"> <span class="keyword">let</span> loading = <span class="built_in">document</span>.getElementById(<span class="string">'Loading'</span>);</span><br><span class="line"> <span class="keyword">if</span> (loading !== <span class="literal">null</span>) {</span><br><span class="line"> <span class="built_in">document</span>.body.removeChild(loading);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"><<span class="regexp">/script></span></span><br></pre></td></tr></table></figure> 打完包以后的首屏加载时间降低到900ms,如下: ![](/img/first-onload/11.png) ![](/img/first-onload/12.png)</code></pre>]]></content>
<tags>
<tag> vue 性能优化 白屏 </tag>
</tags>
</entry>
<entry>
<title>vue3+node(koa)实现微信自定义分享</title>
<link href="/2020/05/23/vue3-node-koa-%E5%AE%9E%E7%8E%B0%E5%BE%AE%E4%BF%A1%E8%87%AA%E5%AE%9A%E4%B9%89%E5%88%86%E4%BA%AB/"/>
<url>/2020/05/23/vue3-node-koa-%E5%AE%9E%E7%8E%B0%E5%BE%AE%E4%BF%A1%E8%87%AA%E5%AE%9A%E4%B9%89%E5%88%86%E4%BA%AB/</url>
<content type="html"><![CDATA[<p>基于 h5 (vue) node(koa2) 微信jssdk实现的微信自定义分享<br><a id="more"></a></p><h3 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h3><p>最近团队有个需求,需要h5在微信中打开然后分享给同事或者朋友圈的时候自定义微信分享图标,标题等,即将如下的图片1做成图片2的形式<br><img src="/img/wx-share/share_01.jpg" alt="图片1"><br><img src="/img/wx-share/share_02.jpg" alt="图片2"></p><h3 id="实现方案"><a href="#实现方案" class="headerlink" title="实现方案"></a>实现方案</h3><h4 id="前期准备"><a href="#前期准备" class="headerlink" title="前期准备"></a>前期准备</h4><pre><code>- 微信sdk官方文档(http://caibaojian.com/wxwiki/0030551f015f01ecaa56d20b88ee3c6cb32503bf.html)- 团队公众号- 服务器域名- 准备 * 公众号设置,功能设置,配置安全域名 ![功能设置](/img/wx-share/share_03.jpg) * 开发,开通开发者功能,配置ip白名单(包含自己本地机器,测试环境机器)- 代码方案 * node层开启8411端口,package.json 中引入 concurrently同时启动客户端和服务端,vue3 开启到 8411 端口 package.json <figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">"dev"</span>: <span class="string">"concurrently \"npm run client\" \"npm run server\" --color "</span>,</span><br></pre></td></tr></table></figure> vue.config.js <figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">'/wechat'</span>: {</span><br><span class="line"> <span class="comment">// target: 'http://[::1]:8411',</span></span><br><span class="line"> target: <span class="string">'http://127.0.0.1:8411'</span>,</span><br><span class="line"> changeOrigin: <span class="literal">true</span>,</span><br><span class="line"> wx: <span class="literal">true</span>,</span><br><span class="line"> pathRewrite: {</span><br><span class="line"> <span class="string">'^/wechat'</span>: <span class="string">'/wechat'</span></span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure> * 在node层按照jssdk微信公众平台的方案用koa2,koa-router写一个接口,监听8411端口 server/index.js <figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> Koa = <span class="built_in">require</span>(<span class="string">'koa'</span>);</span><br><span class="line"><span class="keyword">const</span> path = <span class="built_in">require</span>(<span class="string">'path'</span>);</span><br><span class="line"><span class="keyword">const</span> staticFiles = <span class="built_in">require</span>(<span class="string">'koa-static'</span>)</span><br><span class="line"><span class="keyword">const</span> bodyParser = <span class="built_in">require</span>(<span class="string">'koa-bodyparser'</span>)</span><br><span class="line"><span class="keyword">const</span> cors = <span class="built_in">require</span>(<span class="string">'koa-cors'</span>)</span><br><span class="line"><span class="keyword">const</span> onerror = <span class="built_in">require</span>(<span class="string">'koa-onerror'</span>) <span class="comment">//错误处理</span></span><br><span class="line"><span class="keyword">const</span> getAccess = <span class="built_in">require</span>(<span class="string">'./lib/wxAccess'</span>)</span><br><span class="line"><span class="keyword">const</span> Router = <span class="built_in">require</span>(<span class="string">'koa-router'</span>)</span><br><span class="line"><span class="keyword">const</span> router = <span class="keyword">new</span> Router();</span><br><span class="line"><span class="keyword">const</span> app = <span class="keyword">new</span> Koa();</span><br><span class="line"></span><br><span class="line">onerror(app)</span><br><span class="line"><span class="comment">// logger</span></span><br><span class="line"></span><br><span class="line">app.use(staticFiles(path.resolve(__dirname, <span class="string">"../public"</span>)))</span><br><span class="line">app.use(cors())</span><br><span class="line"></span><br><span class="line">app.use(bodyParser())</span><br><span class="line"></span><br><span class="line">app.use(<span class="keyword">async</span> (ctx, next) => {</span><br><span class="line"> <span class="keyword">await</span> next();</span><br><span class="line"> <span class="keyword">const</span> rt = ctx.response.get(<span class="string">'X-Response-Time'</span>);</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">`<span class="subst">${ctx.method}</span> <span class="subst">${ctx.url}</span> - <span class="subst">${rt}</span>`</span>);</span><br><span class="line">});</span><br><span class="line"></span><br><span class="line">router.post(<span class="string">'/wechat/getConfig'</span>, <span class="keyword">async</span> (ctx, next) => {</span><br><span class="line"> <span class="keyword">const</span> url = ctx.request.body.url;</span><br><span class="line"> <span class="keyword">const</span> resp = <span class="keyword">await</span> getAccess(url);</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">'resp in index'</span>, resp);</span><br><span class="line"> ctx.body = {</span><br><span class="line"> data: resp,</span><br><span class="line"> success: <span class="literal">true</span>,</span><br><span class="line"> message: <span class="string">''</span></span><br><span class="line"> };</span><br><span class="line"> <span class="keyword">await</span> next();</span><br><span class="line">})</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">app.use(router.routes())</span><br><span class="line"></span><br><span class="line">app.use(router.allowedMethods())</span><br><span class="line"></span><br><span class="line">app.listen(<span class="number">8411</span>, () => {</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">'server is listen port:8411'</span>)</span><br><span class="line">})</span><br></pre></td></tr></table></figure> /lib/wxAccess <figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> sha1 = <span class="built_in">require</span>(<span class="string">'sha1'</span>)</span><br><span class="line"><span class="keyword">const</span> config = <span class="built_in">require</span>(<span class="string">'./wxConfig'</span>)</span><br><span class="line"><span class="keyword">const</span> cache = <span class="built_in">require</span>(<span class="string">'memory-cache'</span>)</span><br><span class="line"><span class="keyword">const</span> rp = <span class="built_in">require</span>(<span class="string">'request-promise'</span>)</span><br><span class="line"><span class="keyword">const</span> crypto = <span class="built_in">require</span>(<span class="string">'crypto'</span>);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> jsApiList = [</span><br><span class="line"> <span class="string">'checkJsApi'</span>,</span><br><span class="line"> <span class="string">'onMenuShareTimeline'</span>,</span><br><span class="line"> <span class="string">'onMenuShareAppMessage'</span>,</span><br><span class="line"> <span class="string">'onMenuShareQQ'</span>,</span><br><span class="line"> <span class="string">'onMenuShareWeibo'</span>,</span><br><span class="line"> <span class="string">'hideMenuItems'</span>,</span><br><span class="line"> <span class="string">'showMenuItems'</span>,</span><br><span class="line"> <span class="string">'hideAllNonBaseMenuItem'</span>,</span><br><span class="line"> <span class="string">'showAllNonBaseMenuItem'</span>,</span><br><span class="line"> <span class="string">'translateVoice'</span>,</span><br><span class="line"> <span class="string">'startRecord'</span>,</span><br><span class="line"> <span class="string">'stopRecord'</span>,</span><br><span class="line"> <span class="string">'onRecordEnd'</span>,</span><br><span class="line"> <span class="string">'playVoice'</span>,</span><br><span class="line"> <span class="string">'pauseVoice'</span>,</span><br><span class="line"> <span class="string">'stopVoice'</span>,</span><br><span class="line"> <span class="string">'uploadVoice'</span>,</span><br><span class="line"> <span class="string">'downloadVoice'</span>,</span><br><span class="line"> <span class="string">'chooseImage'</span>,</span><br><span class="line"> <span class="string">'previewImage'</span>,</span><br><span class="line"> <span class="string">'uploadImage'</span>,</span><br><span class="line"> <span class="string">'downloadImage'</span>,</span><br><span class="line"> <span class="string">'getNetworkType'</span>,</span><br><span class="line"> <span class="string">'openLocation'</span>,</span><br><span class="line"> <span class="string">'getLocation'</span>,</span><br><span class="line"> <span class="string">'hideOptionMenu'</span>,</span><br><span class="line"> <span class="string">'showOptionMenu'</span>,</span><br><span class="line"> <span class="string">'closeWindow'</span>,</span><br><span class="line"> <span class="string">'scanQRCode'</span>,</span><br><span class="line"> <span class="string">'chooseWXPay'</span>,</span><br><span class="line"> <span class="string">'openProductSpecificView'</span>,</span><br><span class="line"> <span class="string">'addCard'</span>,</span><br><span class="line"> <span class="string">'chooseCard'</span>,</span><br><span class="line"> <span class="string">'openCard'</span></span><br><span class="line">];</span><br><span class="line"><span class="keyword">const</span> getAccess = <span class="keyword">async</span> (url) => {</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="keyword">async</span> (resolve, reject) => {</span><br><span class="line"> <span class="keyword">const</span> noncestr = crypto.randomBytes(<span class="built_in">Math</span>.ceil(<span class="number">32</span> / <span class="number">2</span>)).toString(<span class="string">'hex'</span>).slice(<span class="number">0</span>, <span class="number">32</span>);;</span><br><span class="line"> <span class="keyword">const</span> timestamp = <span class="built_in">Math</span>.floor(<span class="built_in">Date</span>.now() / <span class="number">1000</span>); <span class="comment">//???</span></span><br><span class="line"> <span class="keyword">let</span> wxdata = <span class="literal">null</span>;</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="comment">// ???????????????????</span></span><br><span class="line"> <span class="keyword">if</span> (cache.get(<span class="string">'ticket'</span>)) {</span><br><span class="line"> <span class="comment">// console.log('ticket in cache', cache.get('ticket'))</span></span><br><span class="line"> <span class="keyword">const</span> jsapi_ticket = cache.get(<span class="string">'ticket'</span>);</span><br><span class="line"> wxdata = {</span><br><span class="line"> appId: config.wxappid,</span><br><span class="line"> noncestr,</span><br><span class="line"> timestamp,</span><br><span class="line"> url,</span><br><span class="line"> jsapi_ticket,</span><br><span class="line"> signature: sha1(<span class="string">`jsapi_ticket=<span class="subst">${jsapi_ticket}</span>&noncestr=<span class="subst">${noncestr}</span>&timestamp=<span class="subst">${timestamp}</span>&url=<span class="subst">${url}</span>`</span>),</span><br><span class="line"> jsApiList</span><br><span class="line"> }</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">const</span> tokenMap = <span class="keyword">await</span> rp({<span class="attr">uri</span>: <span class="string">`https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=<span class="subst">${config.wxappid}</span>&secret=<span class="subst">${config.wxappsecret}</span>`</span>});</span><br><span class="line"> <span class="comment">// console.log('rp res', JSON.parse(tokenMap));</span></span><br><span class="line"> <span class="keyword">const</span> resp = <span class="keyword">await</span> rp({<span class="attr">uri</span>: <span class="string">`https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=<span class="subst">${<span class="built_in">JSON</span>.parse(tokenMap).access_token}</span>&type=jsapi`</span>});</span><br><span class="line"> <span class="keyword">const</span> ticketMap = <span class="built_in">JSON</span>.parse(resp);</span><br><span class="line"> cache.put(<span class="string">'ticket'</span>, ticketMap.ticket, (<span class="number">1000</span> * <span class="number">7200</span>));</span><br><span class="line"> <span class="keyword">var</span> resultCode = sha1(<span class="string">`jsapi_ticket=<span class="subst">${ticketMap.ticket}</span>&noncestr=<span class="subst">${noncestr}</span>&timestamp=<span class="subst">${timestamp}</span>&url=http://192.168.3.9:8080/sharepage/download`</span>);</span><br><span class="line"> <span class="comment">// console.log('resultCode', resultCode);</span></span><br><span class="line"> </span><br><span class="line"> wxdata = {</span><br><span class="line"> appId: config.wxappid,</span><br><span class="line"> noncestr,</span><br><span class="line"> timestamp,</span><br><span class="line"> url,</span><br><span class="line"> jsapi_ticket: ticketMap.ticket,</span><br><span class="line"> signature: resultCode,</span><br><span class="line"> jsApiList</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">'wx data'</span>, wxdata);</span><br><span class="line"> resolve(wxdata);</span><br><span class="line"> } <span class="keyword">catch</span>(e) {</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">'catch exception'</span>, <span class="built_in">JSON</span>.stringify(e));</span><br><span class="line"> reject(<span class="string">'catch exception'</span>, <span class="built_in">JSON</span>.stringify(e));</span><br><span class="line"> }</span><br><span class="line"> })</span><br><span class="line">}</span><br><span class="line"><span class="built_in">module</span>.exports = getAccess;</span><br></pre></td></tr></table></figure> ./wxConfig <figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> config = {</span><br><span class="line"> wxappid: <span class="string">'wx2389aa4213cf6e5b'</span>, <span class="comment">//AppID </span></span><br><span class="line"> wxappsecret: <span class="string">'deec172ab3ba65ceef13a41c1218ef0e'</span>, <span class="comment">//AppSecret</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="built_in">module</span>.exports = config</span><br></pre></td></tr></table></figure> * 前端vue引用 <figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br></pre></td><td class="code"><pre><span class="line"> <span class="comment">// weixin.js</span></span><br><span class="line"> <span class="keyword">import</span> wx <span class="keyword">from</span> <span class="string">'weixin-js-sdk'</span> <span class="comment">// 微信sdk依赖</span></span><br><span class="line"> <span class="keyword">import</span> http <span class="keyword">from</span> <span class="string">'@/utils/http'</span></span><br><span class="line"> </span><br><span class="line"> </span><br><span class="line"> <span class="keyword">const</span> getWxConfig = <span class="function">(<span class="params">wxConf = {}</span>) =></span> {</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function">(<span class="params">resolve, reject</span>) =></span> {</span><br><span class="line"> <span class="keyword">if</span> (!wxConf.appId) {</span><br><span class="line"> reject({})</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> resolve({</span><br><span class="line"> debug: <span class="literal">false</span>,</span><br><span class="line"> appId: wxConf.appId,</span><br><span class="line"> timestamp: wxConf.timestamp,</span><br><span class="line"> nonceStr: wxConf.noncestr,</span><br><span class="line"> signature: wxConf.signature,</span><br><span class="line"> jsApiList: wxConf.jsApiList</span><br><span class="line"> })</span><br><span class="line"> }</span><br><span class="line"> })</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">export</span> <span class="keyword">const</span> shareOnWx = <span class="keyword">async</span> () => {</span><br><span class="line"> <span class="keyword">let</span> url = <span class="built_in">window</span>.location.href.split(<span class="string">'#'</span>)[<span class="number">0</span>] <span class="comment">//url不能写死</span></span><br><span class="line"> <span class="comment">// console.log('url', url);</span></span><br><span class="line"> <span class="keyword">const</span> imgUrl = <span class="string">'https://iflybudstest.iflytek.com/sharepage/download/sharelogo.jpg'</span>;</span><br><span class="line"> <span class="keyword">const</span> {<span class="attr">data</span>: wxConf} = <span class="keyword">await</span> http({</span><br><span class="line"> url: <span class="string">`/wechat/getConfig`</span>,</span><br><span class="line"> data: {url},</span><br><span class="line"> method: <span class="string">'post'</span>,</span><br><span class="line"> headers: {</span><br><span class="line"> <span class="string">'Content-type'</span>: <span class="string">'application/json; charset=utf-8'</span>,</span><br><span class="line"> <span class="string">'Accept'</span>: <span class="string">'application/json'</span></span><br><span class="line"> }</span><br><span class="line"> });</span><br><span class="line"> <span class="keyword">const</span> wxConfig = <span class="keyword">await</span> getWxConfig(wxConf);</span><br><span class="line"> wx.config(wxConfig);</span><br><span class="line"> <span class="comment">// 分享给朋友</span></span><br><span class="line"> wx.ready(<span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>{</span><br><span class="line"> wx.onMenuShareAppMessage({</span><br><span class="line"> title: <span class="string">'点击下载iFLYBUDS App,通话转文字,记录更轻松'</span>, <span class="comment">// 分享标题</span></span><br><span class="line"> desc: <span class="built_in">window</span>.location.href.split(<span class="string">'?'</span>)[<span class="number">0</span>], <span class="comment">// 分享描述</span></span><br><span class="line"> link: url, <span class="comment">// 分享链接</span></span><br><span class="line"> imgUrl: <span class="string">'https://iflybudstest.iflytek.com/img/wx_logo.jpg'</span>,</span><br><span class="line"> type: <span class="string">'link'</span>, <span class="comment">// 分享类型,music、video或link,不填默认为link</span></span><br><span class="line"> success: <span class="function"><span class="keyword">function</span> (<span class="params">res</span>) </span>{</span><br><span class="line"> },</span><br><span class="line"> cancel: <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>{</span><br><span class="line"> }</span><br><span class="line"> })</span><br><span class="line"> <span class="comment">// 分享到朋友圈</span></span><br><span class="line"> wx.onMenuShareTimeline({</span><br><span class="line"> title: <span class="string">'点击下载iFLYBUDS App,通话转文字,记录更轻松'</span>, <span class="comment">// 分享标题</span></span><br><span class="line"> desc: <span class="built_in">window</span>.location.href.split(<span class="string">'?'</span>)[<span class="number">0</span>], <span class="comment">// 分享描述</span></span><br><span class="line"> link: url, <span class="comment">// 分享链接</span></span><br><span class="line"> imgUrl: <span class="string">'https://iflybudstest.iflytek.com/img/wx_logo.jpg'</span>,</span><br><span class="line"> type: <span class="string">'link'</span>, <span class="comment">// 分享类型,music、video或link,不填默认为link</span></span><br><span class="line"> success: <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>{</span><br><span class="line"> },</span><br><span class="line"> cancel: <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>{</span><br><span class="line"> }</span><br><span class="line"> })</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> wx.error(<span class="function"><span class="keyword">function</span> (<span class="params">res</span>) </span>{</span><br><span class="line"> alert(<span class="built_in">JSON</span>.stringify(res))</span><br><span class="line"> <span class="comment">// config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名。</span></span><br><span class="line"> })</span><br><span class="line"> })</span><br><span class="line">}</span><br></pre></td></tr></table></figure></code></pre><ul><li><p>踩坑点</p><ul><li>vue端口不监听8411, 需要在vue.config.js中调用</li><li>签名出错,记得要按照微信公众平台的步骤来,可以通过<a href="https://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=jsapisign看签名是否正确" target="_blank" rel="noopener">https://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=jsapisign看签名是否正确</a></li><li>图片不展示,图片地址需要为服务器地址,并且该服务器域名为准备工作中配的js安全域名下</li><li><p>问题跟进</p><ul><li><p>最近把整个vue项目由history路由换成hash模式,当时好开心啊,解决了运维每次配置nginx这个问题,可是,当沉浸在开心的快乐中时,没想到,测试提出来一个问题,下载页无法分享了,分享出来再点击进去是空白了,好慌好慌啊</p><ul><li><p>问题定位:<br>1、vue hash模式下的路径自动带#,然后微信会直接截取#后面的字符串,然后加上自己的标识字符串,这样会导致自己的vue项目无法辨别自己的vue路径,会自动跳到首页,如下:<br>原: <a href="https://iflybudstest.iflytek.com/#/download" target="_blank" rel="noopener">https://iflybudstest.iflytek.com/#/download</a><br>新: <a href="https://iflybudstest.iflytek.com/?from=singlemessage&isappinstalled=0#/download" target="_blank" rel="noopener">https://iflybudstest.iflytek.com/?from=singlemessage&isappinstalled=0#/download</a><br>2、如果在vue hash模式下与history模式下对微信做签名的url还是全路径的话,比如history模式下的路径是 <a href="http://192.168.3.9:8080/sharepage/download,那么在hash模式下传递到微信签名端的url只要是域名就可以了,也即是第一个#" target="_blank" rel="noopener">http://192.168.3.9:8080/sharepage/download,那么在hash模式下传递到微信签名端的url只要是域名就可以了,也即是第一个#</a> 之前的部分<br>在前端写微信分享的时候,会有两个字符串,一个是图片,一个是分享链接<br>a) 对于分享链接,因为微信会对分享的链接做#拦截,所以这里需要对分享链接做组合:如下: url + ‘#’ + window.location.href.split(‘#’)[1]<br>b) 对于分享图片,要保证图片的地址路径在域名服务器上可查找,但是试了这个方法后,分享出去的图片还是错误的,所以百度试了其他方法,在head里面加个img标签,如下:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><img id=<span class="string">"shareImg"</span> src=<span class="string">"<%= BASE_URL %>sharelogo.jpg"</span> width=<span class="string">"0"</span> height=<span class="string">"0"</span> /></span><br></pre></td></tr></table></figure><p>然后在分享的配置图片中写</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">imgUrl: <span class="built_in">document</span>.getElementById(<span class="string">'shareImg'</span>).src,</span><br></pre></td></tr></table></figure></li></ul></li></ul></li></ul></li><li><p>如上,整个与微信分享从测试环境的测试与线上环境的测试已完毕,下面我把全部代码贴出,如下:<br>.vue项目中</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> { shareOnWx } <span class="keyword">from</span> <span class="string">'../utils/wx'</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> {</span><br><span class="line"> created() {</span><br><span class="line"> shareOnWx();</span><br><span class="line"> },</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>wx.js</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// weixin.js</span></span><br><span class="line"><span class="keyword">import</span> wx <span class="keyword">from</span> <span class="string">'weixin-js-sdk'</span>; <span class="comment">// 微信sdk依赖</span></span><br><span class="line"><span class="keyword">import</span> http <span class="keyword">from</span> <span class="string">'@/utils/http'</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> getWxConfig = <span class="function">(<span class="params">wxConf = {}</span>) =></span> {</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function">(<span class="params">resolve, reject</span>) =></span> {</span><br><span class="line"> <span class="keyword">if</span> (!wxConf.appId) {</span><br><span class="line"> reject({})</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> resolve({</span><br><span class="line"> debug: <span class="literal">false</span>,</span><br><span class="line"> appId: wxConf.appId,</span><br><span class="line"> timestamp: wxConf.timestamp,</span><br><span class="line"> nonceStr: wxConf.noncestr,</span><br><span class="line"> signature: wxConf.signature,</span><br><span class="line"> jsApiList: wxConf.jsApiList</span><br><span class="line"> })</span><br><span class="line"> }</span><br><span class="line"> })</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">const</span> shareOnWx = <span class="keyword">async</span> () => {</span><br><span class="line"> <span class="keyword">let</span> url = <span class="built_in">window</span>.location.href.split(<span class="string">'#'</span>)[<span class="number">0</span>] <span class="comment">//url不能写死</span></span><br><span class="line"> <span class="comment">// console.log('share img', `${url}sharelogo.jpg`)</span></span><br><span class="line"> <span class="comment">// console.log('url', `${url}?path=download`)</span></span><br><span class="line"> <span class="comment">// console.log('shareImg.src',document.getElementById('shareImg').src)</span></span><br><span class="line"> <span class="keyword">const</span> {<span class="attr">data</span>: wxConf} = <span class="keyword">await</span> http({</span><br><span class="line"> url: <span class="string">`/wechat/getConfig`</span>,</span><br><span class="line"> data: {url},</span><br><span class="line"> method: <span class="string">'post'</span>,</span><br><span class="line"> headers: {</span><br><span class="line"> <span class="string">'Content-type'</span>: <span class="string">'application/json; charset=utf-8'</span>,</span><br><span class="line"> <span class="string">'Accept'</span>: <span class="string">'application/json'</span></span><br><span class="line"> }</span><br><span class="line"> });</span><br><span class="line"> <span class="keyword">const</span> wxConfig = <span class="keyword">await</span> getWxConfig(wxConf);</span><br><span class="line"> wx.config(wxConfig);</span><br><span class="line"> <span class="comment">// 分享给朋友</span></span><br><span class="line"> wx.ready(<span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>{ </span><br><span class="line"> wx.onMenuShareAppMessage({</span><br><span class="line"> title: <span class="string">'点击下载iFLYBUDS App,通话转文字,记录更轻松'</span>, <span class="comment">// 分享标题</span></span><br><span class="line"> desc: <span class="built_in">window</span>.location.href.split(<span class="string">'?'</span>)[<span class="number">0</span>], <span class="comment">// 分享描述</span></span><br><span class="line"> link: url + <span class="string">'#'</span> + <span class="built_in">window</span>.location.href.split(<span class="string">'#'</span>)[<span class="number">1</span>],</span><br><span class="line"> imgUrl: <span class="built_in">document</span>.getElementById(<span class="string">'shareImg'</span>).src,</span><br><span class="line"> type: <span class="string">'link'</span>, <span class="comment">// 分享类型,music、video或link,不填默认为link</span></span><br><span class="line"> success: <span class="function"><span class="keyword">function</span> (<span class="params">res</span>) </span>{</span><br><span class="line"> <span class="comment">// console.log('分享给朋友 onMenuShareAppMessage', res);</span></span><br><span class="line"> <span class="comment">// 设置成功</span></span><br><span class="line"> },</span><br><span class="line"> cancel: <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>{</span><br><span class="line"> alert(<span class="string">'分享cancel'</span>)</span><br><span class="line"> <span class="comment">// 用户取消分享后执行的回调函数</span></span><br><span class="line"> <span class="comment">// console.log('分享给朋友cacel');</span></span><br><span class="line"> }</span><br><span class="line"> })</span><br><span class="line"> <span class="comment">// 分享到朋友圈</span></span><br><span class="line"> wx.onMenuShareTimeline({</span><br><span class="line"> title: <span class="string">'点击下载iFLYBUDS App,通话转文字,记录更轻松'</span>, <span class="comment">// 分享标题</span></span><br><span class="line"> desc: <span class="built_in">window</span>.location.href.split(<span class="string">'?'</span>)[<span class="number">0</span>], <span class="comment">// 分享描述</span></span><br><span class="line"> link: url + <span class="string">'#'</span> + <span class="built_in">window</span>.location.href.split(<span class="string">'#'</span>)[<span class="number">1</span>], <span class="comment">// 分享链接</span></span><br><span class="line"> imgUrl: <span class="built_in">document</span>.getElementById(<span class="string">'shareImg'</span>).src,</span><br><span class="line"> type: <span class="string">'link'</span>, <span class="comment">// 分享类型,music、video或link,不填默认为link</span></span><br><span class="line"> success: <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>{</span><br><span class="line"> <span class="comment">// 设置成功</span></span><br><span class="line"> },</span><br><span class="line"> cancel: <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>{</span><br><span class="line"> <span class="comment">// 用户取消分享后执行的回调函数</span></span><br><span class="line"> }</span><br><span class="line"> })</span><br><span class="line"> wx.error(<span class="function"><span class="keyword">function</span> (<span class="params">res</span>) </span>{</span><br><span class="line"> alert(<span class="built_in">JSON</span>.stringify(res))</span><br><span class="line"> <span class="comment">// config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名。</span></span><br><span class="line"> })</span><br><span class="line"> })</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>node 端 .wxAccess.js</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> sha1 = <span class="built_in">require</span>(<span class="string">'sha1'</span>)</span><br><span class="line"><span class="keyword">const</span> config = <span class="built_in">require</span>(<span class="string">'./wxConfig'</span>)</span><br><span class="line"><span class="keyword">const</span> cache = <span class="built_in">require</span>(<span class="string">'memory-cache'</span>)</span><br><span class="line"><span class="keyword">const</span> rp = <span class="built_in">require</span>(<span class="string">'request-promise'</span>)</span><br><span class="line"><span class="keyword">const</span> crypto = <span class="built_in">require</span>(<span class="string">'crypto'</span>);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> jsApiList = [</span><br><span class="line"> <span class="string">'checkJsApi'</span>,</span><br><span class="line"> <span class="string">'onMenuShareTimeline'</span>,</span><br><span class="line"> <span class="string">'onMenuShareAppMessage'</span>,</span><br><span class="line"> <span class="string">'onMenuShareQQ'</span>,</span><br><span class="line"> <span class="string">'onMenuShareWeibo'</span>,</span><br><span class="line"> <span class="string">'hideMenuItems'</span>,</span><br><span class="line"> <span class="string">'showMenuItems'</span>,</span><br><span class="line"> <span class="string">'hideAllNonBaseMenuItem'</span>,</span><br><span class="line"> <span class="string">'showAllNonBaseMenuItem'</span>,</span><br><span class="line"> <span class="string">'translateVoice'</span>,</span><br><span class="line"> <span class="string">'startRecord'</span>,</span><br><span class="line"> <span class="string">'stopRecord'</span>,</span><br><span class="line"> <span class="string">'onRecordEnd'</span>,</span><br><span class="line"> <span class="string">'playVoice'</span>,</span><br><span class="line"> <span class="string">'pauseVoice'</span>,</span><br><span class="line"> <span class="string">'stopVoice'</span>,</span><br><span class="line"> <span class="string">'uploadVoice'</span>,</span><br><span class="line"> <span class="string">'downloadVoice'</span>,</span><br><span class="line"> <span class="string">'chooseImage'</span>,</span><br><span class="line"> <span class="string">'previewImage'</span>,</span><br><span class="line"> <span class="string">'uploadImage'</span>,</span><br><span class="line"> <span class="string">'downloadImage'</span>,</span><br><span class="line"> <span class="string">'getNetworkType'</span>,</span><br><span class="line"> <span class="string">'openLocation'</span>,</span><br><span class="line"> <span class="string">'getLocation'</span>,</span><br><span class="line"> <span class="string">'hideOptionMenu'</span>,</span><br><span class="line"> <span class="string">'showOptionMenu'</span>,</span><br><span class="line"> <span class="string">'closeWindow'</span>,</span><br><span class="line"> <span class="string">'scanQRCode'</span>,</span><br><span class="line"> <span class="string">'chooseWXPay'</span>,</span><br><span class="line"> <span class="string">'openProductSpecificView'</span>,</span><br><span class="line"> <span class="string">'addCard'</span>,</span><br><span class="line"> <span class="string">'chooseCard'</span>,</span><br><span class="line"> <span class="string">'openCard'</span></span><br><span class="line">];</span><br><span class="line"><span class="keyword">const</span> getAccess = <span class="keyword">async</span> (url) => {</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="keyword">async</span> (resolve, reject) => {</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">'1321414324324325435'</span>);</span><br><span class="line"> <span class="keyword">const</span> noncestr = crypto.randomBytes(<span class="built_in">Math</span>.ceil(<span class="number">32</span> / <span class="number">2</span>)).toString(<span class="string">'hex'</span>).slice(<span class="number">0</span>, <span class="number">32</span>);;</span><br><span class="line"> <span class="keyword">const</span> timestamp = <span class="built_in">Math</span>.floor(<span class="built_in">Date</span>.now() / <span class="number">1000</span>); <span class="comment">//timestamp</span></span><br><span class="line"> <span class="keyword">let</span> wxdata = <span class="literal">null</span>;</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="comment">// ticket</span></span><br><span class="line"> <span class="keyword">if</span> (cache.get(<span class="string">'ticket'</span>)) {</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">'ticket in cache'</span>, cache.get(<span class="string">'ticket'</span>))</span><br><span class="line"> <span class="keyword">const</span> jsapi_ticket = cache.get(<span class="string">'ticket'</span>);</span><br><span class="line"> wxdata = {</span><br><span class="line"> appId: config.wxappid,</span><br><span class="line"> noncestr,</span><br><span class="line"> timestamp,</span><br><span class="line"> url,</span><br><span class="line"> jsapi_ticket,</span><br><span class="line"> signature: sha1(<span class="string">`jsapi_ticket=<span class="subst">${jsapi_ticket}</span>&noncestr=<span class="subst">${noncestr}</span>&timestamp=<span class="subst">${timestamp}</span>&url=<span class="subst">${url}</span>`</span>),</span><br><span class="line"> jsApiList</span><br><span class="line"> }</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">const</span> tokenMap = <span class="keyword">await</span> rp({<span class="attr">uri</span>: <span class="string">`https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=<span class="subst">${config.wxappid}</span>&secret=<span class="subst">${config.wxappsecret}</span>`</span>});</span><br><span class="line"> <span class="comment">// console.log('rp res', JSON.parse(tokenMap));</span></span><br><span class="line"> <span class="keyword">const</span> resp = <span class="keyword">await</span> rp({<span class="attr">uri</span>: <span class="string">`https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=<span class="subst">${<span class="built_in">JSON</span>.parse(tokenMap).access_token}</span>&type=jsapi`</span>});</span><br><span class="line"> <span class="keyword">const</span> ticketMap = <span class="built_in">JSON</span>.parse(resp);</span><br><span class="line"> <span class="comment">// console.log('ticketMap', ticketMap);</span></span><br><span class="line"> cache.put(<span class="string">'ticket'</span>, ticketMap.ticket, (<span class="number">1000</span> * <span class="number">7200</span>));</span><br><span class="line"> <span class="keyword">var</span> resultCode = sha1(<span class="string">`jsapi_ticket=<span class="subst">${ticketMap.ticket}</span>&noncestr=<span class="subst">${noncestr}</span>&timestamp=<span class="subst">${timestamp}</span>&url=<span class="subst">${url}</span>`</span>);</span><br><span class="line"> <span class="comment">// console.log('resultCode', `jsapi_ticket=${ticketMap.ticket}&noncestr=${noncestr}&timestamp=${timestamp}&url=${url}`);</span></span><br><span class="line"> <span class="comment">// console.log('download url', downloadUrl)</span></span><br><span class="line"> wxdata = {</span><br><span class="line"> appId: config.wxappid,</span><br><span class="line"> noncestr,</span><br><span class="line"> timestamp,</span><br><span class="line"> url,</span><br><span class="line"> jsapi_ticket: ticketMap.ticket,</span><br><span class="line"> signature: resultCode,</span><br><span class="line"> jsApiList</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">'wx data'</span>, wxdata);</span><br><span class="line"> resolve(wxdata);</span><br><span class="line"> } <span class="keyword">catch</span>(e) {</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">'catch exception'</span>, <span class="built_in">JSON</span>.stringify(e));</span><br><span class="line"> reject(<span class="string">'catch exception'</span>, <span class="built_in">JSON</span>.stringify(e));</span><br><span class="line"> }</span><br><span class="line"> })</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="built_in">module</span>.exports = getAccess;</span><br></pre></td></tr></table></figure><p>参考文档<br><a href="https://www.jianshu.com/p/97729dd2c94d" target="_blank" rel="noopener">https://www.jianshu.com/p/97729dd2c94d</a><br><a href="https://cn.bing.com/search?q=vue+hash%E6%A8%A1%E5%BC%8F%E5%BE%AE%E4%BF%A1%E5%88%86%E4%BA%AB&PC=U316&FORM=CHROMN" target="_blank" rel="noopener">https://cn.bing.com/search?q=vue+hash%E6%A8%A1%E5%BC%8F%E5%BE%AE%E4%BF%A1%E5%88%86%E4%BA%AB&PC=U316&FORM=CHROMN</a></p></li></ul>]]></content>
<tags>
<tag> vue3 koa2 微信 </tag>
</tags>
</entry>
<entry>
<title>vue请求跨域</title>
<link href="/2020/05/23/vue%E8%AF%B7%E6%B1%82%E8%B7%A8%E5%9F%9F/"/>
<url>/2020/05/23/vue%E8%AF%B7%E6%B1%82%E8%B7%A8%E5%9F%9F/</url>
<content type="html"><![CDATA[<p>vue3与后端交互请求跨域解决</p><a id="more"></a><h2 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h2><p>起的新项目页面登录第一个接口和后端做交互的时候,请求一直打不过去,报错如下:<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Access to XMLHttpRequest at <span class="string">'https://iflybudstest.iflytek.com/iflybudsERP/login/auth'</span> (redirected from <span class="string">'http://192.168.3.9:3002/api/login/auth'</span>) from origin <span class="string">'http://192.168.3.9:3002'</span> has been blocked by CORS policy: Response to preflight request doesn<span class="string">'t pass access control check: No '</span>Access-Control-Allow-Origin<span class="string">' header is present on the requested resource.</span></span><br></pre></td></tr></table></figure></p><p><img src="/img/axios/axios_error.png" alt="IMAGE"><br><img src="/img/axios/axios_network.png" alt="IMAGE"><br><img src="/img/axios/axios_network_02.png" alt="IMAGE"></p><p>大概意思是浏览器不允许跨域,然后用chrome查看浏览器的请求,发现请求内容缺少太多</p><h3 id="解决办法"><a href="#解决办法" class="headerlink" title="解决办法"></a>解决办法</h3><p>在自己的vue项目中配置如下:</p><p>login.vue<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">this</span>.$http({</span><br><span class="line"> url: <span class="string">'/api/login/auth'</span>,</span><br><span class="line"> method: <span class="string">'post'</span>,</span><br><span class="line"> data: {</span><br><span class="line"> username: <span class="string">'admin'</span>,</span><br><span class="line"> password: <span class="string">'123456'</span></span><br><span class="line"> }</span><br><span class="line"> }).then(<span class="function"><span class="params">res</span> =></span> {</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">'res'</span>, res);</span><br><span class="line">})</span><br></pre></td></tr></table></figure></p><p>axios.js</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> Vue <span class="keyword">from</span> <span class="string">'vue'</span></span><br><span class="line"><span class="keyword">import</span> axios <span class="keyword">from</span> <span class="string">'axios'</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> instance = axios.create({</span><br><span class="line"> timeout: <span class="number">10000</span>,</span><br><span class="line"> headers: {</span><br><span class="line"> <span class="string">'Content-Type'</span>: <span class="string">"application/json;charset=utf-8"</span></span><br><span class="line"> }</span><br><span class="line">});</span><br><span class="line"><span class="comment">//axios.defaults.baseURL = '/api'</span></span><br><span class="line"></span><br><span class="line">Vue.prototype.$http = axios;</span><br><span class="line"></span><br><span class="line"><span class="comment">// Vue.use(axios)</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> {</span><br><span class="line"> install(Vue){</span><br><span class="line"> <span class="built_in">Object</span>.defineProperty(Vue.prototype,<span class="string">'$http'</span>,{<span class="attr">value</span>:axios})</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>vue.config.js</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">module</span>.exports = {</span><br><span class="line"> lintOnSave: <span class="literal">false</span>,</span><br><span class="line"> devServer: {</span><br><span class="line"> <span class="comment">//port: 3001,</span></span><br><span class="line"> proxy: {</span><br><span class="line"> <span class="string">'/api'</span>: {</span><br><span class="line"> target: <span class="string">'https://iflybudstest.iflytek.com/iflybudsERP/'</span>,</span><br><span class="line"> changeOrigin: <span class="literal">true</span>,</span><br><span class="line"> ws:<span class="literal">true</span>,</span><br><span class="line"> pathRewrite: {</span><br><span class="line"> <span class="string">'^/api'</span>: <span class="string">''</span></span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> },</span><br><span class="line"> productionSourceMap: <span class="literal">false</span>,</span><br></pre></td></tr></table></figure><p>一开始总是找不到原因,加上了 changeOrigin: true 还是不对,最后把当前的访问地址用ie打开后,发现报错和请求和再chrome中完全不一样,截图忘记截了<br>然后百度那个问题发现是协议不同导致的跨域问题,只需要在vue.config.js中配置https为true即可,最终版如下:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">module</span>.exports = {</span><br><span class="line"> lintOnSave: <span class="literal">false</span>,</span><br><span class="line"> devServer: {</span><br><span class="line"> <span class="comment">//port: 3001,</span></span><br><span class="line"> https:<span class="literal">true</span>, <span class="comment">// here </span></span><br><span class="line"> proxy: {</span><br><span class="line"> <span class="string">'/api'</span>: {</span><br><span class="line"> target: <span class="string">'https://iflybudstest.iflytek.com/iflybudsERP/'</span>,</span><br><span class="line"> changeOrigin: <span class="literal">true</span>,</span><br><span class="line"> ws:<span class="literal">true</span>,</span><br><span class="line"> pathRewrite: {</span><br><span class="line"> <span class="string">'^/api'</span>: <span class="string">''</span></span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> },</span><br><span class="line"> productionSourceMap: <span class="literal">false</span>,</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>关于跨域:<br>哪些不同会出现跨域: 域名,端口,协议,这里是协议不同,http访问https出现了协议不同的跨域</p>]]></content>
<tags>
<tag> vue3 axios 跨域 </tag>
</tags>
</entry>
<entry>
<title>git操作之revert</title>
<link href="/2020/04/01/git%E6%93%8D%E4%BD%9C%E4%B9%8Brevert/"/>
<url>/2020/04/01/git%E6%93%8D%E4%BD%9C%E4%B9%8Brevert/</url>
<content type="html"><![CDATA[<p>git revert 回退版本以及 git resert 与 git resert的区别<br><a id="more"></a></p><h3 id="背景"><a href="#背景" class="headerlink" title="背景"></a><strong>背景</strong></h3><p>最近有个需求,来来会回折腾,前端开发完毕,但后端涉及到的RD太多,交接太麻烦,一个部门的RD对需求开发不理解,导致对接的RD这边有需求有误解,有时候严重需要回退当前需求的分支还原开发前的状态,但是在开发时,公共分支受不同人控制,不能回退自己分支时让其他同事的需求代码受到影响。</p><h3 id="解决办法"><a href="#解决办法" class="headerlink" title="解决办法"></a><strong>解决办法</strong></h3><p> git revert </p><p> 如下:<br> 我们需要将test环境的分支的制定commit去除,但是不影响其他commit的提交顺序</p><h4 id="step1-找到需要回退的commit"><a href="#step1-找到需要回退的commit" class="headerlink" title="step1 找到需要回退的commit"></a>step1 找到需要回退的commit</h4><p> <img src="/img/git-revert/git_revert_01.png" alt="IMAGE"></p><p> 如上图,因为这两个commit包含一个merge,这里我们只revert倒数2,3两个commit,</p><h4 id="step2-回退"><a href="#step2-回退" class="headerlink" title="step2 回退"></a>step2 回退</h4><p> <img src="/img/git-revert/git_revert_02.png" alt="IMAGE"></p><h4 id="step3-提交"><a href="#step3-提交" class="headerlink" title="step3 提交"></a>step3 提交</h4><p> <img src="/img/git-revert/git_revert_03.png" alt="IMAGE"></p><h4 id="step4-查看最新log"><a href="#step4-查看最新log" class="headerlink" title="step4 查看最新log"></a>step4 查看最新log</h4><p><img src="/img/git-revert/git_revert_04.png" alt="IMAGE"></p><p>可以看到最新占位的commit已经被revert。</p><h3 id="确认"><a href="#确认" class="headerlink" title="确认"></a>确认</h3><p>如果想要查看自己revert的代码是否自己真正想要回退的,可以diff自己已经revert的commit,如下:<br><img src="/img/git-revert/git_revert_05.png" alt="IMAGE"><br><img src="/img/git-revert/git_revert_06.png" alt="IMAGE"></p><h3 id="注意"><a href="#注意" class="headerlink" title="注意"></a>注意</h3><ul><li><p>git reset<br>git reset 也可以实现版本的回退,具体操作不做详细讲解,步骤可以发在下面</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">git log</span><br><span class="line">git reset --hard [commitID]</span><br><span class="line">git push -f origin [分支名]</span><br></pre></td></tr></table></figure></li><li><p>git reset 与 git revert 的区别<br>1) git revert用一次新的commit来回滚之前的commit, git reset 直接删除之前的commit<br>2)在回滚这一操作上来看,效果都差不多。但是日后继续merge 之前的老版本时有区别。因为git resert 是用一次逆向的commit “中和”之前的提交,因此日后合并老的分支时,导致这部分改变不会再出现,但是git reset 是之间的某个commit在某个分支上删除,因而当该分支再去和老的分支时,这些被回滚的commit还会被再次引入。<br>3) git reset 是把head向后移动了一下,而git resert 是把head继续向前推进,只是新的commit的内容和要revert的内容正好相反,能够抵消要被revert的内容。</p></li></ul>]]></content>
<tags>
<tag> git revert </tag>
</tags>
</entry>
<entry>
<title>samesite</title>
<link href="/2020/03/17/samesite/"/>
<url>/2020/03/17/samesite/</url>
<content type="html"><![CDATA[<p>chorme samesite 特性致使跨域无法种cookie<br><a id="more"></a></p><h3 id="问题简介"><a href="#问题简介" class="headerlink" title="问题简介"></a>问题简介</h3><p>最近有运营同事反馈,外部审核平台接入的内部系统审核界面无法打开,切换成QQ浏览器就好使了,如下:<br><img src="/img/samesite/samesite_01.png" alt="IMAGE"></p><p>发现登陆一直在重定向,一直在login和callback.</p><h3 id="问题排查"><a href="#问题排查" class="headerlink" title="问题排查"></a>问题排查</h3><p>1、询问那位同事的chorme版本,经反馈,chorme版本为80<br>2、打开报错的那个请求,发现单点登陆种入的 cookie没有了,考虑可能登陆发现浏览器没有种入cookie导致一直重定向<br><img src="/img/samesite/samesite_02.png" alt="IMAGE"><br>3、切换到console,看浏览器有无报错信息,发现有个warning<br><img src="/img/samesite/samesite_03.png" alt="IMAGE"><br>4、百度发现正式这个warning导致的问题</p><h3 id="原因"><a href="#原因" class="headerlink" title="原因"></a>原因</h3><p>由于HTTP协议是无状态的,而cookie是可用于向网站添加持久状态的方法之一,但它很不安全,第三方网站发起的请求中会携带cookie,这样很容易造成CSRF 攻击和用户追踪。</p><p>Chrome 51 开始,浏览器的 Cookie 新增加了一个SameSite属性,用来防止 CSRF 攻击和用户追踪。<br>关于SameSite的了解,可以看这两篇文章<br><a href="http://www.ruanyifeng.com/blog/2019/09/cookie-samesite.html" target="_blank" rel="noopener">Cookie 的 SameSite 属性</a><br><a href="https://www.cnblogs.com/ziyunfei/p/5637945.html" target="_blank" rel="noopener">紫云飞的samesite</a></p><p>因为chorme只灰度了一部分的chrome浏览器,所以这个现象只是出现在一部分人的电脑里。<br>对Chrome的安全策略有所了解后,可以明确的知道三方cookie带不过去是SameSite搞的鬼,虽说Chrome51开始cookie加上了SameSite属性,但不是强制执行的,而Chrome80稳定版遍开始陆陆续续的强制使用SameSite。更新内容如下:<br><img src="/img/samesite/samesite_04.png" alt="IMAGE"><br>更细日志请参考:<a href="https://www.chromium.org/updates/same-site" target="_blank" rel="noopener">https://www.chromium.org/updates/same-site</a></p><p>这里不得不吐槽一下万恶的chrome,居然采取了部分用户强制执行的策略。</p><p>当中招的浏览器会走默认的 SameSite=Lax,会导致跨域cookie无法种入;</p><h3 id="解决方案"><a href="#解决方案" class="headerlink" title="解决方案"></a>解决方案</h3><p>发现问题后,首先让运营配置了自己电脑的chrome,如下:<br>1、在谷歌浏览器中输入这个地址 chrome://flags/<br>2、然后 在输入框中搜索 samesite<br>3、有一个选项SameSite by default cookies,将她后面的下拉框选择disabled<br><img src="/img/samesite/samesite_05.png" alt="IMAGE"></p><p>上面的方法比较暴力,并且只能暂时解决几个人的问题,今天看了下代码,可以采用如下解决办法<br>1、升级cookies的版本到0.8或以上,升级依赖 低于0.8以下的cookie的其他包<br>2、因为服务端用的是koa, 项目通过ngix代理将https反向代理成http打到服务器上,可以在koa入口将proxy设置成true,app.proxy=true(Cookie 只能通过 HTTPS 协议发送,否则无效,这里非https配置proxy代理),即req.protocol=https。<br>package中的cookies在判断secure时也采用的是req.protocol来获取协议的。<br><img src="/img/samesite/samesite_06.png" alt="IMAGE"><br>注意: 通过日志可以发现X-Forwarded-Proto 的值是https,X-Forwarded-Proto (XFP) 是一个事实上的标准首部,用来确定客户端与代理服务器或者负载均衡服务器之间的连接所采用的传输协议(HTTP 或 HTTPS)。<br>3、在需要种cookie前将cookie的SameSite配置成none,secure即可,这里因为项目中种cookie的地方是依赖的第三方单点登陆包,只需要将对应包版本升级,并且加入需要的配置</p><h3 id="注意"><a href="#注意" class="headerlink" title="注意"></a><strong>注意</strong></h3><p>这只是解决chorme浏览器,但是在上safari因为识别不了samesite,走的是strict模式,所以问题也是同样存在</p>]]></content>
<tags>
<tag> chrome cookies </tag>
</tags>
</entry>
<entry>
<title>动态菜单获取</title>
<link href="/2020/01/13/%E5%8A%A8%E6%80%81%E8%8F%9C%E5%8D%95%E8%8E%B7%E5%8F%96/"/>
<url>/2020/01/13/%E5%8A%A8%E6%80%81%E8%8F%9C%E5%8D%95%E8%8E%B7%E5%8F%96/</url>
<content type="html"><![CDATA[<p>需求: 根据数组转成树,渲染成菜单</p><a id="more"></a><h2 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h2><p>原先系统用户具有点击菜单的权限,而对于那些没有页面url访问权限的用户来说,点击菜单是很影响用户体验的。我们需要pm或者研发可以一开始就可以去获取用户菜单的访问权限。即将在代码中写死的menu放在平台上可配置。<br>for me: node端接入后端的接口获取当前用户可访问的菜单权限,然后在前端渲染</p><h2 id="难点"><a href="#难点" class="headerlink" title="难点"></a>难点</h2><p>1、如何在node端自动请求rpc接口获取数据<br>2、获取到的数据如何解决<br>3、对于后端的平铺数组,如何将其转成树结构然后在前端渲染</p><h3 id="踩坑点"><a href="#踩坑点" class="headerlink" title="踩坑点"></a>踩坑点</h3><ul><li><p>1、一开始是想在 node端单点登陆的时候同时请求后端 thrift接口,然后对数据做树转换处理,写到固定路径下的文件中,最后client端拿到权限数据,渲染到页面上<br><strong>看上去,这种处理是合理的,本地也能跑通,但是一旦发布到test环境机器上面,请求存在,但是文件并没有写入,权限也并没有生效,一直走的是默认配置,本地生效是因为本地client端代码一直在不停构建,但是线上代码是构建打包后在请求的,所以一直走的是默认权限配置</strong></p><ul><li>2、在一开始定的时候,想着node自请求,但是容易出现文件写乱的情况</li><li>3、后来换了另一个方案,node端写一个接口,client端在原先获取默认菜单配置的时候去调这个接口,然后node端处理返回的数据,再将处理过的数据返回到前端渲染,这样会存在一个问题,在network中会请求多次。<br>*解决办法:利用react shouldComponentUpdate 合理请求渲染即可**</li></ul><h3 id="部分代码如下"><a href="#部分代码如下" class="headerlink" title="部分代码如下"></a>部分代码如下</h3></li><li><p><strong>node 端 rpc请求</strong></p></li></ul><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> { <span class="attr">thriftOptions</span>: options } = <span class="built_in">require</span>(<span class="string">'config'</span>);</span><br><span class="line"><span class="keyword">const</span> koaRouter = <span class="built_in">require</span>(<span class="string">'koa-router'</span>);</span><br><span class="line"><span class="keyword">const</span> koaBody = <span class="built_in">require</span>(<span class="string">'koa-bodyparser'</span>);</span><br><span class="line"><span class="keyword">const</span> RPC = <span class="built_in">require</span>(<span class="string">'../lib/rpc'</span>);</span><br><span class="line"><span class="keyword">const</span> getTreeData = <span class="built_in">require</span>(<span class="string">'../lib/menu'</span>);</span><br><span class="line"></span><br><span class="line"><span class="built_in">module</span>.exports = <span class="function"><span class="params">app</span> =></span> {</span><br><span class="line"> <span class="keyword">const</span> router = koaRouter();</span><br><span class="line"></span><br><span class="line"> router</span><br><span class="line"> .post(<span class="string">'/rpc/mpm'</span>, koaBody(), <span class="function"><span class="keyword">function</span>* <span class="title">rpcHandler</span>(<span class="params"></span>) </span>{</span><br><span class="line"> <span class="keyword">const</span> rpc = <span class="keyword">new</span> RPC(options);</span><br><span class="line"> <span class="keyword">const</span> { <span class="attr">request</span>: { body = {} } } = <span class="keyword">this</span>;</span><br><span class="line"> <span class="keyword">const</span> { service, <span class="attr">method</span>: methodName, params } = body;</span><br><span class="line"> <span class="keyword">const</span> { data } = <span class="keyword">yield</span> rpc.exec({ service, methodName, params });</span><br><span class="line"></span><br><span class="line"> <span class="keyword">const</span> bdMenu = data.data.filter(<span class="function"><span class="params">item</span> =></span> {</span><br><span class="line"> <span class="keyword">return</span> item.title.indexOf(<span class="string">'xxxxx-'</span>) === <span class="number">-1</span>;</span><br><span class="line"> });</span><br><span class="line"> <span class="keyword">const</span> adminMenu = data.data.filter(<span class="function"><span class="params">item</span> =></span> {</span><br><span class="line"> <span class="keyword">return</span> item.title.indexOf(<span class="string">'xxxxxxxxxx-'</span>) > <span class="number">-1</span>;</span><br><span class="line"> });</span><br><span class="line"> bdMenu.splice(<span class="number">0</span>, <span class="number">0</span>, bdMenu.find(<span class="function"><span class="params">item</span> =></span> item.title === <span class="string">'xxxxxxx'</span>));</span><br><span class="line"> <span class="keyword">const</span> bdMenudata = getTreeData(bdMenu || [], <span class="number">-1</span>);</span><br><span class="line"> <span class="keyword">const</span> adminMenudata = getTreeData(adminMenu || [], <span class="number">-1</span>);</span><br><span class="line"> <span class="keyword">const</span> response = {</span><br><span class="line"> success: <span class="literal">true</span>,</span><br><span class="line"> message: <span class="string">''</span>,</span><br><span class="line"> data: [{</span><br><span class="line"> name: <span class="string">'xxxxx'</span>,</span><br><span class="line"> href: <span class="string">'/xxxxx'</span>,</span><br><span class="line"> children: bdMenudata || []</span><br><span class="line"> }, {</span><br><span class="line"> name: <span class="string">'xxxxx'</span>,</span><br><span class="line"> href: <span class="string">'/xxxx'</span>,</span><br><span class="line"> children: adminMenudata || []</span><br><span class="line"> }]</span><br><span class="line"> };</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">'response'</span>, response);</span><br><span class="line"> <span class="keyword">this</span>.body = response;</span><br><span class="line"> });</span><br><span class="line"> app.use(router.routes());</span><br><span class="line">};</span><br></pre></td></tr></table></figure><ul><li><strong>对thrift平铺的数据转成树</strong></li></ul><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> getTreeData = <span class="function">(<span class="params">data, parentId</span>) =></span> {</span><br><span class="line"> <span class="keyword">const</span> result = [];</span><br><span class="line"> <span class="keyword">let</span> temp = [];</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i < data.length; i++) {</span><br><span class="line"> <span class="keyword">if</span> (data[i].parentId === parentId) {</span><br><span class="line"> <span class="keyword">const</span> name = data[i].title.indexOf(<span class="string">'xxxxxxx-'</span>) > <span class="number">-1</span> ? data[i].title.split(<span class="string">'-'</span>)[<span class="number">1</span>] : data[i].title;</span><br><span class="line"> <span class="keyword">const</span> obj = {name, <span class="attr">href</span>: data[i].url, <span class="attr">parentId</span>: data[i].parentId, <span class="attr">menuId</span>: data[i].menuId};</span><br><span class="line"> temp = getTreeData(data, data[i].menuId);</span><br><span class="line"> <span class="keyword">if</span> (temp.length > <span class="number">0</span>) {</span><br><span class="line"> obj.children = temp;</span><br><span class="line"> }</span><br><span class="line"> result.push(obj);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> result;</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="built_in">module</span>.exports = getTreeData;</span><br></pre></td></tr></table></figure><ul><li><strong>前端处理多请求</strong></li></ul><p>父组件 willMount的时候 调用接口,第一次渲染后,自组件的 shouldComponentUpdate 返回false即可</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">{currentMenuData.length > <span class="number">0</span> ? (</span><br><span class="line"> <SlideMenu data={currentMenuData} selected={current} active={current} /></span><br><span class="line">) : <span class="literal">null</span>}</span><br><span class="line"><span class="comment">// 在组件SlideMenu中</span></span><br><span class="line">shouldComponentUpdate() {</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>]]></content>
<tags>
<tag> javascript node </tag>
</tags>
</entry>
<entry>
<title>thrift环境搭建</title>
<link href="/2020/01/13/thrift%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA/"/>
<url>/2020/01/13/thrift%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA/</url>
<content type="html"><![CDATA[<p>rpc请求thrift 环境搭建</p><a id="more"></a><h3 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h3><blockquote><p>负责的项目由http请求转为thrift请求,需要搭建 thrift环境,node端处理thrift请求打到后端</p></blockquote><h3 id="搭建"><a href="#搭建" class="headerlink" title="搭建"></a>搭建</h3><ul><li><h4 id="官方地址"><a href="#官方地址" class="headerlink" title="官方地址"></a><strong>官方地址</strong></h4></li></ul><blockquote><p><a href="https://thrift.apache.org/docs/BuildingFromSource" target="_blank" rel="noopener">官方地址</a><br> <a href="https://github.com/apache/thrift" target="_blank" rel="noopener">官方仓库</a></p></blockquote><ul><li><h4 id="安装"><a href="#安装" class="headerlink" title="安装"></a><strong>安装</strong></h4></li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">brew install boost</span><br><span class="line">brew install Bison</span><br><span class="line">brew install libtool</span><br><span class="line">brew install automake</span><br><span class="line"><span class="comment"># 如果系统没有安装openssl</span></span><br><span class="line">brew install openssl</span><br><span class="line">brew install pkg-config</span><br><span class="line">cp /usr/<span class="built_in">local</span>/Cellar/pkg-config/0.29.2/share/aclocal/pkg.m4 ./aclocal/</span><br></pre></td></tr></table></figure><ul><li><h4 id="编译"><a href="#编译" class="headerlink" title="编译"></a><strong>编译</strong></h4></li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">./bootstrap.sh</span><br><span class="line"><span class="comment"># 由于 python 在 mac 下的路径权限问题无法解决,先忽略掉 python</span></span><br><span class="line">./configure LDFLAGS=<span class="string">'-L/usr/local/opt/openssl/lib'</span> CPPFLAGS=<span class="string">'-I/usr/local/opt/openssl/include'</span> --without-php --without-python --prefix=/usr/<span class="built_in">local</span>/ --with-boost=/usr/<span class="built_in">local</span> --with-libevent=/usr/<span class="built_in">local</span></span><br><span class="line">make</span><br><span class="line">make install</span><br></pre></td></tr></table></figure><p><strong>1、如果pkg-config 没有安装,会如下错误“./configure: line 16976: syntax error near unexpected token `QT,’”</strong><br><strong>2、出现 fatal error: ‘openssl/opensslv.h’ file not found,需要在configure 中指定 openssl 的查找路径 ./configure LDFLAGS=’-L/usr/local/opt/openssl/lib’ CPPFLAGS=’-I/usr/local/opt/openssl/include’</strong></p><ul><li><h4 id="使用"><a href="#使用" class="headerlink" title="使用"></a><strong>使用</strong></h4></li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">thrift -r --gen js:node my_file.thrift</span><br></pre></td></tr></table></figure><ul><li><h4 id="备注"><a href="#备注" class="headerlink" title="备注"></a><strong>备注</strong></h4>1、mac权限问题需要加sudo<br>2、bison安装出错参考 <a href="https://stackoverflow.com/questions/31805431/how-to-install-bison-on-mac-osx" target="_blank" rel="noopener">https://stackoverflow.com/questions/31805431/how-to-install-bison-on-mac-osx</a></li></ul>]]></content>
<tags>
<tag> node thrift </tag>
</tags>
</entry>
<entry>
<title>爬楼梯</title>
<link href="/2020/01/13/%E7%88%AC%E6%A5%BC%E6%A2%AF/"/>
<url>/2020/01/13/%E7%88%AC%E6%A5%BC%E6%A2%AF/</url>
<content type="html"><![CDATA[<p>斐波拉契数列变形<br><a id="more"></a></p><h3 id="题目描述"><a href="#题目描述" class="headerlink" title="题目描述"></a>题目描述</h3><p>假设你正在爬楼梯。需要 n 阶你才能到达楼顶。</p><p>每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?</p><p><strong>注意:</strong> 给定 n 是一个正整数<br><strong>示例1</strong></p><blockquote><p>输入: 2<br>输出: 2<br>解释: 有两种方法可以爬到楼顶。</p><ol><li>1 阶 + 1 阶</li><li>2 阶</li></ol></blockquote><p><strong>示例 2:</strong></p><blockquote><p>输入: 3<br>输出: 3<br>解释: 有三种方法可以爬到楼顶。</p><ol><li>1 阶 + 1 阶 + 1 阶</li><li>1 阶 + 2 阶</li><li>2 阶 + 1 阶</li></ol></blockquote><p><strong>解析</strong></p><blockquote><p>其实这道题目是典型的斐波那契数列问题,在一开始,我是按照解决斐波拉契数列问题的解法适用递归,在整体过测试用例的时候发现用时过长,超出时间限制,并且在执行 n= 46的时候内存益处</p></blockquote><p>后面的时候采用动态规划解法,将前一步的step缓存起来,然后再往下执行,会好很多,代码如下:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @param {number} n</span></span><br><span class="line"><span class="comment"> * @return {number}</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">var</span> climbStairs = <span class="function"><span class="keyword">function</span>(<span class="params">n</span>) </span>{</span><br><span class="line"> <span class="keyword">if</span> (n <= <span class="number">2</span>) <span class="keyword">return</span> n;</span><br><span class="line"> <span class="keyword">let</span> stepOne = <span class="number">1</span>, stepTwo = <span class="number">2</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">3</span>; i <= n; i++) {</span><br><span class="line"> <span class="keyword">let</span> temp = stepOne + stepTwo;</span><br><span class="line"> stepOne = stepTwo;</span><br><span class="line"> stepTwo = temp;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> stepTwo;</span><br><span class="line">};</span><br></pre></td></tr></table></figure>]]></content>
<tags>
<tag> 算法 javascript </tag>
</tags>
</entry>
<entry>
<title>react 升级问题汇总</title>
<link href="/2020/01/13/react-%E5%8D%87%E7%BA%A7%E9%97%AE%E9%A2%98%E6%B1%87%E6%80%BB/"/>
<url>/2020/01/13/react-%E5%8D%87%E7%BA%A7%E9%97%AE%E9%A2%98%E6%B1%87%E6%80%BB/</url>
<content type="html"><![CDATA[<p>react 二期升级问题汇总</p><a id="more"></a><h3 id="No-1-编译打包antd样式文件无法识别"><a href="#No-1-编译打包antd样式文件无法识别" class="headerlink" title="No.1 编译打包antd样式文件无法识别"></a>No.1 编译打包antd样式文件无法识别</h3><p><img src="/img/react_01.png" alt=""><br>如上,在用antd 中的Menu替换 bootstrap中的menu时发现这部分打包报错</p><h4 id="原因"><a href="#原因" class="headerlink" title="原因"></a>原因</h4><blockquote><p>antd中Menu为css,但是webpack打包是按照less打包的,打开这部分的css报错的文件,发现background的后面有\9,以下为webpack打包样式的规则:<br><img src="/img/react_02.png" alt=""></p></blockquote><p>解决办法:</p><blockquote><p>将less与css文件打包拆开,如下<br><img src="/img/react_03.png" alt=""><br>编译打包后,没问题,原先报错文件,中不存在\9,如下:<br><img src="/img/react_04.png" alt=""></p></blockquote><h3 id="No-2-项目老旧,多页面系统,存在layout中用script引入-react低版本"><a href="#No-2-项目老旧,多页面系统,存在layout中用script引入-react低版本" class="headerlink" title="No.2 项目老旧,多页面系统,存在layout中用script引入 react低版本"></a>No.2 项目老旧,多页面系统,存在layout中用script引入 react低版本</h3><p>解决办法:</p><blockquote><p>移除该script引用,在入口App中,引入现在所依赖的react包,然后通过window挂载全局使用</p></blockquote><h3 id="No-3-项目老旧,存在原先同事开发的包,后续该包未升级,内部react还是依赖的14-x"><a href="#No-3-项目老旧,存在原先同事开发的包,后续该包未升级,内部react还是依赖的14-x" class="headerlink" title="No.3 项目老旧,存在原先同事开发的包,后续该包未升级,内部react还是依赖的14.x"></a>No.3 项目老旧,存在原先同事开发的包,后续该包未升级,内部react还是依赖的14.x</h3><p>解决办法:</p><blockquote><p>将对应的包在github下载下来,或者在node_modules中找到,放在项目中</p></blockquote>]]></content>
<tags>
<tag> react </tag>
</tags>
</entry>
<entry>
<title>React14.x升16.8</title>
<link href="/2020/01/13/React14-x%E5%8D%8716-8/"/>
<url>/2020/01/13/React14-x%E5%8D%8716-8/</url>
<content type="html"><![CDATA[<p>react 14升16.8 二期总结</p><a id="more"></a><h3 id="以下总结摘自:"><a href="#以下总结摘自:" class="headerlink" title="以下总结摘自:"></a>以下总结摘自:</h3><p><strong><a href="https://blog.csdn.net/mapbar_front/article/details/80187123" target="_blank" rel="noopener">React16版本更新的新特性</a><br><a href="https://blog.csdn.net/Napoleonxxx/article/details/81120854" target="_blank" rel="noopener">React v15到v16.3, v16.4新生命周期总结以及使用场景</a><br><a href="https://blog.csdn.net/u013451157/article/details/78719374" target="_blank" rel="noopener">【ReactJS】V0.14版本前后的变化</a><br><a href="https://www.jianshu.com/p/a8bc5b292561" target="_blank" rel="noopener">react14到15版本主要变更</a><br><a href="https://blog.csdn.net/xiaozhuo_tang/article/details/88878858" target="_blank" rel="noopener">React15至今的重要变化人肉梳理</a></strong></p><h3 id="总结如下:"><a href="#总结如下:" class="headerlink" title="总结如下:"></a>总结如下:</h3><ul><li><h3 id="react-14-到-15"><a href="#react-14-到-15" class="headerlink" title="react 14 到 15"></a><strong>react 14 到 15</strong></h3><ul><li>当在挂载组件时使用document.createElement而不是innerHTML,这样我们就摆脱了data-reactid。并且document.createElement在现代浏览器中也更快;<br><strong>值得注意:</strong> data-reactid在client端已经去除了,但依旧存在在服务端渲染中,不过更小更简 单是简单递增的。</li><li>由于历史原因对SVG的不完整支持,在React 15中支持了所有被现代浏览器所支持的SVG属性;</li><li>社区(Michael Wiencek)的贡献使得React 15不再需要多余的对text进行包裹;</li><li>渲染Null现在使用comment nodes(注释节点)了;</li><li>函数式组件现在也能返回null了;</li><li>移除和弃用<ul><li>移除包括:<br><strong>indDOMNode,render,renderToSring,renderToStaticMarkup和unmountComponentAtNode</strong>几个顶级API,不过他们都能在<strong>ReactDom和ReactDomServer</strong>中找到;</li><li>移除的插件: <strong>cloneWithProps和batchedUpdates</strong></li><li>移除的组件实例方法:<strong>setProps、replaceProps和getDOMNode</strong></li></ul></li></ul></li><li><h3 id="react-15-的一些重大变化"><a href="#react-15-的一些重大变化" class="headerlink" title="react 15 的一些重大变化"></a><strong>react 15 的一些重大变化</strong></h3><ul><li>彻底分离<strong>React和React DOM</strong>,现在React中将只含有与渲染无关的代码例如:<strong>React.Component和React.createElement()</strong></li><li>React DOM Server包体积大小几乎与React相当,因为他有一份自己的React reconciler。<strong>不建议在client端使用React DOM Server</strong></li><li>拆分了React.PropTypes和React.createClass到独立的包中;</li><li>React.PropTypes迁移到了prop-types包中,迁移指南;</li><li>React.createClass迁移到create-react-class中,但由于ES2015对class的支持,React也开始使用原生的class来创建components;</li><li>data-和aria-的属性将会任我们自定义</li></ul></li><li><h3 id="react-16的一些重大变化"><a href="#react-16的一些重大变化" class="headerlink" title="react 16的一些重大变化"></a><strong>react 16的一些重大变化</strong></h3><ul><li>NEW FEATURE:fragments、error boundaries(已经介绍过不做赘述)、portals</li><li>NEW SUPPORT:custom DOM attributes</li><li>IMPROVEMENT:server-side rendering</li><li>render函数能return:React elements、Array和<a href="https://reactjs.org/docs/fragments.html" target="_blank" rel="noopener">fragments</a>、Portals、Booleans or null、String and numbers</li><li><a href="https://reactjs.org/docs/portals.html" target="_blank" rel="noopener">portals</a>是由React DOM提供的方法createPortal(child, container)所创建出来的,能够让元素脱离于React Tree在DOM Tree的其他地方出现,但事件冒泡依旧是遵循React DOM tree的。这个方法可以用来实现Modal、dialog、tooltips等。</li><li>更好的服务端渲染:支持流式的传输、三倍快与React 15的渲染速度。值得注意的是,React 16 hydrate工作在client端时会使用已经在服务端渲染好的DOM结构,而不会做细致检查,只会在Client端提示你数据不统一,并且也不建议在server端渲染和client端hydrate时数据不同</li><li>降低了包大小:react 5.3kb(2.2kb gzipped)、react-dom 103.7kb(32.6kb gzipped)</li><li>Breaking changes摘要:<ul><li>setState(null)不再会引起更新、setState的callback将会在componentDidMount/componentDidUpdate后立即执行,而不是在所有components渲染后执行</li><li><b>替换<a>时,B的componentWillMount总会发生在A的componentWIllUnmount之前</a></b></li><li>shallow renderer不会再出发componentDidUpdate因为DOM refs是拿不到的,并与componentDidMount表现一致</li><li>功能剥离:React.PropTypes => prop-types、React.Dom => react-dom-factories、react-addons-test-utils => react-dom/test-utils、shallow renderer => react-test-renderer/shallow</li></ul></li><li>React 16依赖于Map和Set,如果要支持老旧浏览器和设备,应该引入全局的polyfill,例如core-js和babel-polyfill,同样也依赖于requestAnimationFrame,可以用raf包来弥补</li><li>异步渲染的更新:Two Demos<ul><li>ime slicing、suspense</li></ul></li><li>正式的<a href="https://reactjs.org/docs/context.html" target="_blank" rel="noopener">Context API</a></li><li><a href="https://reactjs.org/docs/refs-and-the-dom.html" target="_blank" rel="noopener">createRef API</a>、<a href="https://reactjs.org/docs/refs-and-the-dom.html" target="_blank" rel="noopener">forwardRef API</a></li><li>生命周期的变更,可参看<a href="https://blog.csdn.net/xiaozhuo_tang/article/details/83824824" target="_blank" rel="noopener">【译】React16.3+ 生命周期</a><ul><li>componentWillMount、componentWillReceiveProps、componentWillUpdate都不建议在使用并且在17中将会被冠上UNSAFE_的前缀;</li><li>新增了getDerivedStateFromProps、getSnapshotBeforeUpdate两个生命周期</li></ul></li><li>React 16.5.0以上在React Devtools新增了一个新功能Profiler,来帮助我们梳理React项目各组件的性能</li><li>React.memo 让Function组件用上PureComponent</li><li>React.lazy配合Suspence和动态引入import(’’)来优化体验(例如loading状态)</li><li>static contextType</li><li><a href="https://zh-hans.reactjs.org/docs/hooks-intro.html" target="_blank" rel="noopener">hooks</a></li></ul></li></ul>]]></content>
<tags>
<tag> react </tag>
</tags>
</entry>
<entry>
<title>bootstrap 转antd调研处理</title>
<link href="/2020/01/13/bootstrap-%E8%BD%ACantd%E8%B0%83%E7%A0%94%E5%A4%84%E7%90%86/"/>
<url>/2020/01/13/bootstrap-%E8%BD%ACantd%E8%B0%83%E7%A0%94%E5%A4%84%E7%90%86/</url>
<content type="html"><![CDATA[<p>项目升级 bootstrap转antd调研<br><a id="more"></a></p><h3 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h3><blockquote><p>团队内部现有UI库为antd,现升级react 至 16,UI库为bootstrap和react-bootstrap, 考虑升级成本与替换成本差不多,现计划将BD和BDAdmin的UI库统一为antd</p></blockquote><h4 id="项目中用到的常用组件"><a href="#项目中用到的常用组件" class="headerlink" title="项目中用到的常用组件"></a>项目中用到的常用组件</h4><ul><li>Button</li><li>Modal</li><li>Table</li><li>Tabs</li><li>Tab</li><li>SplitButton</li><li>MenuItem</li><li>Pagination</li><li>Tooltip</li><li>OverlayTrigger</li><li>react-select</li><li>react-simple-radio-group</li></ul><h3 id="细化"><a href="#细化" class="headerlink" title="细化"></a>细化</h3><blockquote><p>以下会对上述项目中所用到的组件逐个对比,评估迁移成本与解决方案</p></blockquote><ul><li><h2 id="Button-按钮"><a href="#Button-按钮" class="headerlink" title="Button 按钮"></a><strong>Button</strong> 按钮</h2></li></ul><table><thead><tr><th>-</th><th>react-bootstrap 0.27.3</th><th>antd 3.22.1</th></tr></thead><tbody><tr><td>引入方式</td><td>import Button from ‘react-bootstrap/lib/Button’;</td><td>import { Button } from ‘antd’;</td><td></td></tr><tr><td>属性</td><td></td><td>disabled,ghost,href, htmlType, icon, loading, shape, size,target, type,onClick,block</td><td></td></tr></tbody></table><blockquote><p>完成情况: done</p></blockquote><ul><li><h2 id="Modal-弹框"><a href="#Modal-弹框" class="headerlink" title="Modal 弹框"></a><strong>Modal</strong> 弹框</h2></li></ul><table><thead><tr><th>-</th><th>react-bootstrap 0.27.3</th><th>antd 3.22.1</th></tr></thead><tbody><tr><td>引入方式</td><td>import Modal from ‘react-bootstrap/lib/Modal’;</td><td>import { Modal } from ‘antd’;</td><td></td></tr><tr><td>属性</td><td>show,onHide,onExit,onExited, onEnter,onEntering,onEntered</td><td>afterClose,bodyStyle, cancelText, centered, centered, closeIcon, confirmLoading, destroyOnClose, footer, forceRender, getContainer, keyboard, mask, maskClosable, maskStyle, okText, okType, okButtonProps, cancelButtonProps, style, title, visible, width, wrapClassName, zIndex, onCancel, onOk</td><td></td></tr></tbody></table><blockquote><p><strong>备注:</strong><br> 1、<a href="https://ant.design/components/modal-cn/" target="_blank" rel="noopener">antd-modal</a><br> 2、替换成本大<br> 3、完成情况 done</p></blockquote><ul><li><h2 id="Table"><a href="#Table" class="headerlink" title="Table"></a>Table</h2></li></ul><table><thead><tr><th>-</th><th>react-bootstrap 0.27.3</th><th>antd 3.22.1</th></tr></thead><tbody><tr><td>引入方式</td><td>import Table from ‘react-bootstrap/lib/Table’; 或者 import Table from ‘@myfe/table2’;</td><td>import { Table } from ‘antd’;</td><td></td></tr><tr><td>属性</td><td></td><td>disabled,ghost,href, htmlType, icon, loading, shape, size,target, type,onClick,block</td><td></td></tr></tbody></table><blockquote><p>备注:<br> 1、注意工作量评估,会比较坑<br> 2、内部引用myfe/table2 对现有升级没有影响,暂不考虑升级<br> 3、后续table代码引入可以考虑逐步替换成antd的table</p></blockquote><ul><li><h2 id="Tabs"><a href="#Tabs" class="headerlink" title="Tabs"></a><strong>Tabs</strong></h2></li></ul><table><thead><tr><th>-</th><th>react-bootstrap 0.27.3</th><th>antd 3.22.1</th></tr></thead><tbody><tr><td>引入方式</td><td>import { Tabs, Tab } from ‘react-bootstrap’;</td><td>import { Tabs, Tab } from ‘antd’;</td><td></td></tr><tr><td>属性</td><td></td><td>activeKey, animated, renderTabBar, defaultActiveKey, hideAdd, size, tabBarExtraContent, tabBarGutter, tabBarStyle, tabPosition, type, onChange, onEdit, onNextClick, onPrevClick, onTabClick</td><td></td></tr></tbody></table><ul><li><h2 id="Tab"><a href="#Tab" class="headerlink" title="Tab"></a><strong>Tab</strong></h2></li></ul><table><thead><tr><th>-</th><th>react-bootstrap 0.27.3</th><th>antd 3.22.1</th></tr></thead><tbody><tr><td>引入方式</td><td>import { Tabs, Tab } from ‘react-bootstrap’;</td><td>const { TabPane } = Tabs;</td><td></td></tr><tr><td>属性</td><td></td><td>forceRender, key, tab</td><td></td></tr></tbody></table><blockquote><p>备注:<br> 1、react-bootstrap 在 antd中叫法为TabPane<br> 2、注意方式引用<br> 3、完成情况:done</p></blockquote><ul><li><h2 id="SplitButton"><a href="#SplitButton" class="headerlink" title="SplitButton"></a>SplitButton</h2></li></ul><table><thead><tr><th>-</th><th>react-bootstrap 0.27.3</th><th>antd 3.22.1</th></tr></thead><tbody><tr><td>引入方式</td><td>import SplitButton from ‘react-bootstrap/lib/SplitButton’;</td><td>import { Menu, Dropdown, Icon } from ‘antd’;</td><td></td></tr></tbody></table><blockquote><p>备注:<br>1、menu 样式css与内部less webpack打包规则问题,整理到升级问题汇总中<br>2、完成情况: done</p></blockquote><ul><li><h2 id="MenuItem"><a href="#MenuItem" class="headerlink" title="MenuItem"></a>MenuItem</h2></li></ul><table><thead><tr><th>-</th><th>react-bootstrap 0.27.3</th><th>antd 3.22.1</th></tr></thead><tbody><tr><td>引入方式</td><td>import MenuItem fqrom ‘react-bootstrap/lib/MenuItem’;</td><td>import { Menu, Dropdown, Icon } from ‘antd’;</td><td></td></tr></tbody></table><blockquote><p>备注:以上两个地方调用是一起的,看能不能调研一起使用<br> 1、menu 样式css与内部less webpack打包规则问题,整理到升级问题汇总中<br> 2、完成情况: done</p></blockquote><ul><li><h2 id="Pagination"><a href="#Pagination" class="headerlink" title="Pagination"></a>Pagination</h2></li></ul><table><thead><tr><th>-</th><th>react-bootstrap 0.27.3</th><th>antd 3.22.1</th></tr></thead><tbody><tr><td>引入方式</td><td>import { Pagination } from ‘react-bootstrap’;</td><td>import { Pagination } from ‘antd’;</td><td></td></tr></tbody></table><blockquote><p>备注:<br> 1、暂时调研只需要修改引用的地方,传参方式尽量不修改,需要修改引入的地方的参数名<br> 2、完成情况: done</p></blockquote><ul><li><h2 id="Tooltip"><a href="#Tooltip" class="headerlink" title="Tooltip"></a>Tooltip</h2></li></ul><table><thead><tr><th>-</th><th>react-bootstrap 0.27.3</th><th>antd 3.22.1</th></tr></thead><tbody><tr><td>引入方式</td><td>import Tooltip from ‘react-bootstrap/lib/Tooltip’;</td><td>import { Tooltip } from ‘antd’;</td><td></td></tr></tbody></table><ul><li><h2 id="OverlayTrigger"><a href="#OverlayTrigger" class="headerlink" title="OverlayTrigger"></a>OverlayTrigger</h2></li><li><h2 id="react-select"><a href="#react-select" class="headerlink" title="react-select"></a>react-select</h2></li></ul><blockquote><p>考虑使用antd中的select<br> 完成情况: done</p></blockquote><ul><li>react-simple-radio-group<blockquote><p>考虑使用antd 的 radio<br>内部依赖react版本 14.3,须替换<br>注意工作量评估,会比较坑</p></blockquote></li></ul>]]></content>
<tags>
<tag> antd react </tag>
</tags>
</entry>
<entry>
<title>判断是否为ie浏览器</title>
<link href="/2020/01/13/%E5%88%A4%E6%96%AD%E6%98%AF%E5%90%A6%E4%B8%BAie%E6%B5%8F%E8%A7%88%E5%99%A8/"/>
<url>/2020/01/13/%E5%88%A4%E6%96%AD%E6%98%AF%E5%90%A6%E4%B8%BAie%E6%B5%8F%E8%A7%88%E5%99%A8/</url>
<content type="html"><![CDATA[<p>userAgent<br><a id="more"></a></p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="keyword">const</span> userAgent = navigator && navigator.userAgent;</span><br><span class="line"><span class="keyword">const</span> IS_IE = navigator && navigator.userAgent && (navigator.userAgent.indexOf(<span class="string">'MSIE'</span>) > <span class="number">-1</span> || navigator.userAgent.indexOf(<span class="string">'Trident'</span>) > <span class="number">-1</span>);</span><br></pre></td></tr></table></figure><p>关于 userAgent 的学习,可以查看<a href="https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/User-Agent" target="_blank" rel="noopener">mdn</a>上对应的文档</p>]]></content>
<tags>
<tag> javscript https </tag>
</tags>
</entry>
<entry>
<title>git 踩坑点总结</title>
<link href="/2020/01/13/git-%E8%B8%A9%E5%9D%91%E7%82%B9%E6%80%BB%E7%BB%93/"/>
<url>/2020/01/13/git-%E8%B8%A9%E5%9D%91%E7%82%B9%E6%80%BB%E7%BB%93/</url>
<content type="html"><![CDATA[<p>日常 git 操作踩坑点总结</p><a id="more"></a><h3 id="No-1-在相同文件本地提交到远程以后,当修改过本地文件,再次提交如果没有git-diff-的话,这时如果git-commit-以及git-push-origin-到远程分支的话,这时远程的文件可能会有冲突"><a href="#No-1-在相同文件本地提交到远程以后,当修改过本地文件,再次提交如果没有git-diff-的话,这时如果git-commit-以及git-push-origin-到远程分支的话,这时远程的文件可能会有冲突" class="headerlink" title="No.1 在相同文件本地提交到远程以后,当修改过本地文件,再次提交如果没有git diff 的话,这时如果git commit 以及git push origin 到远程分支的话,这时远程的文件可能会有冲突"></a>No.1 在相同文件本地提交到远程以后,当修改过本地文件,再次提交如果没有git diff 的话,这时如果git commit 以及git push origin 到远程分支的话,这时远程的文件可能会有冲突</h3><p>解答:</p><blockquote><p>01、 当本地代码与远程存在冲突的时候,如果想push到远程,一般会携带冲突的代码到远程,即远程代码存在冲> 突,只要git pull 再重新解决即可<br>02、如果发现冲突时,本地已经有修改过的其他代码,只要git stash -u 将已经修改的代码暂存在本地,然后pull 解决冲突,最后git stash pop 将暂存的代码pop出来即可.</p></blockquote><h3 id="No-2-时间A,从master切出新分支,改动代码,此时同事将自己的其他业务线的代码合并到master,在提交到远程的时候发现有冲突,远程pr中发现有冲突,但是本地vscode中暂未发现有冲突的点,为何?如何解决"><a href="#No-2-时间A,从master切出新分支,改动代码,此时同事将自己的其他业务线的代码合并到master,在提交到远程的时候发现有冲突,远程pr中发现有冲突,但是本地vscode中暂未发现有冲突的点,为何?如何解决" class="headerlink" title="No.2 时间A,从master切出新分支,改动代码,此时同事将自己的其他业务线的代码合并到master,在提交到远程的时候发现有冲突,远程pr中发现有冲突,但是本地vscode中暂未发现有冲突的点,为何?如何解决?"></a>No.2 时间A,从master切出新分支,改动代码,此时同事将自己的其他业务线的代码合并到master,在提交到远程的时候发现有冲突,远程pr中发现有冲突,但是本地vscode中暂未发现有冲突的点,为何?如何解决?</h3><p>解答:</p><blockquote><p>01、原因: 本地自己的分支的改动是基于时间A下的master分支,而同事在合并master代码以后,远程master分支有改动,而本地没有,可理解为本地master分支低了远程master分支一个版本,故在本地看不到产生冲突的文件和代码<br>02、解决办法:将本地master与远程master保持同步,然后再将本地新分支 与master作合并即可看到冲突,最后解决冲突即可, 如下:</p></blockquote><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">git:(master) git pull origin master</span><br><span class="line">git:(fetature/A) git megre master</span><br></pre></td></tr></table></figure><h3 id="No-3-代码提交到远程后code-review时发现提交了不必要的文件"><a href="#No-3-代码提交到远程后code-review时发现提交了不必要的文件" class="headerlink" title="No.3 代码提交到远程后code review时发现提交了不必要的文件"></a>No.3 代码提交到远程后code review时发现提交了不必要的文件</h3><p>解决办法:</p><blockquote><p>找到那个文件的commit,然后将那个文件的commit还原到指定commit,再提交到远程即可</p></blockquote><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">git <span class="built_in">log</span> + 文件A路径</span><br><span class="line">git checkout + 指定commit + 文件A路径</span><br><span class="line">git status</span><br><span class="line">git add + 文件A路径</span><br><span class="line">git commit -m <span class="string">''</span></span><br><span class="line">git push origin + 分支</span><br></pre></td></tr></table></figure><h3 id="No-4-如果将本地修改的A文件push到远程分支,后续又对该分支做过多次commit-和-push-操作,请问:-如何将该A文件回退到第一次提交前的版本而不影响整个分支的其他文件"><a href="#No-4-如果将本地修改的A文件push到远程分支,后续又对该分支做过多次commit-和-push-操作,请问:-如何将该A文件回退到第一次提交前的版本而不影响整个分支的其他文件" class="headerlink" title="No.4 如果将本地修改的A文件push到远程分支,后续又对该分支做过多次commit 和 push 操作,请问: 如何将该A文件回退到第一次提交前的版本而不影响整个分支的其他文件?"></a>No.4 如果将本地修改的A文件push到远程分支,后续又对该分支做过多次commit 和 push 操作,请问: 如何将该A文件回退到第一次提交前的版本而不影响整个分支的其他文件?</h3><p>此部分解决方式与上面一致</p><h3 id="No-5-如果误用git-push-origin-分支名1-分支名-2-,请问所push的以分支名1-为准还是分支名2为准"><a href="#No-5-如果误用git-push-origin-分支名1-分支名-2-,请问所push的以分支名1-为准还是分支名2为准" class="headerlink" title="No.5 如果误用git push origin + 分支名1 + 分支名 2 ,请问所push的以分支名1 为准还是分支名2为准"></a>No.5 如果误用git push origin + 分支名1 + 分支名 2 ,请问所push的以分支名1 为准还是分支名2为准</h3><blockquote><p>远程仓库中会存在两个分支,分别为分支名1和分支名2</p></blockquote><h3 id="No-6-在分支A下,不小心提交了要提交在分支B下的代码,如何解决?"><a href="#No-6-在分支A下,不小心提交了要提交在分支B下的代码,如何解决?" class="headerlink" title="No.6 在分支A下,不小心提交了要提交在分支B下的代码,如何解决?"></a>No.6 在分支A下,不小心提交了要提交在分支B下的代码,如何解决?</h3><blockquote><p>将在分支A下的commit拿出来,然后再放在分支B上,即可</p></blockquote><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">(feature/A): git <span class="built_in">log</span> + 分支A (提取commit)</span><br><span class="line">(feature/B): git cherry-pick + commit</span><br></pre></td></tr></table></figure><h3 id="No-7-20190403-git-错误操作"><a href="#No-7-20190403-git-错误操作" class="headerlink" title="No.7 20190403 git 错误操作"></a>No.7 20190403 git 错误操作</h3><blockquote><p>背景: 当时把所有的业务代码都写完了,看了pr,想优化下分支中的一些文件,就用了以下命令</p></blockquote><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">git status</span><br><span class="line">git <span class="built_in">log</span> + 文件路径 // 查找到想要会退的commit,例如commit id 为 saasasa</span><br><span class="line">git reset -- hard saasasa</span><br><span class="line">git push -f origin + 本地分支名</span><br></pre></td></tr></table></figure><blockquote><p>问题: 直接导致远程代码被reset了,后提交的所有commit都不存在,导致代码数据全部都没有了,毁灭,难受,心塞,心慌</p></blockquote><blockquote><p>解决办法:</p></blockquote><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">git reflog show // 查找最近操作的head</span><br><span class="line">git reset + 想要回退的操作的headId</span><br><span class="line">git <span class="built_in">log</span> // 即可看到上一次reset前的<span class="built_in">log</span></span><br></pre></td></tr></table></figure><p>注释:例如我操作我本地的分支的一个 git reflog show</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line">fc2310c9 (HEAD -> git/<span class="built_in">test</span>) HEAD@{0}: checkout: moving from feature/optional-settlement to git/<span class="built_in">test</span></span><br><span class="line">26284977 (origin/feature/optional-settlement, feature/optional-settlement) HEAD@{1}: reset: moving to HEAD</span><br><span class="line">26284977 (origin/feature/optional-settlement, feature/optional-settlement) HEAD@{2}: checkout: moving from git/<span class="built_in">test</span> to feature/optional-settlement</span><br><span class="line">fc2310c9 (HEAD -> git/<span class="built_in">test</span>) HEAD@{3}: reset: moving to HEAD@{2}</span><br><span class="line">d730bc53 (origin/git/<span class="built_in">test</span>) HEAD@{4}: reset: moving to HEAD@{0}</span><br><span class="line">d730bc53 (origin/git/<span class="built_in">test</span>) HEAD@{5}: reset: moving to d730bc5333a6f0054227d9476dffb5dc5308f5e8</span><br><span class="line">fc2310c9 (HEAD -> git/<span class="built_in">test</span>) HEAD@{6}: commit: git测试</span><br><span class="line">5d1965a0 (origin/master, origin/HEAD, master) HEAD@{7}: checkout: moving from master to git/<span class="built_in">test</span></span><br><span class="line">5d1965a0 (origin/master, origin/HEAD, master) HEAD@{8}: checkout: moving from qatest to master</span><br><span class="line">83eede1e (origin/qatest, qatest) HEAD@{9}: commit (merge): 合同</span><br><span class="line">ed915fc5 HEAD@{10}: merge feature/remove-branch: Merge made by the <span class="string">'recursive'</span> strategy.</span><br><span class="line">f3d9ba99 HEAD@{11}: merge feature/customer-log: Merge made by the <span class="string">'recursive'</span> strategy.</span><br><span class="line">26284977 (origin/feature/optional-settlement, feature/optional-settlement) HEAD@{12}: merge feature/optional-settlement: Fast-forward</span><br><span class="line">5d1965a0 (origin/master, origin/HEAD, master) HEAD@{13}: checkout: moving from master to qatest</span><br><span class="line">5d1965a0 (origin/master, origin/HEAD, master) HEAD@{14}: checkout: moving from qatest to master</span><br><span class="line">8254f765 HEAD@{15}: reset: moving to HEAD</span><br><span class="line">8254f765 HEAD@{16}: checkout: moving from feature/optional-settlement to qatest</span><br><span class="line">26284977 (origin/feature/optional-settlement, feature/optional-settlement) HEAD@{17}: commit: 删除注</span><br><span class="line">释 & 字段修改</span><br><span class="line">2f3028b0 HEAD@{18}: commit: 选座优化</span><br></pre></td></tr></table></figure><h4 id="反思"><a href="#反思" class="headerlink" title="反思"></a>反思</h4><blockquote><p>01、git reset –hard 和 git push -f 和 git pull -f 这些强制性的操作太过于危险,最好不要使用,切勿在公共分支使用<br>02、如果想将某个提交过的文件回退,可以使用如下操作<br> <figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">git <span class="built_in">log</span> -- 文件路径</span><br><span class="line">git checkout + commitId + 文件路径</span><br></pre></td></tr></table></figure></p></blockquote><blockquote><p>03、对于分支强拉或者强推 ,最好不要使用 -force ,可以考虑使用 rebase 操作,不会重新生成 commitId, 操作比较柔和</p></blockquote>]]></content>
<tags>
<tag> git </tag>
</tags>
</entry>
<entry>
<title>对称二叉树</title>
<link href="/2019/09/22/%E5%AF%B9%E7%A7%B0%E4%BA%8C%E5%8F%89%E6%A0%91/"/>
<url>/2019/09/22/%E5%AF%B9%E7%A7%B0%E4%BA%8C%E5%8F%89%E6%A0%91/</url>
<content type="html"><![CDATA[<p>检查一个二叉树是否镜像对称</p><a id="more"></a><h3 id="对称二叉树"><a href="#对称二叉树" class="headerlink" title="对称二叉树"></a><a href="https://leetcode-cn.com/problems/symmetric-tree/submissions/" target="_blank" rel="noopener">对称二叉树</a></h3><h4 id="题目描述"><a href="#题目描述" class="headerlink" title="题目描述:"></a>题目描述:</h4><blockquote><p>给定一个二叉树,检查它是否是镜像对称的。<br>例如,二叉树 [1,2,2,3,4,4,3] 是对称的。<br><img src="/img/tree_01.png" alt="示例1"><br>但是下面这个 [1,2,2,null,3,null,3] 则不是镜像对称的:<br><img src="/img/tree_02.png" alt="示例2"></p></blockquote><h4 id="思路"><a href="#思路" class="headerlink" title="思路"></a>思路</h4><blockquote><p>1、递归<br>2、如果一个树的左子树和右子树镜像对称,那么这个树是对称的.<br><img src="/img/tree_03.png" alt="转换关系]"><br>3、因此,该问题就可转换为:两个树在什么条件下镜像对称?<br>如果同时满足以下条件,则这两个树互为镜像对称</p></blockquote><ul><li>他们的跟节点具有相同的值</li><li>每个树的右子树都与另一个树的左子树镜像对称<br><img src="/img/tree_04.png" alt="左右子树镜像对称图"></li></ul><h4 id="代码"><a href="#代码" class="headerlink" title="代码"></a>代码</h4><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Definition for a binary tree node.</span></span><br><span class="line"><span class="comment"> * function TreeNode(val) {</span></span><br><span class="line"><span class="comment"> * this.val = val;</span></span><br><span class="line"><span class="comment"> * this.left = this.right = null;</span></span><br><span class="line"><span class="comment"> * }</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @param {TreeNode} root</span></span><br><span class="line"><span class="comment"> * @return {boolean}</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">var</span> isSymmetric = <span class="function"><span class="keyword">function</span>(<span class="params">root</span>) </span>{</span><br><span class="line"> <span class="keyword">return</span> isMinor(root, root)</span><br><span class="line">}</span><br><span class="line"><span class="keyword">var</span> isMinor = <span class="function"><span class="keyword">function</span>(<span class="params">t1, t2</span>) </span>{</span><br><span class="line"> <span class="keyword">if</span> (t1 === <span class="literal">null</span> && t2 === <span class="literal">null</span>) <span class="keyword">return</span> <span class="literal">true</span></span><br><span class="line"> <span class="keyword">if</span> (t1 === <span class="literal">null</span> || t2 === <span class="literal">null</span>) <span class="keyword">return</span> <span class="literal">false</span></span><br><span class="line"> <span class="keyword">return</span> (</span><br><span class="line"> t1.val === t2.val &&</span><br><span class="line"> isMinor(t1.left, t2.right) &&</span><br><span class="line"> isMinor(t1.right, t2.left)</span><br><span class="line"> )</span><br><span class="line">}</span><br></pre></td></tr></table></figure>]]></content>
<tags>
<tag> leetcode </tag>
<tag> 算法 </tag>
</tags>
</entry>
<entry>
<title>矩阵置零</title>
<link href="/2019/09/22/%E7%9F%A9%E9%98%B5%E7%BD%AE%E9%9B%B6/"/>
<url>/2019/09/22/%E7%9F%A9%E9%98%B5%E7%BD%AE%E9%9B%B6/</url>
<content type="html"><![CDATA[<p>给定一个 m x n 的矩阵,如果一个元素为 0,则将其所在行和列的所有元素都设为 0。请使用原地算法</p><a id="more"></a><h3 id="矩阵置零"><a href="#矩阵置零" class="headerlink" title="矩阵置零"></a><a href="https://leetcode-cn.com/problems/set-matrix-zeroes/" target="_blank" rel="noopener">矩阵置零</a></h3><h4 id="题目描述"><a href="#题目描述" class="headerlink" title="题目描述"></a>题目描述</h4><blockquote><p>给定一个 m x n 的矩阵,如果一个元素为 0,则将其所在行和列的所有元素都设为 0。请使用原地算法<br><strong>示例 1</strong><br>输入: [ [1,1,1],[1,0,1],[1,1,1] ]<br>输出: [ [1,0,1],[0,0,0],[1,0,1] ]</p></blockquote><p><strong>示例 2</strong></p><blockquote><p>输入:<br>输入:<br>[ [0,1,2,0], [3,4,5,2], [1,3,1,5] ]<br>输出:<br>[ [0,0,0,0], [0,4,5,0], [0,3,1,0] ]</p></blockquote><h4 id="思路"><a href="#思路" class="headerlink" title="思路"></a>思路</h4><blockquote><p>1、原地置换,表示空间复杂度要求为 O(1)<br>2、第一次遍历,记录二维数组中值为 0 的下标,分别记录行号和列号<br>3、第二次遍历,赋值,如果当前遍历位置的下标只要有一个在之前记录的下标中,就置为 0</p></blockquote><h4 id="代码如下:"><a href="#代码如下:" class="headerlink" title="代码如下:"></a>代码如下:</h4><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @param {number[][]} matrix</span></span><br><span class="line"><span class="comment"> * @return {void} Do not return anything, modify matrix in-place instead.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">var</span> setZeroes = <span class="function"><span class="keyword">function</span>(<span class="params">matrix</span>) </span>{</span><br><span class="line"> <span class="keyword">const</span> length = matrix.length</span><br><span class="line"> <span class="keyword">const</span> high = matrix[<span class="number">0</span>].length</span><br><span class="line"> <span class="keyword">let</span> rowFlag = [],</span><br><span class="line"> columnFlag = []</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i < length; i++) {</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">let</span> j = <span class="number">0</span>; j < high; j++) {</span><br><span class="line"> <span class="keyword">if</span> (matrix[i][j] === <span class="number">0</span>) {</span><br><span class="line"> rowFlag.push(i)</span><br><span class="line"> columnFlag.push(j)</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i < length; i++) {</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">let</span> j = <span class="number">0</span>; j < high; j++) {</span><br><span class="line"> <span class="keyword">if</span> (rowFlag.indexOf(i) > <span class="number">-1</span> || columnFlag.indexOf(j) > <span class="number">-1</span>) {</span><br><span class="line"> matrix[i][j] = <span class="number">0</span></span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> matrix</span><br><span class="line">}</span><br></pre></td></tr></table></figure>]]></content>
<tags>
<tag> leetcode </tag>
<tag> 算法 </tag>
</tags>
</entry>
<entry>
<title>记一次请求转发处理</title>
<link href="/2019/09/22/%E8%AE%B0%E4%B8%80%E6%AC%A1%E8%AF%B7%E6%B1%82%E8%BD%AC%E5%8F%91%E5%A4%84%E7%90%86/"/>
<url>/2019/09/22/%E8%AE%B0%E4%B8%80%E6%AC%A1%E8%AF%B7%E6%B1%82%E8%BD%AC%E5%8F%91%E5%A4%84%E7%90%86/</url>
<content type="html"><![CDATA[<p>公司部分项目后端迁移,迁移后需要在请求头里面加一个用来标识用户 id 的字段</p><a id="more"></a><h3 id="背景"><a href="#背景" class="headerlink" title="背景:"></a>背景:</h3><blockquote><p>公司部分项目后端迁移,迁移后需要在请求头里面加一个用来标识用户 id 的字段</p></blockquote><h3 id="思路:"><a href="#思路:" class="headerlink" title="思路:"></a>思路:</h3><blockquote><p>其实思路理解起来很简单</p></blockquote><ul><li>方案一、<br>1、在用户登陆的时候在 server 端拿出用户 id 字段<br>2、将这个字段挂载到 koa 的上下文中<br>3、node 请求代理转发的时候将这个值通过 ctx.req.header[‘userId’] = ctx.userId;这种方式挂载到 request 中转发到后端</li><li>方案二<br>1、在用户登陆的时候在 server 端拿出标识用户 id 的字段<br>2、将这个字段通过<script>window.User={}</script>的方式在页面渲染的时候挂载到 window 全局对象中<br>3、在 client 端用户请求时 header 中带入这个所需的字段和值也可</li></ul><h3 id="遇到的问题"><a href="#遇到的问题" class="headerlink" title="遇到的问题"></a>遇到的问题</h3><blockquote><p>1、本项目与其他所负责的项目不同,在 node 端代理转发引的是开源脚手架,没有 header 这种外部传入 option,即无法通过 koa 上下文在代理转发的方式将所需传入的字段和值注入 header 中,方案一搁浅<br>2、在用方案二做处理时,可以参看以下代码:</p></blockquote><p>模版注入: spa.js</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">await</span> ctx.render(<span class="string">'layout.js'</span>, { user })</span><br></pre></td></tr></table></figure><p>在 layout.js 模版中</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">;<span class="function">(<span class="params">{ user }</span>) =></span> {</span><br><span class="line"> <span class="keyword">return</span> <span class="string">`</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"> <script></span></span><br><span class="line"><span class="string"> window.User = {</span></span><br><span class="line"><span class="string"> userId: <span class="subst">${user.id}</span>,</span></span><br><span class="line"><span class="string"> };</span></span><br><span class="line"><span class="string"> </script></span></span><br><span class="line"><span class="string"> `</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>request 在 client 端</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> newHeaders = {</span><br><span class="line"> ...headers,</span><br><span class="line"> UserId: (<span class="built_in">window</span>.User && <span class="built_in">window</span>.User.userId) || <span class="string">''</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><blockquote><p>如上,script 在模版中的引入写在页面最底部,一开始通过 log 日志发现,winodw 中挂载的用户信息总是在请求以后才会正常展示,在请求前总是 log 出默认的空值</p></blockquote><p>原因:</p><blockquote><p>渲染页面时,lib 是渲染在当前项目所有脚本的最前面,如果将挂载用户信息的脚本写在最后面也就是在 jsx 文件加载完以后再挂载用户信息,这样的话,用户信息的挂载就没有用了,即在该项目中,挂载用户信息的 script 应写在页面渲染的最前面,可直接挂载在 header 中,这样 window 中的 user 值即可在请求前挂载</p></blockquote><h3 id="写在最后"><a href="#写在最后" class="headerlink" title="写在最后"></a>写在最后</h3><p>1、注意总结<br>2、注意细节</p>]]></content>
<tags>
<tag> koa </tag>
</tags>
</entry>
<entry>
<title>两个数组的交集 II</title>
<link href="/2019/09/01/%E4%B8%A4%E4%B8%AA%E6%95%B0%E7%BB%84%E7%9A%84%E4%BA%A4%E9%9B%86-II/"/>
<url>/2019/09/01/%E4%B8%A4%E4%B8%AA%E6%95%B0%E7%BB%84%E7%9A%84%E4%BA%A4%E9%9B%86-II/</url>
<content type="html"><![CDATA[]]></content>
</entry>
<entry>
<title>找到字符串中所有字母异位词</title>
<link href="/2019/09/01/%E6%89%BE%E5%88%B0%E5%AD%97%E7%AC%A6%E4%B8%B2%E4%B8%AD%E6%89%80%E6%9C%89%E5%AD%97%E6%AF%8D%E5%BC%82%E4%BD%8D%E8%AF%8D/"/>
<url>/2019/09/01/%E6%89%BE%E5%88%B0%E5%AD%97%E7%AC%A6%E4%B8%B2%E4%B8%AD%E6%89%80%E6%9C%89%E5%AD%97%E6%AF%8D%E5%BC%82%E4%BD%8D%E8%AF%8D/</url>
<content type="html"><![CDATA[]]></content>
</entry>
<entry>
<title>时间safari与chrome</title>
<link href="/2019/09/01/%E6%97%B6%E9%97%B4safari%E4%B8%8Echrome/"/>
<url>/2019/09/01/%E6%97%B6%E9%97%B4safari%E4%B8%8Echrome/</url>
<content type="html"><![CDATA[<p>关于时间问题 safari 与 chrome 的兼容处理。</p><a id="more"></a><h3 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h3><blockquote><p>最近所负责的项目遇到这样一个问题,在 safari 浏览器中,从后台拉取的时间值在前端展示为 NaN-NaN,并且这个问题只是在 iPhone 手机中遇到,安卓是好的。</p></blockquote><p>在解决这个问题时,通过 charles 线上 remote 到本地代码 alert 查看,发现在通过本地代码 alert 的时候时间值展示为 NaN,这说明不光线上,本地也可以复现到这个问题</p><h3 id="解决过程"><a href="#解决过程" class="headerlink" title="解决过程"></a>解决过程</h3><p>想到 iphone 与安卓对应的原生浏览器不同,本地用 safari 访问项目时,发现也会出现同样的问题,究其原因,发现:</p><blockquote><p>1、在 js 中处理 Date 时,发现 IE 与 Safari 和其他浏览器的支持方式不一样<br>例如: 2019-09-01 00:00:00<br>在其他浏览器中,使用这个格式的字符串进行 new Date 操作没有问题,但是在 Safari 会提示 Invalid Date<br>Safari 中不支持’-‘ 格式的日期字符串,将其替换成’/‘变成 2019/09/01 00:00:00 即可正常使用<br>2、例如:2019/09/01T00:00:00 此格式字符串在 Safari 中也是得不到支持的,需要将’T’替换成空格,变成 2019/09/01 00:00:00 格式<br>这个问题直接导致 IE 与 Safari 浏览器中不能处理与 Date 相关的程序</p></blockquote><h3 id="解决办法"><a href="#解决办法" class="headerlink" title="解决办法"></a>解决办法</h3><p><strong>办法一:</strong></p><blockquote><p>进行两个符号的替换即可。’-‘替换成’/‘, ‘T’替换成空格</p></blockquote><blockquote><p>项目中原先存在 moment 包,将原先用 new Date 的方式用 moment().format 的方式引入</p></blockquote>]]></content>
<tags>
<tag> javascript 兼容 </tag>
</tags>
</entry>
<entry>
<title>es6-promise摘</title>
<link href="/2019/09/01/es6-promise%E6%91%98/"/>
<url>/2019/09/01/es6-promise%E6%91%98/</url>
<content type="html"><![CDATA[<blockquote><p>最近看到一篇文章比较好,摘抄下来可以以后学习查看<a href="https://zhuanlan.zhihu.com/p/30797777" target="_blank" rel="noopener">Promise 必知必会(十道题)</a></p></blockquote><a id="more"></a><h3 id="一"><a href="#一" class="headerlink" title="一"></a>一</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> promise = <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function">(<span class="params">resolve, reject</span>) =></span> {</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="number">1</span>);</span><br><span class="line"> resolve();</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="number">2</span>);</span><br><span class="line">});</span><br><span class="line">promise.then(<span class="function"><span class="params">()</span> =></span> {</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="number">3</span>);</span><br><span class="line">});</span><br><span class="line"><span class="built_in">console</span>.log(<span class="number">4</span>);</span><br></pre></td></tr></table></figure><p>运行结果</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">1</span>;</span><br><span class="line"><span class="number">2</span>;</span><br><span class="line"><span class="number">3</span>;</span><br><span class="line"><span class="number">4</span>;</span><br></pre></td></tr></table></figure><blockquote><p>解释:Promise 构造函数是同步执行的,promise.then 中的函数是异步执行的。</p></blockquote><h3 id="二"><a href="#二" class="headerlink" title="二"></a>二</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> promise1 = <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function">(<span class="params">resolve, reject</span>) =></span> {</span><br><span class="line"> setTimeout(<span class="function"><span class="params">()</span> =></span> {</span><br><span class="line"> resolve(<span class="string">"success"</span>);</span><br><span class="line"> }, <span class="number">1000</span>);</span><br><span class="line">});</span><br><span class="line"><span class="keyword">const</span> promise2 = promise1.then(<span class="function"><span class="params">()</span> =></span> {</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> <span class="built_in">Error</span>(<span class="string">"error!!!"</span>);</span><br><span class="line">});</span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(<span class="string">"promise1"</span>, promise1);</span><br><span class="line"><span class="built_in">console</span>.log(<span class="string">"promise2"</span>, promise2);</span><br><span class="line"></span><br><span class="line">setTimeout(<span class="function"><span class="params">()</span> =></span> {</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"promise1"</span>, promise1);</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"promise2"</span>, promise2);</span><br><span class="line">}, <span class="number">2000</span>);</span><br></pre></td></tr></table></figure><p>运行结果</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">promise1 <span class="built_in">Promise</span> { <pending> }</span><br><span class="line">promise2 <span class="built_in">Promise</span> { <pending> }</span><br><span class="line">(node:<span class="number">50928</span>) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: <span class="number">1</span>): <span class="built_in">Error</span>: error!!!</span><br><span class="line">(node:<span class="number">50928</span>) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process <span class="keyword">with</span> a non-zero exit code.</span><br><span class="line">promise1 <span class="built_in">Promise</span> { <span class="string">'success'</span> }</span><br><span class="line">promise2 <span class="built_in">Promise</span> {</span><br><span class="line"> <rejected> <span class="built_in">Error</span>: error!!!</span><br><span class="line"> at promise.then (...)</span><br><span class="line"> at <anonymous> }</span><br></pre></td></tr></table></figure><blockquote><p>解释: Promise 只有三种状态:pending,fulfilled 或 reject.状态改变只能 pending->fulfilled 或者 pending->rejected,状态一旦改变则不能再变,上面 promise2 并不是 promise1,而是返回的一个新的 Promise 实例。</p></blockquote><h3 id="三"><a href="#三" class="headerlink" title="三"></a>三</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> promise = <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function">(<span class="params">resolve, reject</span>) =></span> {</span><br><span class="line"> resolve(<span class="string">"success1"</span>);</span><br><span class="line"> reject(<span class="string">"error"</span>);</span><br><span class="line"> resolve(<span class="string">"success2"</span>);</span><br><span class="line">});</span><br><span class="line"></span><br><span class="line">promise</span><br><span class="line"> .then(<span class="function"><span class="params">res</span> =></span> {</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"then: "</span>, res);</span><br><span class="line"> })</span><br><span class="line"> .catch(<span class="function"><span class="params">err</span> =></span> {</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"catch: "</span>, err);</span><br><span class="line"> });</span><br></pre></td></tr></table></figure><p>运行结果:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">then: success1;</span><br></pre></td></tr></table></figure><blockquote><p>解释:构造函数中的 resolve 或 reject 只有第一次执行有效,多次调用没有任何作用,呼应代码二结论:promise 状态一旦改变则不能再变。</p></blockquote><h3 id="四"><a href="#四" class="headerlink" title="四"></a>四</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">Promise</span>.resolve(<span class="number">1</span>)</span><br><span class="line"> .then(<span class="function"><span class="params">res</span> =></span> {</span><br><span class="line"> <span class="built_in">console</span>.log(res);</span><br><span class="line"> <span class="keyword">return</span> <span class="number">2</span>;</span><br><span class="line"> })</span><br><span class="line"> .catch(<span class="function"><span class="params">err</span> =></span> {</span><br><span class="line"> <span class="keyword">return</span> <span class="number">3</span>;</span><br><span class="line"> })</span><br><span class="line"> .then(<span class="function"><span class="params">res</span> =></span> {</span><br><span class="line"> <span class="built_in">console</span>.log(res);</span><br><span class="line"> });</span><br></pre></td></tr></table></figure><p>运行结果:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">1</span>;</span><br><span class="line"><span class="number">2</span>;</span><br></pre></td></tr></table></figure><blockquote><p>解释:promise 可以链式调用。提起链式调用我们通常会想到通过 return this 实现,不过 Promise 并不是这样实现的。promise 每次调用 .then 或者 .catch 都会返回一个新的 promise,从而实现了链式调用。</p></blockquote>]]></content>
<tags>
<tag> javascript promise </tag>
</tags>
</entry>
<entry>
<title>优化整理之react14至16</title>
<link href="/2019/08/26/%E4%BC%98%E5%8C%96%E6%95%B4%E7%90%8601/"/>
<url>/2019/08/26/%E4%BC%98%E5%8C%96%E6%95%B4%E7%90%8601/</url>
<content type="html"><![CDATA[<p>总结了一些负责项目升级点</p><a id="more"></a><h3 id="以下总结摘自:"><a href="#以下总结摘自:" class="headerlink" title="以下总结摘自:"></a>以下总结摘自:</h3><p><strong><a href="https://blog.csdn.net/mapbar_front/article/details/80187123" target="_blank" rel="noopener">React16 版本更新的新特性</a><br><a href="https://blog.csdn.net/Napoleonxxx/article/details/81120854" target="_blank" rel="noopener">React v15 到 v16.3, v16.4 新生命周期总结以及使用场景</a><br><a href="https://blog.csdn.net/u013451157/article/details/78719374" target="_blank" rel="noopener">【ReactJS】V0.14 版本前后的变化</a><br><a href="https://www.jianshu.com/p/a8bc5b292561" target="_blank" rel="noopener">react14 到 15 版本主要变更</a><br><a href="https://blog.csdn.net/xiaozhuo_tang/article/details/88878858" target="_blank" rel="noopener">React15 至今的重要变化人肉梳理</a></strong></p><h3 id="总结如下:"><a href="#总结如下:" class="headerlink" title="总结如下:"></a>总结如下:</h3><ul><li><h3 id="react-14-到-15"><a href="#react-14-到-15" class="headerlink" title="react 14 到 15"></a><strong>react 14 到 15</strong></h3><ul><li>当在挂载组件时使用 document.createElement 而不是 innerHTML,这样我们就摆脱了 data-reactid。并且 document.createElement 在现代浏览器中也更快;<br><strong>值得注意:</strong> data-reactid 在 client 端已经去除了,但依旧存在在服务端渲染中,不过更小更简 单是简单递增的。</li><li>由于历史原因对 SVG 的不完整支持,在 React 15 中支持了所有被现代浏览器所支持的 SVG 属性;</li><li>社区(Michael Wiencek)的贡献使得 React 15 不再需要多余的对 text 进行包裹;</li><li>渲染 Null 现在使用 comment nodes(注释节点)了;</li><li>函数式组件现在也能返回 null 了;</li><li>移除和弃用<ul><li>移除包括:<br><strong>indDOMNode,render,renderToSring,renderToStaticMarkup 和 unmountComponentAtNode</strong>几个顶级 API,不过他们都能在<strong>ReactDom 和 ReactDomServer</strong>中找到;</li><li>移除的插件: <strong>cloneWithProps 和 batchedUpdates</strong></li><li>移除的组件实例方法:<strong>setProps、replaceProps 和 getDOMNode</strong></li></ul></li></ul></li><li><h3 id="react-15-的一些重大变化"><a href="#react-15-的一些重大变化" class="headerlink" title="react 15 的一些重大变化"></a><strong>react 15 的一些重大变化</strong></h3><ul><li>彻底分离<strong>React 和 React DOM</strong>,现在 React 中将只含有与渲染无关的代码例如:<strong>React.Component 和 React.createElement()</strong></li><li>React DOM Server 包体积大小几乎与 React 相当,因为他有一份自己的 React reconciler。<strong>不建议在 client 端使用 React DOM Server</strong></li><li>拆分了 React.PropTypes 和 React.createClass 到独立的包中;</li><li>React.PropTypes 迁移到了 prop-types 包中,迁移指南;</li><li>React.createClass 迁移到 create-react-class 中,但由于 ES2015 对 class 的支持,React 也开始使用原生的 class 来创建 components;</li><li>data-和 aria-的属性将会任我们自定义</li></ul></li><li><h3 id="react-16-的一些重大变化"><a href="#react-16-的一些重大变化" class="headerlink" title="react 16 的一些重大变化"></a><strong>react 16 的一些重大变化</strong></h3><ul><li>NEW FEATURE:fragments、error boundaries(已经介绍过不做赘述)、portals</li><li>NEW SUPPORT:custom DOM attributes</li><li>IMPROVEMENT:server-side rendering</li><li>render 函数能 return:React elements、Array 和<a href="https://reactjs.org/docs/fragments.html" target="_blank" rel="noopener">fragments</a>、Portals、Booleans or null、String and numbers</li><li><a href="https://reactjs.org/docs/portals.html" target="_blank" rel="noopener">portals</a>是由 React DOM 提供的方法 createPortal(child, container)所创建出来的,能够让元素脱离于 React Tree 在 DOM Tree 的其他地方出现,但事件冒泡依旧是遵循 React DOM tree 的。这个方法可以用来实现 Modal、dialog、tooltips 等。</li><li>更好的服务端渲染:支持流式的传输、三倍快与 React 15 的渲染速度。值得注意的是,React 16 hydrate 工作在 client 端时会使用已经在服务端渲染好的 DOM 结构,而不会做细致检查,只会在 Client 端提示你数据不统一,并且也不建议在 server 端渲染和 client 端 hydrate 时数据不同</li><li>降低了包大小:react 5.3kb(2.2kb gzipped)、react-dom 103.7kb(32.6kb gzipped)</li><li>Breaking changes 摘要:<ul><li>setState(null)不再会引起更新、setState 的 callback 将会在 componentDidMount/componentDidUpdate 后立即执行,而不是在所有 components 渲染后执行</li><li><b>替换<a>时,B 的 componentWillMount 总会发生在 A 的 componentWIllUnmount 之前</a></b></li><li>shallow renderer 不会再出发 componentDidUpdate 因为 DOM refs 是拿不到的,并与 componentDidMount 表现一致</li><li>功能剥离:React.PropTypes => prop-types、React.Dom => react-dom-factories、react-addons-test-utils => react-dom/test-utils、shallow renderer => react-test-renderer/shallow</li></ul></li><li>React 16 依赖于 Map 和 Set,如果要支持老旧浏览器和设备,应该引入全局的 polyfill,例如 core-js 和 babel-polyfill,同样也依赖于 requestAnimationFrame,可以用 raf 包来弥补</li><li>异步渲染的更新:Two Demos<ul><li>ime slicing、suspense</li></ul></li><li>正式的<a href="https://reactjs.org/docs/context.html" target="_blank" rel="noopener">Context API</a></li><li><a href="https://reactjs.org/docs/refs-and-the-dom.html" target="_blank" rel="noopener">createRef API</a>、<a href="https://reactjs.org/docs/refs-and-the-dom.html" target="_blank" rel="noopener">forwardRef API</a></li><li>生命周期的变更,可参看<a href="https://blog.csdn.net/xiaozhuo_tang/article/details/83824824" target="_blank" rel="noopener">【译】React16.3+ 生命周期</a><ul><li>componentWillMount、componentWillReceiveProps、componentWillUpdate 都不建议在使用并且在 17 中将会被冠上 UNSAFE_的前缀;</li><li>新增了 getDerivedStateFromProps、getSnapshotBeforeUpdate 两个生命周期</li></ul></li><li>React 16.5.0 以上在 React Devtools 新增了一个新功能 Profiler,来帮助我们梳理 React 项目各组件的性能</li><li>React.memo 让 Function 组件用上 PureComponent</li><li>React.lazy 配合 Suspence 和动态引入 import(’’)来优化体验(例如 loading 状态)</li><li>static contextType</li><li><a href="https://zh-hans.reactjs.org/docs/hooks-intro.html" target="_blank" rel="noopener">hooks</a></li></ul></li></ul><p><strong><a href="https://zh-hans.reactjs.org/docs/getting-started.html" target="_blank" rel="noopener">参考学习</a></strong></p>]]></content>
<tags>
<tag> react </tag>
</tags>
</entry>
<entry>
<title>反转部分单链表</title>
<link href="/2019/08/18/%E5%8F%8D%E8%BD%AC%E9%83%A8%E5%88%86%E5%8D%95%E9%93%BE%E8%A1%A8/"/>
<url>/2019/08/18/%E5%8F%8D%E8%BD%AC%E9%83%A8%E5%88%86%E5%8D%95%E9%93%BE%E8%A1%A8/</url>
<content type="html"><![CDATA[<p>javascript实现单链表的部分反转</p><a id="more"></a><h3 id="题目描述"><a href="#题目描述" class="headerlink" title="题目描述"></a>题目描述</h3><p>反转从位置 m 到 n 的链表。请使用一趟扫描完成反转。</p><p><strong>说明:</strong><br>1 ≤ m ≤ n ≤ 链表长度。</p><p><strong>示例:</strong></p><blockquote><p>输入: 1->2->3->4->5->NULL, m = 2, n = 4<br> 输出: 1->4->3->2->5->NULL</p></blockquote><p> <strong>解答:</strong><br> 本题有可能存在换头的问题,比如题目的第二个例子,所以函数应该返回调整后的新头节点,整个处理过程如下:<br> 1、先判断是否满足 1 <= from <= to <= N,如果不满足,则直接返回原来的头节点<br> 2、找到第from - 1个节点fPre,和第to + 1个节点 fPos. fPre即是要反转部分的前一个节点。fPos是反转部分的后一个节点。把反转的部分先反转,然后正确地链接fPre和 fPos.<br> 例如:1 -> 2 -> 3 -> 4 -> NULL,假设fPre为节点1,fPos为节点4,要反转部分为2 -> 3。先反转成3->2,然后fPre连向即诶单3,节点2连向fPos,就变成了 1 -> 3 -> 2 -> 4 -> NULL.<br>3, 如果fPre为NULL,说明反转部分是包含头节点的,则返回新的头节点,也就是没反转之前反转部分的最后一个节点,也是反转之后反转部分的第一个节点。如果fPre不为null,则返回旧的头节点。全部过程代码如下:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Definition for singly-linked list.</span></span><br><span class="line"><span class="comment"> * function ListNode(val) {</span></span><br><span class="line"><span class="comment"> * this.val = val;</span></span><br><span class="line"><span class="comment"> * this.next = null;</span></span><br><span class="line"><span class="comment"> * }</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @param {ListNode} head</span></span><br><span class="line"><span class="comment"> * @param {number} m</span></span><br><span class="line"><span class="comment"> * @param {number} n</span></span><br><span class="line"><span class="comment"> * @return {ListNode}</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">var</span> reverseBetween = <span class="function"><span class="keyword">function</span>(<span class="params">head, m, n</span>) </span>{</span><br><span class="line"> <span class="keyword">let</span> len = <span class="number">0</span>, node1 = head, fPre = <span class="literal">null</span>, fPos = <span class="literal">null</span>;</span><br><span class="line"> <span class="keyword">while</span> (ndoe1 !== <span class="literal">null</span>) {</span><br><span class="line"> fPre = m - <span class="number">1</span> === len ? node1 : fPre;</span><br><span class="line"> fPos = n + <span class="number">1</span> === len ? node1 : fPos;</span><br><span class="line"> node1 = node1.next;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (m > n || m < <span class="number">1</span> || n > len) <span class="keyword">return</span> head;</span><br><span class="line"> node1 = fPre == <span class="literal">null</span> ? head : fPre.next;</span><br><span class="line"> <span class="keyword">let</span> node2 = node1.next;</span><br><span class="line"> node1.next = fPos;</span><br><span class="line"> <span class="keyword">let</span> next = <span class="literal">null</span>;</span><br><span class="line"> <span class="keyword">while</span> (node2 !== fPos) {</span><br><span class="line"> next = node2.next;</span><br><span class="line"> node2.next = node1;</span><br><span class="line"> nod1 = node2;</span><br><span class="line"> node2 = next;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (fPre !== <span class="literal">null</span>) {</span><br><span class="line"> fPre.next = node1;</span><br><span class="line"> <span class="keyword">return</span> headl</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> node1;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>]]></content>
<categories>
<category> 算法 </category>
</categories>
<tags>
<tag> javascript 单链表 leetcode </tag>
</tags>
</entry>
<entry>
<title>单链表反转</title>
<link href="/2019/08/14/%E5%8D%95%E9%93%BE%E8%A1%A8%E5%8F%8D%E8%BD%AC/"/>
<url>/2019/08/14/%E5%8D%95%E9%93%BE%E8%A1%A8%E5%8F%8D%E8%BD%AC/</url>
<content type="html"><![CDATA[<p>javascript实现单链表的反转</p><a id="more"></a><p>###题目描述<br>反转一个单链表<br><strong>示例</strong></p><blockquote><p>输入 1 -> 2 -> 3 -> 4 -> 5 -> null<br> 输出 5 -> 4 -> 3 -> 2 -> 1 -> null</p></blockquote><p> <strong>进阶:你可以迭代或递归地反转链表。你能否用两种方法解决这道题?</strong></p><p><strong>思路:</strong><br>循环遍历每个节点:</p><ul><li>记录当前节点的下一个节点</li><li>将当前节点指向当前节点的前一个节点</li><li>当前节点的前一个节点移到当前节点</li><li>当前节点移到当前节点的下一个节点<br>整个函数返回链表的新的头节点<br>如下图所示<br><img src="/img/reverse_link.png" alt="单链表反转思路图"></li></ul><p>javascript对单链表的结构构造如下:<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">linkNode</span>(<span class="params">val</span>) </span>{</span><br><span class="line"> <span class="keyword">this</span>.val = val;</span><br><span class="line"> <span class="keyword">this</span>.next = <span class="literal">null</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><p>整体代码如下:<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Definition for singly-linked list.</span></span><br><span class="line"><span class="comment"> * function ListNode(val) {</span></span><br><span class="line"><span class="comment"> * this.val = val;</span></span><br><span class="line"><span class="comment"> * this.next = null;</span></span><br><span class="line"><span class="comment"> * }</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @param {ListNode} head</span></span><br><span class="line"><span class="comment"> * @return {ListNode}</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">var</span> reverseList = <span class="function"><span class="keyword">function</span> (<span class="params">head</span>) </span>{</span><br><span class="line"> <span class="keyword">let</span> pre = <span class="literal">null</span>;</span><br><span class="line"> <span class="keyword">let</span> next = <span class="literal">null</span>;</span><br><span class="line"> <span class="keyword">while</span> (head) {</span><br><span class="line"> next = head.next;</span><br><span class="line"> head.next = pre;</span><br><span class="line"> pre = head;</span><br><span class="line"> head = next;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> pre;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><p>注意: 本来打算用node转数组然后用数组reverse写的,但是在代码中需要返回node格式的数据,所以在执行代码中报错。如下</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> reverseList = <span class="function"><span class="keyword">function</span> (<span class="params">head</span>) </span>{</span><br><span class="line"> <span class="keyword">let</span> result = [];</span><br><span class="line"> <span class="keyword">while</span> (head) {</span><br><span class="line"> result.push(head);</span><br><span class="line"> head = head.next;</span><br><span class="line"> }</span><br><span class="line"> result = result.reverse();</span><br><span class="line"> <span class="keyword">return</span> result;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>这种怎么说呢,可能思路可以,但是不符合题目要求。</p>]]></content>
<categories>
<category> 算法 </category>
</categories>
<tags>
<tag> javascript leetcode 链表 </tag>
</tags>
</entry>
<entry>
<title>三数之和</title>
<link href="/2019/08/14/%E4%B8%89%E6%95%B0%E4%B9%8B%E5%92%8C/"/>
<url>/2019/08/14/%E4%B8%89%E6%95%B0%E4%B9%8B%E5%92%8C/</url>
<content type="html"><![CDATA[<p>给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。</p><a id="more"></a><p><a href="https://leetcode-cn.com/problems/two-sum/" target="_blank" rel="noopener">leetcode</a></p><p>你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。示例:</p><blockquote><p>给定 nums = [2, 7, 11, 15], target = 9<br>因为 nums[0] + nums[1] = 2 + 7 = 9<br>所以返回 [0, 1]</p></blockquote><p>题解:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @param {number[]} nums</span></span><br><span class="line"><span class="comment"> * @param {number} target</span></span><br><span class="line"><span class="comment"> * @return {number[]}</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">var</span> twoSum = <span class="function"><span class="keyword">function</span>(<span class="params">nums, target</span>) </span>{</span><br><span class="line"> <span class="keyword">let</span> numsMap = {};</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i < nums.length; i++) {</span><br><span class="line"> <span class="keyword">if</span> (numsMap[target - nums[i]] >= <span class="number">0</span>) {</span><br><span class="line"> <span class="keyword">return</span> [numsMap[target - nums[i]], i];</span><br><span class="line"> }</span><br><span class="line"> numsMap[nums[i]] = i;</span><br><span class="line"> }</span><br><span class="line">};</span><br></pre></td></tr></table></figure>]]></content>
<categories>
<category> 算法 </category>
</categories>
<tags>
<tag> javascript leetcode 算法 </tag>
</tags>
</entry>
<entry>
<title>html转markdown</title>
<link href="/2019/08/14/html%E8%BD%ACmarkdown/"/>
<url>/2019/08/14/html%E8%BD%ACmarkdown/</url>
<content type="html"><![CDATA[<p>根据路径url和cookie截取指定页面html并将整个页面转成markdown格式输出。<br><a id="more"></a></p><h3 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h3><blockquote><p>最近接到一个需求,系统迁移,需要将公司wiki通过代码的形式转成markdown的形式然后将对应的markdown在另一个系统中转成html,在另一个系统中显示出来<br>for me: 需要我将wiki转成markdown的形式,然后供其他同事使用</p></blockquote><h3 id="解决方案"><a href="#解决方案" class="headerlink" title="解决方案"></a>解决方案</h3><blockquote><p>01、传入 {url, cookie}<br> 02、获取 dom, 截取某个id内的url<br> 03、将截取到的html转成xml<br> 04、递归xml节点信息,边遍历边将指定节点信息转成markdown格式,遍历后至节点hasRead为true<br> 05、输出markdownStr</p></blockquote><h3 id="难点"><a href="#难点" class="headerlink" title="难点"></a>难点</h3><blockquote><p>01、如何根据 url和cookie去获取dom<br> 02、wiki获取的dom有混淆,遍历时需要排除已遍历的节点信息<br> 03、行内元素和块级元素的处理<br> 04、对wiki内存在表格和code的元素,截取的html都是table,如何根据信息将表格和code区分开<br> 05、某些dom元素渲染如下<code><p><strong>确认</strong><p>信息</p><a>链接</a>如下</p></code> ,这种dom树如何正确转成markdown</p></blockquote><h3 id="对封装的代码解析如下"><a href="#对封装的代码解析如下" class="headerlink" title="对封装的代码解析如下:"></a>对封装的代码解析如下:</h3><ul><li><h4 id="入口"><a href="#入口" class="headerlink" title="入口"></a><strong>入口</strong></h4></li></ul><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">"use strict"</span>;</span><br><span class="line"><span class="keyword">const</span> { ConfluenceToMarkdown } = <span class="built_in">require</span>(<span class="string">"lib/index.js"</span>);</span><br><span class="line"></span><br><span class="line"><span class="built_in">module</span>.exports = <span class="function"><span class="keyword">function</span>(<span class="params">options</span>) </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> ConfluenceToMarkdown(options);</span><br><span class="line">};</span><br></pre></td></tr></table></figure><ul><li><strong>lib下index入口</strong></li></ul><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">'use strict'</span>;</span><br><span class="line"><span class="keyword">const</span> _ = <span class="built_in">require</span>(<span class="string">'lodash'</span>);</span><br><span class="line"><span class="keyword">const</span> assert = <span class="built_in">require</span>(<span class="string">'assert'</span>);</span><br><span class="line"><span class="keyword">const</span> { confluence2md } = <span class="built_in">require</span>(<span class="string">'./lib/confluence2md'</span>);</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">ConfluenceToMarkdown</span> </span>{</span><br><span class="line"> <span class="keyword">constructor</span>(options) {</span><br><span class="line"> <span class="keyword">var</span> options =</span><br><span class="line"> <span class="built_in">arguments</span>.length > <span class="number">0</span> && <span class="built_in">arguments</span>[<span class="number">0</span>] !== <span class="literal">undefined</span> ? <span class="built_in">arguments</span>[<span class="number">0</span>] : {};</span><br><span class="line"> assert.ok(</span><br><span class="line"> options.url,</span><br><span class="line"> <span class="string">'缺少confluence文件路径----myfe/confluencetomarkdown'</span></span><br><span class="line"> );</span><br><span class="line"> assert.ok(</span><br><span class="line"> options.cookie,</span><br><span class="line"> <span class="string">'缺少当前用户cookie----myfe/confluencetomarkdown'</span></span><br><span class="line"> );</span><br><span class="line"></span><br><span class="line"> <span class="keyword">this</span>.url = options.url;</span><br><span class="line"> <span class="keyword">this</span>.cookie = options.cookie;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">async</span> tomarkdown() {</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function">(<span class="params">resolve, reject</span>) =></span> {</span><br><span class="line"> <span class="keyword">if</span> (!<span class="keyword">this</span>.url || !<span class="keyword">this</span>.cookie) {</span><br><span class="line"> <span class="keyword">return</span> <span class="built_in">Promise</span>.resolve({</span><br><span class="line"> success: <span class="literal">false</span>,</span><br><span class="line"> code: <span class="number">400</span>,</span><br><span class="line"> message: <span class="string">'请求参数缺失'</span></span><br><span class="line"> });</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (!_.isString(<span class="keyword">this</span>.url) ||</span><br><span class="line"> !_.isString(<span class="keyword">this</span>.cookie) ||</span><br><span class="line"> !<span class="keyword">new</span> <span class="built_in">RegExp</span>(<span class="string">'https://wiki.maoyan.com/pages'</span>).test(<span class="keyword">this</span>.url)</span><br><span class="line"> ) {</span><br><span class="line"> <span class="keyword">return</span> <span class="built_in">Promise</span>.resolve({</span><br><span class="line"> success: <span class="literal">false</span>,</span><br><span class="line"> code: <span class="number">400</span>,</span><br><span class="line"> message: <span class="string">'请求参数格式不正确'</span></span><br><span class="line"> });</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> confluence2md({ <span class="attr">url</span>: <span class="keyword">this</span>.url, <span class="attr">cookie</span>: <span class="keyword">this</span>.cookie });</span><br><span class="line"> });</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="built_in">module</span>.exports = ConfluenceToMarkdown;</span><br></pre></td></tr></table></figure><ul><li><strong>confluence2md 文件,利用superagent包将指定url获取dom节点信息</strong></li></ul><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> superagent = <span class="built_in">require</span>(<span class="string">'superagent'</span>);</span><br><span class="line"><span class="keyword">const</span> { html2Xml } = <span class="built_in">require</span>(<span class="string">'./util/html2xml'</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> confluence2md = <span class="keyword">async</span> (url, cookie) => {</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function">(<span class="params">resolve, reject</span>) =></span> {</span><br><span class="line"> superagent.get(url)</span><br><span class="line"> .set(<span class="string">'Cookie'</span>, cookie)</span><br><span class="line"> .end(<span class="function">(<span class="params">err, res</span>) =></span> {</span><br><span class="line"> <span class="keyword">if</span> (err) {</span><br><span class="line"> <span class="built_in">console</span>.info(<span class="string">'get page error url => '</span> + url);</span><br><span class="line"> <span class="keyword">return</span> reject({</span><br><span class="line"> success: <span class="literal">false</span>,</span><br><span class="line"> code: <span class="number">500</span>,</span><br><span class="line"> message: <span class="string">'url转换出错'</span></span><br><span class="line"> });</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">const</span> markdownText = <span class="keyword">await</span> html2Xml(res.text);</span><br><span class="line"> <span class="keyword">return</span> resolve({</span><br><span class="line"> success: <span class="literal">true</span>,</span><br><span class="line"> code: <span class="number">200</span>,</span><br><span class="line"> message: <span class="string">'成功转换markdown'</span>,</span><br><span class="line"> data: markdownText</span><br><span class="line"> });</span><br><span class="line"> });</span><br><span class="line"> });</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="built_in">module</span>.exports = confluence2md;</span><br></pre></td></tr></table></figure><ul><li><p><strong>html2xml, 截取指定id内dom信息,转成xml,递归遍历xml节点信息,转成markdown格式</strong></p><h4 id="依赖和标签"><a href="#依赖和标签" class="headerlink" title="依赖和标签"></a>依赖和标签</h4></li></ul><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> xpath = <span class="built_in">require</span>(<span class="string">'xpath'</span>);</span><br><span class="line"><span class="keyword">const</span> xmlDom = <span class="built_in">require</span>(<span class="string">'xmldom'</span>).DOMParser;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> httpUrl = <span class="string">'https://baidu.com'</span>; <span class="comment">// url</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> markdownStr = <span class="string">``</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> IMGSRC = <span class="string">'data-image-src'</span>;</span><br><span class="line"><span class="keyword">const</span> BASEURL = <span class="string">'data-base-url'</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> tagHtml = [</span><br><span class="line"> {<span class="attr">key</span>: <span class="string">'h1'</span>, <span class="attr">value</span>: <span class="string">'#'</span>},</span><br><span class="line"> {<span class="attr">key</span>: <span class="string">'h2'</span>, <span class="attr">value</span>: <span class="string">'##'</span>},</span><br><span class="line"> {<span class="attr">key</span>: <span class="string">'h3'</span>, <span class="attr">value</span>: <span class="string">'###'</span>},</span><br><span class="line"> {<span class="attr">key</span>: <span class="string">'h4'</span>, <span class="attr">value</span>: <span class="string">'####'</span>},</span><br><span class="line"> {<span class="attr">key</span>: <span class="string">'h5'</span>, <span class="attr">value</span>: <span class="string">'#####'</span>},</span><br><span class="line"> {<span class="attr">key</span>: <span class="string">'h6'</span>, <span class="attr">value</span>: <span class="string">'######'</span>},</span><br><span class="line"> {<span class="attr">key</span>: <span class="string">'strong'</span>, <span class="attr">value</span>: <span class="string">'**'</span>},</span><br><span class="line"> {<span class="attr">key</span>: <span class="string">'hr'</span>, <span class="attr">value</span>: <span class="string">'---'</span>},</span><br><span class="line"> {<span class="attr">key</span>: <span class="string">'p'</span>, <span class="attr">value</span>: <span class="string">''</span>},</span><br><span class="line"> {<span class="attr">key</span>: <span class="string">'span'</span>, <span class="attr">value</span>: <span class="string">''</span>},</span><br><span class="line"> {<span class="attr">key</span>: <span class="string">'pre'</span>, <span class="attr">value</span>: <span class="string">''</span>},</span><br><span class="line"> {<span class="attr">key</span>: <span class="string">'br'</span>, <span class="attr">value</span>: <span class="string">''</span>},</span><br><span class="line"> {<span class="attr">key</span>: <span class="string">'table'</span>, <span class="attr">value</span>: <span class="string">''</span>},</span><br><span class="line"> {<span class="attr">key</span>: <span class="string">'tr'</span>, <span class="attr">value</span>: <span class="string">''</span>},</span><br><span class="line"> {<span class="attr">key</span>: <span class="string">'a'</span>, <span class="attr">value</span>: <span class="string">'[]()'</span>},</span><br><span class="line"> {<span class="attr">key</span>: <span class="string">'ul'</span>, <span class="attr">value</span>: <span class="string">''</span>},</span><br><span class="line"> {<span class="attr">key</span>: <span class="string">'ol'</span>, <span class="attr">value</span>: <span class="string">''</span>},</span><br><span class="line"> {<span class="attr">key</span>: <span class="string">'img'</span>, <span class="attr">value</span>: <span class="string">'![]'</span>},</span><br><span class="line"> {<span class="attr">key</span>: <span class="string">'br'</span>, <span class="attr">value</span>: <span class="string">`\n`</span>},</span><br><span class="line">];</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> blockLevelTag = [<span class="string">'p'</span>, <span class="string">'h1'</span>, <span class="string">'h2'</span>, <span class="string">'h3'</span>, <span class="string">'h4'</span>, <span class="string">'h5'</span>, <span class="string">'h6'</span>];</span><br><span class="line"><span class="keyword">const</span> tableNode = [<span class="string">'tr'</span>, <span class="string">'td'</span>, <span class="string">'th'</span>, <span class="string">'table'</span>, <span class="string">'tbody'</span>, <span class="string">'thead'</span>];</span><br><span class="line"><span class="keyword">const</span> thdTag = [<span class="string">'td'</span>, <span class="string">'th'</span>];</span><br><span class="line"><span class="keyword">const</span> lineFlagArr = [<span class="string">'#'</span>, <span class="string">''</span>, <span class="string">'|'</span>];</span><br></pre></td></tr></table></figure><ul><li><strong>html2Xml</strong></li></ul><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> html2Xml = <span class="keyword">async</span> (str) => {</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function">(<span class="params">resolve, reject</span>) =></span> {</span><br><span class="line"> <span class="keyword">let</span> $ = cheerio.load(str);</span><br><span class="line"> <span class="keyword">let</span> contentStr = $(<span class="string">'#main-content'</span>).html(); <span class="comment">// 截取指定id内的dom</span></span><br><span class="line"> <span class="keyword">const</span> doc = <span class="keyword">new</span> xmlDom().parseFromString(contentStr); <span class="comment">// html转成xml</span></span><br><span class="line"> <span class="keyword">let</span> length = <span class="number">0</span>;</span><br><span class="line"> <span class="comment">// 递归xml,转成md</span></span><br><span class="line"> length = doc.childNodes && doc.childNodes.length ;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">let</span> nodeIndex = <span class="number">0</span>; nodeIndex < length; nodeIndex ++) {</span><br><span class="line"> deepTraversal(doc.childNodes[nodeIndex]);</span><br><span class="line"> }</span><br><span class="line"> <span class="built_in">console</span>.info(markdownStr);</span><br><span class="line"> <span class="keyword">return</span> markdownStr;</span><br><span class="line"> });</span><br><span class="line">};</span><br></pre></td></tr></table></figure><ul><li><strong>deepTraversal</strong> 递归时需注意行内元素和块级元素</li></ul><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> deepTraversal = <span class="function">(<span class="params">node</span>) =></span> {</span><br><span class="line"> <span class="keyword">let</span> nodes = [];</span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 过滤目录</span></span><br><span class="line"><span class="comment"> * 过滤code中toolbar div</span></span><br><span class="line"><span class="comment"> * */</span></span><br><span class="line"> <span class="keyword">const</span> marcDom = <span class="keyword">new</span> xmlDom().parseFromString(node.toString());</span><br><span class="line"> <span class="keyword">const</span> marcNode = xpath.select1(<span class="string">"/div/@class"</span>, marcDom);</span><br><span class="line"> <span class="keyword">if</span> ((marcNode !== <span class="literal">undefined</span> && marcNode.value.indexOf(<span class="string">'toc'</span>) > <span class="number">-1</span>) || (marcNode !== <span class="literal">undefined</span> && marcNode.value === <span class="string">'toolbar'</span>)) {</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (node !== <span class="literal">null</span>) {</span><br><span class="line"> nodes.push(node);</span><br><span class="line"> <span class="keyword">let</span> children = node.childNodes;</span><br><span class="line"> <span class="keyword">const</span> markdown = xml2Md(node);</span><br><span class="line"> <span class="keyword">const</span> currentTagFlag = blockLevelTag.indexOf(node.nodeName) > <span class="number">-1</span>;</span><br><span class="line"> <span class="keyword">const</span> parentTagFlag = blockLevelTag.indexOf(node.parentNode.nodeName) > <span class="number">-1</span>;</span><br><span class="line"> <span class="comment">// 块级元素整体换行</span></span><br><span class="line"> <span class="keyword">if</span> (lineFlagArr.indexOf(markdown.trim().substr(<span class="number">-1</span>)) > <span class="number">-1</span> || (!currentTagFlag && parentTagFlag)) {</span><br><span class="line"> markdownStr += <span class="string">`<span class="subst">${markdown}</span>`</span>;</span><br><span class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (markdownStr.trim().substr(<span class="number">-1</span>) === <span class="string">'*'</span> && markdownStr.trim().substr(<span class="number">-2</span>) !== <span class="string">'**'</span>){</span><br><span class="line"> markdownStr += <span class="string">` <span class="subst">${markdown}</span>\n`</span>;</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> markdownStr += <span class="string">`<span class="subst">${markdown}</span>\n`</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (children) {</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i < children.length; i++ ) {</span><br><span class="line"> deepTraversal(children[i]);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">};</span><br></pre></td></tr></table></figure><ul><li><strong>xml2Md</strong></li></ul><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> xml2Md = <span class="function">(<span class="params">node</span>) =></span> {</span><br><span class="line"> <span class="keyword">let</span> mds = <span class="string">``</span>;</span><br><span class="line"></span><br><span class="line"> tagHtml.filter(<span class="function">(<span class="params">item</span>) =></span> {</span><br><span class="line"> <span class="keyword">const</span> nodeName = node.nodeName;</span><br><span class="line"> <span class="keyword">if</span> (item.key === nodeName) {</span><br><span class="line"> <span class="keyword">let</span> md = <span class="string">``</span>;</span><br><span class="line"> <span class="keyword">switch</span>(item.key) {</span><br><span class="line"> <span class="keyword">case</span> <span class="string">'img'</span>:</span><br><span class="line"> md = img2Md(node, item);</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="string">'a'</span>:</span><br><span class="line"> md = a2Md(node, item);</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="string">'table'</span>:</span><br><span class="line"> md = table2Md(node) + <span class="string">`\n`</span>;</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="string">'strong'</span>:</span><br><span class="line"> md = strong2Md(node, item);</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="string">'p'</span>:</span><br><span class="line"> md = p2Md(node, item) + <span class="string">`\n`</span>;</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="string">'ol'</span>:</span><br><span class="line"> md = ul2Md(node, item);</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="string">'ul'</span>:</span><br><span class="line"> md = ul2Md(node, item);</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="string">'pre'</span>:</span><br><span class="line"> md = code2Md(node, item);</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">default</span>:</span><br><span class="line"> md = default2Md(node, item);</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (blockLevelTag.indexOf(node.nodeName) > <span class="number">-1</span>) mds += <span class="string">`\n`</span>;</span><br><span class="line"> mds += md;</span><br><span class="line"> }</span><br><span class="line"> });</span><br><span class="line"> mds.replace(<span class="string">`\n`</span>, <span class="string">''</span>);</span><br><span class="line"> <span class="keyword">return</span> mds;</span><br><span class="line">};</span><br></pre></td></tr></table></figure><ul><li><strong>default2Md</strong></li></ul><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> default2Md = <span class="function">(<span class="params">node, item</span>) =></span> {</span><br><span class="line"> <span class="comment">// 已读节点不再读取</span></span><br><span class="line"> <span class="keyword">if</span> (node.hasRead) <span class="keyword">return</span> <span class="string">''</span>;</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 过滤由table带过来的遍历</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">const</span> parentDom = <span class="keyword">new</span> xmlDom().parseFromString(node.parentNode.toString());</span><br><span class="line"> <span class="keyword">const</span> parentClass = xpath.select1(<span class="string">"//@class"</span>, parentDom) && xpath.select1(<span class="string">"//@class"</span>, parentDom).nodeValue;</span><br><span class="line"> <span class="keyword">if</span> (parentClass && parentClass.indexOf(<span class="string">'table'</span>) > <span class="number">-1</span>) <span class="keyword">return</span> <span class="string">''</span>;</span><br><span class="line"> <span class="keyword">if</span> (tableNode.indexOf(node.parentNode.nodeName) > <span class="number">-1</span>) <span class="keyword">return</span> <span class="string">''</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">const</span> tableFlag = filterTable(node);</span><br><span class="line"> <span class="keyword">let</span> md = <span class="string">``</span>;</span><br><span class="line"> <span class="keyword">if</span> (tableFlag) <span class="keyword">return</span> <span class="string">''</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">const</span> blockFlag = blockLevelTag.indexOf(node.nodeName) > <span class="number">-1</span>;</span><br><span class="line"> <span class="comment">// 主体</span></span><br><span class="line"> <span class="keyword">if</span> (blockFlag) {</span><br><span class="line"> md += blockFlag2Md(node, item);</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">let</span> value = <span class="string">``</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">let</span> dIndex = <span class="number">0</span>; dIndex < node.childNodes.length; dIndex ++) {</span><br><span class="line"> <span class="keyword">const</span> ccnode = node.childNodes[dIndex];</span><br><span class="line"> <span class="keyword">if</span> (node.childNodes[dIndex] && node.childNodes[dIndex].hasRead) <span class="keyword">return</span>;</span><br><span class="line"> <span class="keyword">if</span> (node.childNodes[dIndex] && node.childNodes[dIndex].nodeName === <span class="string">'#text'</span>) value += node.childNodes[dIndex].data;</span><br><span class="line"> value += xml2Md(ccnode && node.childNodes[dIndex]);</span><br><span class="line"> }</span><br><span class="line"> md = value === <span class="string">''</span> ? <span class="string">`<span class="subst">${item.value}</span> `</span> : blockFlag ? <span class="string">`<span class="subst">${item.value}</span> <span class="subst">${value}</span>\n`</span> : <span class="string">`<span class="subst">${item.value}</span> <span class="subst">${value}</span>`</span>;</span><br><span class="line"> }</span><br><span class="line"> node.hasRead = <span class="literal">true</span>;</span><br><span class="line"> <span class="comment">// md += `\n`;</span></span><br><span class="line"> <span class="keyword">return</span> md;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><ul><li><strong>blockFlag2Md</strong></li></ul><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> blockFlag2Md = <span class="function">(<span class="params">node, item</span>) =></span> {</span><br><span class="line"> <span class="keyword">if</span> (node.hasRead) <span class="keyword">return</span> <span class="string">''</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">let</span> md = <span class="string">`<span class="subst">${item.value}</span> `</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">let</span> index = <span class="number">0</span>; index < node.childNodes.length; index ++) {</span><br><span class="line"> <span class="keyword">if</span> (node.childNodes[index].hasRead) <span class="keyword">return</span>;</span><br><span class="line"> <span class="keyword">if</span> (node.childNodes[index].nodeName === <span class="string">'#text'</span>) md += node.childNodes[index].data;</span><br><span class="line"> md += xml2Md(node.childNodes[index]);</span><br><span class="line"> node.childNodes[index].hasRead = <span class="literal">true</span>;</span><br><span class="line"> }</span><br><span class="line"> node.hasRead = <span class="literal">true</span>;</span><br><span class="line"> <span class="keyword">return</span> md;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><ul><li><strong>img2Md</strong></li></ul><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> img2Md = <span class="function">(<span class="params">node, item</span>) =></span> {</span><br><span class="line"> <span class="keyword">if</span> (node.hasRead) <span class="keyword">return</span> <span class="string">''</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">const</span> tableFlag = filterTable(node);</span><br><span class="line"> <span class="keyword">if</span> (tableFlag) <span class="keyword">return</span> <span class="string">''</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">let</span> attrLen = node.attributes.length;</span><br><span class="line"> <span class="keyword">let</span> imgBase = <span class="string">''</span>, imgSour = <span class="string">''</span>, imgSrc = <span class="string">''</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">let</span> attrIndex = <span class="number">0</span>; attrIndex < attrLen; attrIndex ++) {</span><br><span class="line"> <span class="keyword">const</span> attrItem = node.attributes[attrIndex];</span><br><span class="line"> <span class="keyword">if</span> (attrItem.nodeName === IMGSRC) imgSour = attrItem.nodeValue;</span><br><span class="line"> <span class="keyword">if</span> (attrItem.nodeName === BASEURL) imgBase = attrItem.nodeValue;</span><br><span class="line"> imgSrc = imgBase + imgSour;</span><br><span class="line"> }</span><br><span class="line"> node.hasRead = <span class="literal">true</span>;</span><br><span class="line"> <span class="keyword">return</span> <span class="string">`<span class="subst">${item.value}</span>(<span class="subst">${imgSrc}</span>)`</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><ul><li><strong>a2Md</strong></li></ul><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> a2Md = <span class="function">(<span class="params">node, item</span>) =></span> {</span><br><span class="line"> <span class="keyword">if</span> (node.hasRead) <span class="keyword">return</span> <span class="string">''</span>;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="keyword">const</span> tableFlag = filterTable(node);</span><br><span class="line"> <span class="keyword">if</span> (tableFlag) <span class="keyword">return</span> <span class="string">''</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">let</span> alink = <span class="string">''</span>;</span><br><span class="line"> <span class="keyword">const</span> aNode = <span class="keyword">new</span> xmlDom().parseFromString(node.toString());</span><br><span class="line"> <span class="keyword">const</span> hrefpath = xpath.select1(<span class="string">'/a/@href'</span>, aNode);</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">let</span> aIndex = <span class="number">0</span>; aIndex < node.attributes.length; aIndex ++) {</span><br><span class="line"> <span class="keyword">const</span> aItem = node.attributes[aIndex];</span><br><span class="line"> <span class="keyword">if</span> (aItem.nodeName === <span class="string">'href'</span>) {</span><br><span class="line"> alink = aItem.nodeValue;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (alink.substr(<span class="number">0</span>,<span class="number">1</span>) === <span class="string">'/'</span>) alink = <span class="string">`<span class="subst">${httpUrl}</span><span class="subst">${alink}</span>`</span>;</span><br><span class="line"> alink = <span class="string">`[<span class="subst">${node.childNodes[<span class="number">0</span>].data}</span>](<span class="subst">${alink}</span>)`</span>;</span><br><span class="line"> node.hasRead = <span class="literal">true</span>;</span><br><span class="line"> <span class="keyword">return</span><span class="string">`<span class="subst">${alink}</span>`</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><ul><li><strong>strong2Md</strong></li></ul><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> strong2Md = <span class="function">(<span class="params">node, item</span>) =></span> {</span><br><span class="line"> <span class="keyword">if</span> (node.hasRead) <span class="keyword">return</span> <span class="string">''</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">const</span> tableFlag = filterTable(node);</span><br><span class="line"> <span class="keyword">if</span> (tableFlag) <span class="keyword">return</span> <span class="string">''</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">let</span> md = <span class="string">``</span>;</span><br><span class="line"> <span class="keyword">const</span> currntBlockFlag = node.nextSibling;</span><br><span class="line"> <span class="keyword">const</span> parentSubFlag = blockLevelTag.indexOf(node.parentNode.nodeName) <= <span class="number">-1</span> && node.parentNode.nextSibling;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">let</span> value = <span class="string">` **`</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">let</span> sIndex = <span class="number">0</span>; sIndex < node.childNodes.length; sIndex ++) {</span><br><span class="line"> <span class="keyword">if</span> (node.childNodes[sIndex] && node.childNodes[sIndex].hasRead) <span class="keyword">return</span>;</span><br><span class="line"> <span class="keyword">if</span> (node.childNodes[sIndex] && node.childNodes[sIndex].nodeName === <span class="string">'#text'</span>) value += node.childNodes[sIndex].data.trim() || <span class="string">''</span>;</span><br><span class="line"> value += xml2Md(node.childNodes[sIndex]).trim();</span><br><span class="line"> node.childNodes[sIndex].hasRead = <span class="literal">true</span>;</span><br><span class="line"> }</span><br><span class="line"> md += value === <span class="string">'**'</span> ? <span class="string">''</span> : parentSubFlag || currntBlockFlag ? <span class="string">`<span class="subst">${value}</span>** `</span> : <span class="string">`<span class="subst">${value}</span>** \n`</span> ;</span><br><span class="line"> node.hasRead = <span class="literal">true</span>;</span><br><span class="line"> <span class="keyword">return</span> md;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><ul><li><strong>p2Md</strong></li></ul><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> p2Md = <span class="function">(<span class="params">node, item</span>) =></span> {</span><br><span class="line"> <span class="comment">// 过滤已读</span></span><br><span class="line"> <span class="keyword">if</span> (node.hasRead) <span class="keyword">return</span> <span class="string">''</span>;</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 过滤table</span></span><br><span class="line"> <span class="keyword">const</span> tableFlag = filterTable(node);</span><br><span class="line"> <span class="keyword">if</span> (tableFlag) <span class="keyword">return</span> <span class="string">''</span>;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="keyword">const</span> nodeChild = node.childNodes;</span><br><span class="line"> <span class="keyword">let</span> md = <span class="string">``</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">let</span> index = <span class="number">0</span>; index < nodeChild.length; index ++) {</span><br><span class="line"> <span class="keyword">if</span> (nodeChild[index].hasRead) <span class="keyword">return</span>;</span><br><span class="line"> <span class="keyword">if</span> (nodeChild[index].nodeName === <span class="string">'#text'</span>) md += nodeChild[index].data;</span><br><span class="line"> md += xml2Md(nodeChild[index]);</span><br><span class="line"> nodeChild[index].hasRead = <span class="literal">true</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> node.hasRead = <span class="literal">true</span>;</span><br><span class="line"> <span class="keyword">return</span> md;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><ul><li><strong>ul2Md</strong></li></ul><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> ul2Md = <span class="function">(<span class="params">node, item</span>) =></span> {</span><br><span class="line"> <span class="keyword">if</span> (node.hasRead) <span class="keyword">return</span> <span class="string">''</span>;</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 过滤table</span></span><br><span class="line"> <span class="keyword">const</span> tableFlag = filterTable(node);</span><br><span class="line"> <span class="keyword">if</span> (tableFlag) <span class="keyword">return</span> <span class="string">''</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">let</span> key = <span class="string">`*`</span>, ulMd = <span class="string">``</span>, liFlag = <span class="literal">false</span>; <span class="comment">// 默认为无序列表</span></span><br><span class="line"> <span class="keyword">if</span> (item.key === <span class="string">'ol'</span>) key = [];</span><br><span class="line"> <span class="keyword">if</span> (node.parentNode.nodeName === <span class="string">'li'</span>) {</span><br><span class="line"> liFlag = <span class="literal">true</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">let</span> index = <span class="number">0</span>; index < node.childNodes.length; index ++) {</span><br><span class="line"> <span class="keyword">if</span> (node.childNodes[index].hasRead) <span class="keyword">return</span>;</span><br><span class="line"> <span class="keyword">if</span> (ulMd.substr(<span class="number">-1</span>) === <span class="string">'*'</span>) ulMd = ulMd.trim();</span><br><span class="line"> ulMd += <span class="string">`<span class="subst">${key === <span class="string">'*'</span> ? <span class="string">`<span class="subst">${liFlag ? <span class="string">`\n `</span>: <span class="string">''</span>}</span>*`</span> : <span class="string">`<span class="subst">${liFlag ? <span class="string">`\n `</span>: <span class="string">''</span>}</span><span class="subst">${index + <span class="number">1</span>}</span>、`</span>}</span> <span class="subst">${li2Md(node && node.childNodes && node.childNodes[index], key)}</span> \n`</span>;</span><br><span class="line"> node.childNodes[index].hasRead = <span class="literal">true</span>;</span><br><span class="line"> }</span><br><span class="line"> node.hasRead = <span class="literal">true</span>;</span><br><span class="line"> <span class="keyword">return</span> ulMd;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><ul><li><strong>li2Md</strong></li></ul><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> li2Md = <span class="function">(<span class="params">node, key</span>) =></span> {</span><br><span class="line"> <span class="keyword">if</span> (node.hasRead) <span class="keyword">return</span> <span class="string">''</span>;</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 过滤table</span></span><br><span class="line"> <span class="keyword">const</span> tableFlag = filterTable(node);</span><br><span class="line"> <span class="keyword">if</span> (tableFlag) <span class="keyword">return</span> <span class="string">''</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">let</span> limd = <span class="string">``</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">let</span> index = <span class="number">0</span>; index < node.childNodes.length; index ++) {</span><br><span class="line"> <span class="keyword">if</span>(node.childNodes[index].hasRead) <span class="keyword">return</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (node.childNodes[index].nodeName === <span class="string">'#text'</span>) {</span><br><span class="line"> <span class="keyword">if</span> (limd.substr(<span class="string">'*'</span>)) limd = limd.trim();</span><br><span class="line"> limd += <span class="string">`<span class="subst">${node.childNodes[index].data}</span>`</span></span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">if</span> (limd.substr(<span class="string">'*'</span>)) limd = limd.trim();</span><br><span class="line"> limd += xml2Md(node.childNodes[index]);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> node.childNodes[index].hasRead = <span class="literal">true</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> node.hasRead = <span class="literal">true</span>;</span><br><span class="line"> <span class="keyword">return</span> limd;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><ul><li><strong>table2Md</strong></li></ul><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> table2Md = <span class="function">(<span class="params">node</span>) =></span> {</span><br><span class="line"> <span class="keyword">if</span> (node.hasRead) <span class="keyword">return</span> <span class="string">''</span>;</span><br><span class="line"> <span class="keyword">let</span> nodestr = node.toString();</span><br><span class="line"></span><br><span class="line"> <span class="comment">// table元素闭合问题</span></span><br><span class="line"> nodestr = nodestr.replace(<span class="string">'</table>'</span>, <span class="string">''</span>);</span><br><span class="line"> nodestr = nodestr.replace(<span class="string">'</tbody>'</span>, <span class="string">'</tbody></table>'</span>);</span><br><span class="line"> nodestr = nodestr.substr(<span class="number">0</span>, nodestr.indexOf(<span class="string">'</table>'</span>)) + <span class="string">'</table>'</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">let</span> tbodymd = <span class="string">`<span class="subst">${tbody2Md(nodestr)}</span>`</span> || <span class="string">``</span>;</span><br><span class="line"> node.hasRead = <span class="literal">true</span>;</span><br><span class="line"> <span class="keyword">return</span> tbodymd;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><ul><li><strong>tbody2Md</strong></li></ul><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> tbody2Md = <span class="function">(<span class="params">nodestr</span>) =></span> {</span><br><span class="line"> <span class="keyword">const</span> node = <span class="keyword">new</span> xmlDom().parseFromString(nodestr);</span><br><span class="line"> <span class="keyword">if</span> (node.hasRead) <span class="keyword">return</span> <span class="string">''</span>;</span><br><span class="line"> <span class="keyword">const</span> tableClass = xpath.select1(<span class="string">"/table/@class"</span>, node) && xpath.select1(<span class="string">"/table/@class"</span>, node) && xpath.select1(<span class="string">"/table/@class"</span>, node).value;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">let</span> tbodymd = <span class="string">``</span>;</span><br><span class="line"> <span class="keyword">if</span> (tableClass && tableClass.indexOf(<span class="string">'confluenceTable'</span>) > <span class="number">-1</span>) {</span><br><span class="line"> <span class="comment">// table</span></span><br><span class="line"> tbodymd += <span class="string">`\n <span class="subst">${nodestr}</span> \n`</span>;</span><br><span class="line"> node.hasRead = <span class="literal">true</span>;</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="comment">// code</span></span><br><span class="line"> <span class="keyword">const</span> trDom = <span class="keyword">new</span> xmlDom().parseFromString(nodestr);</span><br><span class="line"> <span class="keyword">const</span> trxpath = xpath.select(<span class="string">'//tr'</span>, trDom);</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">let</span> trIndex = <span class="number">0</span>; trIndex < trxpath.length; trIndex ++) {</span><br><span class="line"> tbodymd += codeTrMd(trxpath[trIndex]);</span><br><span class="line"> trxpath[trIndex].hasRead = <span class="literal">true</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> node.hasRead = <span class="literal">true</span>;</span><br><span class="line"> <span class="keyword">return</span> tbodymd;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><ul><li><strong>codeTrMd</strong></li></ul><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// code to markdown</span></span><br><span class="line"><span class="keyword">const</span> codeTrMd = <span class="function">(<span class="params">node</span>) =></span> {</span><br><span class="line"> <span class="keyword">if</span> (node.hasRead) <span class="keyword">return</span> <span class="string">''</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">const</span> tdDom = <span class="keyword">new</span> xmlDom().parseFromString(node.toString());</span><br><span class="line"> <span class="keyword">const</span> tdpath = xpath.select(<span class="string">"//td/div/div"</span>, tdDom);</span><br><span class="line"> <span class="keyword">let</span> codemd = <span class="string">'\n'</span> + <span class="string">'```'</span> + <span class="string">`\n`</span>;</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">let</span> codeIndex = <span class="number">0</span>; codeIndex < tdpath.length; codeIndex ++) {</span><br><span class="line"> <span class="keyword">const</span> codeDom = <span class="keyword">new</span> xmlDom().parseFromString(tdpath[codeIndex].toString());</span><br><span class="line"> <span class="keyword">let</span> mdValue = xpath.select(<span class="string">"//code/text()"</span>, codeDom);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">let</span> mdValueIndex = <span class="number">0</span>; mdValueIndex < mdValue.length; mdValueIndex ++) {</span><br><span class="line"> codemd += mdValue[mdValueIndex].data;</span><br><span class="line"> }</span><br><span class="line"> codemd += <span class="string">`\n`</span>;</span><br><span class="line"> }</span><br><span class="line"> codemd += <span class="string">'```\n'</span>;</span><br><span class="line"> <span class="keyword">return</span> codemd;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><ul><li><strong>filterTable</strong></li></ul><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> filterTable = <span class="function">(<span class="params">node</span>) =></span> {</span><br><span class="line"> <span class="keyword">const</span> tdNode = findtd(node);</span><br><span class="line"> <span class="keyword">if</span> (!tdNode) <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line"> <span class="keyword">const</span> filClass = xpath.select1(<span class="string">'//td/@class'</span>, tdNode);</span><br><span class="line"> <span class="keyword">const</span> thClass = xpath.select1(<span class="string">'//th/@class'</span>, tdNode);</span><br><span class="line"> <span class="keyword">if</span> (filClass && (filClass.value.indexOf(<span class="string">'confluenceT'</span>) > <span class="number">-1</span> || thClass.value.indexOf(<span class="string">'confluenceT'</span>) > <span class="number">-1</span>)) <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><ul><li><strong>findtd</strong></li></ul><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> findtd = <span class="function">(<span class="params">node</span>) =></span> {</span><br><span class="line"> <span class="keyword">const</span> parent_node = node.parentNode;</span><br><span class="line"> <span class="keyword">const</span> pppnode = parent_node && parent_node.parentNode;</span><br><span class="line"> <span class="keyword">const</span> forthnode = pppnode && pppnode.parentNode;</span><br><span class="line"> <span class="keyword">const</span> fifthnode = forthnode && forthnode.parentNode;</span><br><span class="line"> <span class="keyword">if</span> (node && thdTag.indexOf(node.nodeName) > <span class="number">-1</span>) <span class="keyword">return</span> node;</span><br><span class="line"> <span class="keyword">if</span> (parent_node && thdTag.indexOf(parent_node.nodeName) > <span class="number">-1</span>) <span class="keyword">return</span> parent_node;</span><br><span class="line"> <span class="keyword">if</span> (pppnode && thdTag.indexOf(pppnode.nodeName) > <span class="number">-1</span>) <span class="keyword">return</span> pppnode;</span><br><span class="line"> <span class="keyword">if</span> (forthnode && thdTag.indexOf(forthnode.nodeName) > <span class="number">-1</span>) <span class="keyword">return</span> forthnode;</span><br><span class="line"> <span class="keyword">if</span> (fifthnode && thdTag.indexOf(fifthnode.nodeName) > <span class="number">-1</span>) <span class="keyword">return</span> fifthnode;</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><ul><li><strong>code2Md</strong></li></ul><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// pre tag code to markdown</span></span><br><span class="line"><span class="keyword">const</span> code2Md = <span class="function">(<span class="params">node</span>) =></span> {</span><br><span class="line"></span><br><span class="line"> <span class="comment">// console.info(node.toString());</span></span><br><span class="line"> <span class="keyword">if</span> (node.hasRead) <span class="keyword">return</span> <span class="string">''</span>;</span><br><span class="line"></span><br><span class="line"> <span class="comment">// filter code tag from table</span></span><br><span class="line"> <span class="keyword">const</span> tableFlag = filterTable(node);</span><br><span class="line"> <span class="keyword">if</span> (tableFlag) <span class="keyword">return</span> <span class="string">''</span>;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="keyword">const</span> codeDom = <span class="keyword">new</span> xmlDom().parseFromString(node.toString());</span><br><span class="line"> <span class="keyword">const</span> nodepath = xpath.select1(<span class="string">"/pre/text()"</span>,codeDom);</span><br><span class="line"> <span class="keyword">const</span> nodeClass = xpath.select1(<span class="string">"/pre/@class"</span>, codeDom);</span><br><span class="line"> <span class="keyword">if</span>(!nodeClass || nodeClass === <span class="string">'undefined'</span> || (nodeClass && nodeClass.nodeValue).indexOf(<span class="string">'highlighter'</span>) <= <span class="number">-1</span>) <span class="keyword">return</span> nodepath && nodepath.nodeValue || <span class="string">''</span>;</span><br><span class="line"> <span class="keyword">const</span> lanagepath = xpath.select1(<span class="string">"/pre/@data-syntaxhighlighter-params"</span>, codeDom);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="keyword">let</span> md = <span class="string">'```'</span>;</span><br><span class="line"> <span class="keyword">let</span> lanage = lanagepath && lanagepath.nodeValue && lanagepath.nodeValue.split(<span class="string">';'</span>) && lanagepath.nodeValue.split(<span class="string">';'</span>)[<span class="number">0</span>].split(<span class="string">':'</span>)[<span class="number">1</span>] || <span class="string">''</span>;</span><br><span class="line"> md += <span class="string">`<span class="subst">${lanage}</span> \n <span class="subst">${nodepath && nodepath.nodeValue || <span class="string">''</span>}</span> \n`</span>;</span><br><span class="line"> md += <span class="string">'```'</span>;</span><br><span class="line"> node.hasRead = <span class="literal">true</span>;</span><br><span class="line"> <span class="keyword">return</span> md;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><a href="https://github.com/benyl-nie/html-markdown" target="_blank" rel="noopener">github地址</a></p>]]></content>
<categories>
<category> javascript html markdown </category>
</categories>
<tags>
<tag> javascript cheerio xml markdown </tag>
</tags>
</entry>
<entry>
<title>react14to16</title>
<link href="/2019/08/14/React%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96%E6%8A%80%E5%B7%A7%E5%AD%A6%E4%B9%A0%E6%95%B4%E7%90%86/"/>
<url>/2019/08/14/React%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96%E6%8A%80%E5%B7%A7%E5%AD%A6%E4%B9%A0%E6%95%B4%E7%90%86/</url>
<content type="html"><![CDATA[<p>看了最近一篇微信订阅号推送的文章,感觉很不错,摘抄下来方便以后查看,摘自 <a href="https://mp.weixin.qq.com/s/iZqV6GAi5zyX5P48hR4VLA" target="_blank" rel="noopener">你需要掌握的 21 个 React 性能优化技巧</a></p><a id="more"></a><blockquote><p>React 为高性能应用设计提供了许多优化方案,本文列举了其中的一些最佳实践</p></blockquote><p>在以下场景中,父组件和子组件通常会重新渲染:</p><ul><li>在同一组件或父组件中调用 setState 时</li><li>在父级收到的“props”的值发生变化</li><li>调用组件中的 forceUpdate</li></ul><p>下面是提升 React 应用性能的 21 个技巧:</p><h3 id="1、使用纯组件"><a href="#1、使用纯组件" class="headerlink" title="1、使用纯组件"></a>1、使用纯组件</h3><p>如果 React 组件为相同的状态和 props 渲染相同的输出,则可以将 7 其 ️ 是为纯组件。</p><p>对于像 this 的类组件来说,React 提供了 PureComponent 基类。扩展 React.PureComponent 类的类组件被视为纯组件。<br>它与普通组件时一样的,只是 PureComponents 负责 shouldComponentUpdate— 他对状态和 props 数据进行浅层比较(shallow comparision).</p><p>如果先前的状态和 props 数据与下一个 props 数据或者状态相同,则组件不会重新渲染。</p><ul><li>什么是浅层渲染?<blockquote><p>在对比先前的 props 和状态与下一个 props 和状态时,浅层比较将检查他们的基元是否有相同的值(例如:1 等于 1 或真等于真),还会检查更复杂的 Javascript 值(如对象和数组)之间的引用是否相同</p></blockquote></li></ul><p>比较基元和对象引用的开销比更新组件视图要低。<br>因此,查找状态和 props 值的变化会比不必要的更新更快。</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> React <span class="keyword">from</span> <span class="string">'react'</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="class"><span class="keyword">class</span> <span class="title">ApplicationComponent</span> <span class="keyword">extends</span> <span class="title">React</span>.<span class="title">Component</span> </span>{</span><br><span class="line"> <span class="keyword">constructor</span>() {</span><br><span class="line"> <span class="keyword">super</span>();</span><br><span class="line"> <span class="keyword">this</span>.state = {</span><br><span class="line"> name: <span class="string">'Mayank'</span></span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> updateState = <span class="function"><span class="params">()</span> =></span> {</span><br><span class="line"> setInterval(<span class="function"><span class="params">()</span> =></span> {</span><br><span class="line"> <span class="keyword">this</span>.setState({</span><br><span class="line"> name: <span class="string">'Mayank</span></span><br><span class="line"><span class="string"> })</span></span><br><span class="line"><span class="string"> }, 1000);</span></span><br><span class="line"><span class="string"> }</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"> componentDidMount() {</span></span><br><span class="line"><span class="string"> this.updateState();</span></span><br><span class="line"><span class="string"> }</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"> render() {</span></span><br><span class="line"><span class="string"> console.log('</span>Render called Again<span class="string">');</span></span><br><span class="line"><span class="string"> return (</span></span><br><span class="line"><span class="string"> <div></span></span><br><span class="line"><span class="string"> <RegularChiildComponent name={this.state.name} /></span></span><br><span class="line"><span class="string"> <PureChildComponet name={this.state.name} /></span></span><br><span class="line"><span class="string"> </div></span></span><br><span class="line"><span class="string"> );</span></span><br><span class="line"><span class="string"> }</span></span><br><span class="line"><span class="string">}</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">class RegularChildComponent extends React.Component {</span></span><br><span class="line"><span class="string"> render() {</span></span><br><span class="line"><span class="string"> console.log('</span>Regular Compoment Rendered..<span class="string">');</span></span><br><span class="line"><span class="string"> return <div>{this.props.name}</div>;</span></span><br><span class="line"><span class="string"> }</span></span><br><span class="line"><span class="string">}</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">class PureChildComponent extends React.PureComponent {</span></span><br><span class="line"><span class="string"> // Pure Component are the component that do not re-render if the state data or props data is still the same</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"> render() {</span></span><br><span class="line"><span class="string"> console.log('</span>Pure Component are Rendered...<span class="string">');</span></span><br><span class="line"><span class="string"> return <div>{this.props.name}</div>;</span></span><br><span class="line"><span class="string"> }</span></span><br><span class="line"><span class="string">}</span></span><br></pre></td></tr></table></figure><p>在上面的示例中,状态被传播到自组件 RegularChildComponent 和 PureChildComponent。PureChildComponent 是一个纯组件。</p><p>setState 在一秒的间隔之后被调用,这将重新触发组件的视图渲染。由于初始 props 和新 props 的值相同,因此组件(PureChildComponent) 不会被重新渲染<br>状态的浅层比较表明 props 或状态的数据没有变化,因此不需要渲染数据,从而提高了性能</p><h3 id="2、使用-React-memo-进行组件记忆"><a href="#2、使用-React-memo-进行组件记忆" class="headerlink" title="2、使用 React.memo 进行组件记忆"></a>2、使用 React.memo 进行组件记忆</h3><p>React.memo 是一个高阶组件。</p><p>它很像 PureComponent,但 PureComponent 属于 Component 的类实现,而‘memo’则用于创建函数组件。</p><p>这里与纯组件类似,如果输入 props 相同则跳过组件渲染,从而提升组件性能。</p><p>它会记忆上次某个输入 props 的执行输出并提升应用性能。即使在这些组件中比较也是浅层的。</p><p>你还可以为这个组件传递自定义比较逻辑。</p><p>用户可以用自定义逻辑深度对比(deep comparision)对象。如果比较函数返回 false 则重新渲染组件,否则就不会重新渲染</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">CustomisedComponent</span>(<span class="params">props</span>) </span>{</span><br><span class="line"> <span class="keyword">return</span> (</span><br><span class="line"> <div></span><br><span class="line"> <b>User name: {props.name}<<span class="regexp">/b></span></span><br><span class="line"><span class="regexp"> <b>User age: {props.age}</</span>b></span><br><span class="line"> <b>User designation: {props.designation}<<span class="regexp">/b></span></span><br><span class="line"><span class="regexp"> </</span>div></span><br><span class="line"> );</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// the compoment below is rhe optimised version for the Default component</span></span><br><span class="line"><span class="comment">// The Component will not re-render if same props value for 'name' property</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> memoComponet = React.mmeo(CustomisedComponent);</span><br></pre></td></tr></table></figure><p>上面的组件将对前后两个 props 的值进行浅层比较<br>如果我们将对象引用作为 props 传递给 memo 组件,则需要一些自定义登陆以进行比较。在这种情况下,我们可以将比较函数作为第二个参数传递给 React.memo 函数<br>假设 props 值(user)是一个对象引用,包含特定用户的 name,age 和 designation。<br>这种情况下需要进行深入比较,我们可以创建一个自定义函数,查找前后两个 props 值的 name,age 和 designation 的值,如果它们不相同则返回 false<br>这样,即使我们将参考数据作为 memo 组件的输入,组件也不会重新渲染</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// The following function takes 'user' Object as input parameter in props</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">CustomisedComponent</span>(<span class="params">props</span>) </span>{</span><br><span class="line"> <span class="keyword">return</span> (</span><br><span class="line"> <div></span><br><span class="line"> <b>User name: {props.name}<<span class="regexp">/b></span></span><br><span class="line"><span class="regexp"> <b>User age: {props.age}</</span>b></span><br><span class="line"> <b>User designation: {props.designation}<<span class="regexp">/b></span></span><br><span class="line"><span class="regexp"> </</span>div></span><br><span class="line"> );</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">userComparator</span>(<span class="params">previonProps, nextProps</span>) </span>{</span><br><span class="line"> <span class="keyword">if</span> (</span><br><span class="line"> previonProps.user.name == nextProps.user.name ||</span><br><span class="line"> previonProps.user.age == nextProps.user.age ||</span><br><span class="line"> previonProps.user.designation == nextProps.user.designation</span><br><span class="line"> ) {</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> memoComponent = React.memo(CustomisedComponent, userComparator);</span><br></pre></td></tr></table></figure><p>上面的代码提供了用于比较的自定义逻辑</p><h3 id="3、使用-shouldComponentUpdate-生命周期函数"><a href="#3、使用-shouldComponentUpdate-生命周期函数" class="headerlink" title="3、使用 shouldComponentUpdate 生命周期函数"></a>3、使用 shouldComponentUpdate 生命周期函数</h3><blockquote><p>这是在重新渲染组件之前触发的其中一个生命周期事件</p></blockquote><p>可以利用此事件来决定何时需要重新渲染组件,如果组件 props 更改或调用 setState,则此函数返回一个 Boolean 值。<br>在这两种情况下组件都会重新渲染。我们可以在这个生命周期事件中放置一个自定义逻辑,以决定是否调用组件的 render 函数</p><p>这个函数将 nextState 和 nextProps 作为输入,并可将其与当前 props 和状态做对比,以决定是否需要重新渲染。<br>比如说我想再网页上显示员工的详细资料。每位员工都包含多个属性,如姓名,年龄,牌号,薪水,当前经理,前任经理,奖金等。</p><p>我想只在网页上渲染员工的姓名和年龄。员工的牌号会在某时刻更新。</p><p>由于员工牌号不在视图内,理想情况下视图是无需要更新的,我们可以在组件中添加自定义逻辑,哦安段是否需要组件更新视图</p><p>代码如下:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> React <span class="keyword">from</span> <span class="string">'react'</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="class"><span class="keyword">class</span> <span class="title">ShouldComponentUpdateState</span> <span class="keyword">extends</span> <span class="title">React</span>.<span class="title">Component</span> </span>{</span><br><span class="line"> <span class="keyword">constructor</span>(props) {</span><br><span class="line"> <span class="keyword">super</span>(props);</span><br><span class="line"> <span class="keyword">this</span>.state = {</span><br><span class="line"> name: <span class="string">'Mayank'</span>,</span><br><span class="line"> age: <span class="number">30</span>,</span><br><span class="line"> designation: <span class="string">'Architect</span></span><br><span class="line"><span class="string"> }</span></span><br><span class="line"><span class="string"> }</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"> ComponentDidMount() {</span></span><br><span class="line"><span class="string"> setTimeout(() => {</span></span><br><span class="line"><span class="string"> this.setState({</span></span><br><span class="line"><span class="string"> designation: '</span>hhhhhhh<span class="string">'</span></span><br><span class="line"><span class="string"> })</span></span><br><span class="line"><span class="string"> })</span></span><br><span class="line"><span class="string"> }</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"> shouleComponentUpdate(nextProps, nextState) {</span></span><br><span class="line"><span class="string"> if (nextState.age != this.state.age || nextState.name != this.state.name) return true;</span></span><br><span class="line"><span class="string"> return false;</span></span><br><span class="line"><span class="string"> }</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"> render() {</span></span><br><span class="line"><span class="string"> return (</span></span><br><span class="line"><span class="string"> <div></span></span><br><span class="line"><span class="string"> <b>User name: {props.name}</b></span></span><br><span class="line"><span class="string"> <b>User age: {props.age}</b></span></span><br><span class="line"><span class="string"> </div></span></span><br><span class="line"><span class="string"> );</span></span><br><span class="line"><span class="string"> }</span></span><br><span class="line"><span class="string">}</span></span><br></pre></td></tr></table></figure><p>这里即使组件中 designation 发生变化也不会影响应用的视图。</p><p>调用 setState 时组件会重新渲染,但因为 designation 更改不会改变/影响组件的视图,因此在更改 designation 时重新渲染组件会带来额外开销。</p><p>为了避免这种开销。我们可以使用自定义逻辑检查 name 或 age 是否更新,因为视图仅受他们的影响</p><p>shouleComponentUpdate 将输入参数作为状态和 props 的新值</p><p>我们可以比较 name 和 age 的当前值和新值,有任何一个发生变化就可以触发重新渲染。</p><p>从 shouleComponentUpdate 传递 true 就意味着可以重新渲染组件,反之亦然。所以正确使用 shouleComponentUpdate 就可以优化应用组件的性能。</p><p>对比初始状态和 props 后我们就可以决定祖耀重新渲染组件。这样就可以减少重新渲染的需求来提升性能。</p><h3 id="4-懒加载组件"><a href="#4-懒加载组件" class="headerlink" title="4. 懒加载组件"></a>4. 懒加载组件</h3><p>导入多个文件合并到一个文件中的过程叫打包,使应用不必导入大量外部文件。</p><p>所有主要组件和外部依赖项都合并为一个文件,通过网络传送出去以启动并运行 Web 应用。</p><p>这样可以节省大量网络调用,但这个文件会变得很大,消耗大量网络带宽。</p><p>应用需要等待这个文件的加载和执行,所以传输延迟会带来严重的影响。</p><p>为了解决这个问题,我们引入代码拆分的概念。</p><p>像 webpack 这样的打包器支持就支持代码拆分,它可以为应用创建多个包,并在运行时动态加载,减少初始包的大小。</p><p>为此我们使用 Suspense 和 lazy</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> React, { lazy, Suspense } <span class="keyword">from</span> <span class="string">"react"</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="class"><span class="keyword">class</span> <span class="title">CallingLazyComponents</span> <span class="keyword">extends</span> <span class="title">React</span>.<span class="title">Component</span> </span>{</span><br><span class="line"> render() {</span><br><span class="line"> <span class="keyword">var</span> ComponentToLazyLoad = <span class="literal">null</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">this</span>.props.name == <span class="string">"Mayank"</span>) {</span><br><span class="line"> ComponentToLazyLoad = lazy(<span class="function"><span class="params">()</span> =></span> <span class="keyword">import</span>(<span class="string">"./mayankComponent"</span>));</span><br><span class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (<span class="keyword">this</span>.props.name == <span class="string">"Anshul"</span>) {</span><br><span class="line"> ComponentToLazyLoad = lazy(<span class="function"><span class="params">()</span> =></span> <span class="keyword">import</span>(<span class="string">"./anshulComponent"</span>));</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> (</span><br><span class="line"> <div></span><br><span class="line"> <h1>This is the Base User: {<span class="keyword">this</span>.state.name}<<span class="regexp">/h1></span></span><br><span class="line"><span class="regexp"> <Suspense fallback={<div>Loading...</</span>div>}></span><br><span class="line"> <ComponentToLazyLoad /></span><br><span class="line"> <<span class="regexp">/Suspense></span></span><br><span class="line"><span class="regexp"> </</span>div></span><br><span class="line"> );</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>上面的代码中有一个条件语句,它查找 props 值,并根据指定的条件加载主组件中的两个组件。</p><p>我们可以按需懒惰加载这些拆分出来的组件,增强应用的整体性能。</p><p>假设有两个组件 WelcomeComponent 或 GuestComponents,我们根据用户是否登录而渲染其中一个。</p><p>我们可以根据具体的条件延迟组件加载,无需一开始就加载两个组件。</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> React, { lazy, Suspense } <span class="keyword">from</span> <span class="string">"react"</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="class"><span class="keyword">class</span> <span class="title">UserSalutation</span> <span class="keyword">extends</span> <span class="title">React</span>.<span class="title">Component</span> </span>{</span><br><span class="line"> render() {</span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">this</span>.props.username !== <span class="string">""</span>) {</span><br><span class="line"> <span class="keyword">const</span> WelcomeComponent = lazy(<span class="function"><span class="params">()</span> =></span> <span class="keyword">import</span>(<span class="string">"./welcomeComponent"</span>));</span><br><span class="line"> <span class="keyword">return</span> (</span><br><span class="line"> <div></span><br><span class="line"> <Suspense fallback={<div>Loading...<<span class="regexp">/div>}></span></span><br><span class="line"><span class="regexp"> <WelcomeComponent /</span>></span><br><span class="line"> <<span class="regexp">/Suspense></span></span><br><span class="line"><span class="regexp"> </</span>div></span><br><span class="line"> );</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">const</span> GuestComponent = lazy(<span class="function"><span class="params">()</span> =></span> <span class="keyword">import</span>(<span class="string">"./guestComponent"</span>));</span><br><span class="line"> <span class="keyword">return</span> (</span><br><span class="line"> <div></span><br><span class="line"> <Suspense fallback={<div>Loading...<<span class="regexp">/div>}></span></span><br><span class="line"><span class="regexp"> <GuestComponent /</span>></span><br><span class="line"> <<span class="regexp">/Suspense></span></span><br><span class="line"><span class="regexp"> </</span>div></span><br><span class="line"> );</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>在上面的代码中我们没有预加载 WelcomeCompoment 和 GuestComponents 这两个组件,而是进行一个条件检查。</p><p>如果用户名存在(或相反),我们就根据指定的条件决定将某个组件作为单独的包加载。</p><ul><li>这个方法的好处<blockquote><p>1、主包体积变小,消耗的网络传输时间更少。<br>2、动态单独加载的包比较小,可以迅速加载完成。</p></blockquote></li></ul><p>我们可以分析应用来决定懒加载哪些组件,从而减少应用的初始加载时间。</p><h3 id="5-使用-React-Fragments-避免额外标记"><a href="#5-使用-React-Fragments-避免额外标记" class="headerlink" title="5. 使用 React Fragments 避免额外标记"></a>5. 使用 React Fragments 避免额外标记</h3><p>使用 Fragments 减少了包含的额外标记数量,这些标记只是为了满足在 React 组件中具有公共父级的要求。</p><p>用户创建新组件时,每个组件应具有单个父标签。父级不能有两个标签,所以顶部要有一个公共标签。所以我们经常在组件顶部添加额外标签,例如:</p><p><img src="https://mmbiz.qpic.cn/mmbiz_jpg/XIibZ0YbvibkVq7r2MICNGrSmLzFDicvKSNLsyKLGfsAGibof63PPoMe7dHCicaMjtUyM7IficHJianqDaROTJg0zUQ9A/640?wx_fmt=jpeg&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1" alt="举例图片"></p><p>在上面指定的组件中,我们需要一个额外的标签为要渲染的组件提供公共父级。</p><p>除了充当组件的父标签之外,这个额外的 div 没有其他用途。</p><p>在顶层有多个标签会导致以下错误:<br><img src="https://mmbiz.qpic.cn/mmbiz_jpg/XIibZ0YbvibkVq7r2MICNGrSmLzFDicvKSNwXEYVZC2ibgpw4ibfBWQxtRNaoBYDsn7JuySLDBETXaDKwXQsYQAficHw/640?wx_fmt=jpeg&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1" alt="举例图片2"><br>要解决此问题,我们可以将元素包含在片段(fragement)中。</p><p>片段不会向组件引入任何额外标记,但它仍然为两个相邻标记提供父级,因此满足在组件顶级具有单个父级的条件。</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="class"><span class="keyword">class</span> <span class="title">NestedRoutingComponent</span> <span class="keyword">extends</span> <span class="title">React</span>.<span class="title">Component</span> </span>{</span><br><span class="line"> render() {</span><br><span class="line"> <span class="keyword">return</span> (</span><br><span class="line"> <></span><br><span class="line"> <h1>This is the Header Component<<span class="regexp">/h1></span></span><br><span class="line"><span class="regexp"> <h2>Welcome To Demo Page</</span>h2></span><br><span class="line"> <<span class="regexp">/></span></span><br><span class="line"><span class="regexp"> );</span></span><br><span class="line"><span class="regexp"> }</span></span><br><span class="line"><span class="regexp">}</span></span><br></pre></td></tr></table></figure><p>上面的代码没有额外的标记,因此节省了渲染器渲染额外元素的工作量。</p><p>详细信息参考:<br><a href="https://github.com/facebook/react/issues/2127" target="_blank" rel="noopener">https://github.com/facebook/react/issues/2127</a></p><h3 id="6-不要使用内联函数定义"><a href="#6-不要使用内联函数定义" class="headerlink" title="6. 不要使用内联函数定义"></a>6. 不要使用内联函数定义</h3><p>如果我们使用内联函数,则每次调用“render”函数时都会创建一个新的函数实例。</p><p>当 React 进行虚拟 DOM diffing 时,它每次都会找到一个新的函数实例;因此在渲染阶段它会会绑定新函数并将旧实例扔给垃圾回收。</p><p>因此直接绑定内联函数就需要额外做垃圾回收和绑定到 DOM 的新函数的工作。</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> React <span class="keyword">from</span> <span class="string">"react"</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="class"><span class="keyword">class</span> <span class="title">InlineFunctionComponent</span> <span class="keyword">extends</span> <span class="title">React</span>.<span class="title">Component</span> </span>{</span><br><span class="line"> render() {</span><br><span class="line"> <span class="keyword">return</span> (</span><br><span class="line"> <div></span><br><span class="line"> <h1>Welcome Guest<<span class="regexp">/h1></span></span><br><span class="line"><span class="regexp"> <input</span></span><br><span class="line"><span class="regexp"> type="button"</span></span><br><span class="line"><span class="regexp"> onClick={e => {</span></span><br><span class="line"><span class="regexp"> this.setState({ inputValue: e.target.value });</span></span><br><span class="line"><span class="regexp"> }}</span></span><br><span class="line"><span class="regexp"> value="Click For Inline Function"</span></span><br><span class="line"><span class="regexp"> /</span>></span><br><span class="line"> <<span class="regexp">/div></span></span><br><span class="line"><span class="regexp"> );</span></span><br><span class="line"><span class="regexp"> }</span></span><br><span class="line"><span class="regexp">}</span></span><br></pre></td></tr></table></figure><p>上面的函数创建了内联函数。每次调用 render 函数时都会创建一个函数的新实例,render 函数会将该函数的新实例绑定到该按钮。</p><p>此外最后一个函数实例会被垃圾回收,大大增加了 React 应用的工作量。</p><p>所以不要用内联函数,而是在组件内部创建一个函数,并将事件绑定到该函数本身。这样每次调用 render 时就不会创建单独的函数实例了,参考组件如下。</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> React <span class="keyword">from</span> <span class="string">"react"</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="class"><span class="keyword">class</span> <span class="title">InlineFunctionComponent</span> <span class="keyword">extends</span> <span class="title">React</span>.<span class="title">Component</span> </span>{</span><br><span class="line"> setNewStateData = <span class="function"><span class="params">event</span> =></span> {</span><br><span class="line"> <span class="keyword">this</span>.setState({</span><br><span class="line"> inputValue: e.target.value</span><br><span class="line"> });</span><br><span class="line"> };</span><br><span class="line"></span><br><span class="line"> render() {</span><br><span class="line"> <span class="keyword">return</span> (</span><br><span class="line"> <div></span><br><span class="line"> <h1>Welcome Guest<<span class="regexp">/h1></span></span><br><span class="line"><span class="regexp"> <input</span></span><br><span class="line"><span class="regexp"> type="button"</span></span><br><span class="line"><span class="regexp"> onClick={this.setNewStateData}</span></span><br><span class="line"><span class="regexp"> value="Click For Inline Function"</span></span><br><span class="line"><span class="regexp"> /</span>></span><br><span class="line"> <<span class="regexp">/div></span></span><br><span class="line"><span class="regexp"> );</span></span><br><span class="line"><span class="regexp"> }</span></span><br><span class="line"><span class="regexp">}</span></span><br></pre></td></tr></table></figure><h3 id="7-避免-componentWillMount-中的异步请求"><a href="#7-避免-componentWillMount-中的异步请求" class="headerlink" title="7. 避免 componentWillMount()中的异步请求"></a>7. 避免 componentWillMount()中的异步请求</h3><p>componentWillMount 是在渲染组件之前调用的。</p><p>这个函数用的不多,可用来配置组件的初始配置,但使用 constructor 方法自己也能做到。</p><p>该方法无法访问 DOM 元素,因为组件还没挂载上来。</p><p>一些开发人员认为这个函数可以用来做异步数据 API 调用,但其实这没什么好处。</p><p>由于 API 调用是异步的,因此组件在调用 render 函数之前不会等待 API 返回数据。于是在初始渲染中渲染组件时没有任何数据。</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> React <span class="keyword">from</span> <span class="string">"react"</span>;</span><br><span class="line"><span class="keyword">import</span> axios <span class="keyword">from</span> <span class="string">"axios"</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="class"><span class="keyword">class</span> <span class="title">UsingAsyncInComponentWillMount</span> <span class="keyword">extends</span> <span class="title">React</span>.<span class="title">Component</span> </span>{</span><br><span class="line"> <span class="keyword">constructor</span>() {</span><br><span class="line"> <span class="keyword">this</span>.state = {</span><br><span class="line"> userData: <span class="literal">null</span></span><br><span class="line"> };</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> componentWillMount() {</span><br><span class="line"> axios.get(<span class="string">"someResourceUrl"</span>).then(<span class="function"><span class="params">data</span> =></span> {</span><br><span class="line"> <span class="keyword">this</span>.setState({</span><br><span class="line"> userData: data</span><br><span class="line"> });</span><br><span class="line"> });</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> render() {</span><br><span class="line"> <span class="keyword">return</span> (</span><br><span class="line"> <></span><br><span class="line"> <b>UserName: {<span class="keyword">this</span>.state.name}<<span class="regexp">/b></span></span><br><span class="line"><span class="regexp"> <b>UserAge: {this.state.age}</</span>b></span><br><span class="line"> <<span class="regexp">/></span></span><br><span class="line"><span class="regexp"> );</span></span><br><span class="line"><span class="regexp"> }</span></span><br><span class="line"><span class="regexp">}</span></span><br></pre></td></tr></table></figure><p>在上面的代码中,我们正在进行异步调用以获取数据。由于数据调用是异步的,需要一段时间才能获取到。</p><p>在检索数据时 React 会触发组件的 render 函数。因此第一个调用的渲染仍然不包含它所需的数据。</p><p>这样一开始渲染组件没有数据,然后检索数据,调用 setState,还得重新渲染组件。在 componentWillMount 阶段进行 AJAX 调用没有好处可言。</p><p>我们应避免在此函数中发出 Async 请求。这些函数和调用可以延迟到 componentDidMount 生命周期事件里。</p><p><strong>注意</strong>:React 16.3 不推荐使用 componentWillMount。如果你使用的是最新版本的 React,请避免使用这个生命周期事件。</p><h3 id="8-在-Constructor-的早期绑定函数"><a href="#8-在-Constructor-的早期绑定函数" class="headerlink" title="8. 在 Constructor 的早期绑定函数"></a>8. 在 Constructor 的早期绑定函数</h3><p>当我们在 React 中创建函数时,我们需要使用 bind 关键字将函数绑定到当前上下文。</p><p>绑定可以在构造函数中完成,也可以在我们将函数绑定到 DOM 元素的位置上完成。</p><p>两者之间似乎没有太大差异,但性能表现是不一样的。</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> React <span class="keyword">from</span> <span class="string">"react"</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="class"><span class="keyword">class</span> <span class="title">DelayedBinding</span> <span class="keyword">extends</span> <span class="title">React</span>.<span class="title">Component</span> </span>{</span><br><span class="line"> <span class="keyword">constructor</span>() {</span><br><span class="line"> <span class="keyword">this</span>.state = {</span><br><span class="line"> name: <span class="string">"Mayank"</span></span><br><span class="line"> };</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> handleButtonClick() {</span><br><span class="line"> alert(<span class="string">"Button Clicked: "</span> + <span class="keyword">this</span>.state.name);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> render() {</span><br><span class="line"> <span class="keyword">return</span> (</span><br><span class="line"> <></span><br><span class="line"> <input</span><br><span class="line"> type=<span class="string">"button"</span></span><br><span class="line"> value=<span class="string">"Click"</span></span><br><span class="line"> onClick={<span class="keyword">this</span>.handleButtonClick.bind(<span class="keyword">this</span>)}</span><br><span class="line"> /></span><br><span class="line"> <<span class="regexp">/></span></span><br><span class="line"><span class="regexp"> );</span></span><br><span class="line"><span class="regexp"> }</span></span><br><span class="line"><span class="regexp">}</span></span><br></pre></td></tr></table></figure><p>在上面的代码中,我们在 render 函数的绑定期间将函数绑定到按钮上。</p><p>上面代码的问题在于,每次调用 render 函数时都会创建并使用绑定到当前上下文的新函数,但在每次渲染时使用已存在的函数效率更高。优化方案如下:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> React <span class="keyword">from</span> <span class="string">"react"</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="class"><span class="keyword">class</span> <span class="title">DelayedBinding</span> <span class="keyword">extends</span> <span class="title">React</span>.<span class="title">Component</span> </span>{</span><br><span class="line"> <span class="keyword">constructor</span>() {</span><br><span class="line"> <span class="keyword">this</span>.state = {</span><br><span class="line"> name: <span class="string">"Mayank"</span></span><br><span class="line"> };</span><br><span class="line"> <span class="keyword">this</span>.handleButtonClick = <span class="keyword">this</span>.handleButtonClick.bind(<span class="keyword">this</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> handleButtonClick() {</span><br><span class="line"> alert(<span class="string">"Button Clicked: "</span> + <span class="keyword">this</span>.state.name);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> render() {</span><br><span class="line"> <span class="keyword">return</span> (</span><br><span class="line"> <></span><br><span class="line"> <input type=<span class="string">"button"</span> value=<span class="string">"Click"</span> onClick={<span class="keyword">this</span>.handleButtonClick} /></span><br><span class="line"> <<span class="regexp">/></span></span><br><span class="line"><span class="regexp"> );</span></span><br><span class="line"><span class="regexp"> }</span></span><br><span class="line"><span class="regexp">}</span></span><br></pre></td></tr></table></figure><p>最好在构造函数调用期间使用绑定到当前上下文的函数覆盖 handleButtonClick 函数。</p><p>这将减少将函数绑定到当前上下文的开销,无需在每次渲染时重新创建函数,从而提高应用的性能。</p><h3 id="9-箭头函数与构造函数中的绑定"><a href="#9-箭头函数与构造函数中的绑定" class="headerlink" title="9. 箭头函数与构造函数中的绑定"></a>9. 箭头函数与构造函数中的绑定</h3><p>处理类时的标准做法就是使用箭头函数。使用箭头函数时会保留执行的上下文。</p><p>我们调用它时不需要将函数绑定到上下文。</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> React <span class="keyword">from</span> <span class="string">"react"</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="class"><span class="keyword">class</span> <span class="title">DelayedBinding</span> <span class="keyword">extends</span> <span class="title">React</span>.<span class="title">Component</span> </span>{</span><br><span class="line"> <span class="keyword">constructor</span>() {</span><br><span class="line"> <span class="keyword">this</span>.state = {</span><br><span class="line"> name: <span class="string">"Mayank"</span></span><br><span class="line"> };</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> handleButtonClick = <span class="function"><span class="params">()</span> =></span> {</span><br><span class="line"> alert(<span class="string">"Button Clicked: "</span> + <span class="keyword">this</span>.state.name);</span><br><span class="line"> };</span><br><span class="line"></span><br><span class="line"> render() {</span><br><span class="line"> <span class="keyword">return</span> (</span><br><span class="line"> <></span><br><span class="line"> <input type=<span class="string">"button"</span> value=<span class="string">"Click"</span> onClick={<span class="keyword">this</span>.handleButtonClick} /></span><br><span class="line"> <<span class="regexp">/></span></span><br><span class="line"><span class="regexp"> );</span></span><br><span class="line"><span class="regexp"> }</span></span><br><span class="line"><span class="regexp">}</span></span><br></pre></td></tr></table></figure><p>箭头函数好处多多,但也有缺点。</p><blockquote><p>当我们添加箭头函数时,该函数被添加为对象实例,而不是类的原型属性。这意味着如果我们多次复用组件,那么在组件外创建的每个对象中都会有这些函数的多个实例。<br>每个组件都会有这些函数的一份实例,影响了可复用性。此外因为它是对象属性而不是原型属性,所以这些函数在继承链中不可用。</p></blockquote><p>因此箭头函数确实有其缺点。实现这些函数的最佳方法是在构造函数中绑定函数,如上所述。</p><h3 id="10-避免使用内联样式属性"><a href="#10-避免使用内联样式属性" class="headerlink" title="10. 避免使用内联样式属性"></a>10. 避免使用内联样式属性</h3><p>使用内联样式时浏览器需要花费更多时间来处理脚本和渲染,因为它必须映射传递给实际 CSS 属性的所有样式规则。</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> React <span class="keyword">from</span> <span class="string">"react"</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="class"><span class="keyword">class</span> <span class="title">InlineStyledComponents</span> <span class="keyword">extends</span> <span class="title">React</span>.<span class="title">Component</span> </span>{</span><br><span class="line"> render() {</span><br><span class="line"> <span class="keyword">return</span> (</span><br><span class="line"> <></span><br><span class="line"> <b style={{ <span class="attr">backgroundColor</span>: <span class="string">"blue"</span> }}>Welcome to Sample Page<<span class="regexp">/b></span></span><br><span class="line"><span class="regexp"> </</span>></span><br><span class="line"> );</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>在上面创建的组件中,我们将内联样式附加到组件。添加的内联样式是 JavaScript 对象而不是样式标记。</p><p>样式 backgroundColor 需要转换为等效的 CSS 样式属性,然后才应用样式。这样就需要额外的脚本处理和 JS 执行工作。</p><p>更好的办法是将 CSS 文件导入组件。</p><h3 id="11-优化-React-中的条件渲染"><a href="#11-优化-React-中的条件渲染" class="headerlink" title="11. 优化 React 中的条件渲染"></a>11. 优化 React 中的条件渲染</h3><p>安装和卸载 React 组件是昂贵的操作。为了提升性能,我们需要减少安装和卸载的操作。</p><p>很多情况下在我们可能会渲染或不渲染特定元素,这时可以用条件渲染。</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> React <span class="keyword">from</span> <span class="string">"react"</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> AdminHeaderComponent <span class="keyword">from</span> <span class="string">"./AdminHeaderComponent"</span>;</span><br><span class="line"><span class="keyword">import</span> HeaderComponent <span class="keyword">from</span> <span class="string">"./HeaderComponent"</span>;</span><br><span class="line"><span class="keyword">import</span> ContentComponent <span class="keyword">from</span> <span class="string">"./ContentComponent"</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="class"><span class="keyword">class</span> <span class="title">ConditionalRendering</span> <span class="keyword">extends</span> <span class="title">React</span>.<span class="title">Component</span> </span>{</span><br><span class="line"> <span class="keyword">constructor</span>() {</span><br><span class="line"> <span class="keyword">this</span>.state = {</span><br><span class="line"> name: <span class="string">"Mayank"</span></span><br><span class="line"> };</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> render() {</span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">this</span>.state.name == <span class="string">"Mayank"</span>) {</span><br><span class="line"> <span class="keyword">return</span> (</span><br><span class="line"> <></span><br><span class="line"> <AdminHeaderComponent><span class="xml"><span class="tag"></<span class="name">AdminHeaderComponent</span>></span></span></span><br><span class="line"> <HeaderComponent><span class="xml"><span class="tag"></<span class="name">HeaderComponent</span>></span></span></span><br><span class="line"> <ContentComponent><span class="xml"><span class="tag"></<span class="name">ContentComponent</span>></span></span></span><br><span class="line"> <<span class="regexp">/></span></span><br><span class="line"><span class="regexp"> );</span></span><br><span class="line"><span class="regexp"> } else {</span></span><br><span class="line"><span class="regexp"> return (</span></span><br><span class="line"><span class="regexp"> <></span></span><br><span class="line"><span class="regexp"> <HeaderComponent></</span>HeaderComponent></span><br><span class="line"> <ContentComponent><span class="xml"><span class="tag"></<span class="name">ContentComponent</span>></span></span></span><br><span class="line"> <<span class="regexp">/></span></span><br><span class="line"><span class="regexp"> );</span></span><br><span class="line"><span class="regexp"> }</span></span><br><span class="line"><span class="regexp"> }</span></span><br><span class="line"><span class="regexp">}</span></span><br></pre></td></tr></table></figure><p>在上面的代码中有一个条件语句,让组件根据指定的条件渲染。如果状态包含名称值 Mayank,则不会渲染 AdminHeaderComponent。</p><p>条件运算符和 if else 条件似乎没问题,但后面的代码有性能问题,需要分析一下。</p><p>每次调用 render 函数,并且值在 Mayank 和另一个值之间切换时,都会执行不同的 if else 语句。</p><p>diffing 算法会运行一个检查,比较每个位置的元素类型。在 diffing 期间,它看到 AdminHeaderComponent 不可用,并且需要渲染的第一个组件是 HeaderComponent。</p><p>React 将观察元素的位置。它看到位置 1 和位置 2 的组件已更改并将卸载组件。</p><p>组件 HeaderComponent 和 ContentComponent 将在位置 1 和位置 2 卸载并重新安装。其实这是用不着的,因为这些组件没有更改,这是一项昂贵的操作。优化方案如下:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> React <span class="keyword">from</span> <span class="string">"react"</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> AdminHeaderComponent <span class="keyword">from</span> <span class="string">"./AdminHeaderComponent"</span>;</span><br><span class="line"><span class="keyword">import</span> HeaderComponent <span class="keyword">from</span> <span class="string">"./HeaderComponent"</span>;</span><br><span class="line"><span class="keyword">import</span> ContentComponent <span class="keyword">from</span> <span class="string">"./ContentComponent"</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="class"><span class="keyword">class</span> <span class="title">ConditionalRendering</span> <span class="keyword">extends</span> <span class="title">React</span>.<span class="title">Component</span> </span>{</span><br><span class="line"> <span class="keyword">constructor</span>() {</span><br><span class="line"> <span class="keyword">this</span>.state = {</span><br><span class="line"> name: <span class="string">"Mayank"</span></span><br><span class="line"> };</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> render() {</span><br><span class="line"> <span class="keyword">return</span> (</span><br><span class="line"> <></span><br><span class="line"> {<span class="keyword">this</span>.state.name == <span class="string">"Mayank"</span> && (</span><br><span class="line"> <AdminHeaderComponent><span class="xml"><span class="tag"></<span class="name">AdminHeaderComponent</span>></span></span></span><br><span class="line"> )}</span><br><span class="line"> <HeaderComponent><span class="xml"><span class="tag"></<span class="name">HeaderComponent</span>></span></span></span><br><span class="line"> <ContentComponent><span class="xml"><span class="tag"></<span class="name">ContentComponent</span>></span></span></span><br><span class="line"> <<span class="regexp">/></span></span><br><span class="line"><span class="regexp"> );</span></span><br><span class="line"><span class="regexp"> }</span></span><br><span class="line"><span class="regexp">}</span></span><br></pre></td></tr></table></figure><p>在上面的代码中,当 name 不是 Mayank 时,React 在位置 1 处放置 null。</p><p>开始 DOM diffing 时,位置 1 的元素从 AdminHeaderComponent 变为 null,但位置 2 和位置 3 的组件保持不变。</p><p>由于元素没变,因此组件不会卸载,减少了不必要的操作。</p><p>详细信息请参阅:<br><a href="https://medium.com/@cowi4030/optimizing-conditional-rendering-in-react-3fee6b197a20" target="_blank" rel="noopener">https://medium.com/@cowi4030/optimizing-conditional-rendering-in-react-3fee6b197a20</a></p><h3 id="12-不要在-render-方法中导出数据"><a href="#12-不要在-render-方法中导出数据" class="headerlink" title="12. 不要在 render 方法中导出数据"></a>12. 不要在 render 方法中导出数据</h3><p>Render 方法是 React 开发人员最熟悉的生命周期事件。</p><p>和其他生命周期事件不一样的是,我们的核心原则是将 render() 函数作为纯函数。</p><ul><li>纯函数对 render 方法意味着什么?<blockquote><p>纯函数意味着我们应该确保 setState 和查询原生 DOM 元素等任何可以修改应用状态的东西不会被调用。<br>该函数永远不该更新应用的状态。<br>更新组件状态的问题在于,当状态更新时会触发另一个 render 循环,后者在内部会再触发一个 render 循环,以此类推。</p></blockquote></li></ul><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> React <span class="keyword">from</span> <span class="string">"react"</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="class"><span class="keyword">class</span> <span class="title">RenderFunctionOptimization</span> <span class="keyword">extends</span> <span class="title">React</span>.<span class="title">Component</span> </span>{</span><br><span class="line"> <span class="keyword">constructor</span>() {</span><br><span class="line"> <span class="keyword">this</span>.state = {</span><br><span class="line"> name: <span class="string">"Mayank"</span></span><br><span class="line"> };</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> render() {</span><br><span class="line"> <span class="keyword">this</span>.setState({</span><br><span class="line"> name: <span class="keyword">this</span>.state.name + <span class="string">"_"</span></span><br><span class="line"> });</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> (</span><br><span class="line"> <div></span><br><span class="line"> <b>User Name: {<span class="keyword">this</span>.state.name}<<span class="regexp">/b></span></span><br><span class="line"><span class="regexp"> </</span>div></span><br><span class="line"> );</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>在上面的代码中,每次调用 render 函数时都会更新状态。状态更新后组件将立即重新渲染。因此更新状态会导致 render 函数的递归调用。</p><p>render 函数应保持纯净,以确保组件以一致的方式运行和渲染。</p><h3 id="13-为组件创建错误边界"><a href="#13-为组件创建错误边界" class="headerlink" title="13. 为组件创建错误边界"></a>13. 为组件创建错误边界</h3><p>组件渲染错误是很常见的情况。</p><p>在这种情况下,组件错误不应该破坏整个应用。创建错误边界可避免应用在特定组件发生错误时中断。</p><p>错误边界是一个 React 组件,可以捕获子组件中的 JavaScript 错误。我们可以包含错误、记录错误消息,并为 UI 组件故障提供回退机制。</p><p>错误边界是基于高阶组件的概念。</p><p>详细信息参阅:<br><a href="https://levelup.gitconnected.com/introduction-to-reacts-higher-order-components-hocs-c42182fb634" target="_blank" rel="noopener">https://levelup.gitconnected.com/introduction-to-reacts-higher-order-components-hocs-c42182fb634</a></p><p>错误边界涉及一个高阶组件,包含以下方法:static getDerivedStateFromError() 和 componentDidCatch()。</p><p>static 函数用于指定回退机制,并从收到的错误中获取组件的新状态。</p><p>componentDidCatch 函数用来将错误信息记录到应用中。</p><p>下面是代码示例:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> React <span class="keyword">from</span> <span class="string">"react"</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="class"><span class="keyword">class</span> <span class="title">ErrorBoundaries</span> <span class="keyword">extends</span> <span class="title">React</span>.<span class="title">Component</span> </span>{</span><br><span class="line"> <span class="keyword">constructor</span>(props) {</span><br><span class="line"> <span class="keyword">super</span>(props);</span><br><span class="line"> <span class="keyword">this</span>.state = {</span><br><span class="line"> hasErrors: <span class="literal">false</span></span><br><span class="line"> };</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> componentDidCatch(error, info) {</span><br><span class="line"> <span class="built_in">console</span>.dir(<span class="string">"Component Did Catch Error"</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">static</span> getDerivedStateFromError(error) {</span><br><span class="line"> <span class="built_in">console</span>.dir(<span class="string">"Get Derived State From Error"</span>);</span><br><span class="line"> <span class="keyword">return</span> {</span><br><span class="line"> hasErrors: <span class="literal">true</span></span><br><span class="line"> };</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> render() {</span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">this</span>.state.hasErrors === <span class="literal">true</span>) {</span><br><span class="line"> <span class="keyword">return</span> <span class="xml"><span class="tag"><<span class="name">div</span>></span>This is a Error<span class="tag"></<span class="name">div</span>></span></span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> (</span><br><span class="line"> <div></span><br><span class="line"> <ShowData name=<span class="string">"Mayank"</span> /></span><br><span class="line"> <<span class="regexp">/div></span></span><br><span class="line"><span class="regexp"> );</span></span><br><span class="line"><span class="regexp"> }</span></span><br><span class="line"><span class="regexp">}</span></span><br><span class="line"><span class="regexp"></span></span><br><span class="line"><span class="regexp">export class ShowData extends React.Component {</span></span><br><span class="line"><span class="regexp"> constructor() {</span></span><br><span class="line"><span class="regexp"> super();</span></span><br><span class="line"><span class="regexp"> this.state = {</span></span><br><span class="line"><span class="regexp"> name: "Mayank"</span></span><br><span class="line"><span class="regexp"> };</span></span><br><span class="line"><span class="regexp"> }</span></span><br><span class="line"><span class="regexp"></span></span><br><span class="line"><span class="regexp"> changeData = () => {</span></span><br><span class="line"><span class="regexp"> this.setState({</span></span><br><span class="line"><span class="regexp"> name: "Anshul"</span></span><br><span class="line"><span class="regexp"> });</span></span><br><span class="line"><span class="regexp"> };</span></span><br><span class="line"><span class="regexp"> render() {</span></span><br><span class="line"><span class="regexp"> if (this.state.name === "Anshul") {</span></span><br><span class="line"><span class="regexp"> throw new Error("Sample Error");</span></span><br><span class="line"><span class="regexp"> }</span></span><br><span class="line"><span class="regexp"></span></span><br><span class="line"><span class="regexp"> return (</span></span><br><span class="line"><span class="regexp"> <div></span></span><br><span class="line"><span class="regexp"> <b>This is the Child Component {this.state.name}</</span>b></span><br><span class="line"> <input</span><br><span class="line"> type=<span class="string">"button"</span></span><br><span class="line"> onClick={<span class="keyword">this</span>.changeData}</span><br><span class="line"> value=<span class="string">"Click To Throw Error"</span></span><br><span class="line"> /></span><br><span class="line"> <<span class="regexp">/div></span></span><br><span class="line"><span class="regexp"> );</span></span><br><span class="line"><span class="regexp"> }</span></span><br><span class="line"><span class="regexp">}</span></span><br></pre></td></tr></table></figure><p>当 name 更新为 Anshul 时,上面的代码会抛出错误。</p><p>组件 ShowData 是 ErrorBoundaries 组件内的嵌入。</p><p>因此,如果错误是从 ShowData 函数内抛出的,则它会被父组件捕获,我们使用 static getDerivedStateFromError 函数和 componentDidCatch 生命周期事件中的日志数据部署回退 UI。</p><h3 id="14-组件的不可变数据结构"><a href="#14-组件的不可变数据结构" class="headerlink" title="14. 组件的不可变数据结构"></a>14. 组件的不可变数据结构</h3><p>React 的灵魂是函数式编程。如果我们希望组件能一致工作,则 React 组件中的状态和 props 数据应该是不可变的。</p><p>对象的突变可能导致输出不一致。</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> React <span class="keyword">from</span> <span class="string">"react"</span></span><br><span class="line"></span><br><span class="line">expoort <span class="keyword">default</span> <span class="class"><span class="keyword">class</span> <span class="title">ImmutableComponentData</span> <span class="keyword">extends</span> <span class="title">React</span>.<span class="title">Component</span> </span>{</span><br><span class="line"> <span class="keyword">constructor</span>() {</span><br><span class="line"> <span class="keyword">this</span>.state = {</span><br><span class="line"> userInfo: {</span><br><span class="line"> name: <span class="string">"Mayank"</span>,</span><br><span class="line"> age: <span class="number">30</span>,</span><br><span class="line"> designation: <span class="string">"Software Architect"</span></span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> updateUser() {</span><br><span class="line"> <span class="keyword">this</span>.setState({</span><br><span class="line"> userInfo: {</span><br><span class="line"> name: <span class="string">"OtherUser"</span></span><br><span class="line"> }</span><br><span class="line"> })</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> shouldComponentUpdate(nextProps, nextState) {</span><br><span class="line"> <span class="keyword">if</span>(nextState.userInfo != <span class="keyword">this</span>.state.userInfo) {</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> render() {</span><br><span class="line"> <span class="keyword">return</span> (</span><br><span class="line"> <></span><br><span class="line"> <b>User Name: {<span class="keyword">this</span>.state.userName}</span><br><span class="line"> <<span class="regexp">/></span></span><br><span class="line"><span class="regexp"> )</span></span><br><span class="line"><span class="regexp"> }</span></span><br><span class="line"><span class="regexp">}</span></span><br></pre></td></tr></table></figure><p>如上所示。在 shouldComponentUpdate 函数中我们指定,如果 userInfo 的初始值与 userInfo 的新值不同,则应该重新渲染该组件;反之不应重新渲染组件。</p><p>详细信息参阅:<br><a href="https://blog.logrocket.com/immutability-in-react-ebe55253a1cc" target="_blank" rel="noopener">https://blog.logrocket.com/immutability-in-react-ebe55253a1cc</a></p><h3 id="15-使用唯一键迭代"><a href="#15-使用唯一键迭代" class="headerlink" title="15. 使用唯一键迭代"></a>15. 使用唯一键迭代</h3><p>当我们需要渲染项目列表时应该为项目添加一个键。</p><p>键可以用来识别已更改、添加或删除的项目。键为元素提供了稳定的标识。一个键应该对应列表中的唯一一个元素。</p><p>如果开发人员没有为元素提供键,则它将 index 作为默认键。在下面的代码中我们默认不添加任何键,因此 index 将用作列表的默认键。</p><p>使用 index 作为键就不会出现标识不唯一的问题了,因为 index 只会标识所渲染的组件。</p><blockquote><p>我们可以在以下场景中使用 index 作为键:</p></blockquote><ul><li>列表项是静态的,项目不随时间变化。</li><li>Items 没有唯一 ID。</li><li>List 永远不会重新排序或过滤。</li><li>不会从顶部或中间添加或删除项目</li></ul><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line">export default class ComponentRecreation extends React.Component {</span><br><span class="line"> constructor() {</span><br><span class="line"> super();</span><br><span class="line"> this.state = {</span><br><span class="line"> inputName: "",</span><br><span class="line"> arrayData: ["Mayank", "Meha", "Anshul", "Arjun"]</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> updateUserName(event) {</span><br><span class="line"> this.setState({</span><br><span class="line"> inputName: event.target.value</span><br><span class="line"> })</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> addUserData() {</span><br><span class="line"> this.setState({</span><br><span class="line"> arrayData: [this.state.inputName, ...this.state.arrayData]</span><br><span class="line"> })</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> render() {</span><br><span class="line"> var dataList = this.state.arrayData.map((data, index) => {</span><br><span class="line"> return <div>{data}</div>;</span><br><span class="line"> })</span><br><span class="line"> return (</span><br><span class="line"> <div></span><br><span class="line"> <input type="text" value={this.state.inputName} placeholder="Enter Unique Name" onChange={this.updateUserName.bind(this)} /></span><br><span class="line"> <input type="button" onClick={this.addUserData.bind(this)} value="Click To Add" /><br></br><br></br></span><br><span class="line"> <b>List of Users: </b><br></br><br></br></span><br><span class="line"> {dataList}<br></br></span><br><span class="line"> </div></span><br><span class="line"> )</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><blockquote><p>在列表中添加项目<br>使用 index 作为键会加大错误率并降低应用的性能。</p></blockquote><p>每当新元素添加到列表时,默认情况下 React 会同时遍历新创建的列表和旧列表,并在需要时进行突变。</p><p>在列表顶部添加一个新元素(包含 index 作为键)时,全部已有组件的索引都会更新。</p><p>索引更新后,之前键值为 1 的元素现在的键值变成了 2。更新所有组件会拖累性能。</p><p>上面的代码允许用户在列表顶部添加新项目。但在顶部插入元素后果最严重。因为顶部元素一变,后面所有的元素都得跟着改键值,从而导致性能下降。</p><p>因此,我们应该确保键值和元素一一对应不会变化。</p><ul><li><p>Key 不仅影响性能,更重要的作用是标识。随机分配和更改的值不算是标识。</p></li><li><p>我们得知道数据的建模方式才能提供合适的键值。如果你没有 ID,我建议使用某种哈希函数生成 ID。</p></li><li><p>我们在使用数组时已经有了内部键,但它们是数组中的索引。插入新元素时这些键是错误的</p></li></ul><p>详细信息请参阅:</p><ul><li><p><a href="https://reactjs.org/docs/reconciliation.html?#recursing-on-children" target="_blank" rel="noopener">https://reactjs.org/docs/reconciliation.html?#recursing-on-children</a></p></li><li><p><a href="https://medium.com/@robinpokorny/index-as-a-key-is-an-anti-pattern-e0349aece318" target="_blank" rel="noopener">https://medium.com/@robinpokorny/index-as-a-key-is-an-anti-pattern-e0349aece318</a></p></li></ul><h3 id="16-事件节流和防抖"><a href="#16-事件节流和防抖" class="headerlink" title="16. 事件节流和防抖"></a>16. 事件节流和防抖</h3><p>节流(throttling)和防抖(debouncing)可用来限制在指定时间内调用的事件处理程序的数量。</p><p>事件处理程序是响应不同事件(如鼠标单击和页面滚动)而调用的函数。事件触发事件处理程序的速率是不一样的。</p><p><strong>节流的概念</strong></p><blockquote><p>节流意味着延迟函数执行。<br>这些函数不会立即执行,在触发事件之前会加上几毫秒延迟。<br>比如在页面滚动时,我们不会过于频繁地触发滚动事件,而是将事件延迟一段时间以便将多个事件堆叠在一起。<br>它确保函数在特定时间段内至少调用一次。如果函数最近运行过了,它将阻止函数运行,确保函数以固定间隔定期运行。<br>当我们处理无限滚动并且当用户接近页面底部必须获取数据时,我们可以使用节流。<br>否则滚动到页面底部将触发多个事件,并且触发对网络的多次调用,从而导致性能问题。</p></blockquote><p><strong>防抖的概念</strong></p><blockquote><p>防抖是指在调用停止一段时间之前忽略事件处理程序调用。<br>假设我们有一个事件,有一秒钟的 debounce 时间。一旦用户停止触发事件,该事件的事件处理程序将在一秒钟后触发</p></blockquote><p><img src="https://mmbiz.qpic.cn/mmbiz_jpg/XIibZ0YbvibkVq7r2MICNGrSmLzFDicvKSN9L65kcvyr2sAH200o44aMSWnBbyb8IaV20sQ0dfyGkLOkOGG4YTrIA/640?wx_fmt=jpeg&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1" alt="用例图"></p><blockquote><p>典型的例子是用户在自动填充搜索框中键入数据。<br>一旦用户停止键入,就会进行 AJAX 查询以从 API 获取数据。每次键入都进行 AJAX 调用就需要多次查询数据库。<br>因此,我们对该事件做 debounce,直到用户不再输入数据为止,从而减少网络调用并提升性能。<br>我们可以使用第三方库来实现和使用节流和防抖功能,例如 throttle-debounce。具体用法参阅:<br><a href="https://www.npmjs.com/package/throttle-debounce。" target="_blank" rel="noopener">https://www.npmjs.com/package/throttle-debounce。</a></p></blockquote><h3 id="17-使用-CDN"><a href="#17-使用-CDN" class="headerlink" title="17. 使用 CDN"></a>17. 使用 CDN</h3><p>谷歌、亚马逊和微软等公司提供了许多内容分发网络。</p><p>这些 CDN 是可在你的应用中使用的外部资源。我们甚至可以创建私有 CDN 并托管我们的文件和资源。</p><p>使用 CDN 有以下好处:</p><ul><li><strong>不同的域名。</strong> 浏览器限制了单个域名的并发连接数量,具体取决于浏览器设置。假设允许的并发连接数为 10。如果要从单个域名中检索 11 个资源,那么同时完成的只有 10 个,还有 1 个需要再等一会儿。CDN 托管在不同的域名 / 服务器上。因此资源文件可以分布在不同的域名中,提升了并发能力。</li><li><strong>文件可能已被缓存。</strong> 有很多网站使用这些 CDN,因此你尝试访问的资源很可能已在浏览器中缓存好了。这时应用将访问文件的已缓存版本,从而减少脚本和文件执行的网络调用和延迟,提升应用性能。</li><li><strong>高容量基础设施。</strong> 这些 CDN 由大公司托管,因此可用的基础设施非常庞大。他们的数据中心遍布全球。向 CDN 发出请求时,它们将通过最近的数据中心提供服务,从而减少延迟。这些公司会对服务器做负载平衡,以确保请求到达最近的服务器并减少网络延迟,提升应用性能。</li></ul><p>如果担心安全性,可以使用私有 CDN。</p><h3 id="18-用-CSS-动画代替-JavaScript-动画"><a href="#18-用-CSS-动画代替-JavaScript-动画" class="headerlink" title="18. 用 CSS 动画代替 JavaScript 动画"></a>18. 用 CSS 动画代替 JavaScript 动画</h3><p>在 HTML 5 和 CSS 3 出现之前,动画曾经是 JavaScript 的专属,但随着 HTML 5 和 CSS 3 的引入情况开始变化。现在动画甚至可以由 CSS 3 来处理了。</p><blockquote><p>我们可以制定一些规则:</p></blockquote><ul><li>如果 CSS 可以实现某些 JS 功能,那就用 CSS。</li><li>如果 HTML 可以实现某些 JS 功能,那就用 HTML。</li></ul><blockquote><p>理由如下:</p></blockquote><ul><li>破损的 CSS 规则和样式不会导致网页损坏,而 JavaScript 则不然。</li><li>解析 CSS 是非常便宜的,因为它是声明性的。我们可以为样式并行创建内存中的表达,可以推迟样式属性的计算,直到元素绘制完成。</li><li>为动画加载 JavaScript 库的成本相对较高,消耗更多网络带宽和计算时间。</li><li>虽然 JavaScript 可以提供比 CSS 更多的优化,但优化过的 JavaScript 代码也可能卡住 UI 并导致 Web 浏览器崩溃。</li></ul><p>详细信息参阅:<br><a href="https://developers.google.com/web/fundamentals/design-and-ux/animations/css-vs-javascript" target="_blank" rel="noopener">https://developers.google.com/web/fundamentals/design-and-ux/animations/css-vs-javascript</a></p><h3 id="19-在-Web-服务器上启用-gzip-压缩"><a href="#19-在-Web-服务器上启用-gzip-压缩" class="headerlink" title="19. 在 Web 服务器上启用 gzip 压缩"></a>19. 在 Web 服务器上启用 gzip 压缩</h3><p>压缩是节省网络带宽和加速应用的最简单方法。</p><p>我们可以把网络资源压缩到更小的尺寸。Gzip 是一种能够快速压缩和解压缩文件的数据压缩算法。</p><p>它可以压缩几乎所有类型的文件,例如图像、文本、JavaScript 文件、样式文件等。Gzip 减少了网页需要传输到客户端的数据量。</p><p>当 Web 服务器收到请求时,它会提取文件数据并查找 Accept-Encoding 标头以确定如何压缩应用。</p><p>如果服务器支持 gzip 压缩,资源会被压缩后通过网络发送。每份资源的压缩副本(添加了 Content-Encoding 标头)指定使用 gzip 解压。</p><p>然后,浏览器将内容解压缩原始版本在渲染给用户。</p><p>只是 gzip 压缩需要付出成本,因为压缩和解压缩文件属于 CPU 密集型任务。但我们还是建议对网页使用 gzip 压缩。</p><p>详细信息参阅:<br><a href="https://royal.pingdom.com/can-gzip-compression-really-improve-web-performance" target="_blank" rel="noopener">https://royal.pingdom.com/can-gzip-compression-really-improve-web-performance</a></p><h3 id="20-使用-Web-Workers-处理-CPU-密集任务"><a href="#20-使用-Web-Workers-处理-CPU-密集任务" class="headerlink" title="20. 使用 Web Workers 处理 CPU 密集任务"></a>20. 使用 Web Workers 处理 CPU 密集任务</h3><p>JavaScript 是一个单线程应用,但在渲染网页时需要执行多个任务:</p><p>处理 UI 交互、处理响应数据、操纵 DOM 元素、启用动画等。所有这些任务都由单个线程处理。</p><p>可以使用 worker 来分担主线程的负载。</p><p>Worker 线程在后台运行,可以在不中断主线程的情况下执行多个脚本和 JavaScript 任务。</p><p>每当需要执行长时间的 CPU 密集任务时,可以使用 worker 在单独的线程上执行这些逻辑块。</p><p>它们在隔离环境中执行,并且使用进程间线程通信与主线程交互。主线程就可以腾出手来处理渲染和 DOM 操作任务。</p><p>详细信息参阅:<br><a href="https://medium.com/prolanceer/optimizing-react-app-performance-using-web-workers-79266afd4a7" target="_blank" rel="noopener">https://medium.com/prolanceer/optimizing-react-app-performance-using-web-workers-79266afd4a7</a></p><h3 id="21-React-组件的服务端渲染"><a href="#21-React-组件的服务端渲染" class="headerlink" title="21. React 组件的服务端渲染"></a>21. React 组件的服务端渲染</h3><p>服务端渲染可以减少初始页面加载延迟。</p><p>我们可以让网页从服务端加载初始页面,而不是在客户端上渲染。这样对 SEO 非常有利。</p><p>服务端渲染是指第一个组件显示的内容是从服务器本身发送的,而不是在浏览器级别操作。之后的页面直接从客户端加载。</p><p>这样我们就能把初始内容放在服务端渲染,客户端只按需加载部分页面。</p><blockquote><p>其好处包括:</p></blockquote><ul><li>性能:初始页面内容和数据是从服务器本身加载的,因此我们不需要添加加载器和下拉列表,而是等待初始页面加载完毕后再加载初始组件。</li><li>SEO 优化:爬虫在应用初始加载时查找页面内容。在客户端渲染时初始 Web 页面不包含所需的组件,这些组件需要等 React 脚本等文件加载完毕后才渲染出来</li></ul><p>服务端渲染还可以使用第三方库,如 Next.js。详细信息参阅: <a href="https://nextjs.org/" target="_blank" rel="noopener">https://nextjs.org/</a></p><p>这里有服务端渲染的示例项目:<a href="https://github.com/Mayankgupta688/reactServerRendering。只需从项目存储库执行以下步骤即可运行应用" target="_blank" rel="noopener">https://github.com/Mayankgupta688/reactServerRendering。只需从项目存储库执行以下步骤即可运行应用</a></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">npm install</span><br><span class="line">npm start</span><br></pre></td></tr></table></figure><p>这个应用中“pages”文件夹里的文件是可以用服务端渲染加载的初始 URL</p><blockquote><p>参考</p></blockquote><ul><li>示例代码 GitHub 仓库: <a href="https://github.com/Mayankgupta688/react-demos" target="_blank" rel="noopener">https://github.com/Mayankgupta688/react-demos</a></li><li>英文原文:<a href="https://medium.com/better-programming/https-medium-com-mayank-gupta-6-88-21-performance-optimizations-techniques-for-react-d15fa52c2349" target="_blank" rel="noopener">https://medium.com/better-programming/https-medium-com-mayank-gupta-6-88-21-performance-optimizations-techniques-for-react-d15fa52c2349</a></li></ul>]]></content>
<categories>
<category> react </category>
</categories>
<tags>
<tag> React 性能优化 javascript </tag>
</tags>
</entry>
<entry>
<title>js原生array之map</title>
<link href="/2019/07/01/js%E5%8E%9F%E7%94%9Farray%E4%B9%8Bmap/"/>
<url>/2019/07/01/js%E5%8E%9F%E7%94%9Farray%E4%B9%8Bmap/</url>
<content type="html"><![CDATA[<p>最近看mdn中 Array.prototype.map,以下为看的总结点</p><a id="more"></a><h2 id="Array-prototype-map"><a href="#Array-prototype-map" class="headerlink" title="Array.prototype.map()"></a>Array.prototype.map()</h2><h3 id="简介"><a href="#简介" class="headerlink" title="简介"></a>简介</h3><p> map()方法创建一个新数组,其结果是该数组中每个元素都调用一个提供的函数后返回的结果<br> 举例如下:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">var Array1 = [1, 4, 9, 6];</span><br><span class="line">// pass a <span class="keyword">function</span> to map</span><br><span class="line"></span><br><span class="line">const map1 = array1.map(x => x * 2);</span><br><span class="line">console.log(map1);</span><br><span class="line">// expected output: [2, 8, 18, 12]</span><br></pre></td></tr></table></figure><h3 id="语法"><a href="#语法" class="headerlink" title="语法"></a>语法</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">var newArray = arr.map(<span class="keyword">function</span> callback(currentValue[, index[, array]])) {</span><br><span class="line"><span class="built_in">return</span> element <span class="keyword">for</span> new_array</span><br><span class="line">}[, thisArg]);</span><br></pre></td></tr></table></figure><h4 id="参数"><a href="#参数" class="headerlink" title="参数"></a>参数</h4><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">callback</span><br></pre></td></tr></table></figure><p>生成新的数组函数,使用三个参数</p> <figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">currentValue</span><br></pre></td></tr></table></figure><p> callback数组中正在处理的当前元素.</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">index</span><br></pre></td></tr></table></figure><p> (可选) callback 数组中正在处理的当前元素的索引.</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">array</span><br></pre></td></tr></table></figure><p>(可选)执行callback函数时使用的this值。</p><h4 id="返回值"><a href="#返回值" class="headerlink" title="返回值"></a>返回值</h4><p>一个新数组,每个元素都是回调函数的结果。</p><h3 id="描述"><a href="#描述" class="headerlink" title="描述"></a>描述</h3><p>map方法会给原数组中的每个元素都按顺序调用一次callback函数。callback每次执行后的返回值(包括undefined)组合起来形成一个新数组。callback函数只会在有值的索引上被调用;那些从来没被赋过值或者使用delete删除的索引则不会被调用。<br>callback 函数会被自动传入三个参数:数组元素、元素索引、原数组本身。<br>如果thisArg参数有值,则每次callback函数被调用的时候,this都会指向thisArg参数上的这个对象.如果省略了thisArg参数,后者赋值为null活undefined,则this指向全局对象。<br>map不修改调用它的原数组本身(当然可以在callback执行时改变原数组).<br>使用map方法处理数组时,数组元素的范围在callback方法第一次调用之前就已经确定了。在map方法执行的过程中:原数组中新增加的元素将不会被callback访问到;若已经存在的元素被改变或删除了,则他们的传递到callback的值map方法便利到它们的那一时刻的值;而被删除的元素不会被访问到。</p><h3 id="示例"><a href="#示例" class="headerlink" title="示例"></a>示例</h3><h4 id="求数组中每个元素的平方根"><a href="#求数组中每个元素的平方根" class="headerlink" title="求数组中每个元素的平方根"></a>求数组中每个元素的平方根</h4><p>下面的代码创建了一个新数组,值为原数组中对应数字的平方根</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">var numbers = [1, 4, 9];</span><br><span class="line">var roots = numbers.map(Math.sqrt);</span><br><span class="line">// roots的值为[1,2,3], numbers的值仍为[1,4,9]</span><br></pre></td></tr></table></figure><h4 id="使用map重新格式化数组中的对象"><a href="#使用map重新格式化数组中的对象" class="headerlink" title="使用map重新格式化数组中的对象"></a>使用map重新格式化数组中的对象</h4><p>以下代码使用一个包含对象的数组来重新创建一个格式化的数组.</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">var kvArray = [{key: 1, value: 10},</span><br><span class="line"> {key: 2, value: 20},</span><br><span class="line"> {key: 3, value: 30},</span><br><span class="line"> ];</span><br><span class="line">var reformattedArray = kvArray.map(<span class="keyword">function</span>(obj) {</span><br><span class="line">var rObj = {};</span><br><span class="line">rObj[obj.key] = obj.value;</span><br><span class="line"><span class="built_in">return</span> rObj;</span><br><span class="line">});</span><br><span class="line">// reforamttedArray 数组为: [{1: 10}, {2: 20}, {3: 30}];</span><br><span class="line">// kvArray 数组未被修改</span><br><span class="line">// [{key: 1, value: 10},</span><br><span class="line">//{key: 2, value: 20},</span><br><span class="line">//{key: 3, value: 30}]</span><br></pre></td></tr></table></figure><h4 id="使用一个包含一个参数的函数来mapping-构建-一个数字数组"><a href="#使用一个包含一个参数的函数来mapping-构建-一个数字数组" class="headerlink" title="使用一个包含一个参数的函数来mapping(构建)一个数字数组"></a>使用一个包含一个参数的函数来mapping(构建)一个数字数组</h4><p>下面的代码表示了当函数需要一个参数时map的工作方式。当map循环便利原始数组时,这个参数回自动被分配成数组中对应的每个元素。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">var numbers = [1, 4, 9];</span><br><span class="line">var doubles = numbers.map(<span class="keyword">function</span>(item) => {</span><br><span class="line"><span class="built_in">return</span> num * 2;</span><br><span class="line">});</span><br><span class="line"></span><br><span class="line">// doubles数组的值为: [2, 8, 18];</span><br><span class="line">// numbers数组未被修改 [1, 4, 9]</span><br></pre></td></tr></table></figure><h4 id="一般的map方法"><a href="#一般的map方法" class="headerlink" title="一般的map方法"></a>一般的map方法</h4><p>下面的例子演示如何在一个String上使用map方法获取字符串中每个字符多对应的ASCII码组成的数组。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">var map = Array.prototype.map;</span><br><span class="line">var a = map.call(<span class="string">'Hello World'</span>, <span class="keyword">function</span>(x) {</span><br><span class="line"><span class="built_in">return</span> x.charCodeAt(0);</span><br><span class="line">});</span><br></pre></td></tr></table></figure><h4 id="querySelectorAll-应用"><a href="#querySelectorAll-应用" class="headerlink" title="querySelectorAll 应用"></a>querySelectorAll 应用</h4><p>下面代码展示了如何去遍历用querySelectorAll 得到的动态对象集合。在这里,我们获得了文档里所有选中的选项,并将其打印:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">var elems =document.querySelectorAll(<span class="string">'select option:checked'</span>);</span><br><span class="line">var values = Array.prototype.map.call(elems. <span class="keyword">function</span>(obj) {</span><br><span class="line"><span class="built_in">return</span> obj.value;</span><br><span class="line">});</span><br></pre></td></tr></table></figure><h4 id="使用技巧案例"><a href="#使用技巧案例" class="headerlink" title="使用技巧案例"></a>使用技巧案例</h4><p>通常情况下,map方法中的callback函数只需要接受一个参数,就是正在被遍历的数组元素本身。但这并不意味着map只给callback传了一个参数。这个思维惯性可能会让我们犯一个很容易犯的错误。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line">// 下面的语句返回什么呢:</span><br><span class="line">[<span class="string">'1'</span>, <span class="string">'2'</span>, <span class="string">'3'</span>].map(parseInt);</span><br><span class="line">// 你可能觉得会是 [1, 2, 3];</span><br><span class="line">// 但实际结果是[1, NaN, NaN];</span><br><span class="line"></span><br><span class="line">// 通常使用parseInt时,只需要传递一个参数</span><br><span class="line">// 但实际上,parseInt可以有两个参数,第二个参数是进制数</span><br><span class="line">// 可以通过语句 <span class="string">'alert(parseInt.length) === 2'</span>来验证</span><br><span class="line">// map方法在调用callback函数时,会给它传递三个参数:当前正在遍历的元素,元素索引,原数组本身。</span><br><span class="line">// 第三个参数parseInt 会忽视,但第二个参数不会,也就是说,parseInt把传过来的索引值当成进制数来使用,从而返回了NaN</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> returnInt (element) {</span><br><span class="line"><span class="built_in">return</span> parseInt(element, 10);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">[<span class="string">'1'</span>, <span class="string">'2'</span>, <span class="string">'3'</span>].map(returnInt); // [1, 2, 3] 意料之中的结果</span><br><span class="line"></span><br><span class="line">// 也可以使用简单的箭头函数,结果同上</span><br><span class="line">[<span class="string">'1'</span>, <span class="string">'2'</span>, <span class="string">'3'</span>].map( str => parseInt(str));</span><br><span class="line"></span><br><span class="line">// 一个简单的方式:</span><br><span class="line">[<span class="string">'1'</span>, <span class="string">'2'</span>, <span class="string">'3'</span>].map(Number); // [1, 2, 3]</span><br><span class="line"></span><br><span class="line">// 与`parseInt`不同,下面的结果会返回浮点数或指数</span><br><span class="line">[<span class="string">'1.1'</span>, <span class="string">'2.2e2'</span>, <span class="string">'3e300'</span>].map(Number); // [1.1, 220, 3e+300]</span><br></pre></td></tr></table></figure><h4 id="Polyfill"><a href="#Polyfill" class="headerlink" title="Polyfill"></a>Polyfill</h4><p>map是在最近的ECMA-262 标准中新添加的方法;所以一些旧版本的浏览器可能没有实现该方法。在那些没有原生支持map方法的浏览器中,你可以使用下面的Javascript代码来实现它。所使用的算法正式ECMA-262,第五版规定的。假定Object,TypeError, 和Array有他们的原始值。而且callback.call的原始值也是Function.prototype.call</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br></pre></td><td class="code"><pre><span class="line">// 实现ECMA-262, Edition 5,15.4.4.19</span><br><span class="line"> //参考: http://es5.github/com/<span class="comment">#x15.4.4.19</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (!Array.prototype.map) {</span><br><span class="line"> Array.prototype.map = <span class="keyword">function</span>(callback, thisArg) {</span><br><span class="line"> var T,A,k;</span><br><span class="line"> <span class="keyword">if</span>(this == null) {</span><br><span class="line"> throw new TypeError(<span class="string">' this is null or not defined'</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> // 1.将0赋值为调用map方法的数组</span><br><span class="line"> var 0 = Object(this);</span><br><span class="line"></span><br><span class="line"> // 2.将len赋值为数组0的长度</span><br><span class="line"> var len = 0.length >>> 0;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> // 3.如果callback 不是函数,则跑出TypeError异常</span><br><span class="line"> <span class="keyword">if</span> (Object.prototype.toString.call(callback) != <span class="string">'[object Function]'</span>) {</span><br><span class="line"> throw new TypeError(callback + <span class="string">' is not a function'</span>);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">// 4. 如果参数thisArg有值,则将T赋值为thisArg;</span><br><span class="line"><span class="keyword">if</span> (thisArg) {</span><br><span class="line">T = thisArg;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">// 5. 创建新数组A,长度为原数组0长度len</span><br><span class="line">A = new Array(len);</span><br><span class="line"></span><br><span class="line">// 6. 将k赋值为0</span><br><span class="line">k = 0;</span><br><span class="line"></span><br><span class="line">// 7. 当k < len时,执行循环</span><br><span class="line"><span class="keyword">while</span>(k < len) {</span><br><span class="line">var kValue, mappedValue;</span><br><span class="line">// 遍历0,k为原数组索引</span><br><span class="line"><span class="keyword">if</span> (k <span class="keyword">in</span> 0) {</span><br><span class="line">// kValue为索引k对应的值</span><br><span class="line">kValue = 0[k];</span><br><span class="line"></span><br><span class="line">// 执行callback,this指向T,参数有三个,分别是kValue:值,k:索引,0:原数组</span><br><span class="line">mappedValue = callback.call(T,kValue,k,0);</span><br><span class="line">// 返回值添加到新数组A中</span><br><span class="line">A[k] = mappedValue;</span><br><span class="line"></span><br><span class="line">}</span><br><span class="line">// k自增1</span><br><span class="line">k ++;</span><br><span class="line">}</span><br><span class="line">// 返回新数组</span><br><span class="line"><span class="built_in">return</span> A;</span><br><span class="line"> };</span><br><span class="line"> }</span><br></pre></td></tr></table></figure>]]></content>
</entry>
<entry>
<title>js之map</title>
<link href="/2019/06/22/js%E4%B9%8Bmap/"/>
<url>/2019/06/22/js%E4%B9%8Bmap/</url>
<content type="html"><![CDATA[<p>对比学习 Array.prototype.map 与 js的 map</p><a id="more"></a><h3 id="一、简介"><a href="#一、简介" class="headerlink" title="一、简介"></a>一、简介</h3><p> <strong>map</strong> 对象保存键值对。任何值(对象或原始值)都可以作为一个键或一个值。</p><h3 id="二、语法"><a href="#二、语法" class="headerlink" title="二、语法"></a>二、语法</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">new Map([iterable])</span><br></pre></td></tr></table></figure><p>2.1 参数</p><p> <em>iterable</em>可以是数组或者其他iterabled对象,其元素为键值对(两个元素的数组,例如[[1: ‘one’],[2: ‘two’]])。每个键值对都会添加到 <strong>新的Map</strong>。<em>null</em> 会被当作 <em>undefined</em></p><h3 id="三、-描述"><a href="#三、-描述" class="headerlink" title="三、 描述"></a>三、 描述</h3><p>一个Map对象在迭代时会根据对象中元素的插入顺序来进行 — 一个 <em>for…of</em>循环在每次迭代后会返回一个形式为[key,value]数组。</p><h4 id="键的相等(Key-equality)"><a href="#键的相等(Key-equality)" class="headerlink" title="键的相等(Key equality)"></a>键的相等(Key equality)</h4><p>键的比较是基于”Same ValueZero”算法: <em>NaN</em> 是与 <em>NaN</em> 相等的(虽然 <em>NaN !== NaN</em>),剩下所有其他的值是根据 <strong>===</strong> 运算符的结果判断是否相等。在目前的ECMAScript规范中,-0 和 +0 被认为是相等的,尽管在早期的草案中并不是这样。</p><h4 id="Objects-和-Maps的比较"><a href="#Objects-和-Maps的比较" class="headerlink" title="Objects 和 Maps的比较"></a>Objects 和 Maps的比较</h4><p> Objects 和 Maps 类似的是,他们都允许你按键存取一个值、删除键、检测一个键是否绑定了值。因此(并且也没有其他内建的替代方式了)过去我们一直都把对象当成Maps使用。不过Maps和Objects有一些重要的区别,在下列情况里使用Map会是更好的选择。</p><p>1、 一个Object的键只能是<em>字符串</em>或者<em>Symbols</em>,但一个Map的键可以是<strong>任意值</strong>,包括函数、对象、基本类型。<br>2、 Map中的键值是有序的,而添加到对象中的键则不是。因此,当对他进行遍历时,Map对象时按插入的顺序返回键值。<br>3、 你可以通过<em>size</em>属性直接获取一个<em>Map</em>的键值对个数,而<em>Object</em>的键值对个数只能手动计算。<br>4、 Map可直接迭代,而Object的迭代需要先获取他的键值数组,然后再进行迭代。<br>5、 Object都有自己的原型,原型链上的键名有可能和你自己对象上的设置的键名产生冲突。虽然ES5开始可以用 <em>map = Object.create(null)</em> 来创建一个没有原型的对象,但是这种用法不太常见。<br>6、 Map在涉及频繁增删键值对的场景下会有些性能优势。</p><h3 id="四、属性"><a href="#四、属性" class="headerlink" title="四、属性"></a>四、属性</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Map.length</span><br></pre></td></tr></table></figure><p> 属性length的值为0</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">get Map[@@species]</span><br></pre></td></tr></table></figure><p>本构造函数用于创建派生对象</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Map.prototype</span><br></pre></td></tr></table></figure><p>表示Map构造器的原型。允许添加属性从而应用于所有的Map对象</p><h3 id="五、Map-实例"><a href="#五、Map-实例" class="headerlink" title="五、Map 实例"></a>五、Map 实例</h3><p>所有的Map对象实例都会继承 Map.prototype</p><h4 id="属性"><a href="#属性" class="headerlink" title="属性"></a>属性</h4> <figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Map.prototype.constructor</span><br></pre></td></tr></table></figure><p> 返回一个函数,它创建了实例的原型。默认时Map函数</p> <figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Map.prototype.size</span><br></pre></td></tr></table></figure><p> 返回Map对象的键/值对的数量</p><h4 id="方法"><a href="#方法" class="headerlink" title="方法"></a>方法</h4> <figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Map.prototype.clear()</span><br></pre></td></tr></table></figure><p> 移除Map对象的所有键/值对。</p> <figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Map.prototype.delete(key)</span><br></pre></td></tr></table></figure><p> 如果Map对象中存在该元素,则移除它并返回true;否则如果该元素不存在则返回false</p> <figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Map.prototype.entries()</span><br></pre></td></tr></table></figure><p> 返回一个新的 <em>Iterator</em> 对象,它按插入顺序包含了Map对象中每个元素的<strong>[key,value]</strong>数组。</p> <figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Map.prototype.forEach(callbackFn[, thisArg])</span><br></pre></td></tr></table></figure><p> 按插入顺序,为Map对象里的每一键值对调用一次callbackFn函数。如果forEach 提供了thisArg,它将在每次回调中作为this值。</p> <figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Map.prototype.get(key)</span><br></pre></td></tr></table></figure><p> 返回键对应的值,如果不存在,则返回undefined</p> <figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Map.prototype.has(key)</span><br></pre></td></tr></table></figure><p> 返回一个布尔值,表示Map实例是否包含键对应的值。</p> <figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Map.prototype.keys()</span><br></pre></td></tr></table></figure><p> 返回一个新的 <em>Iterator</em>对象,他按插入顺序包含了Map对象中的每个元素的<strong>键</strong>。</p> <figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Map.prototype.set(key,value)</span><br></pre></td></tr></table></figure><p> 设置Map对象中键的值。返回该Map对象。</p> <figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Map.prototype.values()</span><br></pre></td></tr></table></figure><p> 返回一个新的<em>Iterator</em>对象,他按插入顺序包含了Map对象中每个元素的<strong>值</strong></p> <figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Map.prototype[@@iterator]()</span><br></pre></td></tr></table></figure><p> 返回一个新的 <em>Iterator</em>对象,他按插入顺序包含了Map对象中的每个元素的<strong>[key,value]数组</strong>。</p><h3 id="六、示例"><a href="#六、示例" class="headerlink" title="六、示例"></a>六、示例</h3><h4 id="使用Map对象"><a href="#使用Map对象" class="headerlink" title="使用Map对象"></a>使用Map对象</h4><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line">var myMap = new Map();</span><br><span class="line">var keyObj = {},</span><br><span class="line"> keyFunc = <span class="function"><span class="title">function</span></span>() {},</span><br><span class="line"> keyString = <span class="string">'a string'</span>;</span><br><span class="line"></span><br><span class="line"> // 添加键</span><br><span class="line"> myMap.set(keyString, <span class="string">"和键'a string' 关联的值"</span>);</span><br><span class="line"> myMap.set(keyObj, <span class="string">'和键keyObj关联的值'</span>);</span><br><span class="line"> myMap.set(keyFunc, <span class="string">'和键keyFunc关联的值'</span>);</span><br><span class="line"></span><br><span class="line"> myMap.size(); // 3</span><br><span class="line"></span><br><span class="line"> // 读取值</span><br><span class="line"> myMap.get(keyString); // 和键<span class="string">'a string'</span> 关联的值</span><br><span class="line"> myMap.get(keyObj); // 和键keyObj关联的值</span><br><span class="line"> myMap.get(keyFunc); // 和键keyFunc关联的值</span><br><span class="line"></span><br><span class="line"> myMap.get(<span class="string">'a string'</span>); // 和键<span class="string">'a string'</span> 关联的值</span><br><span class="line"> myMap.get({}); // undefined,因为 keyObj !== {}</span><br><span class="line"> myMap.get(<span class="function"><span class="title">function</span></span>() {}); // undefined, 因为keyFunc !== <span class="function"><span class="title">funcetion</span></span>() {}</span><br></pre></td></tr></table></figure><h4 id="将NaN作为Map的键"><a href="#将NaN作为Map的键" class="headerlink" title="将NaN作为Map的键"></a>将NaN作为Map的键</h4><p>NaN 也可以作为Map对象的键。虽然NaN和任何值甚至和自己都不相等(NaN !== NaN 返回 true), 但下面的例子表明,NaN作为Map的键来说是没有区别的:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">var myMap = new Map();</span><br><span class="line">myMap.set(NaN, <span class="string">'not a number'</span>);</span><br><span class="line">MyMap.get(NaN); // <span class="string">'not a number'</span></span><br><span class="line"></span><br><span class="line">var otherNaN = Number(<span class="string">'foo'</span>);</span><br><span class="line">myMap.get(otherNaN); // <span class="string">'not a number'</span></span><br></pre></td></tr></table></figure><h4 id="使用-for…of-方法迭代Map"><a href="#使用-for…of-方法迭代Map" class="headerlink" title="使用 for…of 方法迭代Map"></a>使用 for…of 方法迭代Map</h4><p>Map可以使用<em>for…of</em>循环来实现迭代</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line">var myMap = new Map();</span><br><span class="line">myMap.set(0, <span class="string">'zero'</span>);</span><br><span class="line">myMap.set(1, <span class="string">'one'</span>);</span><br><span class="line"><span class="keyword">for</span>(var [key, value] of myMap) {</span><br><span class="line">console.log(key + <span class="string">' = '</span> + value);</span><br><span class="line">}</span><br><span class="line">// 将会展示两个<span class="built_in">log</span>.一个是<span class="string">'0 = zero'</span> 另一个是 <span class="string">'1 = one'</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> (var key of myMap.keys()) {</span><br><span class="line">console.log(key);</span><br><span class="line">}</span><br><span class="line">// 将会展示两个<span class="built_in">log</span>,一个是<span class="string">'0'</span>,一个是<span class="string">'1'</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span>(var value of myMap.values()) {</span><br><span class="line">console.log(value);</span><br><span class="line">}</span><br><span class="line">// 将会展示两个<span class="built_in">log</span>,一个是<span class="string">'zero'</span> 另一个是<span class="string">'one'</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span>(var [key, value] of myMap.extries()) {</span><br><span class="line"> console.log(key + <span class="string">' = '</span> + value);</span><br><span class="line">}</span><br><span class="line">// 将会展示两个<span class="built_in">log</span>,一个是 0 = zero 另一个是 1 = one</span><br></pre></td></tr></table></figure><h4 id="使用forEach-方法迭代Map"><a href="#使用forEach-方法迭代Map" class="headerlink" title="使用forEach 方法迭代Map"></a>使用forEach 方法迭代Map</h4><p> Map也可以通过<em>forEach()</em>方法迭代</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">myMap.forEach(<span class="keyword">function</span>(value, key) {</span><br><span class="line"> console.log(key + <span class="string">' = '</span> + value);</span><br><span class="line">}, myMap);</span><br><span class="line">// 将会展示两个logs 一个是 0 = zero 另一个是 1 = one</span><br></pre></td></tr></table></figure><h4 id="Map与数组的关系"><a href="#Map与数组的关系" class="headerlink" title="Map与数组的关系"></a>Map与数组的关系</h4><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">var kvArray = [[<span class="string">"key1"</span>, <span class="string">"value1"</span>], [<span class="string">"key2"</span>, <span class="string">"value2"</span>]];</span><br><span class="line"></span><br><span class="line">// 使用常规的Map构造函数可以将一个二维键值对数组转换成一个Map对象</span><br><span class="line"></span><br><span class="line">var myMap = new Map(kvArray);</span><br><span class="line"></span><br><span class="line">myMap.get(<span class="string">"key1"</span>); // 返回值为 value1</span><br><span class="line"></span><br><span class="line">// 使用Array.from 函数可以将一个Map对象转换成一个二维键值对数组</span><br><span class="line">console.log(Array.from(myMap)); // 输出和kvArray相同的数组</span><br><span class="line"></span><br><span class="line">// 或者在键或者值的迭代器上使用Array.from, 进而得到只含有键或者值的数组</span><br><span class="line">console.log(Array.from(myMap.keys())); // 输出[<span class="string">'key1'</span>, <span class="string">'key2'</span>];</span><br></pre></td></tr></table></figure><h4 id="复制或合并Maps"><a href="#复制或合并Maps" class="headerlink" title="复制或合并Maps"></a>复制或合并Maps</h4><p>Map能像数组一样被复制</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">var original = new Map([1, <span class="string">'one'</span>]);</span><br><span class="line">var <span class="built_in">clone</span> = new Map(original);</span><br><span class="line"></span><br><span class="line">console.log(clone.get(1)); // one</span><br><span class="line">console.log(original === <span class="built_in">clone</span>); // <span class="literal">false</span>. Useful <span class="keyword">for</span> shallow comparison</span><br></pre></td></tr></table></figure><p><strong>请记住,数据本身未被克隆</strong></p><p>Map对象间可以进行合并,但是会保持键的唯一性</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">var first = new Map([</span><br><span class="line"> [1, <span class="string">'one'</span>],</span><br><span class="line"> [2, <span class="string">'two'</span>],</span><br><span class="line"> [3, <span class="string">'three'</span>]</span><br><span class="line">]);</span><br><span class="line">var second = new Map([</span><br><span class="line">[1, <span class="string">'uno'</span>],</span><br><span class="line">[2, <span class="string">'doc'</span>]</span><br><span class="line">]);</span><br><span class="line"></span><br><span class="line">// 合并两个Map对象时,如果有重复的键值,则后面的会覆盖前面的</span><br><span class="line"></span><br><span class="line">// 展开运算符本质上是将Map对象转换成数组</span><br><span class="line"></span><br><span class="line">var merged = new Map([...first, ...second]);</span><br><span class="line">console.log(merged.get(1)); // uno</span><br><span class="line">console.log(merged.get(2)); // doc</span><br><span class="line">console.log(merged.get(3)); // three</span><br></pre></td></tr></table></figure><p>Map对象也能与数组合并</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">var first = new Map([</span><br><span class="line"> [1, <span class="string">'one'</span>],</span><br><span class="line"> [2, <span class="string">'two'</span>],</span><br><span class="line"> [3, <span class="string">'three'</span>]</span><br><span class="line"> ]);</span><br><span class="line">var second = new Map([</span><br><span class="line">[1, <span class="string">'uno'</span>],</span><br><span class="line">[2, <span class="string">'doc'</span>]</span><br><span class="line">]);</span><br><span class="line"></span><br><span class="line">// Map对象同数组进行合并时。如果有重复的键值,则后面的会覆盖前面的。</span><br><span class="line">var merged = new Map([...first, ...second, [1, <span class="string">'eins'</span>]]);</span><br><span class="line">onsole.log(merged.get(1)); // eins</span><br><span class="line">console.log(merged.get(2)); // doc</span><br><span class="line">console.log(merged.get(3)); // three</span><br></pre></td></tr></table></figure>]]></content>
<tags>
<tag> javascript es6 </tag>
</tags>
</entry>
<entry>
<title>看javascript技巧有感</title>
<link href="/2019/06/21/%E7%9C%8Bjavascript%E6%8A%80%E5%B7%A7%E6%9C%89%E6%84%9F/"/>
<url>/2019/06/21/%E7%9C%8Bjavascript%E6%8A%80%E5%B7%A7%E6%9C%89%E6%84%9F/</url>
<content type="html"><![CDATA[<p>这段时间听同事面试校招生,发现自己原生js很弱,需要狂补,以下为看<a href="https://mp.weixin.qq.com/s/X6ks8HrhAXvIjkcnZ9qMLw" target="_blank" rel="noopener">《一个合格的中级前端工程师要掌握的javaScript技巧》</a>有感</p><a id="more"></a><h3 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h3><h4 id="这段时间听同事面试校招生,发现自己原生js很弱,需要狂补,以下为看《一个合格的中级前端工程师要掌握的javaScript技巧》有感"><a href="#这段时间听同事面试校招生,发现自己原生js很弱,需要狂补,以下为看《一个合格的中级前端工程师要掌握的javaScript技巧》有感" class="headerlink" title="这段时间听同事面试校招生,发现自己原生js很弱,需要狂补,以下为看《一个合格的中级前端工程师要掌握的javaScript技巧》有感"></a>这段时间听同事面试校招生,发现自己原生js很弱,需要狂补,以下为看<a href="https://mp.weixin.qq.com/s/X6ks8HrhAXvIjkcnZ9qMLw" target="_blank" rel="noopener">《一个合格的中级前端工程师要掌握的javaScript技巧》</a>有感</h4><h4 id="1、判断对象的数据类型"><a href="#1、判断对象的数据类型" class="headerlink" title="1、判断对象的数据类型"></a>1、判断对象的数据类型</h4><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">const isType = <span class="built_in">type</span> => target => `[Object <span class="variable">${type}</span>]` === Object.prototype.toString.call(target);</span><br><span class="line">const isArray = isType(<span class="string">'Array'</span>);</span><br><span class="line">console.log(isArray([])); // <span class="literal">true</span></span><br></pre></td></tr></table></figure><p>以上isType为高阶函数,可翻译如下:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">const isType = (<span class="built_in">type</span>) => {</span><br><span class="line"> (target) => {</span><br><span class="line"> <span class="built_in">return</span> `[Object <span class="variable">${type}</span>]` === Object.prototype.toString.call(target);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>使用 Object.prototype.toString 配合闭包,通过传入不同的判断类型来返回不同的判断函数,一行代码,简洁优雅灵活(注意传入type传入参数时首字母大写)</p><p><em>不推荐将这个函数用来检测可能会产生包装类型的基本数据类型上,因为call会将第一个参数进行装箱操作</em></p><h4 id="2、es5实现数组map方法"><a href="#2、es5实现数组map方法" class="headerlink" title="2、es5实现数组map方法"></a>2、es5实现数组map方法</h4><p> 对于map方法的运用,我们可以在<a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Map" target="_blank" rel="noopener">mdn</a>中查看到对应的用法,如下</p> <figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">const selfMap = <span class="keyword">function</span>(fn, context) {</span><br><span class="line"><span class="built_in">let</span> arr = Array.prototype.slice.call(this);</span><br><span class="line"><span class="built_in">let</span> mappedArr = [];</span><br><span class="line"><span class="keyword">for</span> (<span class="built_in">let</span> i = 0; i< arr.length; i++) {</span><br><span class="line"><span class="keyword">if</span> (!arr.hasOwnProperty(i)) <span class="built_in">continue</span>;</span><br><span class="line">mappedArr.push(fn.call(context, arr[i], i, this)))</span><br><span class="line">}</span><br><span class="line"><span class="built_in">return</span> mappedArr;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p> 值得一提的是,map的第二个参数为第一个参数回调中的this指向,如果第一个参数为箭头函数,那设置第二个this会因为箭头函数的词法绑定而失败。<br> 另外就是对稀疏数组的处理,通过hasOwnProperty来判断当前下标的元素是否存在与数组中</p><h4 id="3-使用reduce实现数组map方法"><a href="#3-使用reduce实现数组map方法" class="headerlink" title="3.使用reduce实现数组map方法"></a>3.使用reduce实现数组map方法</h4><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">const selfMap2 = <span class="keyword">function</span>(fn, context) {</span><br><span class="line"><span class="built_in">let</span> arr = Array.prototype.slice.call(this);</span><br><span class="line"><span class="built_in">return</span> arr.reduce((pre,cur,index) => {</span><br><span class="line"><span class="built_in">return</span> [...pre,fn.call(context, cur, index, this)]</span><br><span class="line">}, [])</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="4-ES5实现数组filter方法"><a href="#4-ES5实现数组filter方法" class="headerlink" title="4.ES5实现数组filter方法"></a>4.ES5实现数组filter方法</h4><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">const selfFilter = <span class="keyword">function</span>(fn, context) {</span><br><span class="line"><span class="built_in">let</span> arr = Array.prototype.slice.call(this);</span><br><span class="line"><span class="built_in">let</span> filteredArr = [];</span><br><span class="line"><span class="keyword">for</span> (<span class="built_in">let</span> i = 0; i< arr.length; i++) {</span><br><span class="line"><span class="keyword">if</span> (!arr.hasOwnProperty(i)) <span class="built_in">continue</span>;</span><br><span class="line">fn.call(context, arr[i], i, this) && filteredArr.push(arr[i]);</span><br><span class="line">}</span><br><span class="line"><span class="built_in">return</span> filteredArr;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="5-使用reduce实现数组filter方法"><a href="#5-使用reduce实现数组filter方法" class="headerlink" title="5.使用reduce实现数组filter方法"></a>5.使用reduce实现数组filter方法</h4><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">const selfFilter2 = <span class="keyword">function</span> (fn, context){</span><br><span class="line"><span class="built_in">return</span> this.reduce((pre, cur, index) => {</span><br><span class="line"><span class="built_in">return</span> fn.call(context, cur, index, this) ? [...pre, cur] : [...pre]</span><br><span class="line">}, [])</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="6-ES5实现数组的some方法"><a href="#6-ES5实现数组的some方法" class="headerlink" title="6. ES5实现数组的some方法"></a>6. ES5实现数组的some方法</h4><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">const selfSome = <span class="keyword">function</span>(fn, context) {</span><br><span class="line"><span class="built_in">let</span> arr = Array.prototype.slice.call(this);</span><br><span class="line"><span class="keyword">if</span> (!arr.length) <span class="built_in">return</span> <span class="literal">false</span>;</span><br><span class="line"><span class="built_in">let</span> flag = <span class="literal">false</span>;</span><br><span class="line"><span class="keyword">for</span> (<span class="built_in">let</span> i = 0; i < arr.length; i++) {</span><br><span class="line"><span class="keyword">if</span> (!arr.hasOwnProperty(i)) <span class="built_in">continue</span>;</span><br><span class="line"><span class="built_in">let</span> res = fn.call(context, arr[i], i, this);</span><br><span class="line"><span class="keyword">if</span> (res) {</span><br><span class="line">flag = <span class="literal">true</span>;</span><br><span class="line"><span class="built_in">break</span>;</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"><span class="built_in">return</span> flag;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="7-ES5实现数组的reduce方法"><a href="#7-ES5实现数组的reduce方法" class="headerlink" title="7.ES5实现数组的reduce方法"></a>7.ES5实现数组的reduce方法</h4><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line">/**</span><br><span class="line">@description 找到第一个empty的元素的下标</span><br><span class="line">@param {Array} arr - 参看说明</span><br><span class="line">@param {Number} {initIndex} - 遍历的起始下标</span><br><span class="line">@<span class="built_in">return</span> {Number}</span><br><span class="line">*/</span><br><span class="line"></span><br><span class="line">const findRealElementIndex = <span class="keyword">function</span>(arr, initIndex) {</span><br><span class="line"><span class="built_in">let</span> index;</span><br><span class="line"><span class="keyword">for</span> (<span class="built_in">let</span> i = initIndex || 0, i < arr.length; i++){</span><br><span class="line"><span class="keyword">if</span> (!arr.hasOwnProperty(i)) <span class="built_in">continue</span>;</span><br><span class="line">index = i;</span><br><span class="line"><span class="built_in">return</span> index;</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">const selfReduce = <span class="keyword">function</span>(fn, initValue) {</span><br><span class="line"><span class="built_in">let</span> arr = Array.prototype.slice.call(this);</span><br><span class="line"><span class="built_in">let</span> res;</span><br><span class="line"><span class="keyword">if</span> (initValue === undefined) {</span><br><span class="line">res= = arr[findRealElementIndex(arr)];</span><br><span class="line"><span class="keyword">for</span> (<span class="built_in">let</span> i = 0; i < arr.length - 1; i++){</span><br><span class="line"><span class="keyword">if</span> (!arr.hasOwnProperty(i)) <span class="built_in">continue</span>;</span><br><span class="line"><span class="built_in">let</span> realElementIndex = findRealElementIndex(arr, i+1);</span><br><span class="line">res = fn.call(null, res, arr[realElementIndex], realElementIndex, this);</span><br><span class="line">} <span class="keyword">else</span> {</span><br><span class="line">res = initValue;</span><br><span class="line"><span class="keyword">for</span> (<span class="built_in">let</span> i = 0; i < arr.length; i++) {</span><br><span class="line"><span class="keyword">if</span> (!arr.hasOwnProperty(i)) <span class="built_in">continue</span>;</span><br><span class="line">res = fn.call(null, res, arr[i], i, this);</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"><span class="built_in">return</span> res;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>因为可能存在稀疏数组的关系,所以reduce实现略有点复杂,需要保证跳过稀疏数组,遍历正确的元素和下标</p><h4 id="8-使用reduce-实现数组的flat方法"><a href="#8-使用reduce-实现数组的flat方法" class="headerlink" title="8.使用reduce 实现数组的flat方法"></a>8.使用reduce 实现数组的flat方法</h4><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">const selfFlat = <span class="keyword">function</span>(depth = 1) {</span><br><span class="line"><span class="built_in">let</span> arr = Array.prototype.slice.call(this);</span><br><span class="line"><span class="keyword">if</span> (depth === 0) <span class="built_in">return</span> arr;</span><br><span class="line"><span class="built_in">return</span> arr.reduce((pre, cur) => {</span><br><span class="line"><span class="keyword">if</span> (Array.isArray(cur)) {</span><br><span class="line"><span class="built_in">return</span> [...pre, ...selfFlat.call(cur, depth - 1)]</span><br><span class="line">} <span class="keyword">else</span> {</span><br><span class="line"><span class="built_in">return</span> [...pre, ...cur]</span><br><span class="line">}</span><br><span class="line">}, [])</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>因为slefFlat是依赖this指向的,所以在reduce遍历时需要指定slefFlat的this指向,否则会默认指向window从而发生错误。<br>远离通过reduce遍历数组,遇到数组的某个元素仍是数组,通过ES6的扩展运算符对其进行降维(ES5可以使用concat方法),而这个数组元素可能内部还嵌套数组,所以需要递归调用slefFlat<br>同时原生的falt方法支持一个depth参数表示较为的深度,默认为1即给数组降一层维度。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">let</span> arr = [1, 2, [3, 4], [5, [6, 7]]];</span><br><span class="line">arr.flat();</span><br><span class="line">// 返回为 [1, 2, 3, 4,5, [6, 7]]</span><br><span class="line">// 传入Inifity 会将传入的数组变成一个一维数组</span><br><span class="line">arr.falt(Infinity)</span><br><span class="line">// [1, 2, 3, 4, 5, 6, 7]</span><br></pre></td></tr></table></figure><p>原理是每递归一次将depth参数减1,如果depth参数为0时,直接返回原数组</p><h4 id="9-实现ES6的classs语法"><a href="#9-实现ES6的classs语法" class="headerlink" title="9.实现ES6的classs语法"></a>9.实现ES6的classs语法</h4><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> inhertit(subType, superType) {</span><br><span class="line">subType.prototype = Object.create(superType.prototype, {</span><br><span class="line">contructor: {</span><br><span class="line">enumerable: <span class="literal">false</span>,</span><br><span class="line">configurable: <span class="literal">true</span>,</span><br><span class="line">writable: <span class="literal">true</span>,</span><br><span class="line">value: superType.contructor</span><br><span class="line">}</span><br><span class="line">})</span><br><span class="line">// 继承递归</span><br><span class="line">Object.setPrototypeOf(subType, superType);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>ES6的class内部时基于寄生组合式继承,它是目前最理想的继承方式,通过Object.create方法创造一个空对象,并将这个空对象继承Object.create方法的参数,再让子类(subType)的原型对象等于这个空对象,就可以实现子类实例的原型等于这个空对象,而这个空对象的原型又等于父类原型对象(superType.peototype)的继承关系。</p><p>而Object.create支持第二个参数,即给生成的空对象定义属性和属性描述符/访问器描述符,我们可以给这个空对象定义一个contructor 属性更加符合默认的继承行为,同时它是不可枚举的内部属性(enumerable: false)</p><p>而ES6的class允许子类继承父类的静态方法和静态属性,而普通的寄生组合式继承只能做到实例与实例之间的继承,对于类与类之间的继承需要额外定义方法,这里使用Object.setPrototypeOf将superType设置为subType的原型,从而能够从父类中继承静态方法和静态属性。</p>]]></content>
<tags>
<tag> javaScript Array </tag>
</tags>
</entry>
<entry>
<title>webpack2.x升级到4.x踩坑点</title>
<link href="/2019/03/05/webpack2-x%E5%8D%87%E7%BA%A7%E5%88%B04-x%E8%B8%A9%E5%9D%91%E7%82%B9/"/>
<url>/2019/03/05/webpack2-x%E5%8D%87%E7%BA%A7%E5%88%B04-x%E8%B8%A9%E5%9D%91%E7%82%B9/</url>
<content type="html"><![CDATA[<p>BD项目webpack 2.X 生 4.X踩坑指南<br><a id="more"></a></p><h4 id="升级时间"><a href="#升级时间" class="headerlink" title="升级时间"></a>升级时间</h4><p>2019-03-03 ~ 2019-03-04</p><h4 id="结果"><a href="#结果" class="headerlink" title="结果"></a>结果</h4><p>升级未完成 20190305业务堆积</p><h4 id="升级遇到问题汇总"><a href="#升级遇到问题汇总" class="headerlink" title="升级遇到问题汇总"></a>升级遇到问题汇总</h4><h4 id="一、旧项目直接升级webpack报错(npm-install-webpack-)"><a href="#一、旧项目直接升级webpack报错(npm-install-webpack-)" class="headerlink" title="一、旧项目直接升级webpack报错(npm install webpack )"></a>一、旧项目直接升级webpack报错(npm install webpack )</h4><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">// 此部分从网上粘贴,报错大致类似</span><br><span class="line"></span><br><span class="line">peerDependencies link ajv@5.5.2 <span class="keyword">in</span> D:\work-span\travel\Travel\node_modules\_ajv-keywords@2.1.1@ajv-keywords unmet with D:\work-span\travel\Travel\node_modules\ajv(6.6.2)</span><br><span class="line">peerDependencies WARNING webpack-dev-server@^3.1.14 requires a peer of webpack@^4.0.0 but webpack@3.12.0 was installed</span><br><span class="line">peerDependencies WARNING webpack-cli@^3.1.2 requires a peer of webpack@^4.x.x but webpack@3.12.0 was installed</span><br><span class="line">peerDependencies WARNING webpack-dev-server@3.1.14 › webpack-dev-middleware@3.4.0 requires a peer of webpack@^4.0.0 but webpack@3.12.0 was installed</span><br><span class="line">deprecate autoprefixer@7.2.6 › browserslist@^2.11.3 Browserslist 2 could fail on reading Browserslist 3.0 config used <span class="keyword">in</span> other tools.</span><br><span class="line">deprecate css-loader@0.28.11 › cssnano@3.10.0 › autoprefixer@6.7.7 › browserslist@^1.7.6 Browserslist 2</span><br><span class="line">could fail on reading Browserslist 3.0 config used <span class="keyword">in</span> other tools.</span><br><span class="line">deprecate eslint@4.19.1 › file-entry-cache@2.0.0 › flat-cache@1.3.4 › circular-json@^0.3.1 CircularJSON</span><br><span class="line">is <span class="keyword">in</span> maintenance only, flatted is its successor.</span><br><span class="line">deprecate webpack-bundle-analyzer@2.13.1 › bfj-node4@^5.2.0 Switch to the `bfj` package <span class="keyword">for</span> fixes and new features!</span><br><span class="line">Recently updated (since 2018-12-18): 9 packages (detail see file D:\work-span\travel\Travel\node_modules\.recently_updates.txt)</span><br><span class="line">√ All packages installed (928 packages installed from npm registry, used 38s(network 37s), speed 529.19</span><br><span class="line">kB/s, json 802(1.72MB), tarball 17.22MB)</span><br></pre></td></tr></table></figure><p> 原因:旧系统本身安装了webpack以及其他包依赖,在升级之前需要先卸载或删除,然后升级才能成功,如下:升级后的版本</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">npm uninstall webpack</span><br><span class="line">npm install webpack</span><br></pre></td></tr></table></figure><h4 id="二、将webpack-webpack-cli-webpack-server-升级成功后,npm-run-build-报错"><a href="#二、将webpack-webpack-cli-webpack-server-升级成功后,npm-run-build-报错" class="headerlink" title="二、将webpack webpack-cli webpack-server 升级成功后,npm run build 报错"></a>二、将webpack webpack-cli webpack-server 升级成功后,npm run build 报错</h4><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">webpack4 Error: webpack.optimize.CommonsChunkPlugin has been removed,</span><br><span class="line"> please use config.optimization.splitChunks instead</span><br></pre></td></tr></table></figure><p>webpack4.x 版本与 2.x 区别之一就是webpack.optimize.CommonsChunkPlugin被移除了,原先在项目中的不可用了,需要用新的config.optimization.splitChunks,原先用法如图:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">new webpack.optimize.CommonsChunkPlugin({</span><br><span class="line"> name: <span class="string">'common'</span>,</span><br><span class="line"> filename: isBuild ? <span class="string">'commons-[chunkhash].min.js'</span> : <span class="string">'commons.js'</span>,</span><br><span class="line">})</span><br></pre></td></tr></table></figure><p>改进后的用法为:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">optimization: {</span><br><span class="line"> splitChunks: {</span><br><span class="line"> name: <span class="string">'common'</span>,</span><br><span class="line"> filename: isBuild ? <span class="string">'commons-[chunkhash].min.js'</span> : <span class="string">'commons.js'</span>,</span><br><span class="line"> },</span><br><span class="line"> runtimeChunk: {</span><br><span class="line"> name: <span class="string">'common'</span></span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="三、如上,splitChunks的写法还有问题,报错信息如图"><a href="#三、如上,splitChunks的写法还有问题,报错信息如图" class="headerlink" title="三、如上,splitChunks的写法还有问题,报错信息如图:"></a>三、如上,splitChunks的写法还有问题,报错信息如图:</h4><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">chunk optimization</span><br><span class="line">SplitChunksPlugin/Users/nieyuling/space/bd-node/node_modules/webpack/lib/optimize/SplitChunksPlugin.js:740</span><br><span class="line">throw new Error(</span><br><span class="line">^</span><br><span class="line">Error: SplitChunksPlugin: You are trying to <span class="built_in">set</span> a filename <span class="keyword">for</span> a chunk <span class="built_in">which</span></span><br><span class="line">is (also) loaded on demand. The runtime can only handle loading of chunks</span><br><span class="line"><span class="built_in">which</span> match the chunkFilename schema. Using a custom filename would fail</span><br><span class="line">at runtime. (cache group: vendors)</span><br></pre></td></tr></table></figure><p>原因:少写 chunks: ‘initial’,<br>加后为</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">optimization: {</span><br><span class="line"> splitChunks: {</span><br><span class="line"> chunks: <span class="string">'initial'</span>,</span><br><span class="line"> name: <span class="string">'common'</span>,</span><br><span class="line"> filename: isBuild ? <span class="string">'commons-[chunkhash].min.js'</span> : <span class="string">'commons.js'</span>,</span><br><span class="line"> },</span><br><span class="line"> runtimeChunk: {</span><br><span class="line"> name: <span class="string">'common'</span></span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="四、-npm-run-build-后-html-webpack-plugin-before-html-generation-报错"><a href="#四、-npm-run-build-后-html-webpack-plugin-before-html-generation-报错" class="headerlink" title="四、 npm run build 后 html-webpack-plugin-before-html-generation 报错"></a>四、 npm run build 后 html-webpack-plugin-before-html-generation 报错</h4><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">/Users/nieyuling/space/bd-node/node_modules/add-asset-html-webpack-plugin</span><br><span class="line">/lib/index.js:119</span><br><span class="line"> beforeGenerationHook.tapPromise(<span class="string">'AddAssetHtmlPlugin'</span>, htmlPluginData =</span><br><span class="line"> ^</span><br><span class="line">TypeError: Cannot <span class="built_in">read</span> property <span class="string">'tapPromise'</span> of undefined</span><br></pre></td></tr></table></figure><p>原因: html-webpack-plugin版本有问题,安装稳定版</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm install html-webpack-plugin@next</span><br></pre></td></tr></table></figure><h4 id="五、webpack提示Cannot-read-property-‘properties’-of-undefined错误"><a href="#五、webpack提示Cannot-read-property-‘properties’-of-undefined错误" class="headerlink" title="五、webpack提示Cannot read property ‘properties’ of undefined错误"></a>五、webpack提示Cannot read property ‘properties’ of undefined错误</h4><p>解决办法:<br>一、将webpack升级到稳定版,如下</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm i webpack-cli@next</span><br></pre></td></tr></table></figure><p>二、将对应的依赖包卸载再重新装,可能是包老的原因</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">npm uninstall</span><br><span class="line">npm install</span><br></pre></td></tr></table></figure><h4 id="六、Tapable-plugin-is-deprecated-Use-new-API-on-hooks-instead"><a href="#六、Tapable-plugin-is-deprecated-Use-new-API-on-hooks-instead" class="headerlink" title="六、Tapable.plugin is deprecated. Use new API on .hooks instead"></a>六、Tapable.plugin is deprecated. Use new API on <code>.hooks</code> instead</h4><p> 原因: 在使用extract-text-webpack-plugin给webpack打包时出现报错,extract-text-webpack-plugin目前版本不支持webpack4。需要将extract-text-webpack-plugin升级到稳定版或者最新版</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">npm uninstall extract-text-webpack-plugin</span><br><span class="line">npm install extract-text-webpack-plugin@next</span><br></pre></td></tr></table></figure><h4 id="七、htmlWebpackPluginBeforeHtmlGeneration-tapPromise-为undefined"><a href="#七、htmlWebpackPluginBeforeHtmlGeneration-tapPromise-为undefined" class="headerlink" title="七、htmlWebpackPluginBeforeHtmlGeneration.tapPromise 为undefined"></a>七、htmlWebpackPluginBeforeHtmlGeneration.tapPromise 为undefined</h4><p>报错版本:</p><p>“webpack”: “^4.29.6”,</p><p>“html-webpack-plugin”: “^2.28.0”,</p><p>需要将html-webpack-plugin升级到最新版或者稳定版</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">npm uminstall html-webpack-plugin</span><br><span class="line">npm install html-webpack-plugin@next</span><br></pre></td></tr></table></figure><h4 id="八、webpack-config-js配置遇到Error-Cannot-find-module-‘-babel-core’-amp-amp-Cannot-find-module-‘-babel-plugin-transform-react-jsx’-问题"><a href="#八、webpack-config-js配置遇到Error-Cannot-find-module-‘-babel-core’-amp-amp-Cannot-find-module-‘-babel-plugin-transform-react-jsx’-问题" class="headerlink" title="八、webpack.config.js配置遇到Error: Cannot find module ‘@babel/core’&&Cannot find module ‘@babel/plugin-transform-react-jsx’ 问题"></a>八、webpack.config.js配置遇到Error: Cannot find module ‘@babel/core’&&Cannot find module ‘@babel/plugin-transform-react-jsx’ 问题</h4><p> 原因:babel-core 应用 babel-loader的版本用起来须对应上,一般来说,高版本的需要需要同时运用,当时 babel-code的版本为”@babel/core”: “^7.3.4”, 而 “babel-loader”:8.x 两个版本同时运用会出错,需要将”babel-loader”的版本降低:降低后为 “babel-loader”: “^6.2.4”</p><h4 id="官方解释:官方默认babel-loader-babel-对应的版本需要一致-即babel-loader需要搭配最新版本babel"><a href="#官方解释:官方默认babel-loader-babel-对应的版本需要一致-即babel-loader需要搭配最新版本babel" class="headerlink" title="官方解释:官方默认babel-loader | babel 对应的版本需要一致: 即babel-loader需要搭配最新版本babel"></a>官方解释:官方默认babel-loader | babel 对应的版本需要一致: 即babel-loader需要搭配最新版本babel</h4><h4 id="九、cannot-find-‘less-loader’"><a href="#九、cannot-find-‘less-loader’" class="headerlink" title="九、cannot find ‘less-loader’"></a>九、cannot find ‘less-loader’</h4><p>less-loader版本低,需要先卸载less以及less-loader,再install重新安装</p><h4 id="十、Cannot-read-property-‘fileLoader’-of-undefined"><a href="#十、Cannot-read-property-‘fileLoader’-of-undefined" class="headerlink" title="十、Cannot read property ‘fileLoader’ of undefined"></a>十、Cannot read property ‘fileLoader’ of undefined</h4><p> file-loader版本低,需要先卸载less以及less-loader,再install重新安装</p><h4 id="十、less-version-3-9-0-is-not-currently-supported"><a href="#十、less-version-3-9-0-is-not-currently-supported" class="headerlink" title="十、less version 3.9.0 is not currently supported"></a>十、less version 3.9.0 is not currently supported</h4><p>原因: less版本过高,与package内gulp-less版本不搭</p><p>做法: less降低版本</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">npm uninstall less</span><br><span class="line">npm install less@2.7.0</span><br></pre></td></tr></table></figure><h4 id="十一、Cannot-read-property-‘hash’-of-undefined"><a href="#十一、Cannot-read-property-‘hash’-of-undefined" class="headerlink" title="十一、Cannot read property ‘hash’ of undefined"></a>十一、Cannot read property ‘hash’ of undefined</h4><p>报错信息意思是htmlWebpackPlugin插件有问题</p><p>原因:webpack打包有问题<br>也就是webpack配置有问题<br>跟斯腾(同事)请教,可以先只配置报错信息的插件,也就是htmlWebpackPlugin插件,然后一步步注释放开,最后判断问题在插件speed-measure-webpack-plugin上,将其不使用,build正常</p><h4 id="十二、build正常,dev-start正常以及dev-server正常,但是本地浏览器访问时,页面空白,没有html渲染"><a href="#十二、build正常,dev-start正常以及dev-server正常,但是本地浏览器访问时,页面空白,没有html渲染" class="headerlink" title="十二、build正常,dev-start正常以及dev-server正常,但是本地浏览器访问时,页面空白,没有html渲染"></a>十二、build正常,dev-start正常以及dev-server正常,但是本地浏览器访问时,页面空白,没有html渲染</h4><h4 id="十三、webpack4-一些plugin移除,例如:"><a href="#十三、webpack4-一些plugin移除,例如:" class="headerlink" title="十三、webpack4 一些plugin移除,例如:"></a>十三、webpack4 一些plugin移除,例如:</h4><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">Error: webpack.optimize.UglifyJsPlugin has been removed,</span><br><span class="line">please use config.optimization.minimize instead.</span><br></pre></td></tr></table></figure><p>原因: webpack4基于零配置的思想,部分插件被移除,如webpack.optimize.UglifyJsPlugin在webpack4中已经被移除,在optimization对象中配置optimization.minimize=true即可,如果是生产环境的模式(mode:production)下,则该属性默认为true,默认压缩</p><h4 id="十四、webpack4所有都build完毕,本地访问页面空白,打开元素查看dom无html节点元素"><a href="#十四、webpack4所有都build完毕,本地访问页面空白,打开元素查看dom无html节点元素" class="headerlink" title="十四、webpack4所有都build完毕,本地访问页面空白,打开元素查看dom无html节点元素"></a>十四、webpack4所有都build完毕,本地访问页面空白,打开元素查看dom无html节点元素</h4><p>原因,将所有打包文件用chunks方式命名,没有触发chunks渲染<br>解决办法:将打包chunks的方式注释,如下:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">optimization: {</span><br><span class="line">// splitChunks: {</span><br><span class="line">// chunks: <span class="string">'all'</span>,</span><br><span class="line">// name: <span class="literal">true</span>,</span><br><span class="line">// // filename: isBuild ? <span class="string">'common-code-[chunkhash].min.js'</span> : <span class="string">'common-code.js'</span>,</span><br><span class="line">// },</span><br><span class="line">// runtimeChunk: {</span><br><span class="line">// name: <span class="string">'runtime'</span></span><br><span class="line">// }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="十五、大部分页面渲染无误,少部分页面渲染有问题,报错信息如下"><a href="#十五、大部分页面渲染无误,少部分页面渲染有问题,报错信息如下" class="headerlink" title="十五、大部分页面渲染无误,少部分页面渲染有问题,报错信息如下"></a>十五、大部分页面渲染无误,少部分页面渲染有问题,报错信息如下</h4><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">Error: Command failed: /Users/nieyuling/space/bd-node/node_modules/</span><br><span class="line">freemarker.js/fmpp/fmpp /Users/nieyuling/space/bd-node/client/view/pages/admin/</span><br><span class="line">cinema_activity/index.ftl -C /var/folders/bw/16rd988j6_d_1_rz4r0tnvph0000gn/T/</span><br><span class="line">a336def9-848d-4a77-a9e1-1805fd9a8a4e</span><br></pre></td></tr></table></figure>]]></content>
<categories>
<category> webpack </category>
</categories>
</entry>
<entry>
<title>扁平化数据处理</title>
<link href="/2019/03/03/%E6%89%81%E5%B9%B3%E5%8C%96%E6%95%B0%E6%8D%AE%E5%A4%84%E7%90%86/"/>
<url>/2019/03/03/%E6%89%81%E5%B9%B3%E5%8C%96%E6%95%B0%E6%8D%AE%E5%A4%84%E7%90%86/</url>
<content type="html"><![CDATA[<p>给定一个嵌套的整型列表。设计一个迭代器,使其能够遍历这个整型列表中的所有整数。列表中的项或者为一个整数,或者是另一个列表。</p><a id="more"></a><h4 id="给定一个嵌套的整型列表。设计一个迭代器,使其能够遍历这个整型列表中的所有整数。列表中的项或者为一个整数,或者是另一个列表。"><a href="#给定一个嵌套的整型列表。设计一个迭代器,使其能够遍历这个整型列表中的所有整数。列表中的项或者为一个整数,或者是另一个列表。" class="headerlink" title="给定一个嵌套的整型列表。设计一个迭代器,使其能够遍历这个整型列表中的所有整数。列表中的项或者为一个整数,或者是另一个列表。"></a>给定一个嵌套的整型列表。设计一个迭代器,使其能够遍历这个整型列表中的所有整数。列表中的项或者为一个整数,或者是另一个列表。</h4><h4 id="示例一"><a href="#示例一" class="headerlink" title="示例一"></a>示例一</h4><p>输入: [[1,1],2,[1,1]]</p><p>输出: [1,1,2,1,1]</p><p>解释: 通过重复调用 next 直到 hasNext 返回false,next 返回的元素的顺序应该是:[1,1,2,1,1]。</p><h4 id="示例二:"><a href="#示例二:" class="headerlink" title="示例二:"></a>示例二:</h4><p> 输入: [1,[4,[6]]]</p><p> 输出: [1,4,6]</p><p> 解释: 通过重复调用 next 直到 hasNext 返回false,next 返回的元素的顺序应该是: [1,4,6]。</p><h4 id="思路:"><a href="#思路:" class="headerlink" title="思路:"></a>思路:</h4><p> 可以利用栈递归实现,依次判断各元素是否为空或者元素类型,递归调用输出,注意内存溢出</p><h4 id="用javascript实现"><a href="#用javascript实现" class="headerlink" title="用javascript实现"></a>用javascript实现</h4><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">var returnItems = [];</span><br><span class="line"><span class="keyword">function</span> Main(listArray) {</span><br><span class="line"> <span class="keyword">for</span> (var i = 0; i <= listArray.length - 1; i++) {</span><br><span class="line"> <span class="keyword">if</span> (typeof (listArray[i]) === <span class="string">'number'</span>) {</span><br><span class="line"> returnItems.push(listArray[i]);</span><br><span class="line"> console.log(returnItems.pop());</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> Main(listArray[i]);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">var list = new Array();</span><br><span class="line">list = [1,[2,[5,7]],3,4];</span><br><span class="line">Main(list);</span><br></pre></td></tr></table></figure><h3 id="方法二"><a href="#方法二" class="headerlink" title="方法二"></a>方法二</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">class NestedIterator {</span><br><span class="line">constructor(list = []) {</span><br><span class="line">this.currArray = list;</span><br><span class="line">this.currArray.currIndex = 0;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"> flat(list) {</span><br><span class="line"> this.currArray = list;</span><br><span class="line"> const currIndex = list.currIndex;</span><br><span class="line"> <span class="built_in">let</span> value = list[ currIndex ];</span><br><span class="line"></span><br><span class="line"> list.currIndex = currIndex + 1;</span><br><span class="line"> <span class="keyword">if</span> (Object.prototype.toString.call(value).slice(8, -1) === <span class="string">'Array'</span>) {</span><br><span class="line"> this.currArray = value;</span><br><span class="line"> this.currArray.parent = list;</span><br><span class="line"> this.currArray.currIndex = 0;</span><br><span class="line"> value = this.flat(value);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (this.currArray.currIndex >= this.currArray.length && this.currArray.parent) {</span><br><span class="line"> const parent = this.currArray.parent;</span><br><span class="line"> this.currArray.parent = null;</span><br><span class="line"> this.currArray = parent;</span><br><span class="line"> }</span><br><span class="line"> <span class="built_in">return</span> value;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="title">hasNext</span></span>() {</span><br><span class="line"> const currArray = this.currArray;</span><br><span class="line"> <span class="keyword">if</span> (currArray.currIndex < currArray.length) {</span><br><span class="line"> <span class="built_in">return</span> <span class="literal">true</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="built_in">return</span> <span class="literal">false</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="title">next</span></span>() {</span><br><span class="line"> <span class="keyword">if</span> (!this.hasNext()) {</span><br><span class="line"> throw new Error(<span class="string">'已经没有值了'</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="built_in">return</span> this.flat(this.currArray);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">const nestedList = [1, 2, [3, 4, [5]], [6, [7, 8], [9, 10]]];</span><br><span class="line"><span class="built_in">let</span> i = new NestedIterator(nestedList);</span><br><span class="line"><span class="keyword">while</span> (i.hasNext()) {</span><br><span class="line"> console.log(i.next());</span><br><span class="line">};</span><br></pre></td></tr></table></figure><h4 id="用java实现"><a href="#用java实现" class="headerlink" title="用java实现"></a>用java实现</h4><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br></pre></td><td class="code"><pre><span class="line">/**</span><br><span class="line"> * // This is the interface that allows <span class="keyword">for</span> creating nested lists.</span><br><span class="line"> * // You should not implement it, or speculate about its implementation</span><br><span class="line"> * class NestedInteger {</span><br><span class="line"> * public:</span><br><span class="line"> * // Return <span class="literal">true</span> <span class="keyword">if</span> this NestedInteger holds a single <span class="built_in">integer</span>, rather than a nested list.</span><br><span class="line"> * bool isInteger() const;</span><br><span class="line"> *</span><br><span class="line"> * // Return the single <span class="built_in">integer</span> that this NestedInteger holds, <span class="keyword">if</span> it holds a single <span class="built_in">integer</span></span><br><span class="line"> * // The result is undefined <span class="keyword">if</span> this NestedInteger holds a nested list</span><br><span class="line"> * int getInteger() const;</span><br><span class="line"> *</span><br><span class="line"> * // Return the nested list that this NestedInteger holds, <span class="keyword">if</span> it holds a nested list</span><br><span class="line"> * // The result is undefined <span class="keyword">if</span> this NestedInteger holds a single <span class="built_in">integer</span></span><br><span class="line"> * const vector<NestedInteger &getList() const;</span><br><span class="line"> * };</span><br><span class="line"> */</span><br><span class="line">class NestedIterator {</span><br><span class="line">public:</span><br><span class="line">NestedIterator(vector<NestedInteger &nestedList) {</span><br><span class="line">ini(nestedList, vec);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">void ini(vector<NestedInteger nestedList,stack<int &vec) {</span><br><span class="line"><span class="keyword">for</span> (int i = nestedList.size()-1; i =0 ; i--) {</span><br><span class="line"><span class="keyword">if</span> (nestedList[i].isInteger()) vec.push(nestedList[i].getInteger());</span><br><span class="line"><span class="keyword">else</span> {</span><br><span class="line">ini(nestedList[i].getList(),vec);</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line">int <span class="function"><span class="title">next</span></span>() {</span><br><span class="line">int tmp = vec.top();</span><br><span class="line">vec.pop();</span><br><span class="line"><span class="built_in">return</span> tmp;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">bool <span class="function"><span class="title">hasNext</span></span>() {</span><br><span class="line"><span class="keyword">if</span> (vec.empty()) <span class="built_in">return</span> <span class="literal">false</span>;</span><br><span class="line"><span class="built_in">return</span> <span class="literal">true</span>;</span><br><span class="line">}</span><br><span class="line">private:</span><br><span class="line">stack<int vec;</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line">/**</span><br><span class="line"> * Your NestedIterator object will be instantiated and called as such:</span><br><span class="line"> * NestedIterator i(nestedList);</span><br><span class="line"> * <span class="keyword">while</span> (i.hasNext()) cout << i.next();</span><br><span class="line"> */</span><br></pre></td></tr></table></figure>]]></content>
<categories>
<category> 算法 </category>
</categories>
</entry>
<entry>
<title>搭建hexo网站踩坑点</title>
<link href="/2019/02/14/%E6%90%AD%E5%BB%BAhexo%E7%BD%91%E7%AB%99%E8%B8%A9%E5%9D%91%E7%82%B9/"/>
<url>/2019/02/14/%E6%90%AD%E5%BB%BAhexo%E7%BD%91%E7%AB%99%E8%B8%A9%E5%9D%91%E7%82%B9/</url>
<content type="html"><![CDATA[<p>20190214初识hexo框架,以下为踩坑点<br><a id="more"></a></p><h2 id="前提-安装了node-和-git"><a href="#前提-安装了node-和-git" class="headerlink" title="前提: 安装了node 和 git"></a>前提: 安装了node 和 git</h2><h3 id="一:-安装-hexo脚手架"><a href="#一:-安装-hexo脚手架" class="headerlink" title="一: 安装 hexo脚手架"></a>一: 安装 hexo脚手架</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ npm install hexo -g</span><br></pre></td></tr></table></figure><h4 id="会出现以下信息:"><a href="#会出现以下信息:" class="headerlink" title="会出现以下信息:"></a>会出现以下信息:</h4><h5 id="1)"><a href="#1)" class="headerlink" title="1)"></a>1)</h5><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">Error: EACCES: permission denied, access <span class="string">'/usr/local/lib/node_modules'</span></span><br><span class="line">npm ERR! { Error: EACCES: permission denied, access <span class="string">'/usr/local/lib/node_modules'</span></span><br><span class="line">npm ERR! stack: <span class="string">'Error: EACCES: permission denied, access \'</span>/usr/<span class="built_in">local</span>/lib/node_modules\<span class="string">''</span>,</span><br><span class="line">npm ERR! errno: -13,</span><br><span class="line">npm ERR! code: <span class="string">'EACCES'</span>,</span><br><span class="line">npm ERR! syscall: <span class="string">'access'</span>,</span><br><span class="line">npm ERR! path: <span class="string">'/usr/local/lib/node_modules'</span> }</span><br><span class="line">npm ERR!</span><br><span class="line">npm ERR! Please try running this <span class="built_in">command</span> again as root/Administrator.</span><br><span class="line">npm ERR! A complete <span class="built_in">log</span> of this run can be found <span class="keyword">in</span>:</span><br><span class="line">npm ERR! /Users/nieyuling/.npm/_logs/2019-02-14T07_10_39_923Z-debug.log</span><br></pre></td></tr></table></figure><h4 id="原因:-permission-denied-mac电脑没有权限,-需加-sudo-将安装命令改为"><a href="#原因:-permission-denied-mac电脑没有权限,-需加-sudo-将安装命令改为" class="headerlink" title="原因: permission denied, mac电脑没有权限, 需加 sudo, 将安装命令改为"></a>原因: permission denied, mac电脑没有权限, 需加 sudo, 将安装命令改为</h4><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ sudo npm install hexo -g</span><br></pre></td></tr></table></figure><hr><h5 id="2"><a href="#2" class="headerlink" title="2)"></a>2)</h5><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">Error: EACCES: permission denied, mkdir <span class="string">'/usr/local/lib/node_modules/hexo-cli/node_modules/fsevents/build'</span></span><br><span class="line">gyp ERR! System Darwin 18.2.0</span><br><span class="line">gyp ERR! <span class="built_in">command</span> <span class="string">"/usr/local/bin/node"</span> <span class="string">"/usr/local/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js"</span> <span class="string">"configure"</span> <span class="string">"--fallback-to-build"</span> <span class="string">"--module=/usr/local/lib/node_modules/hexo-cli/node_modules/fsevents/lib/binding/Release/node-v57-darwin-x64/fse.node"</span> <span class="string">"--module_name=fse"</span> <span class="string">"--module_path=/usr/local/lib/node_modules/hexo-cli/node_modules/fsevents/lib/binding/Release/node-v57-darwin-x64"</span> <span class="string">"--napi_version=3"</span> <span class="string">"--node_abi_napi=napi"</span></span><br><span class="line">gyp ERR! cwd /usr/<span class="built_in">local</span>/lib/node_modules/hexo-cli/node_modules/fsevents</span><br><span class="line">gyp ERR! node -v v8.11.3</span><br><span class="line">gyp ERR! node-gyp -v v3.6.2</span><br><span class="line">gyp ERR! not ok</span><br><span class="line">node-pre-gyp ERR! build error</span><br></pre></td></tr></table></figure><h4 id="原因:-permission-denied,-同样是没有权限"><a href="#原因:-permission-denied,-同样是没有权限" class="headerlink" title="原因: permission denied, 同样是没有权限"></a>原因: permission denied, 同样是没有权限</h4><h4 id="方案:"><a href="#方案:" class="headerlink" title="方案:"></a>方案:</h4><p>可用命令<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ sudo chown -R <span class="variable">$USER</span> /usr/<span class="built_in">local</span></span><br></pre></td></tr></table></figure></p><p>扩大权限,再重新执行一次<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ npm install hexo -g</span><br></pre></td></tr></table></figure></p><p>即可</p><hr><h3 id="二:安装成功以后"><a href="#二:安装成功以后" class="headerlink" title="二:安装成功以后"></a>二:安装成功以后</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">$ hexo init <folderName></span><br><span class="line"> <span class="comment">#执行时,此folder中会装入很多hexo配置文件和主题文件,文件目录应为一个子文件</span></span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ <span class="built_in">cd</span> <folder> <span class="comment">#进入到hexo的文件中</span></span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ hexo install <span class="comment"># 安装依赖包</span></span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">$ hexo generate <span class="comment">#生成静态页面至public目录</span></span><br><span class="line">$ hexo server <span class="comment">#启动服务,默认在http://localhost:4000</span></span><br></pre></td></tr></table></figure>]]></content>
<categories>
<category> hexo </category>
</categories>
</entry>
</search>