-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.html
More file actions
1895 lines (1210 loc) · 255 KB
/
index.html
File metadata and controls
1895 lines (1210 loc) · 255 KB
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
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="renderer" content="webkit">
<meta http-equiv="X-UA-Compatible" content="IE=edge" >
<link rel="dns-prefetch" href="https://yuchenbin1.github.io">
<title>ycb的博客</title>
<meta name="generator" content="hexo-theme-yilia-plus">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<!-- <meta name="keywords" content="">
<meta name="description" content="这是我的个人技术博客"> -->
<meta name="description" content="这是我的个人技术博客">
<meta property="og:type" content="website">
<meta property="og:title" content="ycb的博客">
<meta property="og:url" content="https://yuchenbin1.github.io/index.html">
<meta property="og:site_name" content="ycb的博客">
<meta property="og:description" content="这是我的个人技术博客">
<meta property="og:locale" content="en_US">
<meta property="article:author" content="ycb">
<meta name="twitter:card" content="summary">
<link rel="alternative" href="/atom.xml" title="ycb的博客" type="application/atom+xml">
<link rel="icon" href="/favicon.ico">
<link rel="apple-touch-icon" href="/apple-touch-icon-180x180.png">
<link rel="stylesheet" type="text/css" href="/./main.b8fa34.css">
<style type="text/css">
#container.show {
background: linear-gradient(200deg,#a0cfe4,#e8c37e);
}
</style>
<script src="/lib/clickLove.js"></script>
</head>
<body>
<div id="container" q-class="show:isCtnShow">
<canvas id="anm-canvas" class="anm-canvas"></canvas>
<div class="left-col" q-class="show:isShow">
<div class="overlay" style="background: #4d4d4d;"></div>
<div class="intrude-less">
<header id="header" class="inner">
<a href="/" class="profilepic">
<img src="/img/touxiang.jpg" class="js-avatar">
</a>
<hgroup>
<h1 class="header-author"><a href="/">ycb</a></h1>
</hgroup>
<nav class="header-menu">
<ul>
<li><a href="/" target="_blank">主页</a></li>
<li><a href="/tags/%E9%9A%8F%E7%AC%94/" target="_blank">随笔</a></li>
</ul>
</nav>
<nav class="header-smart-menu">
<a q-on="click: openSlider(e, 'innerArchive')" href="javascript:void(0)">所有文章</a>
<a q-on="click: openSlider(e, 'friends')" href="javascript:void(0)">友链</a>
<a q-on="click: openSlider(e, 'aboutme')" href="javascript:void(0)">关于我</a>
</nav>
<nav class="header-nav">
<div class="social">
<a class="github" href="https://github.com/yuchenbin1" title="GitHub" target="_blank"><i class="icon-github"></i></a>
<a class="zhihu" href="/img/zhihu.jpg" title="zhihu" target="_blank"><i class="icon-zhihu"></i></a>
<a class="qq" href="/img/qq.jpg" title="QQ" target="_blank"><i class="icon-qq"></i></a>
<a class="bilibili" href="/img/bilibili.png" title="bilibili" target="_blank"><i class="icon-bilibili"></i></a>
<a class="mail" href="mailto:2452846575@qq.com" title="NULL" target="_blank"><i class="icon-mail"></i></a>
</div>
<div>
<iframe frameborder="no" border="0" marginwidth="0" marginheight="0" width="240" height="86" src="//music.163.com/outchain/player?type=2&id=40257964&auto=0&height=66"></iframe>
</div>
<p style="font-size: 12px;">这是首好听的音乐<br>希望您能在忙碌的工作中<br>多多感受生活的美好!<p>
</nav>
</header>
</div>
</div>
<div class="mid-col" q-class="show:isShow,hide:isShow|isFalse">
<a class="forkMe" style="position:absolute;z-index:999;top:0;right:0.5em;"
href="https://github.com/yuchenbin1/yuchenbin1.github.io" target="_blank">
<img src="/img/forkme.png"
class="attachment-full size-full" alt="Fork me on GitHub" data-recalc-dims="1"></a>
<nav id="mobile-nav">
<div class="overlay js-overlay" style="background: #4d4d4d"></div>
<div class="btnctn js-mobile-btnctn">
<div class="slider-trigger list" q-on="click: openSlider(e)"><i class="icon icon-sort"></i></div>
</div>
<div class="intrude-less">
<header id="header" class="inner">
<div class="profilepic">
<a href="/">
<img src="/img/touxiang.jpg" class="js-avatar">
</a>
</div>
<hgroup>
<h1 class="header-author js-header-author">ycb</h1>
</hgroup>
<nav class="header-nav">
<div class="social">
<a class="github" target="_blank" href="https://github.com/yuchenbin1" title="GitHub"><i class="icon-github"></i></a>
<a class="zhihu" target="_blank" href="/img/zhihu.jpg" title="zhihu"><i class="icon-zhihu"></i></a>
<a class="qq" target="_blank" href="/img/qq.jpg" title="QQ"><i class="icon-qq"></i></a>
<a class="bilibili" target="_blank" href="/img/bilibili.png" title="bilibili"><i class="icon-bilibili"></i></a>
<a class="mail" target="_blank" href="mailto:2452846575@qq.com" title="NULL"><i class="icon-mail"></i></a>
</div>
</nav>
<nav class="header-menu js-header-menu">
<ul style="width: 50%">
<li style="width: 50%"><a href="/">主页</a></li>
<li style="width: 50%"><a href="/tags/%E9%9A%8F%E7%AC%94/">随笔</a></li>
</ul>
</nav>
</header>
</div>
<div class="mobile-mask" style="display:none" q-show="isShow"></div>
</nav>
<div id="wrapper" class="body-wrap">
<div class="menu-l">
<div class="canvas-wrap">
<canvas data-colors="#eaeaea" data-sectionHeight="100" data-contentId="js-content" id="myCanvas1"
class="anm-canvas"></canvas>
</div>
<div id="js-content" class="content-ll">
<article id="post-vue源码-数据驱动" class="article article-type-post article-index" itemscope itemprop="blogPost">
<div class="article-inner">
<header class="article-header">
<h1 itemprop="name">
<a class="article-title" href="/2022/07/02/vue%E6%BA%90%E7%A0%81-%E6%95%B0%E6%8D%AE%E9%A9%B1%E5%8A%A8/" target="_blank">vue源码 数据驱动</a>
</h1>
<a href="/2022/07/02/vue%E6%BA%90%E7%A0%81-%E6%95%B0%E6%8D%AE%E9%A9%B1%E5%8A%A8/" class="archive-article-date">
<time datetime="2022-07-02T10:24:51.000Z" itemprop="datePublished"><i class="icon-calendar icon"></i>2022-07-02</time>
</a>
</header>
<div class="article-entry" itemprop="articleBody">
<h1 id="Vue与模版"><a href="#Vue与模版" class="headerlink" title="Vue与模版"></a>Vue与模版</h1><p>使用步骤:</p>
<p>1.编写页面模版</p>
<p>(1)直接在HTML标签中写标签</p>
<p>(2)使用template</p>
<p>(3)使用单文件(<tempalte/>)</p>
<p>2.创建VUE的实例</p>
<p>在vue的构造函数中提供data、methods、computed、watcher、props……</p>
<p>3.将VUE挂载到页面中(mount)</p>
<h1 id="数据驱动模型"><a href="#数据驱动模型" class="headerlink" title="数据驱动模型"></a>数据驱动模型</h1><p>vue的执行流程</p>
<p>1.获取模板:模板中有’’坑’’</p>
<p>2.利用Vue构造函数中的所提供的数据来填坑,得到可以在页面显示的标签</p>
<p>3.将标签替换页面中原来有坑的标签</p>
<h3 id="替换的核心方法"><a href="#替换的核心方法" class="headerlink" title="替换的核心方法"></a>替换的核心方法</h3><figure class="highlight js"><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">let</span> rkuohao = <span class="regexp">/\{\{.+?\}\}/g</span>;<span class="comment">//正则匹配{{}}</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">compiler</span>(<span class="params">template,data</span>)</span>{<span class="comment">//template是需要替换的真实DOM的克隆,data是替换的数据源</span></span><br><span class="line"> <span class="keyword">let</span> childNodes = template.childNodes;<span class="comment">//取出子元素</span></span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">let</span> i = <span class="number">0</span>;i<childNodes.length;i++){</span><br><span class="line"> <span class="keyword">let</span> type = childNodes[i].nodeType;<span class="comment">//1是元素,3是文本</span></span><br><span class="line"> <span class="keyword">if</span>(type===<span class="number">3</span>){</span><br><span class="line"> <span class="keyword">let</span> txt = childNodes[i].nodeValue;</span><br><span class="line"> txt.replace(rkuohao,<span class="function"><span class="keyword">function</span>(<span class="params">_,g</span>)</span>{函数的第n个参数表示正则中的第n组</span><br><span class="line"> <span class="keyword">let</span> key = g.trim();</span><br><span class="line"> <span class="keyword">let</span> value = data[key];</span><br><span class="line"> <span class="keyword">return</span> value;</span><br><span class="line"> })</span><br><span class="line"> }<span class="keyword">else</span> <span class="keyword">if</span>(type===<span class="number">1</span>){</span><br><span class="line"> <span class="keyword">this</span>.compiler(childNodes[i],data)</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h3 id="整合一下"><a href="#整合一下" class="headerlink" title="整合一下"></a>整合一下</h3><figure class="highlight js"><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">let</span> app = <span class="keyword">new</span> Vue({</span><br><span class="line"> el:<span class="string">'#root'</span>,</span><br><span class="line"> data: {</span><br><span class="line"> name:<span class="string">'zhang'</span>,</span><br><span class="line"> message:<span class="string">'info'</span></span><br><span class="line"> }</span><br><span class="line">})</span><br></pre></td></tr></table></figure>
<p>这么用,我写一下构造函数</p>
<figure class="highlight js"><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="function"><span class="keyword">function</span> <span class="title">Vue</span>(<span class="params">options</span>)</span>{</span><br><span class="line"> <span class="keyword">this</span>._data = options.data;</span><br><span class="line"> <span class="keyword">this</span>._el = options.el;</span><br><span class="line"></span><br><span class="line"> <span class="comment">//准备好的模版</span></span><br><span class="line"> <span class="keyword">this</span>.$el = <span class="keyword">this</span>._templateDom = <span class="built_in">document</span>.querySelector(<span class="keyword">this</span>._el);</span><br><span class="line"> <span class="keyword">this</span>._parent = <span class="keyword">this</span>._templateDom.parentNode;</span><br><span class="line"> <span class="comment">//渲染</span></span><br><span class="line"> <span class="keyword">this</span>.render();</span><br><span class="line">}</span><br><span class="line"><span class="comment">//渲染,将有数据的模版更新到Dom中去</span></span><br><span class="line">Vue.protoType.render = <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>{</span><br><span class="line"> <span class="keyword">this</span>.compiler();</span><br><span class="line">}</span><br><span class="line">Vue.protoType.compiler = <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>{</span><br><span class="line"> <span class="keyword">let</span> realHtmlDom = <span class="keyword">this</span>._templateDom.cloneNode(<span class="literal">true</span>);</span><br><span class="line"> compiler(realHtmlDom,<span class="keyword">this</span>._data);</span><br><span class="line"> <span class="keyword">this</span>.update(realHtmlDom,<span class="keyword">this</span>._data);</span><br><span class="line">}</span><br><span class="line"><span class="comment">//更新</span></span><br><span class="line">Vue.protoType.update = <span class="function"><span class="keyword">function</span>(<span class="params">real</span>)</span>{</span><br><span class="line"> <span class="keyword">this</span>._parent.replaceChild(real,<span class="built_in">document</span>.querySelector(<span class="string">'#root'</span>));</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h3 id="层级属性怎么替换?"><a href="#层级属性怎么替换?" class="headerlink" title="层级属性怎么替换?"></a>层级属性怎么替换?</h3><p>比如,可以使用递归查询</p>
<figure class="highlight js"><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="function"><span class="keyword">function</span> <span class="title">getValueByPath</span>(<span class="params">obj,path</span>)</span>{<span class="comment">//obj是data中的对象,path是xxx.yyy.zzz</span></span><br><span class="line"> <span class="keyword">let</span> paths = path.split(<span class="string">'.'</span>);</span><br><span class="line"> <span class="keyword">let</span> res = obj;</span><br><span class="line"> <span class="keyword">let</span> prop;</span><br><span class="line"> <span class="keyword">while</span>(prop = paths.shift()) {</span><br><span class="line"> res= res[prop];</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> res;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>柯里化优化(闭包)</p>
<figure class="highlight js"><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="function"><span class="keyword">function</span> <span class="title">createGetValueByPath</span>(<span class="params">path</span>)</span>{<span class="comment">//</span></span><br><span class="line"> <span class="keyword">let</span> paths = path.split(<span class="string">'.'</span>);</span><br><span class="line"> <span class="keyword">return</span> getValueByPath(obj){</span><br><span class="line"> <span class="keyword">let</span> res =obj;</span><br><span class="line"> <span class="keyword">let</span> prop;</span><br><span class="line"> <span class="keyword">while</span>(prop = paths.shift()) {</span><br><span class="line"> res = res[prop];</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></pre></td></tr></table></figure>
<h1 id="虚拟DOM"><a href="#虚拟DOM" class="headerlink" title="虚拟DOM"></a>虚拟DOM</h1><p>1.怎么将真正的DOM转化为虚拟DOM</p>
<p>2.怎么将虚拟DOM转化为正式的DOM</p>
<p>基本原理就是与深拷贝类似</p>
<p>使用虚拟DOM性能会快很多,因为虚拟DOM在内存中,重新渲染只需要更新一次</p>
<p>dom转化成json对象</p>
<figure class="highlight js"><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"><div/>转化为{<span class="attr">tag</span>:<span class="string">'div'</span>}</span><br><span class="line">文本节点转化为{<span class="attr">tag</span>:<span class="literal">undefined</span>,<span class="attr">value</span>:<span class="string">'文本节点'</span>}</span><br><span class="line"><div title=<span class="string">"1"</span> <span class="class"><span class="keyword">class</span></span>=<span class="string">"c"</span> />转化为{<span class="attr">tag</span>:<span class="string">'div'</span>,<span class="attr">data</span>:{<span class="attr">title</span>:<span class="string">'1'</span>,<span class="attr">class</span>:<span class="string">'c'</span>}}</span><br><span class="line"><div></span><br><span class="line"> <div/>转化为{<span class="attr">tag</span>:<span class="string">'div'</span>,children[{<span class="attr">tag</span>:<span class="string">'div'</span>}]}</span><br><span class="line"><<span class="regexp">/div></span></span><br></pre></td></tr></table></figure>
<p>使用递归遍历DOM元素,生成虚拟DOM</p>
<p>VUE中使用的是 栈结构,使用栈存储父元素来实现,因为vue中是处理的字符串</p>
</div>
<div class="article-info article-info-index">
<div class="article-tag tagcloud">
<i class="icon-price-tags icon"></i>
<ul class="article-tag-list">
<li class="article-tag-list-item">
<a href="javascript:void(0)" class="js-tag article-tag-list-link color4">vue</a>
</li>
</ul>
</div>
<p class="article-more-link">
<a class="article-more-a" href="/2022/07/02/vue%E6%BA%90%E7%A0%81-%E6%95%B0%E6%8D%AE%E9%A9%B1%E5%8A%A8/">展开全文 >></a>
</p>
<div class="clearfix"></div>
</div>
</div>
</article>
<aside class="wrap-side-operation">
<div class="mod-side-operation">
<div class="jump-container" id="js-jump-container" style="display:none;">
<a href="javascript:void(0)" class="mod-side-operation__jump-to-top">
<i class="icon-font icon-back"></i>
</a>
<div id="js-jump-plan-container" class="jump-plan-container" style="top: -11px;">
<i class="icon-font icon-plane jump-plane"></i>
</div>
</div>
</div>
</aside>
<article id="post-浏览器缓存" class="article article-type-post article-index" itemscope itemprop="blogPost">
<div class="article-inner">
<header class="article-header">
<h1 itemprop="name">
<a class="article-title" href="/2022/06/15/%E6%B5%8F%E8%A7%88%E5%99%A8%E7%BC%93%E5%AD%98/" target="_blank">浏览器缓存</a>
</h1>
<a href="/2022/06/15/%E6%B5%8F%E8%A7%88%E5%99%A8%E7%BC%93%E5%AD%98/" class="archive-article-date">
<time datetime="2022-06-15T08:39:08.000Z" itemprop="datePublished"><i class="icon-calendar icon"></i>2022-06-15</time>
</a>
</header>
<div class="article-entry" itemprop="articleBody">
<h1 id="浏览器缓存"><a href="#浏览器缓存" class="headerlink" title="浏览器缓存"></a>浏览器缓存</h1><p>浏览器缓存是在HTTP1.1版本后才支持的</p>
<p>是为了节约网络资源的加速浏览,浏览器对用户访问的页面与文件在磁盘上面做了一个存储。</p>
<p>浏览器根据该请求返回的响应头(respone header)的内容来决定该资源是否会被缓存,会存多久</p>
<h3 id="彻底缓存(强缓存)"><a href="#彻底缓存(强缓存)" class="headerlink" title="彻底缓存(强缓存)"></a>彻底缓存(强缓存)</h3><p>定义:彻底缓存就是浏览器直接读取缓存,不发出任何请求,性能提升最大</p>
<p>会让浏览器执行强缓存的respone header有以下两种:<br>1.Cache-Control:max-age=3600;<br>2.Expires: Thu, 25 May 2020 12:30:00 GMT;</p>
<p>浏览器缓存里, Cache-Control是金字塔顶尖的规则, 它藐视一切其他设置, 只要其他设置与其抵触, 一律覆盖之.不仅如此, 它还是一个复合规则, 包含多种值, 横跨 存储策略, 过期策略 两种, 同时在请求头和响应头都可设置</p>
<p><strong>max-age=3600</strong>即代表该资源会在浏览器缓存3600秒,即1个小时</p>
<p>当max-age 与 max-stale 和 min-fresh 同时使用时, 它们的设置相互之间独立生效, 最为保守的缓存策略总是有效</p>
<p>Expires,这是 Http/1.0 规定的响应头,它的含义就是代表该资源在未来某个时间点失效</p>
<p>Expires有一个很大的弊端,就是它返回的是服务器的时间,但判断的时候用的却是客户端的时间,这就导致Expires很被动,因为用户有可能改变客户端的时间,导致缓存时间判断出错,缓存可能失效</p>
<h2 id="协商缓存"><a href="#协商缓存" class="headerlink" title="协商缓存"></a>协商缓存</h2><p>定义:协商缓存就是浏览器向服务器发送一个请求,服务器会检查该资源是否有更新,如果有更新,就返回最新的资源,状态码200,如果没有更新,状态码304,不返回资源,浏览器从缓存中读取资源</p>
<p>协商缓存字段之ETag</p>
<p>Get请求中,当且仅当服务器上没有任何资源的ETag属性值与这个首部中列出的相匹配的时候,服务器端会才返回所请求的资源,响应码为200。</p>
<p>如果有资源的ETag值相匹配,那么返回304状态码。浏览器就会从缓存中获取该请求资源,从而达到节省开销加快用户访问速度的目的</p>
<p><strong>但实际上,各个浏览器对这部分的实现不太相同。</strong> Chrome浏览器对此的缓存机制是,浏览器会有一套算法去判断当前资源是否过期。<br>如果没有过期的话,直接从缓存中取资源,不会发送请求,而过期了才会去服务端验证该资源是否过期</p>
<p>FireFox不一样,如果是在上面的情况下缓存了该资源,会直接请求服务器来验证资源是否过期</p>
</div>
<div class="article-info article-info-index">
<div class="article-tag tagcloud">
<i class="icon-price-tags icon"></i>
<ul class="article-tag-list">
<li class="article-tag-list-item">
<a href="javascript:void(0)" class="js-tag article-tag-list-link color3">基础</a>
</li>
</ul>
</div>
<p class="article-more-link">
<a class="article-more-a" href="/2022/06/15/%E6%B5%8F%E8%A7%88%E5%99%A8%E7%BC%93%E5%AD%98/">展开全文 >></a>
</p>
<div class="clearfix"></div>
</div>
</div>
</article>
<aside class="wrap-side-operation">
<div class="mod-side-operation">
<div class="jump-container" id="js-jump-container" style="display:none;">
<a href="javascript:void(0)" class="mod-side-operation__jump-to-top">
<i class="icon-font icon-back"></i>
</a>
<div id="js-jump-plan-container" class="jump-plan-container" style="top: -11px;">
<i class="icon-font icon-plane jump-plane"></i>
</div>
</div>
</div>
</aside>
<article id="post-HTTP版本差异" class="article article-type-post article-index" itemscope itemprop="blogPost">
<div class="article-inner">
<header class="article-header">
<h1 itemprop="name">
<a class="article-title" href="/2022/05/28/HTTP%E7%89%88%E6%9C%AC%E5%B7%AE%E5%BC%82/" target="_blank">HTTP版本差异</a>
</h1>
<a href="/2022/05/28/HTTP%E7%89%88%E6%9C%AC%E5%B7%AE%E5%BC%82/" class="archive-article-date">
<time datetime="2022-05-28T08:36:48.000Z" itemprop="datePublished"><i class="icon-calendar icon"></i>2022-05-28</time>
</a>
</header>
<div class="article-entry" itemprop="articleBody">
<h1 id="HTTP-1-0"><a href="#HTTP-1-0" class="headerlink" title="HTTP 1.0"></a>HTTP 1.0</h1><p>首先要知道到OSI模型有7层:物理层、数据链路层、网络层、传输层、会话层、表示层、应用层。</p>
<p>HTTP是属于网络层中的协议</p>
<p>1.0版本是一种无状态、无连接的应用层协议</p>
<h3 id="特点"><a href="#特点" class="headerlink" title="特点"></a>特点</h3><p>1.规定浏览器和服务器保持短暂的链接</p>
<p>2.浏览器每次请求都需要与服务器建立一个TCP连接,服务器处理完成以后立即断开TCP连接(无连接),服务器不跟踪也每个客户单,也不记录过去的请求(无状态)</p>
<p>3.这种无状态性可以借助cookie/session机制来做身份认证和状态记录</p>
<h1 id="HTTP-1-1"><a href="#HTTP-1-1" class="headerlink" title="HTTP 1.1"></a>HTTP 1.1</h1><p>1.1继承了1.0的简单,克服了1.0的性能上面的瓶颈</p>
<p>目前用的最为广泛的就是1.1版本</p>
<h3 id="特点-1"><a href="#特点-1" class="headerlink" title="特点"></a>特点</h3><p>1.<strong>长连接</strong>:HTTP1.1增加Connection字段,通过设置Keep-Alive保持HTTP连接不断卡。避免每次客户端与服务器请求都要重复建立释放建立TCP连接。提高了网络的利用率。如果客户端想关闭HTTP连接,可以在请求头中携带Connection:false来告知服务器关闭请求。</p>
<p>2.<strong>管道化</strong>:HTTP1.1支持请求管道化(pipelining)。基于HTTP1.1的长连接,使得请求管线化成为可能。 管线化使得请求能够“并行”传输。需要注意的是:服务器必须按照客户端请求的先后顺序依次回送相应的结果,以保证客户端能够区分出每次请求的响应内容。</p>
<p>3.<strong>真并行传输 — 浏览器优化策略</strong></p>
<p>HTTP1.1支持管道化,但是服务器也必须进行逐个响应的送回,这个是很大的一个缺陷。实际上,现阶段的浏览器厂商采取了另外一种做法,它允许我们打开多个TCP的会话,也就是说,上图我们看到的并行,其实是不同的TCP连接上的HTTP请求和相应。这才是真正的并行!</p>
<p>4.<strong>缓存处理 — 强缓存、协商缓存</strong></p>
<ul>
<li>此外,HTTP1.1还加入了缓存处理(强缓存和协商缓存),新的字段如cache-control,支持断点传输,以及增加了Host字段(使得一个服务器能够用来创建多个Web站点)</li>
</ul>
<h1 id="HTTP2-0"><a href="#HTTP2-0" class="headerlink" title="HTTP2.0"></a>HTTP2.0</h1><p>1.<strong>二进制分帧</strong></p>
<ul>
<li>HTTP2.0通过在应用层和传输层之间增加一个二进制分层帧,突破了HTTP1.1的性能限制,改进传输性能</li>
</ul>
<p>2.<strong>多路复用(链接共享)— 真并行传输</strong></p>
<ul>
<li>流(stream):已建立连接上的双向字节流。</li>
<li>消息:与逻辑消息对应的完整的一系列数据帧。</li>
<li>帧(frame):HTTP2.0通信的最小单位,每个帧包含头部,至少也会标识出当前所属的流(stream_id)</li>
<li>所有HTTP2.0通信都在一个TCP链接上完成,这个链接可以承载任意流量的双向数据流。 每个数据流以消息的形式发送,而消息由一或多个帧组成。这些帧可以乱序发送,然后再根据每个帧头部的流标识符(Stream_id)重新封装。 多路复用(连接共享)可能会导致关键字被阻塞,HTTP2.0里每个数据流都可以设置优先级和依赖,优先级高的数据流会被服务器优先处理和返回客户端,数据流还可以依赖其他的子数据流。 可见,HTTP2.0实现了真正的并行传输,它能够在一个TCP上进行任意数量的HTTP请求。而这个强大的功能基于“二级制分帧”的特性</li>
</ul>
<p>3.<strong>头部压缩</strong></p>
<ul>
<li>在HTTP1.X中,头部元数据都是以纯文本的形式发送的,通常会给每个请求增加500-8000字节的负荷。</li>
<li>比如cookie,默认情况下,浏览器会在每次请求的时候,把cookie附在header上面发给服务器。</li>
<li>HTTP2.0使用encoder来减少需要传输的header大小,通讯双方各自cache一份header_files表,既避免重复header的传输,又减少了需要传输的大小。</li>
<li>高效的压缩算法可以很大的压缩header,减少发送包的数量从而降低延迟</li>
</ul>
<p>4.<strong>服务器推送</strong></p>
<h1 id="HTTP3-0"><a href="#HTTP3-0" class="headerlink" title="HTTP3.0"></a>HTTP3.0</h1><p>HTTP3.0的核心是QUIC(读音quick)协议,传统的HTTP协议是基于传输层TCP的协议,而QUIC是基于传输层<a href="https://so.csdn.net/so/search?q=UDP&spm=1001.2101.3001.7020" target="_blank" rel="noopener">UDP</a>上的协议,可以定义成:HTTP3.0基于UDP的安全可靠的HTTP2.0协议。</p>
<h3 id="TCP与UDP的区别"><a href="#TCP与UDP的区别" class="headerlink" title="TCP与UDP的区别"></a>TCP与UDP的区别</h3><table>
<thead>
<tr>
<th></th>
<th>TCP</th>
<th>UDP</th>
</tr>
</thead>
<tbody><tr>
<td>是否连接</td>
<td>是</td>
<td>否</td>
</tr>
<tr>
<td>传输可靠性</td>
<td>可靠</td>
<td>不可靠</td>
</tr>
<tr>
<td>应用场景</td>
<td>传输大量的数据</td>
<td>少量数据</td>
</tr>
<tr>
<td>速度</td>
<td>慢</td>
<td>快</td>
</tr>
</tbody></table>
<p>UDP 与 TCP 的主要区别在于 UDP 不一定提供可靠的数据传输。事实上,该协议不能保证数据准确无误地到达目的地。UDP 在许多方面非常有效。当某个程序的目标是尽快地传输尽可能多的信息时(其中任意给定数据的重要性相对较低),可使用 UDP。</p>
<p>当数据传输的性能必须让位于数据传输的完整性、可控制性和可靠性时,TCP协议是当然的选择。当强调传输性能而不是传输的完整性时,如:音频和多媒体应用,UDP是最好的选择。在数据传输时间很短,以至于此前的连接过程成为整个流量主体的情况下,UDP也是一个好的选择,如:DNS交换。把SNMP建立在UDP上的部分原因是设计者认为当发生网络阻塞时,UDP较低的开销使其有更好的机会去传送管理数据。</p>
</div>
<div class="article-info article-info-index">
<div class="article-tag tagcloud">
<i class="icon-price-tags icon"></i>
<ul class="article-tag-list">
<li class="article-tag-list-item">
<a href="javascript:void(0)" class="js-tag article-tag-list-link color3">基础</a>
</li>
</ul>
</div>
<p class="article-more-link">
<a class="article-more-a" href="/2022/05/28/HTTP%E7%89%88%E6%9C%AC%E5%B7%AE%E5%BC%82/">展开全文 >></a>
</p>
<div class="clearfix"></div>
</div>
</div>
</article>
<aside class="wrap-side-operation">
<div class="mod-side-operation">
<div class="jump-container" id="js-jump-container" style="display:none;">
<a href="javascript:void(0)" class="mod-side-operation__jump-to-top">
<i class="icon-font icon-back"></i>
</a>
<div id="js-jump-plan-container" class="jump-plan-container" style="top: -11px;">
<i class="icon-font icon-plane jump-plane"></i>
</div>
</div>
</div>
</aside>
<article id="post-哈希(一)" class="article article-type-post article-index" itemscope itemprop="blogPost">
<div class="article-inner">
<header class="article-header">
<h1 itemprop="name">
<a class="article-title" href="/2022/05/02/%E5%93%88%E5%B8%8C%EF%BC%88%E4%B8%80%EF%BC%89/" target="_blank">哈希(一)</a>
</h1>
<a href="/2022/05/02/%E5%93%88%E5%B8%8C%EF%BC%88%E4%B8%80%EF%BC%89/" class="archive-article-date">
<time datetime="2022-05-02T03:43:17.000Z" itemprop="datePublished"><i class="icon-calendar icon"></i>2022-05-02</time>
</a>
</header>
<div class="article-entry" itemprop="articleBody">
<h1 id="一篇有趣的文章"><a href="#一篇有趣的文章" class="headerlink" title="一篇有趣的文章"></a>一篇有趣的文章</h1><p>最近看到一篇有趣的<a href="https://nee.lv/2021/02/28/How-I-cut-GTA-Online-loading-times-by-70/" target="_blank" rel="noopener">文章</a>,讲的是深入了解GTA的在线模式为什么加载这么慢的问题,作者通过任务管理器、Profiler、反汇编程序副本、Process Dump等工具定位问题,最终定位到一串高达10MB的JSON,有大约63K项条目。</p>
<figure class="highlight"><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><br><span class="line">{</span><br><span class="line"> <span class="attr">"key"</span>: <span class="string">"WP_WCT_TINT_21_t2_v9_n2"</span>,</span><br><span class="line"> <span class="attr">"price"</span>: <span class="number">45000</span>,</span><br><span class="line"> <span class="attr">"statName"</span>: <span class="string">"CHAR_KIT_FM_PURCHASE20"</span>,</span><br><span class="line"> <span class="attr">"storageType"</span>: <span class="string">"BITFIELD"</span>,</span><br><span class="line"> <span class="attr">"bitShift"</span>: <span class="number">7</span>,</span><br><span class="line"> <span class="attr">"bitSize"</span>: <span class="number">1</span>,</span><br><span class="line"> <span class="attr">"category"</span>: [<span class="string">"CATEGORY_WEAPON_MOD"</span>]</span><br><span class="line">},</span><br><span class="line">...</span><br></pre></td></tr></table></figure>
<p>通过一些参考资料了解到这些条目应该是在线模式中商店中的商品和升级的列表,这个还算正常。作者发现在解析项目的时候,发现同一个语句被反复的调用。于是发现了这个罪犯。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">struct { uint64_t *hash; item_t *item;} entry;</span><br></pre></td></tr></table></figure>
<p>在解析项目的时候,每一个条目都会被存储在一个数组里,在存储之前,它会一个一个的检查整个数组,比较项目的哈希值来查看它是否在数组中。大约63K个条目时间复杂度为<code>(n^2+n)/2 = (63000^2+63000)/2 = 1984531500</code>。</p>
<p>你有唯一的哈希为什么不用哈希映射呢?</p>
<p>甚至不需要做校验,因为json中的条目都是唯一的。</p>
<p>去除了重复检查并直接插入优化后GTA在线模式的加载时间缩短了70%。</p>
<p>作者提交了bug与修正方案,得到了游戏公司R<em>的确认,R</em>更新并支付了作者10000$的赏金。</p>
<h1 id="一个思考的问题"><a href="#一个思考的问题" class="headerlink" title="一个思考的问题"></a>一个思考的问题</h1><p>哈希算法产生的哈希值的长度是固定并有限的。最常用于加密的哈希算法是MD5和SHA。现在有一个问题,就是如果一段的字符串生成哈希值,那么哈希值可以解码成这个字符串,然后后面继续MD5编码,生成的是另一个32位的哈希值,一直循环下去…</p>
<p>因为32位的16进制是有限的,一定会有出现一个圈,圈的节点会出现两个值,他们MD5编码的哈希值是一样的。</p>
</div>
<div class="article-info article-info-index">
<div class="article-tag tagcloud">
<i class="icon-price-tags icon"></i>
<ul class="article-tag-list">
<li class="article-tag-list-item">
<a href="javascript:void(0)" class="js-tag article-tag-list-link color3">js</a>
</li>
</ul>
</div>
<p class="article-more-link">
<a class="article-more-a" href="/2022/05/02/%E5%93%88%E5%B8%8C%EF%BC%88%E4%B8%80%EF%BC%89/">展开全文 >></a>
</p>
<div class="clearfix"></div>
</div>
</div>
</article>
<aside class="wrap-side-operation">
<div class="mod-side-operation">
<div class="jump-container" id="js-jump-container" style="display:none;">
<a href="javascript:void(0)" class="mod-side-operation__jump-to-top">
<i class="icon-font icon-back"></i>
</a>
<div id="js-jump-plan-container" class="jump-plan-container" style="top: -11px;">
<i class="icon-font icon-plane jump-plane"></i>
</div>
</div>
</div>
</aside>
<article id="post-target与currentTarget" class="article article-type-post article-index" itemscope itemprop="blogPost">
<div class="article-inner">
<header class="article-header">
<h1 itemprop="name">
<a class="article-title" href="/2022/04/24/target%E4%B8%8EcurrentTarget/" target="_blank">target与currentTarget</a>
</h1>
<a href="/2022/04/24/target%E4%B8%8EcurrentTarget/" class="archive-article-date">
<time datetime="2022-04-24T03:41:11.000Z" itemprop="datePublished"><i class="icon-calendar icon"></i>2022-04-24</time>
</a>
</header>
<div class="article-entry" itemprop="articleBody">
<p>在DOM事件中,有两个属性target和currentTarget这两个属性,有时候他们有时候是同一个元素,有时候不是,这是为什么呢?</p>
<p>target是DOM事件触发的真实元素</p>
<p>currentTarget是DOM事件绑定的元素</p>
<p>事件处理函数中的this指向始终都是currentTarget</p>
<p>那为什么他们有时候是同一个元素,有时候不是?</p>
<p>这是因为事件冒泡</p>
<p>当事件是子元素触发的时候,<code>currentTarget</code>为绑定事件的元素,<code>target</code>为子元素</p>
<p>当事件是元素自身触发的时候,<code>currentTarget</code>和<code>target</code>为同一个元素</p>
</div>
<div class="article-info article-info-index">
<div class="article-tag tagcloud">
<i class="icon-price-tags icon"></i>
<ul class="article-tag-list">
<li class="article-tag-list-item">
<a href="javascript:void(0)" class="js-tag article-tag-list-link color3">js</a>
</li>
</ul>
</div>
<p class="article-more-link">
<a class="article-more-a" href="/2022/04/24/target%E4%B8%8EcurrentTarget/">展开全文 >></a>
</p>
<div class="clearfix"></div>
</div>
</div>
</article>
<aside class="wrap-side-operation">
<div class="mod-side-operation">
<div class="jump-container" id="js-jump-container" style="display:none;">
<a href="javascript:void(0)" class="mod-side-operation__jump-to-top">
<i class="icon-font icon-back"></i>
</a>
<div id="js-jump-plan-container" class="jump-plan-container" style="top: -11px;">
<i class="icon-font icon-plane jump-plane"></i>
</div>
</div>
</div>
</aside>
<article id="post-自定义合同" class="article article-type-post article-index" itemscope itemprop="blogPost">
<div class="article-inner">
<header class="article-header">
<h1 itemprop="name">
<a class="article-title" href="/2022/04/02/%E8%87%AA%E5%AE%9A%E4%B9%89%E5%90%88%E5%90%8C/" target="_blank">自定义合同</a>
</h1>
<a href="/2022/04/02/%E8%87%AA%E5%AE%9A%E4%B9%89%E5%90%88%E5%90%8C/" class="archive-article-date">
<time datetime="2022-04-02T13:49:13.000Z" itemprop="datePublished"><i class="icon-calendar icon"></i>2022-04-02</time>
</a>
</header>
<div class="article-entry" itemprop="articleBody">
<h1 id="基本方案"><a href="#基本方案" class="headerlink" title="基本方案"></a>基本方案</h1><p>在pc端编辑合同模版,生成控件,记录控件的相对大小和位置信息,之后通过移动端解析样式信息,展示在移动端,通过插件<a href="http://html2canvas.hertzen.com/" target="_blank" rel="noopener">html2canvas</a>由html生成canvas,再由<a href="http://raw.githack.com/MrRio/jsPDF/master/docs/index.html" target="_blank" rel="noopener">jspdf</a>由canvas生成pdf,pdf上传oss,签署区由合同中心合到pdf上(传给它们签署的图片base64和位置信息)。</p>
<h3 id="文件目录"><a href="#文件目录" class="headerlink" title="文件目录"></a>文件目录</h3><p>custom 自定义合同相关</p>
<p>—components 组件</p>
<p>—singleText.vue 单行文本控件</p>
<p>—idCardText.vue 身份证控件</p>
<p>—nameText.vue 姓名控件</p>
<p>—phoneText.vue 手机号控件</p>
<p>—optionSetMultiple.vue 多选控件</p>
<p>—optionSetSingle.vue 单选控件</p>
<p>—option.vue 多选与单选的选项</p>
<p>—signAreaText.vue 签署区控件</p>
<p>—setting.vue 编辑器右侧的设置</p>
<p>—constant.js 常量</p>
<p>—template.vue 编辑器主页面</p>
<h3 id="实现思路"><a href="#实现思路" class="headerlink" title="实现思路"></a>实现思路</h3><p>基于vue2.0,充分利用MVVM的特性,先在前端实现视图层与数据层的绑定,把开发重心转移到数据层的控制</p>
<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></pre></td><td class="code"><pre><span class="line"><component</span><br><span class="line"> ref="components"</span><br><span class="line"> class="components"</span><br><span class="line"> v-for="(item, index) in componentArray"</span><br><span class="line"> :is="item.moduleType ? item.moduleType : ''"</span><br><span class="line"> :required="item.required"</span><br><span class="line"> :selected="selectedIndex === index"</span><br><span class="line"> :index="index"</span><br><span class="line"> :key="item.id"</span><br><span class="line"> :ImgToA4Zoom="ImgToA4Zoom"</span><br><span class="line"> :error="item.error || ''"</span><br><span class="line"> :w="item.width"</span><br><span class="line"> :h="item.height"</span><br><span class="line"> :x="item.x"</span><br><span class="line"> :y="item.y"</span><br><span class="line"> :eContractOwnerEnum="item.eContractOwnerEnum || ''"</span><br><span class="line"> :valueList="item.valueList || []"</span><br><span class="line"> :fontSize="item.fontSize || ''"</span><br><span class="line"> :containerWidth="imgWidthAndHeight.width"</span><br><span class="line"> :containerHeight="imgWidthAndHeight.height"</span><br><span class="line"> @changeComponentSetting="changeComponentSetting"</span><br><span class="line"> @mousedown.native="handleSelectComponent(index)"</span><br><span class="line"> @handleUp="showPositionAndStyle"</span><br><span class="line"> @handleOptionUp="showOptionPositionAndStyle"</span><br><span class="line"> @handleComponentDelete="</span><br><span class="line"> handleComponentDelete(index)</span><br><span class="line"> "</span><br><span class="line"> ></span><br><span class="line"></component></span><br></pre></td></tr></table></figure>
<p>通过动态组件匹配对应的控件,控制componentArray这个对象数组可以控制整个视图</p>
<p>componentArray示例:</p>
<figure class="highlight json"><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></pre></td><td class="code"><pre><span class="line">[</span><br><span class="line"> {</span><br><span class="line"> <span class="attr">"eContractOwnerEnum"</span>: <span class="string">"partyA"</span>,</span><br><span class="line"> <span class="attr">"fieldSize"</span>: <span class="number">9</span>,</span><br><span class="line"> <span class="attr">"fontSize"</span>: <span class="number">16</span>,</span><br><span class="line"> <span class="attr">"fontSizeName"</span>: <span class="string">"小四"</span>,</span><br><span class="line"> <span class="attr">"height"</span>: <span class="number">18</span>,</span><br><span class="line"> <span class="attr">"moduleCode"</span>: <span class="string">"name_module"</span>,</span><br><span class="line"> <span class="attr">"moduleIcon"</span>: <span class="string">"http://img.souche.com/f2e/382f74ac6f732d797770d95e6067c6ba.png"</span>,</span><br><span class="line"> <span class="attr">"moduleName"</span>: <span class="string">"姓名"</span>,</span><br><span class="line"> <span class="attr">"moduleType"</span>: <span class="string">"NAME_TEXT"</span>,</span><br><span class="line"> <span class="attr">"page"</span>: <span class="number">1</span>,</span><br><span class="line"> <span class="attr">"required"</span>: <span class="literal">true</span>,</span><br><span class="line"> <span class="attr">"value"</span>: <span class="string">""</span>,</span><br><span class="line"> <span class="attr">"width"</span>: <span class="number">153</span>,</span><br><span class="line"> <span class="attr">"x"</span>: <span class="number">106.68033</span>,</span><br><span class="line"> <span class="attr">"y"</span>: <span class="number">75.1291</span></span><br><span class="line"> },</span><br><span class="line"> {</span><br><span class="line"> <span class="attr">"fontSize"</span>: <span class="number">16</span>,</span><br><span class="line"> <span class="attr">"fontSizeName"</span>: <span class="string">"小四"</span>,</span><br><span class="line"> <span class="attr">"height"</span>: <span class="number">88</span>,</span><br><span class="line"> <span class="attr">"moduleCode"</span>: <span class="string">"single_module"</span>,</span><br><span class="line"> <span class="attr">"moduleIcon"</span>: <span class="string">"http://img.souche.com/f2e/8c2129395b7b4e80caccfe7ef74ac0fe.png"</span>,</span><br><span class="line"> <span class="attr">"moduleName"</span>: <span class="string">"单选"</span>,</span><br><span class="line"> <span class="attr">"moduleType"</span>: <span class="string">"OPTION_SET_SINGLE"</span>,</span><br><span class="line"> <span class="attr">"page"</span>: <span class="number">1</span>,</span><br><span class="line"> <span class="attr">"required"</span>: <span class="literal">true</span>,</span><br><span class="line"> <span class="attr">"valueList"</span>: [</span><br><span class="line"> {</span><br><span class="line"> <span class="attr">"height"</span>: <span class="number">18</span>,</span><br><span class="line"> <span class="attr">"id"</span>: <span class="number">1</span>,</span><br><span class="line"> <span class="attr">"name"</span>: <span class="string">"选项一"</span>,</span><br><span class="line"> <span class="attr">"value"</span>: <span class="literal">false</span>,</span><br><span class="line"> <span class="attr">"width"</span>: <span class="number">50</span>,</span><br><span class="line"> <span class="attr">"x"</span>: <span class="number">227.63217</span>,</span><br><span class="line"> <span class="attr">"y"</span>: <span class="number">264.72568</span></span><br><span class="line"> },</span><br><span class="line"> {</span><br><span class="line"> <span class="attr">"height"</span>: <span class="number">18</span>,</span><br><span class="line"> <span class="attr">"id"</span>: <span class="number">2</span>,</span><br><span class="line"> <span class="attr">"name"</span>: <span class="string">"选项二"</span>,</span><br><span class="line"> <span class="attr">"value"</span>: <span class="literal">false</span>,</span><br><span class="line"> <span class="attr">"width"</span>: <span class="number">50</span>,</span><br><span class="line"> <span class="attr">"x"</span>: <span class="number">227.63217</span>,</span><br><span class="line"> <span class="attr">"y"</span>: <span class="number">290.72568</span></span><br><span class="line"> },</span><br><span class="line"> {</span><br><span class="line"> <span class="attr">"height"</span>: <span class="number">18</span>,</span><br><span class="line"> <span class="attr">"id"</span>: <span class="number">3</span>,</span><br><span class="line"> <span class="attr">"name"</span>: <span class="string">"选项三"</span>,</span><br><span class="line"> <span class="attr">"value"</span>: <span class="literal">false</span>,</span><br><span class="line"> <span class="attr">"width"</span>: <span class="number">50</span>,</span><br><span class="line"> <span class="attr">"x"</span>: <span class="number">227.63217</span>,</span><br><span class="line"> <span class="attr">"y"</span>: <span class="number">316.72568</span></span><br><span class="line"> }</span><br><span class="line"> ],</span><br><span class="line"> <span class="attr">"width"</span>: <span class="number">94</span>,</span><br><span class="line"> <span class="attr">"x"</span>: <span class="number">192.63217</span>,</span><br><span class="line"> <span class="attr">"y"</span>: <span class="number">255.7257</span></span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line">]</span><br></pre></td></tr></table></figure>
<h3 id="编辑器初始化"><a href="#编辑器初始化" class="headerlink" title="编辑器初始化"></a>编辑器初始化</h3><p>编辑器页面有三种状态(新建、编辑、预览)</p>
<p>新建:获取用户填写的数据、初始化底图、初始化事件监听</p>
<p>编辑:获取服务端传的数据、初始化底图、初始化事件监听</p>
<p>预览:获取服务端传的数据、初始化底图</p>
<h4 id="初始化底图"><a href="#初始化底图" class="headerlink" title="初始化底图"></a>初始化底图</h4><p>用户上传的图片大小不一,统一在A4的宽(595px)的容器中等比缩放展示,前端初始化铺满,对应的缩放率为100%</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></pre></td><td class="code"><pre><span class="line">ImgToA4Zoom: <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>{<span class="comment">//当前容器宽度/A4的宽</span></span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">this</span>.isMounted) {</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">this</span>.imgWidthAndHeight.width / A4SIZE.width;</span><br><span class="line"> }</span><br><span class="line">},</span><br><span class="line"></span><br><span class="line">zoom: <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>{<span class="comment">//图片的真实缩放比例</span></span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">this</span>.isMounted) {</span><br><span class="line"> <span class="keyword">let</span> viewWidth = <span class="keyword">this</span>.getDomWidth(<span class="string">'view'</span>);</span><br><span class="line"> <span class="keyword">return</span> viewWidth / <span class="keyword">this</span>.imgRealWidthAndHeight.width;</span><br><span class="line"> }</span><br><span class="line">},</span><br><span class="line"></span><br><span class="line">imgWidthAndHeight: <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>{<span class="comment">//当前图片的宽高</span></span><br><span class="line"> <span class="comment">//imgRealWidthAndHeight图片的真实宽高</span></span><br><span class="line"> <span class="keyword">return</span> {</span><br><span class="line"> width:</span><br><span class="line"> <span class="built_in">Math</span>.round(</span><br><span class="line"> <span class="keyword">this</span>.sliderValue *</span><br><span class="line"> <span class="keyword">this</span>.imgRealWidthAndHeight.width *</span><br><span class="line"> <span class="keyword">this</span>.zoom</span><br><span class="line"> ) / <span class="number">100</span>,</span><br><span class="line"> height:</span><br><span class="line"> <span class="built_in">Math</span>.round(</span><br><span class="line"> <span class="keyword">this</span>.sliderValue *</span><br><span class="line"> <span class="keyword">this</span>.imgRealWidthAndHeight.height *</span><br><span class="line"> <span class="keyword">this</span>.zoom</span><br><span class="line"> ) / <span class="number">100</span></span><br><span class="line"> };</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h3 id="拖攥定位"><a href="#拖攥定位" class="headerlink" title="拖攥定位"></a>拖攥定位</h3><p><img src="https://cdn.nlark.com/yuque/0/2022/gif/2799077/1651116475780-ad4963e3-c388-4210-8a66-257f3ab1a06f.gif" alt="img"></p>
<p>以x坐标为例</p>
<p><img src="https://cdn.nlark.com/yuque/0/2022/png/2799077/1651135558174-2f0eb98d-37c8-4ac9-a266-ac9d8f2f4d27.png" alt="img"></p>
<h2 id="html转pdf"><a href="#html转pdf" class="headerlink" title="html转pdf"></a>html转pdf</h2><p>在移动端解析对应的canvas之后,使用html2canvas转为canvas,使用jspdf把canvas转pdf</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">async</span> <span class="function"><span class="keyword">function</span> (<span class="params">ele, getBlobCallBack, imgArr</span>) </span>{</span><br><span class="line"> <span class="keyword">const</span> { defaultWidth, defaultHeight } = <span class="keyword">await</span> checkImgWidthAndHeight(imgArr[<span class="number">0</span>]);<span class="comment">//获取图片的宽高</span></span><br><span class="line"> <span class="comment">//2022年4月19日,原底图为多宽生成对应的宽的pdf,合同中心签署区被写死为96px,因此无奈固定生成宽为595px的合同</span></span><br><span class="line"> <span class="keyword">const</span> defaultPdfWidth = <span class="number">595</span>;<span class="comment">//设置生成的pdf的宽</span></span><br><span class="line"> <span class="keyword">const</span> defaultPdfHeight = (<span class="number">595</span> / defaultWidth) * defaultHeight;</span><br><span class="line"> <span class="keyword">let</span> scale = <span class="number">2</span>;<span class="comment">//放大提高pdf的清晰度</span></span><br><span class="line"> ele.style.transform = <span class="string">`scale(<span class="subst">${scale}</span>)`</span>;</span><br><span class="line"> <span class="keyword">let</span> eleW = ele.offsetWidth * scale; <span class="comment">// 获得该容器的宽</span></span><br><span class="line"> <span class="keyword">let</span> eleH = ele.scrollHeight * scale; <span class="comment">// 获得该容器的高</span></span><br><span class="line"> <span class="keyword">let</span> eleOffsetTop = ele.offsetTop * scale; <span class="comment">// 获得该容器到文档顶部的距离</span></span><br><span class="line"> <span class="keyword">let</span> eleOffsetLeft = ele.offsetLeft * scale; <span class="comment">// 获得该容器到文档最左的距离</span></span><br><span class="line"> <span class="keyword">var</span> canvas = <span class="built_in">document</span>.createElement(<span class="string">'canvas'</span>);</span><br><span class="line"> <span class="keyword">var</span> abs = <span class="number">0</span>;</span><br><span class="line"> canvas.width = defaultPdfWidth;</span><br><span class="line"> canvas.height = (defaultPdfWidth / eleW) * eleH;</span><br><span class="line"> <span class="keyword">let</span> canvasHeight = canvas.height;</span><br><span class="line"> <span class="keyword">var</span> context = canvas.getContext(<span class="string">'2d'</span>);</span><br><span class="line"> context.scale(<span class="number">2</span>, <span class="number">2</span>); <span class="comment">// 增强图片清晰度</span></span><br><span class="line"> context.translate(-eleOffsetLeft - abs, -eleOffsetTop);</span><br><span class="line"> html2canvas(ele, {</span><br><span class="line"> dpi: <span class="number">300</span>,</span><br><span class="line"> scale: <span class="number">2</span>,</span><br><span class="line"> useCORS: <span class="literal">true</span>, <span class="comment">//允许canvas画布内可以跨域请求外部链接图片, 允许跨域请求。</span></span><br><span class="line"> height: eleH,</span><br><span class="line"> windowHeight: eleH</span><br><span class="line"> }).then(<span class="keyword">async</span> (canvas) => {</span><br><span class="line"> <span class="comment">//一页pdf显示html页面生成的canvas高度;</span></span><br><span class="line"> <span class="keyword">var</span> pageHeight = defaultPdfHeight;</span><br><span class="line"> <span class="comment">//未生成pdf的html页面高度</span></span><br><span class="line"> <span class="keyword">var</span> leftHeight = canvasHeight;</span><br><span class="line"> <span class="comment">//页面偏移</span></span><br><span class="line"> <span class="keyword">var</span> position = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">var</span> imgWidth = defaultPdfWidth;</span><br><span class="line"> <span class="keyword">var</span> imgHeight = defaultPdfHeight;</span><br><span class="line"> <span class="keyword">var</span> pageData = canvas.toDataURL(<span class="string">'image/png'</span>, <span class="number">1.0</span>);</span><br><span class="line"> <span class="keyword">var</span> pdf = <span class="keyword">new</span> JsPDF(<span class="string">''</span>, <span class="string">'pt'</span>, [defaultPdfWidth, defaultPdfHeight], <span class="literal">true</span>);</span><br><span class="line"> <span class="comment">//有两个高度需要区分,一个是html页面的实际高度,和生成pdf的页面高度(841.89)</span></span><br><span class="line"> <span class="comment">//当内容未超过pdf一页显示的范围,无需分页</span></span><br><span class="line"> <span class="keyword">if</span> (leftHeight < pageHeight) {</span><br><span class="line"> <span class="comment">//在pdf.addImage(pageData, 'JPEG', 左,上,宽度,高度)设置在pdf中显示;</span></span><br><span class="line"> pdf.addImage(pageData, <span class="string">'png'</span>, <span class="number">0</span>, <span class="number">0</span>, defaultPdfWidth, defaultPdfHeight, <span class="string">''</span>, <span class="string">'FAST'</span>);</span><br><span class="line"> <span class="comment">// pdf.addImage(pageData, 'JPEG', 20, 40, imgWidth, imgHeight);</span></span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="comment">// 分页</span></span><br><span class="line"> <span class="keyword">while</span> (leftHeight > <span class="number">0</span>) {</span><br><span class="line"> pdf.addImage(</span><br><span class="line"> pageData,</span><br><span class="line"> <span class="string">'png'</span>,</span><br><span class="line"> <span class="number">5</span>,</span><br><span class="line"> position,</span><br><span class="line"> imgWidth,</span><br><span class="line"> imgHeight * imgArr.length,</span><br><span class="line"> <span class="string">''</span>,</span><br><span class="line"> <span class="string">'FAST'</span></span><br><span class="line"> );</span><br><span class="line"> leftHeight -= pageHeight;</span><br><span class="line"> position -= defaultPdfHeight;</span><br><span class="line"> <span class="comment">//避免添加空白页</span></span><br><span class="line"> <span class="keyword">if</span> (leftHeight > <span class="number">100</span>) {</span><br><span class="line"> pdf.addPage();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">let</span> blobPDF = <span class="keyword">new</span> File([pdf.output(<span class="string">'blob'</span>)], <span class="string">'电子合同.pdf'</span>);<span class="comment">//生成pdf</span></span><br><span class="line"> getBlobCallBack(blobPDF);</span><br><span class="line"> });</span><br></pre></td></tr></table></figure>
<p>多页合同示例</p>
<p><img src="https://cdn.nlark.com/yuque/0/2022/jpeg/2799077/1651113048350-bb06d20b-818f-47fc-a150-28b88df48383.jpeg" alt="img"></p>
<h1 id="问题与解决方法"><a href="#问题与解决方法" class="headerlink" title="问题与解决方法"></a>问题与解决方法</h1><h2 id="与合同中心定位不一致"><a href="#与合同中心定位不一致" class="headerlink" title="与合同中心定位不一致"></a>与合同中心定位不一致</h2><p>签署区的姓名签署需要传给合同中心,合同pdf与签署区以及位置,合同中心的定位基于pdf文件的左下角且基点是签署区的中心,但是合同在前端的定位使用的是左上角且基点是签署区的中心。</p>
<p><img src="https://cdn.nlark.com/yuque/0/2022/jpeg/2799077/1652087623057-37f7a22e-24f4-4dc2-b3a7-0874e5a71d0d.jpeg" alt="img"></p>
<p>解决方法:</p>
<p>前端在保存合同模板的时候给后端提供一个合同高度的字段pdfHeight</p>
<p>那么可以计算传给合同中心的位置</p>
<p>x(合同中心)= x + width / 2</p>
<p>y(合同中心)= pdfHeight - y + height / 2</p>
<h2 id="生成pdf的尺寸"><a href="#生成pdf的尺寸" class="headerlink" title="生成pdf的尺寸"></a>生成pdf的尺寸</h2><p>生成pdf的大小在保证清晰度的情况下,大小不应该太大,通过调试校准,合同pdf一页为300+KB。</p>
<p>在传给合同中心前的pdf宽高,因为合同中心签署区的宽高在嵌入到pdf的时候,宽高写死为96px。</p>
<p>因此在编辑合同的时候签署区被迫写死为96px,同时生成的pdf也是一个与签署区相对较为合适的尺寸595px。</p>
<h2 id="字体大小"><a href="#字体大小" class="headerlink" title="字体大小"></a>字体大小</h2><p>字体大小由小五、五号、小四……初号</p>
<p>对应的像素是12px、14px、16px……56px</p>
<p><img src="https://cdn.nlark.com/yuque/0/2022/png/2799077/1652089191340-7d0339b3-e0ed-4eef-bbbb-f21db7066d35.png" alt="img"></p>
<p>字体的大小会影响控件的高和字数,加上一般浏览器和移动端h5会有默认最小字体12px,那么用户在缩放合同的时候如何展示字体小于12px的情况?</p>
<p>解决方法:</p>
<p>字体需要一套标准,相对于595px的宽,如何理解?</p>
<p>假设现在设置字体为小四,合同底图容器的宽为595px,那么字体设置为16px。</p>
<p>假设现在设置字体为小四,合同底图容器的宽为297.5px,那么字体设置为16px,同时合同底图容器scale(0.5),整个容器缩小了一倍。</p>
<p>假设现在设置字体为小四,合同底图容器的宽为1190px,那么字体设置为16px,同时合同底图容器scale(2),整个容器放大了一倍。</p>
<p>这样既解决了小于12px的展示的问题,同时保证了pd端与移动端、pc端与pc端、移动端与移动端的字体样式的一致性,同时也解决用户在生成合同底图时选择不同宽高导致字体的差异性。</p>
<p>总结:采用就是相对于A4的字体标准</p>
<h2 id="html2canvas的兼容性"><a href="#html2canvas的兼容性" class="headerlink" title="html2canvas的兼容性"></a>html2canvas的兼容性</h2><p>html2canvas对input输入框的兼容性不太好,对其line-height属性并不敏感。最终生成的pdf的文字会有偏差。</p>
<p>解决方法:</p>
<p>方案一</p>
<p>div的contenteditable属性,可以让文本处于可以编辑状态</p>
<p>所有主流浏览器都支持 contenteditable 属性</p>
<p>缺点:但是在文本的不换行属性white-space:nowrap失效,无法控制输入的换行</p>
<p>方案二(采用)</p>
<p>使用input在生成canvas的时候把input替换为div</p>
<p>缺点:生成pdf时间会变长,损耗一定的性能</p>
<h2 id="多页pdf生成"><a href="#多页pdf生成" class="headerlink" title="多页pdf生成"></a>多页pdf生成</h2><p>当用户pdf有很多页的时候,生成的pdf会出现空白页。</p>
<p>出现这种情况的原因是因为canvas宽高有上限</p>
<table>
<thead>
<tr>
<th>浏览器</th>
<th>最大宽度(px)</th>
<th>最大高度(px)</th>
<th>最大面积</th>
</tr>
</thead>
<tbody><tr>
<td>Chrome</td>
<td>32767</td>
<td>32767</td>
<td>268435456(16384*16384)</td>
</tr>
<tr>
<td>Firefox</td>
<td>32767</td>
<td>32767</td>
<td>472907776(22528*20992)</td>
</tr>
<tr>
<td>IE</td>
<td>8192</td>
<td>8192</td>
<td></td>
</tr>
<tr>
<td>移动端</td>
<td>一般4,096</td>
<td>一般4,096</td>
<td></td>
</tr>
<tr>
<td>微信小程序</td>
<td>1365</td>
<td>1365</td>
<td></td>
</tr>
</tbody></table>
<p>多页合同生成一个canvas再切割成pdf的方案替换成</p>
<p>每一页都生成单独的canvas,再合成一个pdf(pdf页面设置上限为15页)</p>
</div>
<div class="article-info article-info-index">
<div class="article-tag tagcloud">
<i class="icon-price-tags icon"></i>
<ul class="article-tag-list">
<li class="article-tag-list-item">
<a href="javascript:void(0)" class="js-tag article-tag-list-link color5">页面项目</a>
</li>
</ul>
</div>
<p class="article-more-link">
<a class="article-more-a" href="/2022/04/02/%E8%87%AA%E5%AE%9A%E4%B9%89%E5%90%88%E5%90%8C/">展开全文 >></a>
</p>
<div class="clearfix"></div>
</div>
</div>
</article>
<aside class="wrap-side-operation">
<div class="mod-side-operation">
<div class="jump-container" id="js-jump-container" style="display:none;">
<a href="javascript:void(0)" class="mod-side-operation__jump-to-top">
<i class="icon-font icon-back"></i>
</a>
<div id="js-jump-plan-container" class="jump-plan-container" style="top: -11px;">
<i class="icon-font icon-plane jump-plane"></i>
</div>
</div>
</div>
</aside>
<article id="post-es7装饰器" class="article article-type-post article-index" itemscope itemprop="blogPost">
<div class="article-inner">
<header class="article-header">
<h1 itemprop="name">
<a class="article-title" href="/2022/03/18/es7%E8%A3%85%E9%A5%B0%E5%99%A8/" target="_blank">es7装饰器</a>
</h1>
<a href="/2022/03/18/es7%E8%A3%85%E9%A5%B0%E5%99%A8/" class="archive-article-date">
<time datetime="2022-03-18T13:42:17.000Z" itemprop="datePublished"><i class="icon-calendar icon"></i>2022-03-18</time>
</a>
</header>
<div class="article-entry" itemprop="articleBody">
<h1 id="装饰器"><a href="#装饰器" class="headerlink" title="装饰器"></a>装饰器</h1><p>Decorator,是es7的新语法,是一种与类有关的语法,用来注释类或者修改新增类的方法。</p>
<p>装饰器是一种函数,写成@+函数名,可以放在类或者类方法的前面</p>
<p>并不是新的东西,借鉴了java、python的写法,但是其实是依赖于ES5的Object.defineProperty</p>
<h2 id="基本用法"><a href="#基本用法" class="headerlink" title="基本用法"></a>基本用法</h2><figure class="highlight js"><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">@isTest</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">test</span> </span>{</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">isTest</span>(<span class="params">target</span>) </span>{<span class="comment">//加的类相当于target</span></span><br><span class="line"> target.name=<span class="string">'zhangsan'</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>这里的@isTest就是装饰器,给test类加上了isTest的静态属性,target就是test类本身。</p>
<figure class="highlight js"><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">@isTest</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">test</span> </span>{</span><br><span class="line"> ...</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">//等同于</span></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">test</span> </span>{</span><br><span class="line"> ...</span><br><span class="line">}</span><br><span class="line">test=decorator.(test)||test</span><br></pre></td></tr></table></figure>
<h2 id="添加参数"><a href="#添加参数" class="headerlink" title="添加参数"></a>添加参数</h2><p>装饰器就是一个函数,其中第一个参数就是class类,那么如何传多个参数呢?</p>