-
Notifications
You must be signed in to change notification settings - Fork 7
/
search.xml
1631 lines (1631 loc) · 247 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
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
<?xml version="1.0" encoding="utf-8"?>
<search>
<entry>
<title>8㎡出租房100元小折腾记录--90后杭漂程序员</title>
<url>/2017/09/8%E3%8E%A1%E5%87%BA%E7%A7%9F%E6%88%BF100%E5%85%83%E5%B0%8F%E6%8A%98%E8%85%BE%E8%AE%B0%E5%BD%95-90%E5%90%8E%E6%9D%AD%E6%BC%82%E7%A8%8B%E5%BA%8F%E5%91%98/</url>
<content><![CDATA[<blockquote>
<p>都说房子是租的,但生活不是。同步更新至 <a href="https://zhuanlan.zhihu.com/p/29193378" target="_blank" rel="noopener">知乎专栏文章</a></p>
</blockquote>
<a id="more"></a>
<h3 id="封面镇楼!"><a href="#封面镇楼!" class="headerlink" title="封面镇楼!"></a>封面镇楼!</h3><p><img src="https://github.com/palmerye/pictureBed/raw/master/zhihu/article/1.jpg" alt="image"></p>
<p>先允许我发发牢骚吧,最近杭州出租房整改,到处在拆隔断,房租也随之高涨,无奈原来的房间合同到期,只能告别朝南的大落地窗,出来找房子。咸鱼、五八、豆ban、公司论坛,找房子也是折腾的,只能晚上加完班去看房子,要么就是周末,心很累的,资道吗!</p>
<p>后来好不容易签了一个房间,快到搬进去的前几天,毁约!!!你敢信!!!</p>
<p>眼看周末现在住的房子要到期,要睡马路的节奏有没有!!!附近24小时营业的便利店我都找好了!!!3天要找到房子你敢信!!!但是!!!后来被我找到了你敢信!!!</p>
<p>还是要感谢现在的室友老蔡…不然你可能会某一天的夜晚在某个桥下,看到一个敲代码的农民…</p>
<p>房子在xx小区5层,三室一厅原户型,水电民用,有简易的客厅和厨房,小区周边设施比较全,生活还是很便利的,主要离公司近,走路十几分钟。我的房间朝北次卧,先上图吧,这是老蔡(室友)在咸鱼上挂的照片,当时我二话没说,下班看了房子交了几千块,拿了一把沉甸甸的钥匙🔑。这么果断的原因???离公司近、原户型、性价比、时间紧迫…够了吧…</p>
<p><img src="https://github.com/palmerye/pictureBed/raw/master/zhihu/article/2.jpg" alt="image"></p>
<blockquote>
<p>以下就用“窝”代替我的房间名称了!!!</p>
</blockquote>
<p>交钱拿到钥匙的第二天晚上,下完班拿了一小部分行李去窝里,顺便带着尺子去量以下尺寸。主要是量这么几个东西:</p>
<ul>
<li>床(我一米八多,老怕床不够长)</li>
<li>书桌(有点旧,所以打算铺个桌布)</li>
<li>窗户(这个窗帘有点脏啊)</li>
<li>门和墙(下面👇会看到,西面的墙是斜的)</li>
<li>量完回到家,就画了平米图,像模像样有没有。</li>
</ul>
<p><img src="https://github.com/palmerye/pictureBed/raw/master/zhihu/article/3.jpg" alt="image"></p>
<p>8㎡的空间,实在有限,所以空间是大头。有大致思路后,画了草图,把床挪了方向,书桌不动,因为刚好嵌入凹槽节省一定的空间,而且西侧的墙可以利用起来挂一些东西(后面会重点提到这面墙)。上草图。</p>
<p><img src="https://github.com/palmerye/pictureBed/raw/master/zhihu/article/4.jpg" alt="image"></p>
<blockquote>
<p>来,重点介绍这面墙!</p>
</blockquote>
<p>西侧和斜侧不是实体墙,应该是防火板之类的,掉灰,贴不了墙纸,只有在局部能钉上钉子,我又怕敲敲打打影响隔壁邻居,那么问题来了,如何做到最少的支撑点同时又能满足大量上墙的需求?</p>
<p>我的解决方案是:铁丝网。只需要4个角固定住,中间撑开,网格上就能挂大量物件,美观大方!机智如我!</p>
<blockquote>
<p>买买买</p>
</blockquote>
<p>其实要买的东西不多,因为也不需要刷墙什么的大动干戈,简单列一下大部分清单,主要考虑出门在外租房流动性较大,投入不宜过高,搬家的时候也舍得扔。</p>
<ul>
<li>墙纸(必备,提升逼格利器,十米 ¥8.5)</li>
<li>桌布(必备,提升逼格利器,150*90 ¥18)</li>
<li>毛地毯(光脚踩着舒服极了 60*200 ¥9.9)</li>
<li>镜子(买了4面小的拼凑起来一长条 ¥9.9)</li>
<li>铁丝网(买那种2.5cm孔径 热镀锌铁丝 1米*2米 ¥9.99)</li>
<li>LED灯带(暖白,简直是点睛之笔,记得买带驱动器的 2米 ¥4.3)</li>
<li>门垫(进门要拖鞋,这才有家的感觉吧)</li>
<li>窗帘(叫麻麻寄过来的,无价)</li>
<li>其余的衣柜啊,床头柜啊,走的咸鱼,也没几个钱</li>
</ul>
<blockquote>
<p>开始干活</p>
</blockquote>
<p>先说说窝的基调吧,本来是想走性冷淡风的,就因为那块桌布,后来墙纸也有点立体,有点走工业风了,不过都挺喜欢的,黑色是主调,其余随便揉揉吧。第一步肯定是清洁,特别是把墙纸趴下来的时候掉灰,总体打扫干净后开始挥舞小手干活了。贴墙纸很简单的,挂那个铁丝网真的是费力,因为寄过来的时候是卷的,好不容易把它铺平,上墙的时候调整了很久,最终还是不平整,也罢,反正工业上都没那么讲究的。纯文字描述感觉没什么好说的,直接泼上一些图吧,咱看图说话。</p>
<p><img src="https://github.com/palmerye/pictureBed/raw/master/zhihu/article/5.jpg" alt="image"></p>
<p>咸鱼入的床头柜,刚好在附近,上门自提了,99新,有点小,不过挺正。</p>
<p><img src="https://github.com/palmerye/pictureBed/raw/master/zhihu/article/6.jpg" alt="image"></p>
<p>9块9入的镜子,每次换房子都会买,贴在墙上很牢的。</p>
<p><img src="https://github.com/palmerye/pictureBed/raw/master/zhihu/article/7.jpg" alt="image"></p>
<p>云南买的扎染布画,很正宗的手工扎染,曾被麻麻蹂躏在角落里,现在又被我翻出来了。</p>
<p><img src="https://github.com/palmerye/pictureBed/raw/master/zhihu/article/8.jpg" alt="image"></p>
<p>咸鱼入的方格拼接衣柜,半透明,还不错(没错,我就是喜欢深色,有意见?!)</p>
<p><img src="https://github.com/palmerye/pictureBed/raw/master/zhihu/article/9.jpg" alt="image"></p>
<p>挂窗帘,从小就会的技能(多才多艺的我)。</p>
<p><img src="https://github.com/palmerye/pictureBed/raw/master/zhihu/article/11.jpg" alt="image"></p>
<p>引出的插线板可以粘在书桌盘,这样线不会在桌子上乱飞,旁边那个是垃圾桶,也是黑色。</p>
<p><img src="https://github.com/palmerye/pictureBed/raw/master/zhihu/article/12.jpg" alt="image"></p>
<p>因为是晚上拍的,照片不太亮,桌子后面是LED灯带,只有几瓦,很省电。是不是桌布点睛!因为书桌是老式的,有很多抽屉,东西都能放进去,所以桌面看起来比较干净。看到这面墙了吧,什么东西都能往上怼,很爽有没有!桌面上左边那个是红酒箱,里面还有一瓶没开,不过风格很搭这个桌布,所以,怼!色调以黑白为主,毕竟我是色弱!</p>
<p><img src="https://github.com/palmerye/pictureBed/raw/master/zhihu/article/13.jpg" alt="image"></p>
<p>泼一张熄灯后的图,基本上晚上房间不用开灯,因为都在play computer~</p>
<hr>
<p>以上基本上就是小折腾的全部,其他的我就不泼图了。想着坐在这样的桌前,墙上记录一些些生活,桌前水培的植物带来的生命绿,拟人态的木偶,想必也能在下班后能有一个不一样的环境,来告诉自己,生活真的不止是生存……</p>
<p>这里是杭城的某个角落,驻着一位平凡的程序员,有梦想,晚安。</p>
<h3 id="END"><a href="#END" class="headerlink" title="END"></a>END</h3>]]></content>
<tags>
<tag>出租房,杭漂</tag>
</tags>
</entry>
<entry>
<title>CSS中各种布局的背后(*FC)</title>
<url>/2018/02/CSS%E4%B8%AD%E5%90%84%E7%A7%8D%E5%B8%83%E5%B1%80%E7%9A%84%E8%83%8C%E5%90%8E(*FC)/</url>
<content><![CDATA[<blockquote>
<p>CSS中各种布局的背后,实质上是各种*FC的组合。CSS2.1 中只有 BFC 和 IFC, CSS3 中还增加了 FFC 和 GFC。</p>
</blockquote>
<a id="more"></a>
<h2 id="盒模型-Box-Model"><a href="#盒模型-Box-Model" class="headerlink" title="盒模型(Box Model)"></a>盒模型(Box Model)</h2><p><img src="https://developer.mozilla.org/files/72/boxmodel%20(1" alt="imgage">.png)</p>
<blockquote>
<p>上图为W3C标准盒模型,另外还有一种IE盒模型(IE6以下),唯一的区别就是:前者<code>width = content</code>,后者<code>width = content + padding + border</code></p>
</blockquote>
<blockquote>
<p>若要将IE盒模型转换为标准盒模型,需要在文档顶部加上<code><!DOCTYPE html></code>声明;很有意思的是,后来CSS3 中也增加了<code>box-sizing</code>属性,<code>box-sizing: content-box</code>即标准盒模型,<code>box-sizing: border-box</code>即IE盒模型(width包含内边距和边框),W3C反过来又承认了微软,也是有意思。</p>
</blockquote>
<h2 id="视觉格式化模型-Visual-Formatting-Model"><a href="#视觉格式化模型-Visual-Formatting-Model" class="headerlink" title="视觉格式化模型(Visual Formatting Model)"></a>视觉格式化模型(Visual Formatting Model)</h2><blockquote>
<p>视觉格式化模型(visual formatting model)是用来处理文档并将它显示在视觉媒体上的机制,根据上述的盒模型,为文档元素生成盒(Box)。通俗的说,视觉格式化模型就是文档里的盒子布局呈现的一种规则。</p>
</blockquote>
<p>影响布局的因素</p>
<ol>
<li>盒的尺寸和类型</li>
<li>定位方案 <code>Positioning Scheme</code> (常规流,浮动和绝对定位)</li>
<li>文档树中元素之间的关系</li>
<li>外部信息(如:视口大小,图片的固有尺寸等)</li>
</ol>
<h3 id="FC-–-Formatting-Context"><a href="#FC-–-Formatting-Context" class="headerlink" title="FC – Formatting Context"></a>FC – Formatting Context</h3><blockquote>
<p>FC…是谁在说脏话?! Formatting Context – 格式化上下文,*FC就是视觉格式化模型,用来描述盒子布局规则。</p>
</blockquote>
<h3 id="前方大波概念来袭!"><a href="#前方大波概念来袭!" class="headerlink" title="前方大波概念来袭!"></a>前方大波概念来袭!</h3><blockquote>
<p>块级元素、块级盒、块容器盒、块盒、匿名块盒、行内级元素、行内级盒、原子行内级盒、原子行内盒、行盒、匿名行内盒、<del>插入盒</del>……要报警了!!!这些真的不是我YY出来的,<a href="https://www.w3.org/TR/CSS22/visuren.html" target="_blank" rel="noopener">W3C</a> 里真的有这么多概念好吗!!!感觉进坑了啊!!!headache…来吧,一个个捋清楚… -_-|||</p>
</blockquote>
<ul>
<li><p><strong>块级元素(Block-level elements)</strong>:当元素的 CSS 属性 <code>display:block / list-item / table</code> 时,它就是是块级元素 block-level ,视觉上呈现为块,竖直排列。每个块级元素生成一个主要的块级盒 (Principal Block-level Box) 来包含其后代盒和生成的内容,同时参与定位体系 (Positioning Scheme) 。某些块级元素还会在主要盒之外产生额外的盒: list-item 元素。这些额外的盒会相对于主要盒来摆放。</p>
</li>
<li><p><strong>块级盒(Block-level boxes)</strong>:由块级元素生成,参与块级格式化上下文(BFC)。<strong>描述元素跟它的父元素与兄弟元素之间的表现。</strong></p>
</li>
<li><strong>块容器盒(Block container box)</strong>:只包含其它块级盒,或生成一个行内格式化上下文(inline formatting context),只包含行内盒。有些块级盒,比如表格,不是块容器盒。相反,一些块容器盒,比如非替换行内块及非替换表格单元格,不是块级盒。<strong>描述元素跟它的后代之间的影响。</strong></li>
<li><strong>块盒(Block boxes)</strong>:同时是块容器盒的块级盒。</li>
</ul>
<p><img src="https://mdn.mozillademos.org/files/3559/venn_blocks.png" alt="img"></p>
<ul>
<li><strong>匿名块盒(Anonymous block boxes)</strong>:没有名字,不能被 CSS 选择符选中。块容器盒要么只包含行内级盒,要么只包含块级盒,但通常文档会同时包含两者,在这种情况下,将创建匿名块盒来包含毗邻的行内级盒。</li>
</ul>
<figure class="highlight html"><table><tr><td class="code"><pre><span class="line"><span class="tag"><<span class="name">div</span>></span></span><br><span class="line"> I am Block container box</span><br><span class="line"> <span class="tag"><<span class="name">p</span>></span>I'm Inline-level boxes<span class="tag"></<span class="name">p</span>></span></span><br><span class="line"> I am Block container box</span><br><span class="line"><span class="tag"></<span class="name">div</span>></span></span><br></pre></td></tr></table></figure>
<ul>
<li><strong>行内级元素(Inline-level elements)</strong>:当元素的 CSS 属性 <code>display:inline, inline-block 或 inline-table</code> 时,称它为行内级元素。行内级元素生成行内级盒(inline-level boxes),参与行内格式化上下文(IFC)。</li>
<li><strong>行内级盒(Inline-level boxes)</strong>:所有 <code>display:inline</code> 的非替换元素生成的盒是行内盒。</li>
<li><strong>原子行内级盒(atomic inline-level boxes)</strong>:不参与生成行内格式化上下文的行内级盒称为原子行内级盒(atomic inline-level boxes)。</li>
<li><strong>原子行内盒(atomic inline boxes)</strong>:注意:起初原子行内级盒(atomic inline-level boxes)被称为原子行内盒(atomic inline boxes)。很不幸,它们并非行内盒。规范的勘误表修正了这个错误。不管怎样,当再看到原子行内盒时可以放心的当成原子行内级盒,因为只是改了名字。原子行内盒在行内格式化上下文里不能分成多行。</li>
<li><strong>行盒(Line boxes)</strong>:行盒由行内格式化上下文(IFC)产生的盒,用于表示一行。在块盒里面,行盒从块盒一边排版到另一边。 当有浮动时, 行盒从左浮动的最右边排版到右浮动的最左边。</li>
</ul>
<p><img src="https://developer.mozilla.org/@api/deki/files/6008/=venn_inlines.png" alt="img"></p>
<ul>
<li><strong>匿名行内盒(Anonymous inline boxes)</strong>:匿名行内盒最常见的例子是块盒直接包含文本。</li>
<li><del>插入盒(Run-in boxes)</del>:插入盒(Run-in boxes)从 CSS 2.1 标准中移除了,因为可操作的实现定义不足。 可能 CSS3 会引入,但是这是实验性质,不能用于生产环境。 </li>
</ul>
<h3 id="定位方案-Positioning-schemes"><a href="#定位方案-Positioning-schemes" class="headerlink" title="定位方案(Positioning schemes)"></a>定位方案(Positioning schemes)</h3><h4 id="常规流-Normal-flow"><a href="#常规流-Normal-flow" class="headerlink" title="- 常规流(Normal flow)"></a>- 常规流(Normal flow)</h4><blockquote>
<p>CSS2.1中,常规流包括块级盒的块格式化,行内盒的行内格式化,以及块级盒和行内级盒的相对定位。</p>
</blockquote>
<h4 id="浮动-Floats"><a href="#浮动-Floats" class="headerlink" title="- 浮动(Floats)"></a>- 浮动(Floats)</h4><blockquote>
<p>在浮动模型中,盒首先根据常规流布局,然后从常规流中脱离并尽可能地向左或向右位移。内容可以布局在浮动周围。</p>
</blockquote>
<h4 id="绝对定位-Absolute-positioning"><a href="#绝对定位-Absolute-positioning" class="headerlink" title="- 绝对定位(Absolute positioning)"></a>- 绝对定位(Absolute positioning)</h4><blockquote>
<p>在绝对定位模型中,盒完全从常规流中脱离(对后面的同胞元素无影响)并根据包含块来分配位置。</p>
</blockquote>
<h2 id="BFC-–-Block-Formatting-Context"><a href="#BFC-–-Block-Formatting-Context" class="headerlink" title="BFC – Block Formatting Context"></a>BFC – Block Formatting Context</h2><h3 id="触发条件"><a href="#触发条件" class="headerlink" title="触发条件"></a>触发条件</h3><ol>
<li>根元素或其它包含它的元素</li>
<li>浮动 <code>float: left/right/inherit</code></li>
<li>绝对定位元素 <code>position: absolute/fixed</code></li>
<li>行内块 <code>display: inline-block</code></li>
<li>表格单元格 <code>display: table-cell</code></li>
<li>表格标题 <code>display: table-caption</code></li>
<li>溢出元素 <code>overflow: hidden/scroll/auto/inherit</code></li>
<li>弹性盒子 <code>display: flex/inline-flex</code></li>
</ol>
<h3 id="布局规则"><a href="#布局规则" class="headerlink" title="布局规则"></a>布局规则</h3><ol>
<li>内部的Box会在垂直方向,一个接一个地放置。</li>
<li>Box垂直方向的距离由margin决定。属于同一个BFC的两个相邻Box的margin会发生重叠。</li>
<li>每个元素的margin box的左边, 与包含块border box的左边相接触(对于从左往右的格式化,否则相反)。即使存在浮动也是如此。</li>
<li>BFC的区域不会与float box重叠。</li>
<li>BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。反之也如此。</li>
<li>计算BFC的高度时,浮动元素也参与计算</li>
</ol>
<h3 id="应用场景"><a href="#应用场景" class="headerlink" title="应用场景"></a>应用场景</h3><ul>
<li>闭合浮动:浮动区域不叠加到BFC区域上</li>
<li>防止与浮动元素重叠</li>
<li>防止margin collapse</li>
<li>float 元素高度塌陷</li>
<li>…</li>
</ul>
<h2 id="IFC-–-Inline-Formatting-Contexts"><a href="#IFC-–-Inline-Formatting-Contexts" class="headerlink" title="IFC – Inline Formatting Contexts"></a>IFC – Inline Formatting Contexts</h2><h3 id="触发条件-1"><a href="#触发条件-1" class="headerlink" title="触发条件"></a>触发条件</h3><p>一个块级元素中<strong>仅</strong>包含内联级别元素</p>
<h3 id="布局规则-1"><a href="#布局规则-1" class="headerlink" title="布局规则"></a>布局规则</h3><ul>
<li><p>内部的盒子会在水平方向,一个接一个地放置。</p>
</li>
<li><p>这些盒子垂直方向的起点从包含块盒子的顶部开始。</p>
</li>
<li><p>摆放这些盒子的时候,它们在水平方向上的 padding、border、margin 所占用的空间都会被考虑在内。</p>
</li>
<li><p>在垂直方向上,这些框可能会以不同形式来对齐(vertical-align):它们可能会使用底部或顶部对齐,也可能通过其内部的文本基线(baseline)对齐。</p>
</li>
<li><p>能把在一行上的框都完全包含进去的一个矩形区域,被称为该行的行框(line box)。行框的宽度是由包含块(containing box)和存在的浮动来决定。</p>
</li>
<li><p>IFC中的 line box 一般左右边都贴紧其包含块,但是会因为float元素的存在发生变化。float 元素会位于IFC与与 line box 之间,使得 line box 宽度缩短。</p>
</li>
<li><p>IFC 中的 line box 高度由 CSS 行高计算规则来确定,同个 IFC 下的多个 line box 高度可能会不同(比如一行包含了较高的图片,而另一行只有文本)</p>
</li>
<li><p>当 inline-level boxes 的总宽度少于包含它们的 line box 时,其水平渲染规则由 text-align 属性来确定,如果取值为 justify,那么浏览器会对 inline-boxes(注意不是inline-table 和 inline-block boxes)中的文字和空格做出拉伸。</p>
</li>
<li><p>当一个 inline box 超过 line box 的宽度时,它会被分割成多个boxes,这些 boxes 被分布在多个 line box 里。如果一个 inline box 不能被分割(比如只包含单个字符,或 word-breaking 机制被禁用,或该行内框受 white-space 属性值为 nowrap 或 pre 的影响),那么这个 inline box 将溢出这个 line box。</p>
</li>
</ul>
<h3 id="应用场景-1"><a href="#应用场景-1" class="headerlink" title="应用场景"></a>应用场景</h3><ul>
<li><p>水平居中:当一个块要在环境中水平居中时,设置其为 inline-block 则会在外层产生 IFC,通过设置父容器 text-align:center 则可以使其水平居中。</p>
</li>
<li><p>垂直居中:创建一个IFC,用其中一个元素撑开父元素的高度,然后设置其 vertical-align:middle,其他行内元素则可以在此父元素下垂直居中。</p>
</li>
</ul>
<h2 id="FFC-–-Flex-Formatting-Contexts"><a href="#FFC-–-Flex-Formatting-Contexts" class="headerlink" title="FFC – Flex Formatting Contexts"></a>FFC – Flex Formatting Contexts</h2><h3 id="触发条件-2"><a href="#触发条件-2" class="headerlink" title="触发条件"></a>触发条件</h3><p>当 <code>display</code> 的值为 <code>flex</code> 或 <code>inline-flex</code> 时,将生成弹性容器(Flex Containers), 一个弹性容器为其内容建立了一个新的弹性格式化上下文环境(FFC)</p>
<h3 id="布局规则-2"><a href="#布局规则-2" class="headerlink" title="布局规则"></a>布局规则</h3><ul>
<li>设置为 <code>flex</code> 的容器被渲染为一个块级元素</li>
<li>设置为 <code>inline-flex</code> 的容器则渲染为一个行内元素</li>
<li>弹性容器中的每一个子元素都是一个弹性项目。弹性项目可以是任意数量的。弹性容器外和弹性项目内的一切元素都不受影响。简单地说,Flexbox 定义了弹性容器内弹性项目该如何布局</li>
</ul>
<h2 id="GFC-–-GridLayout-Formatting-Contexts"><a href="#GFC-–-GridLayout-Formatting-Contexts" class="headerlink" title="GFC – GridLayout Formatting Contexts"></a>GFC – GridLayout Formatting Contexts</h2><h3 id="触发条件-3"><a href="#触发条件-3" class="headerlink" title="触发条件"></a>触发条件</h3><p>当为一个元素设置<code>display</code>值为<code>grid</code>的时候,此元素将会获得一个独立的渲染区域</p>
<h3 id="布局规则-3"><a href="#布局规则-3" class="headerlink" title="布局规则"></a>布局规则</h3><p>通过在网格容器(grid container)上定义网格定义行(grid definition rows)和网格定义列(grid definition columns)属性各在网格项目(grid item)上定义网格行(grid row)和网格列(grid columns)为每一个网格项目(grid item)定义位置和空间</p>
<hr>
<p>参考:</p>
<p><a href="https://www.w3.org/TR/CSS22/visuren.html" target="_blank" rel="noopener">Visual formatting model</a></p>
<p><a href="https://developer.mozilla.org/zh-CN/docs/Web/Guide/CSS/Visual_formatting_model" target="_blank" rel="noopener">视觉格式化模型</a></p>
<p><a href="https://www.cnblogs.com/lhb25/p/inside-block-formatting-ontext.html" target="_blank" rel="noopener">BFC 神奇背后的原理</a></p>
]]></content>
<tags>
<tag>BFC</tag>
<tag>IFC</tag>
<tag>FFC</tag>
<tag>GFC</tag>
</tags>
</entry>
<entry>
<title>DOM操作成本到底高在哪儿?</title>
<url>/2018/03/DOM%E6%93%8D%E4%BD%9C%E6%88%90%E6%9C%AC%E5%88%B0%E5%BA%95%E9%AB%98%E5%9C%A8%E5%93%AA%E5%84%BF/</url>
<content><![CDATA[<blockquote>
<p>从我接触前端到现在,一直听到的一句话:操作DOM的成本很高,不要轻易去操作DOM。尤其是React、vue等MV*框架的出现,数据驱动视图的模式越发深入人心,jQuery时代提供的强大便利地操作DOM的API在前端工程里用的越来越少。刨根问底,这里说的成本,到底高在哪儿呢?</p>
</blockquote>
<a id="more"></a>
<h2 id="什么是DOM"><a href="#什么是DOM" class="headerlink" title="什么是DOM"></a>什么是DOM</h2><blockquote>
<p>Document Object Model 文档对象模型</p>
</blockquote>
<p>什么是DOM?可能很多人第一反应就是div、p、span等html标签(至少我是),但要知道,DOM是Model,是Object Model,对象模型,是为HTML(and XML)提供的API。HTML(Hyper Text Markup Language)是一种标记语言,HTML在DOM的模型标准中被视为对象,DOM只提供编程接口,却无法实际操作HTML里面的内容。但在浏览器端,前端们可以用脚本语言(JavaScript)通过DOM去操作HTML内容。</p>
<p>那么问题来了,只有JavaScript才能调用DOM这个API吗?</p>
<p>答案是<strong>NO</strong>。</p>
<p>Python也可以访问DOM。所以DOM不是提供给Javascript的API,也不是Javascript里的API。</p>
<p><strong>PS: 实质上还存在<a href="https://developers.google.com/web/fundamentals/performance/critical-rendering-path/constructing-the-object-model" target="_blank" rel="noopener">CSSOM</a>:CSS Object Model,浏览器将CSS代码解析成树形的数据结构,与DOM是两个独立的数据结构</strong>。</p>
<h2 id="浏览器渲染过程"><a href="#浏览器渲染过程" class="headerlink" title="浏览器渲染过程"></a>浏览器渲染过程</h2><blockquote>
<p>讨论DOM操作成本,肯定要先了解该成本的来源,那么就离不开浏览器渲染。</p>
</blockquote>
<p>这里暂只讨论浏览器拿到HTML之后开始解析、渲染。(怎么拿到HTML资源的可能后续另开篇总结吧,什么握握握手啊挥挥挥挥手啊,万恶的flag…)</p>
<ol>
<li><p>解析HTML,构建DOM树(这里遇到外链,此时会发起请求)</p>
</li>
<li><p>解析CSS,生成CSS规则树</p>
</li>
<li><p>合并DOM树和CSS规则,生成render树</p>
</li>
<li><p>布局render树(Layout/reflow),负责各元素尺寸、位置的计算</p>
</li>
<li><p>绘制render树(paint),绘制页面像素信息</p>
</li>
<li><p>浏览器会将各层的信息发送给GPU,GPU将各层合成(composite),显示在屏幕上</p>
</li>
</ol>
<h3 id="1-构建DOM树"><a href="#1-构建DOM树" class="headerlink" title="1.构建DOM树"></a>1.构建DOM树</h3><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line"><html></span><br><span class="line"> <head></span><br><span class="line"> <meta name="viewport" content="width=device-width,initial-scale=1"></span><br><span class="line"> <link href="style.css" rel="stylesheet"></span><br><span class="line"> <title>Critical Path</title></span><br><span class="line"> </head></span><br><span class="line"> <body></span><br><span class="line"> <p>Hello <span>web performance</span> students!</p></span><br><span class="line"> <div><img src="awesome-photo.jpg"></div></span><br><span class="line"> </body></span><br><span class="line"></html></span><br></pre></td></tr></table></figure>
<blockquote>
<p>无论是DOM还是CSSOM,都是要经过<code>Bytes → characters → tokens → nodes → object model</code>这个过程。</p>
</blockquote>
<p><img src="https://github.com/palmerye/pictureBed/raw/master/blog/bV6yUy.png?fromMac" alt></p>
<blockquote>
<p>DOM树构建过程:当前节点的所有子节点都构建好后才会去构建当前节点的下一个兄弟节点。</p>
</blockquote>
<h3 id="2-构建CSSOM树"><a href="#2-构建CSSOM树" class="headerlink" title="2.构建CSSOM树"></a>2.构建CSSOM树</h3><p>上述也提到了CSSOM的构建过程,也是树的结构,在最终计算各个节点的样式时,浏览器都会先从该节点的普遍属性(比如body里设置的全局样式)开始,再去应用该节点的具体属性。还有要注意的是,每个浏览器都有自己默认的样式表,因此很多时候这棵CSSOM树只是对这张默认样式表的部分替换。</p>
<h3 id="3-生成render树"><a href="#3-生成render树" class="headerlink" title="3.生成render树"></a>3.生成render树</h3><blockquote>
<p>DOM树和CSSOM树合并生成render树</p>
</blockquote>
<p><img src="https://github.com/palmerye/pictureBed/raw/master/blog/bV6yUI.png?fromMac" alt></p>
<p>简单描述这个过程:</p>
<p>DOM树从根节点开始遍历<strong>可见</strong>节点,这里之所以强调了“可见”,是因为如果遇到设置了类似<code>display: none;</code>的不可见节点,在render过程中是会被跳过的(但<code>visibility: hidden; opacity: 0</code>这种仍旧占据空间的节点不会被跳过render),保存各个节点的样式信息及其余节点的从属关系。</p>
<h3 id="4-Layout-布局"><a href="#4-Layout-布局" class="headerlink" title="4.Layout 布局"></a>4.Layout 布局</h3><p>有了各个节点的样式信息和属性,但不知道各个节点的确切位置和大小,所以要通过布局将样式信息和属性转换为实际可视窗口的相对大小和位置。</p>
<h3 id="5-Paint-绘制"><a href="#5-Paint-绘制" class="headerlink" title="5.Paint 绘制"></a>5.Paint 绘制</h3><p>万事俱备,最后只要将确定好位置大小的各节点,通过GPU渲染到屏幕的实际像素。</p>
<h3 id="Tips"><a href="#Tips" class="headerlink" title="Tips"></a><strong>Tips</strong></h3><ul>
<li>在上述渲染过程中,前3点可能要多次执行,比如js脚本去操作dom、更改css样式时,浏览器又要重新构建DOM、CSSOM树,重新render,重新layout、paint;</li>
<li>Layout在Paint之前,因此每次Layout重新布局(reflow 回流)后都要重新出发Paint渲染,这时又要去消耗GPU;</li>
<li>Paint不一定会触发Layout,比如改个颜色改个背景;(repaint 重绘)</li>
<li>图片下载完也会重新出发Layout和Paint;</li>
</ul>
<p><img src="https://github.com/palmerye/pictureBed/raw/master/blog/2193277599-5aaa2e14da341_articlex.png?fromMac" alt></p>
<h2 id="何时触发reflow和repaint"><a href="#何时触发reflow和repaint" class="headerlink" title="何时触发reflow和repaint"></a>何时触发reflow和repaint</h2><blockquote>
<p>reflow(回流): 根据Render Tree布局(几何属性),意味着元素的内容、结构、位置或尺寸发生了变化,需要重新计算样式和渲染树;<br>repaint(重绘): 意味着元素发生的改变只影响了节点的一些样式(背景色,边框颜色,文字颜色等),只需要应用新样式绘制这个元素就可以了;<br>reflow回流的成本开销要高于repaint重绘,一个节点的回流往往回导致子节点以及同级节点的回流;</p>
</blockquote>
<p><a href="https://github.com/GoogleChromeLabs" target="_blank" rel="noopener">GoogleChromeLabs</a> 里面有一个<a href="https://csstriggers.com/" target="_blank" rel="noopener">csstriggers</a>,列出了各个CSS属性对浏览器执行Layout、Paint、Composite的影响。</p>
<h3 id="引起reflow回流"><a href="#引起reflow回流" class="headerlink" title="引起reflow回流"></a>引起reflow回流</h3><blockquote>
<p>现代浏览器会对回流做优化,它会等到足够数量的变化发生,再做一次批处理回流。</p>
</blockquote>
<ol>
<li>页面第一次渲染(初始化)</li>
<li>DOM树变化(如:增删节点)</li>
<li>Render树变化(如:padding改变)</li>
<li>浏览器窗口resize</li>
<li>获取元素的某些属性:<br> 浏览器为了获得正确的值也会<strong>提前触发回流</strong>,这样就使得浏览器的优化失效了,这些属性包括offsetLeft、offsetTop、offsetWidth、offsetHeight、 scrollTop/Left/Width/Height、clientTop/Left/Width/Height、调用了getComputedStyle()或者IE的currentStyle</li>
</ol>
<h3 id="引起repaint重绘"><a href="#引起repaint重绘" class="headerlink" title="引起repaint重绘"></a>引起repaint重绘</h3><ol>
<li>reflow回流必定引起repaint重绘,重绘可以单独触发</li>
<li>背景色、颜色、字体改变(注意:字体大小发生变化时,会触发回流)</li>
</ol>
<h3 id="优化reflow、repaint触发次数"><a href="#优化reflow、repaint触发次数" class="headerlink" title="优化reflow、repaint触发次数"></a>优化reflow、repaint触发次数</h3><ul>
<li>避免逐个修改节点样式,尽量一次性修改</li>
<li>使用DocumentFragment将需要多次修改的DOM元素缓存,最后一次性append到真实DOM中渲染</li>
<li>可以将需要多次修改的DOM元素设置<code>display: none</code>,操作完再显示。(因为隐藏元素不在render树内,因此修改隐藏元素不会触发回流重绘)</li>
<li>避免多次读取某些属性(见上)</li>
<li>将复杂的节点元素脱离文档流,降低回流成本</li>
</ul>
<h2 id="为什么一再强调将css放在头部,将js文件放在尾部"><a href="#为什么一再强调将css放在头部,将js文件放在尾部" class="headerlink" title="为什么一再强调将css放在头部,将js文件放在尾部"></a>为什么一再强调将css放在头部,将js文件放在尾部</h2><h3 id="DOMContentLoaded-和-load"><a href="#DOMContentLoaded-和-load" class="headerlink" title="DOMContentLoaded 和 load"></a>DOMContentLoaded 和 load</h3><ul>
<li>DOMContentLoaded 事件触发时,仅当DOM加载完成,不包括样式表,图片…</li>
<li>load 事件触发时,页面上所有的DOM,样式表,脚本,图片都已加载完成</li>
</ul>
<h3 id="CSS-资源阻塞渲染"><a href="#CSS-资源阻塞渲染" class="headerlink" title="CSS 资源阻塞渲染"></a>CSS 资源阻塞渲染</h3><p>构建Render树需要DOM和CSSOM,所以HTML和CSS都会阻塞渲染。所以需要让CSS尽早加载(如:放在头部),以缩短首次渲染的时间。</p>
<h3 id="JS-资源"><a href="#JS-资源" class="headerlink" title="JS 资源"></a>JS 资源</h3><ul>
<li>阻塞浏览器的解析,也就是说发现一个外链脚本时,需等待脚本下载完成并执行后才会继续解析HTML<ul>
<li>这和之前文章提到的浏览器线程有关,浏览器中js引擎线程和渲染线程是互斥的,详见<a href="https://segmentfault.com/a/1190000013702430#articleHeader2" target="_blank" rel="noopener">《从setTimeout-setInterval看JS线程》</a></li>
</ul>
</li>
<li>普通的脚本会阻塞浏览器解析,加上defer或async属性,脚本就变成异步,可等到解析完毕再执行<ul>
<li>async异步执行,异步下载完毕后就会执行,不确保执行顺序,一定在onload前,但不确定在DOMContentLoaded事件的前后</li>
<li>defer延迟执行,相对于放在body最后(理论上在DOMContentLoaded事件前)</li>
</ul>
</li>
</ul>
<h3 id="举个栗子"><a href="#举个栗子" class="headerlink" title="举个栗子"></a>举个栗子</h3><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line"><html></span><br><span class="line"> <head></span><br><span class="line"> <meta name="viewport" content="width=device-width,initial-scale=1"></span><br><span class="line"> <link href="style.css" rel="stylesheet"></span><br><span class="line"> </head></span><br><span class="line"> <body></span><br><span class="line"> <p>Hello <span>web performance</span> students!</p></span><br><span class="line"> <div><img src="awesome-photo.jpg"></div></span><br><span class="line"> <script src="app.js"></script></span><br><span class="line"> </body></span><br><span class="line"></html></span><br></pre></td></tr></table></figure>
<p><img src="https://github.com/palmerye/pictureBed/raw/master/blog/517718454-5aaa988a999bb_articlex.png?fromMac" alt></p>
<ul>
<li>浏览器拿到HTML后,从上到下顺序解析文档</li>
<li>此时遇到css、js外链,则同时发起请求</li>
<li>开始构建DOM树</li>
<li>这里要特别注意,由于有CSS资源,CSSOM还未构建前,会阻塞js(如果有的话)</li>
<li>无论JavaScript是内联还是外链,只要浏览器遇到 <code>script</code> 标记,唤醒<code>JavaScript解析器</code>,就会进行暂停 <code>blocked</code> 浏览器解析HTML,并等到 <code>CSSOM</code> 构建完毕,才执行js脚本</li>
<li>渲染首屏(DOMContentLoaded 触发,其实不一定是首屏,可能在js脚本执行前DOM树和CSSOM已经构建完render树,已经paint)</li>
</ul>
<h2 id="首屏优化Tips"><a href="#首屏优化Tips" class="headerlink" title="首屏优化Tips"></a>首屏优化Tips</h2><blockquote>
<p>说了这么多,其实可以总结几点浏览器首屏渲染优化的方向</p>
</blockquote>
<ul>
<li>减少资源请求数量(内联亦或是延迟动态加载)</li>
<li>使CSS样式表尽早加载,减少@import的使用,因为需要解析完样式表中所有import的资源才会算CSS资源下载完</li>
<li>异步js:阻塞解析器的 JavaScript 会强制浏览器等待 CSSOM 并暂停 DOM 的构建,导致首次渲染的时间延迟</li>
<li>so on…</li>
</ul>
<h2 id="知道操作DOM成本多高了吗"><a href="#知道操作DOM成本多高了吗" class="headerlink" title="知道操作DOM成本多高了吗?"></a>知道操作DOM成本多高了吗?</h2><blockquote>
<p>其实写了这么多,感觉偏题了,大量的资料参考的是chrome开发者文档。感觉js脚本资源那块还是有点乱,包括和DOMContentLoaded的关系,希望大家能多多指点,多多批评,谢谢大佬们。 </p>
</blockquote>
<p>操作DOM具体的成本,说到底是造成浏览器回流reflow和重绘reflow,从而消耗GPU资源。</p>
<h2 id="参考文献"><a href="#参考文献" class="headerlink" title="参考文献:"></a>参考文献:</h2><p><a href="https://developers.google.com/web/fundamentals/performance/critical-rendering-path/" target="_blank" rel="noopener">https://developers.google.com/web/fundamentals/performance/critical-rendering-path/</a></p>
<blockquote>
<p>已同步至个人博客-<a href="palmer.arkstack.cn/2018/03/DOM操作成本到底高在哪儿/">软硬皆施</a><br><a href="https://github.com/palmerye/palmerye.github.io" target="_blank" rel="noopener">Github</a> 欢迎star :)</p>
</blockquote>
]]></content>
<tags>
<tag>DOM</tag>
</tags>
</entry>
<entry>
<title>Git工作流之一(集中式工作流)</title>
<url>/2017/02/Git%E5%B7%A5%E4%BD%9C%E6%B5%81%E4%B9%8B%E4%B8%80--%E9%9B%86%E4%B8%AD%E5%BC%8F%E5%B7%A5%E4%BD%9C%E6%B5%81/</url>
<content><![CDATA[<h1 id="引言"><a href="#引言" class="headerlink" title="引言"></a>引言</h1><h2 id="一言不合讲个小故事"><a href="#一言不合讲个小故事" class="headerlink" title="一言不合讲个小故事"></a>一言不合讲个小故事</h2><a id="more"></a>
<blockquote>
<p>一个和尚有水喝,两个和尚挑水喝,三个和尚没水喝。</p>
</blockquote>
<p>故事暴露了团队协作的问题,但接下来的故事与和尚无关,只是讲讲团队协作的事儿。</p>
<h2 id="贯穿全文的角色"><a href="#贯穿全文的角色" class="headerlink" title="贯穿全文的角色"></a>贯穿全文的角色</h2><ul>
<li>老A:技术Leader</li>
<li>阿B:工程师</li>
<li>小C:实习生</li>
</ul>
<p><img src="https://github.com/palmerye/pictureBed/raw/master/git/men.png" alt="image"></p>
<h2 id="Git工作流"><a href="#Git工作流" class="headerlink" title="Git工作流"></a>Git工作流</h2><blockquote>
<p>Git是Linux老爹的强大发明之一,用C语言编写。强大的工具也因使用情景、使用对象的不同,衍生出不同的Git工作流。</p>
</blockquote>
<ul>
<li>情景一:集中式工作流</li>
<li>情景二:功能分支工作流</li>
<li>情景三:Gitflow工作流</li>
<li>情景四:Forking工作流</li>
</ul>
<h1 id="情景一:集中式工作流"><a href="#情景一:集中式工作流" class="headerlink" title="情景一:集中式工作流"></a>情景一:集中式工作流</h1><h2 id="1-老A初始化工程"><a href="#1-老A初始化工程" class="headerlink" title="1. 老A初始化工程"></a>1. 老A初始化工程</h2><blockquote>
<p>老A在服务器上新建了一个repository(下文均以本人的<a href="https://github.com/palmerye/git-workflow-story" target="_blank" rel="noopener">github/git-workflow-story</a>为例子)</p>
</blockquote>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">mkdir git-workflow-story && cd "$_"</span><br><span class="line">// 当然你也可以在bash里自定义 mkdir&cd 等快捷命令</span><br><span class="line">git init</span><br><span class="line"></span><br><span class="line">git remote add origin https://github.com/palmerye/git-workflow-story.git</span><br></pre></td></tr></table></figure>
<h2 id="2-阿B开始写故事"><a href="#2-阿B开始写故事" class="headerlink" title="2. 阿B开始写故事"></a>2. 阿B开始写故事</h2><blockquote>
<p>阿B的任务是在repo里写Readme(Markdown)</p>
</blockquote>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">mkdir story-B && cd "$_"</span><br><span class="line"></span><br><span class="line">git clone https://github.com/palmerye/git-workflow-story.git</span><br><span class="line"></span><br><span class="line">vi readme.md</span><br></pre></td></tr></table></figure>
<p>于是阿B在readme里面写了一点东西,打算push到老A建的repo里。<br><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">git add readme.md</span><br><span class="line"></span><br><span class="line">git commit -m "这是阿B的第一次提交"</span><br><span class="line"></span><br><span class="line">git push -u origin master</span><br><span class="line">// -u 参数用来初次push的时候指定默认upstream上游分支</span><br></pre></td></tr></table></figure></p>
<h2 id="3-小C来啦"><a href="#3-小C来啦" class="headerlink" title="3. 小C来啦"></a>3. 小C来啦</h2><blockquote>
<p>有一天,老A觉得阿B一个人忙不过来,找来小C来帮忙</p>
</blockquote>
<p>上班第一天,小C就开始忙活,也打算在老A的repo里写点东西。</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">mkdir story-C && cd "$_"</span><br><span class="line"></span><br><span class="line">git clone https://github.com/palmerye/git-workflow-story.git</span><br></pre></td></tr></table></figure>
<p>这个时候repo里已经有了阿B的第一次push的文件,小C突然发现有个错别字,就顺便改了。</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">git add readme.md</span><br><span class="line"></span><br><span class="line">git commit -m "修改了一个错别字"</span><br><span class="line"></span><br><span class="line">git push -u origin master</span><br></pre></td></tr></table></figure>
<h2 id="4-冲突"><a href="#4-冲突" class="headerlink" title="4. 冲突"></a>4. 冲突</h2><p>阿B下午又写了点东西,和之前一样,暂存/提交/推送,突然git push失败了(错误提示本地仓库落后于远端)。于是机智的阿B有了如下操作:</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">git pull --rebase origin master</span><br></pre></td></tr></table></figure>
<p>再次push的时候发现有冲突,于是去解决冲突。发现和小C改了同一个地方,于是自己修改完继续push。</p>
<blockquote>
<p>git merge的冲突判定机制如下:先寻找两个commit的公共祖先,比较同一个文件分别在ours和theirs下对于公共祖先的差异,然后合并这两组差异。如果双方同时修改了一处地方且修改内容不同,就判定为合并冲突,依次输出双方修改的内容。</p>
</blockquote>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">git add . </span><br><span class="line"></span><br><span class="line">git rebase --continue</span><br><span class="line"></span><br><span class="line">git push origin master</span><br></pre></td></tr></table></figure>
<h2 id="故事完结"><a href="#故事完结" class="headerlink" title="故事完结"></a>故事完结</h2><blockquote>
<p>从此他们在一起过上了幸福的Coder生活。</p>
</blockquote>
<p>由上面的故事我们可以看到,集中式工作流只有一条master分支,而且维护得干净一点,永远只有一条分支。多人协作的时候,推送前要确保自己本地状态和远端保持同步,因此要记得rebase。但局限就是,一条分支很难去管理多个开发状态,因此在集中式工作流的基础上,有了后文的功能分支工作流。 </p>
<h2 id="补充点东西"><a href="#补充点东西" class="headerlink" title="补充点东西"></a>补充点东西</h2><blockquote>
<p>git pull 时,–rebase参数可以让分支更整洁</p>
</blockquote>
<p>git pull前<br><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line"> B1---B2 master</span><br><span class="line"> /</span><br><span class="line">A---B---C origin/master</span><br></pre></td></tr></table></figure></p>
<p>不加–rebase/相当于merge<br><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line"> B1---B2 master</span><br><span class="line"> / \</span><br><span class="line">A---B--------C origin/master</span><br></pre></td></tr></table></figure></p>
<p>加上–rebase,告别合并点,让分支更整洁<br><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">A---B---C---B1---B2 master, origin/master</span><br></pre></td></tr></table></figure></p>
]]></content>
<tags>
<tag>git</tag>
<tag>workflow</tag>
<tag>gitflow</tag>
</tags>
</entry>
<entry>
<title>Nodejs调试的各种姿势</title>
<url>/2019/05/Nodejs%E8%B0%83%E8%AF%95%E7%9A%84%E5%90%84%E7%A7%8D%E5%A7%BF%E5%8A%BF/</url>
<content><![CDATA[<h2 id="Node-js-调试的痛点"><a href="#Node-js-调试的痛点" class="headerlink" title="Node.js 调试的痛点"></a>Node.js 调试的痛点</h2><p>对于绝大部分前端人员,对<code>JavaScript</code>的调试更多停留在浏览器中,类似<code>console.log</code>和<code>debugger</code>,但这种方式对代码侵入性较高,甚至需要刷新页面或重启编译器。转向服务端后,没有浏览器界面,如果仅停留在原来的调试方式,开发效率想必是较低的。因此,前端人员转向服务端开发时,要习惯于命令行及 IDE 等调试手段,走出舒适区,才能准确定位问题,提高开发效率。</p>
<a id="more"></a>
<h2 id="Node-js-调试的手段"><a href="#Node-js-调试的手段" class="headerlink" title="Node.js 调试的手段"></a>Node.js 调试的手段</h2><blockquote>
<p>下文中涉及到的依赖库及软件版本</p>
</blockquote>
<ul>
<li>Node.js - v10.15.3</li>
<li>Chrome - v72.0.3626</li>
<li>VS Code - v1.13.0</li>
</ul>
<blockquote>
<p>以下代码段为例,用<code>koa</code>起一个简单的<code>http server</code></p>
</blockquote>
<figure class="highlight javascript"><table><tr><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> app = <span class="keyword">new</span> Koa();</span><br><span class="line"></span><br><span class="line">app.use(<span class="keyword">async</span> ctx => {</span><br><span class="line"> <span class="keyword">const</span> time = <span class="keyword">new</span> <span class="built_in">Date</span>();</span><br><span class="line"> ctx.body = <span class="string">`hello, hiker! <span class="subst">${time}</span>`</span>;</span><br><span class="line">});</span><br><span class="line"></span><br><span class="line">app.listen(<span class="number">3000</span>, () => {</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">'nodejs listening 3000.'</span>);</span><br><span class="line">});</span><br></pre></td></tr></table></figure>
<h3 id="1-console-log"><a href="#1-console-log" class="headerlink" title="1. console.log()"></a>1. console.log()</h3><p>对前端人员非常友好,与浏览器中调试一样,<code>console.log()</code>、<code>console.error()</code>、<code>console.time()</code>等各种<code>console</code>形式,在代码中需要调试的地方直接写上,只是展示形式有所不同,在<code>Node.js</code>中是在终端命令行中打印。这是最简单快速的调试手段,<strong>缺点</strong>也很明显,对原有代码入侵较大,在特定场景中使用较局限。</p>
<h4 id="举例"><a href="#举例" class="headerlink" title="举例"></a>举例</h4><figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line">app.use(<span class="keyword">async</span> ctx => {</span><br><span class="line"> <span class="keyword">const</span> time = <span class="keyword">new</span> <span class="built_in">Date</span>();</span><br><span class="line"></span><br><span class="line"> <span class="built_in">console</span>.time(<span class="string">'TIME_TAKE'</span>);</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">'this is time'</span>, time);</span><br><span class="line"></span><br><span class="line"> ctx.body = <span class="string">`hello, hiker! <span class="subst">${time}</span>`</span>;</span><br><span class="line"> <span class="built_in">console</span>.timeEnd(<span class="string">'TIME_TAKE'</span>);</span><br><span class="line">});</span><br><span class="line"></span><br><span class="line">app.listen(<span class="number">3000</span>, () => {</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">'nodejs listening 3000.'</span>);</span><br><span class="line">});</span><br></pre></td></tr></table></figure>
<h4 id="结果"><a href="#结果" class="headerlink" title="结果"></a>结果</h4><blockquote>
<p>终端起服务:<code>node index.js</code>,并浏览器访问<code>localhost:3000</code>, 即可在终端命令行中看到相应打印的日志。</p>
</blockquote>
<p><img src="https://github.com/palmerye/pictureBed/raw/master/blog/16cd25265f9ad78d.png" alt></p>
<h3 id="2-Debugger-Protocol-node-inspector"><a href="#2-Debugger-Protocol-node-inspector" class="headerlink" title="2. Debugger Protocol (node-inspector)"></a>2. Debugger Protocol (node-inspector)</h3><blockquote>
<p><code>Nodejs v6.3+</code> 的版本提供了两个用于调试的协议:<code>v8 Debugger Protocol</code> 和 <code>v8 Inspector Protocol</code> 可以使用第三方的 Client/IDE 等监测和介入 Node(v8) 运行过程,进行调试。</p>
</blockquote>
<p><a href="https://github.com/node-inspector/node-inspector" target="_blank" rel="noopener">node-inspector</a>是早期可以基于Chrome,有可视化调试界面的调试工具,用的是<code>v8 Debugger Protocol</code>协议,通过 TCP 端口与 Client/IDE 交互通信。但由于<code>v8 Inspector Protocol</code>的推出,这个工具逐渐被替代,后文会介绍相应替代方案。</p>
<h4 id="使用方式"><a href="#使用方式" class="headerlink" title="使用方式"></a>使用方式</h4><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">$ npm install -g node-inspector</span><br><span class="line"></span><br><span class="line">通过浏览器连接到node-inspector,启动inspector服务:</span><br><span class="line">$ node-inspector</span><br><span class="line"></span><br><span class="line">以debug模式运行node.js应用:</span><br><span class="line">$ node --debug=5858 index.js</span><br><span class="line"></span><br><span class="line">浏览器打开 http://127.0.0.1:8080/debug?port=5858,后台会提供一个类似于 chrome devtools 的 UI 调试界面。</span><br></pre></td></tr></table></figure>
<h3 id="3-Inspector-Protocol-Chrome-DevTools"><a href="#3-Inspector-Protocol-Chrome-DevTools" class="headerlink" title="3. Inspector Protocol + Chrome DevTools"></a>3. Inspector Protocol + Chrome DevTools</h3><blockquote>
<p><code>v8 Inspector Protocol</code> 是 <code>nodejs v6.3</code> 新加入的调试协议,通过 <code>websocket</code>与 Client/IDE 交互,同时基于 Chrome/Chromium 浏览器的 devtools 提供了图形化的调试界面。</p>
</blockquote>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line">$ node --inspect=<span class="number">9222</span> index.js</span><br></pre></td></tr></table></figure>
<blockquote>
<p>如果程序执行完会直接结束进程的,那么<code>--inspect</code>会一闪而过,断点信号还没发送出去前就结束了,断点根本不起作用,这种情况可以用<code>--inspect-brk</code>启动调试器,使得脚本可以代码执行之前<code>break</code>。</p>
</blockquote>
<h4 id="结果-1"><a href="#结果-1" class="headerlink" title="结果"></a>结果</h4><p><img src="https://github.com/palmerye/pictureBed/raw/master/blog/16cd253452dfafe6.png" alt></p>
<p><code>ws://127.0.0.1:9222/a45dc332-2c8c-4614-bf01-1dbf212ae28a</code>这个不是提供给我们在Chrome浏览器中访问的地址,而是Node.js和Chrome之间进行通信的的地址,通过websocket进行通信,从而将调试结果实时展示在Chrome浏览器中。</p>
<p><img src="https://github.com/palmerye/pictureBed/raw/master/blog/16cd25375cf0f310.png" alt></p>
<p>那么如何获取在chrome浏览器中的调试地址?我们可以访问<code>http://localhost:9222/json/list</code>,可以看到相应信息。其中id为UUID,是一个特定的标识,每一个进程都会分配一个uuid,因此每一次调用会有出现不同的结果。<code>devtoolsFrontendUrl</code>则为我们要访问的chrome地址,新窗口打开这个地址即可调试。</p>
<p><img src="https://github.com/palmerye/pictureBed/raw/master/blog/16cd2539f2338697.png" alt></p>
<h4 id="更便捷的调试入口"><a href="#更便捷的调试入口" class="headerlink" title="更便捷的调试入口"></a>更便捷的调试入口</h4><blockquote>
<p>上述步骤是不是有点麻烦,不要紧,强大的Chrome提供了更方便的调试入口。</p>
</blockquote>
<p><code>node --inspect=9222 index.js</code>起服务后,打开浏览器访问http监听端口页面,并打开调试窗口,可以看到一个绿色的按钮,点开即可下断点调试,是不是很方便?</p>
<p><img src="https://github.com/palmerye/pictureBed/raw/master/blog/16cd253da54e566e.png" alt></p>
<blockquote>
<p>这个绿油油的按钮究竟打开了什么呢?我们可以继续看。访问<code>chrome://inspect/#devices</code>,可以看到当前浏览器监听的所有<code>inspect</code></p>
</blockquote>
<p><img src="https://github.com/palmerye/pictureBed/raw/master/blog/16cd2541c7f92416.png" alt></p>
<p>到这里,我们就可以利用Chrome DevTools的各类功能,<code>Sources Panel</code>查看脚本、<code>Profile Panel</code>监测性能等,文中不具体展开。</p>
<h3 id="4-Inspector-Protocol-VS-Code"><a href="#4-Inspector-Protocol-VS-Code" class="headerlink" title="4. Inspector Protocol + VS Code"></a>4. Inspector Protocol + VS Code</h3><blockquote>
<p>对服务端开发来讲,浏览器的使用反而不那么频繁,因此在IDE中调试<code>Nodejs</code>显得格外重要。值得高兴的是,市面上各类IDE对<code>Nodejs</code>的调试还算友好,尤其是VS Code。它内置了<code>Node debugger</code>,支持<code>v8 Debugger Protocol</code>和<code>v8 Inspector Protocol</code>两种协议。</p>
</blockquote>
<h4 id="launch"><a href="#launch" class="headerlink" title="launch"></a>launch</h4><blockquote>
</blockquote>
<p>在VS Code中,打开<code>调试</code>/<code>添加配置</code>/,如下图,添加launch配置,点击开始调试即可。</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">{</span><br><span class="line"> "version": "0.2.0",</span><br><span class="line"> "configurations": [</span><br><span class="line"> {</span><br><span class="line"> "type": "node",</span><br><span class="line"> "request": "launch",</span><br><span class="line"> "name": "Launch Program",</span><br><span class="line"> "program": "${workspaceFolder}\\index.js"</span><br><span class="line"> }</span><br><span class="line"> ]</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p><img src="https://github.com/palmerye/pictureBed/raw/master/blog/16cd25474fd14abd.png" alt></p>
<p>下图展示了调试窗口,可以看到,我们可以直接在IDE中下断点,左侧小窗口中可以看到当前作用域的变量(可展开树),调用堆栈,所有断点等,右上方亦可逐步调试函数、重启等功能,非常强大。</p>
<p><img src="https://github.com/palmerye/pictureBed/raw/master/blog/16cd254e6ded40d6.png" alt></p>
<h4 id="Auto-Attach"><a href="#Auto-Attach" class="headerlink" title="Auto Attach"></a>Auto Attach</h4><blockquote>
<p>同样VS Code提供了自动附加的功能:Auto Attach。不用配置即可快速调试。</p>
</blockquote>
<p><code>Ctrl+Shift+p</code>打开Auto Attach功能,然后同样的方式在终端命令行中:<code>node --inspect=9222 .\index.js</code></p>
<p><img src="https://github.com/palmerye/pictureBed/raw/master/blog/16cd25512aecf597.png" alt></p>
<p><img src="https://github.com/palmerye/pictureBed/raw/master/blog/16cd255462c0dc83.png" alt></p>
<h2 id="醉后"><a href="#醉后" class="headerlink" title="醉后"></a>醉后</h2><p>本文总结了<code>Nodejs</code>的调试方法,基本涵盖了所有的调试手段,包括了命令行调试,Chrome浏览器调试,VS Code编辑器调试,并深入部分调试协议,图文结合,可供其他的<code>Nodejs</code>开发者参考,降低开发人员的学习成本,在项目工程应用中,准确定位问题,提高开发效率。</p>
<h2 id="参考文献:"><a href="#参考文献:" class="headerlink" title="参考文献:"></a>参考文献:</h2><p><a href="http://nodejs.cn/api/inspector.html" target="_blank" rel="noopener">http://nodejs.cn/api/inspector.html</a></p>
<p><a href="http://nodejs.cn/api/debugger.html" target="_blank" rel="noopener">http://nodejs.cn/api/debugger.html</a></p>
<p><a href="http://i5ting.github.io/vsc/#1" target="_blank" rel="noopener">http://i5ting.github.io/vsc/#1</a></p>
]]></content>
<tags>
<tag>Nodejs</tag>
</tags>
</entry>
<entry>
<title>RevealJs(slides演示工具)中文文档</title>
<url>/2017/05/RevealJs-slides%E6%BC%94%E7%A4%BA%E5%B7%A5%E5%85%B7-%E4%B8%AD%E6%96%87%E6%96%87%E6%A1%A3/</url>
<content><![CDATA[<blockquote>
<p>reveal.js 就是在各个互联网大会或者科技发布会常用的幻灯片演示工具,也就是slides,功能强大,自适应移动端和PC端。It translated by <a href="https://github.com/palmerye" target="_blank" rel="noopener">Palmer</a> in 2017/5/13.</p>
</blockquote>
<a id="more"></a>
<p><img src="https://github.com/palmerye/pictureBed/raw/master/revealjs/revealjs-zh.jpg" alt="image"></p>
<blockquote>
<p>示例: 左图为移动端,右图为PC端。完整示例:<a href="http://palmerye.online/demos-Reveal.js/" target="_blank" rel="noopener">Demo 预览</a></p>
</blockquote>
<ul>
<li><a href="http://palmerye.online/demos-Reveal.js/" target="_blank" rel="noopener">Demo 预览</a><ul>
<li>工程位于<a href="https://github.com/palmerye/demos-Reveal.js/tree/gh-pages" target="_blank" rel="noopener">gh-pages</a>分支</li>
</ul>
</li>
<li><a href="#工程安装">工程运行指南</a></li>
<li><a href="#revealjs-中文">中文文档</a></li>
<li><a href="https://github.com/hakimel/reveal.js#revealjs--" target="_blank" rel="noopener">官方英文文档</a></li>
</ul>
<blockquote>
<p>官方文档中文翻译,内容做适当删减</p>
</blockquote>
<ul>
<li>一个使用 <code>HTML</code> 轻松创建精美的演示文稿框架,你只要有一个支持 <code>CSS 3D</code> 切换的浏览器(拥抱Chrome, 拒绝IE)。点击查看 <a href="http://lab.hakim.se/reveal-js/" target="_blank" rel="noopener">Demo</a></li>
<li>reveal.js 配备了广泛的功能,包括嵌套幻灯片,<code>Markdown</code> 内容,<code>PDF</code> 导出,演讲笔记和 <code>JavaScript</code> API。还有一个全功能的可视化编辑器和平台,可生成在线的slide地址,有免费版和收费版:<a href="https://slides.com/" target="_blank" rel="noopener">slides.com</a>。</li>
</ul>
<h2 id="更多功能"><a href="#更多功能" class="headerlink" title="更多功能"></a>更多功能</h2><ul>
<li><a href="https://github.com/hakimel/reveal.js/releases" target="_blank" rel="noopener">更新日志</a>: 获取最新版本.</li>
<li><a href="https://github.com/hakimel/reveal.js/wiki/Example-Presentations" target="_blank" rel="noopener">例子</a>: 这里有一些基于<code>reveal.js</code>的演示例子,也欢迎PR,提供属于你自己的个性例子!</li>
<li><a href="https://github.com/hakimel/reveal.js/wiki/Browser-Support" target="_blank" rel="noopener">浏览器支持</a>: 浏览器兼容情况.</li>
<li><a href="https://github.com/hakimel/reveal.js/wiki/Plugins,-Tools-and-Hardware" target="_blank" rel="noopener">插件</a>: 扩展<code>reveal.js</code>功能的插件列表.</li>
</ul>
<h2 id="在线编辑"><a href="#在线编辑" class="headerlink" title="在线编辑"></a>在线编辑</h2><p>演示文档是使用 <code>HTML</code> 或者 <code>Markdown</code> 编写的,如果你们更喜欢图形界面的在线编辑器,点击 <a href="https://slides.com?ref=github" target="_blank" rel="noopener">https://slides.com</a> 尝试一下。</p>
<h2 id="说明"><a href="#说明" class="headerlink" title="说明"></a>说明</h2><h3 id="结构"><a href="#结构" class="headerlink" title="结构"></a>结构</h3><p>这里有一个简单的例子,充分展示了reveal.js的演示文档结构.<br><figure class="highlight html"><table><tr><td class="code"><pre><span class="line"><span class="tag"><<span class="name">html</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">link</span> <span class="attr">rel</span>=<span class="string">"stylesheet"</span> <span class="attr">href</span>=<span class="string">"css/reveal.css"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">link</span> <span class="attr">rel</span>=<span class="string">"stylesheet"</span> <span class="attr">href</span>=<span class="string">"css/theme/white.css"</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">div</span> <span class="attr">class</span>=<span class="string">"reveal"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"slides"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">section</span>></span>Slide 1<span class="tag"></<span class="name">section</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">section</span>></span>Slide 2<span class="tag"></<span class="name">section</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">script</span> <span class="attr">src</span>=<span class="string">"js/reveal.js"</span>></span><span class="tag"></<span class="name">script</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">script</span>></span></span><br><span class="line"> Reveal.initialize();</span><br><span class="line"> <span class="tag"></<span class="name">script</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">html</span>></span></span><br></pre></td></tr></table></figure></p>
<p>演示文档的标签结构需要 <code>.reveal > .slides > section</code> 包含,一个 <code>section</code> 表示一个 <code>slide</code> 而且可以无限重复。如果你在一个 <code>section</code> 标签里包含了多个 <code>section</code>,那么这几个 <code>section</code> 就会垂直分布(意思就是你需要上下切换 <code>slide</code>),第一个垂直的 <code>slide</code> 位于其它 <code>slide</code> 的顶部,同时也是包含在水平 <code>slide</code> 序列中。举个例子:<br><figure class="highlight html"><table><tr><td class="code"><pre><span class="line"><span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"reveal"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"slides"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">section</span>></span>Single Horizontal Slide<span class="tag"></<span class="name">section</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">section</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">section</span>></span>Vertical Slide 1<span class="tag"></<span class="name">section</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">section</span>></span>Vertical Slide 2<span class="tag"></<span class="name">section</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">section</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></pre></td></tr></table></figure></p>
<h2 id="Markdown"><a href="#Markdown" class="headerlink" title="_Markdown"></a>_Markdown</h2><p><code>reveal.js</code> 支持 <code>Markdown</code> 来实现内容。使用 Markdown 实现内容时,需要在 <code>section</code> 标签中添加 <code>data-markdown</code> 属性,然后将 <code>Markdown</code> 内容写到一个 <code>text/template</code> 脚本中,如下例。</p>
<blockquote>
<p>这是基于 <a href="https://gist.github.com/1343518" target="_blank" rel="noopener">Paul Irish</a> 为了支持 <a href="https://help.github.com/articles/github-flavored-markdown" target="_blank" rel="noopener">GitHub Flavored Markdown</a> 而修改的 <a href="https://gist.github.com/1343518" target="_blank" rel="noopener">data-markdown</a>,所以对缩进和换行符都是敏感的,应该避免tabs和空格混用,也要注意换行的使用。 </p>
</blockquote>
<figure class="highlight html"><table><tr><td class="code"><pre><span class="line"><span class="tag"><<span class="name">section</span> <span class="attr">data-markdown</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">script</span> <span class="attr">type</span>=<span class="string">"text/template"</span>></span></span><br><span class="line"> ## Page title</span><br><span class="line"></span><br><span class="line"><span class="javascript"> A paragraph <span class="keyword">with</span> some text and a [link](http:<span class="comment">//hakim.se).</span></span></span><br><span class="line"> <span class="tag"></<span class="name">script</span>></span></span><br><span class="line"><span class="tag"></<span class="name">section</span>></span></span><br></pre></td></tr></table></figure>
<h3 id="外部-Markdown-文件"><a href="#外部-Markdown-文件" class="headerlink" title="外部 Markdown 文件"></a>外部 Markdown 文件</h3><p>可以把 Markdown 内容写在外部文件里,在 reveal.js 运行时进行加载。 引用外部文件时可设置的参数:</p>
<ul>
<li><code>data-separator</code> 定义划分横向幻灯片的规则(默认值为 <code>^\r?\n---\r?\n$</code>)</li>
<li><code>data-separator-vertical</code> 定义划分纵向幻灯片的规则(默认禁用)</li>
<li><code>data-separator-notes</code> 定义当前幻灯片的演讲备注 (默认值为 <code>note:</code>)</li>
<li><code>data-charset</code> 定义外部文件加载时使用的字符集</li>
</ul>
<p>如果要在本地使用该特性,演示文稿需要运行在<a href="#full-setup">本地服务器上</a></p>
<figure class="highlight html"><table><tr><td class="code"><pre><span class="line"><span class="tag"><<span class="name">section</span> <span class="attr">data-markdown</span>=<span class="string">"example.md"</span> </span></span><br><span class="line"><span class="tag"> <span class="attr">data-separator</span>=<span class="string">"^\n\n\n"</span> </span></span><br><span class="line"><span class="tag"> <span class="attr">data-separator-vertical</span>=<span class="string">"^\n\n"</span> </span></span><br><span class="line"><span class="tag"> <span class="attr">data-separator-notes</span>=<span class="string">"^Note:"</span> </span></span><br><span class="line"><span class="tag"> <span class="attr">data-charset</span>=<span class="string">"iso-8859-15"</span>></span></span><br><span class="line"><span class="tag"></<span class="name">section</span>></span></span><br></pre></td></tr></table></figure>
<h3 id="元素属性"><a href="#元素属性" class="headerlink" title="元素属性"></a>元素属性</h3><p>在 Markdown 内容中,可以通过 html 注释来添加元素属性,如分段:</p>
<figure class="highlight html"><table><tr><td class="code"><pre><span class="line"><span class="tag"><<span class="name">section</span> <span class="attr">data-markdown</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">script</span> <span class="attr">type</span>=<span class="string">"text/template"</span>></span></span><br><span class="line"><span class="xml"> - 列表项 1 <span class="comment"><!-- .element: class="fragment" data-fragment-index="2" --></span></span></span><br><span class="line"><span class="xml"> - 列表项 2 <span class="comment"><!-- .element: class="fragment" data-fragment-index="1" --></span></span></span><br><span class="line"> <span class="tag"></<span class="name">script</span>></span></span><br><span class="line"><span class="tag"></<span class="name">section</span>></span></span><br></pre></td></tr></table></figure>
<h3 id="幻灯片属性"><a href="#幻灯片属性" class="headerlink" title="幻灯片属性"></a>幻灯片属性</h3><p>html 注释也可以用来添加幻灯片 <code><section></code> 元素的属性。</p>
<figure class="highlight html"><table><tr><td class="code"><pre><span class="line"><span class="tag"><<span class="name">section</span> <span class="attr">data-markdown</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">script</span> <span class="attr">type</span>=<span class="string">"text/template"</span>></span></span><br><span class="line"><span class="xml"> <span class="comment"><!-- .slide: data-background="#ff0000" --></span></span></span><br><span class="line"> Markdown 内容</span><br><span class="line"> <span class="tag"></<span class="name">script</span>></span></span><br><span class="line"><span class="tag"></<span class="name">section</span>></span></span><br></pre></td></tr></table></figure>
<h3 id="配置-marked"><a href="#配置-marked" class="headerlink" title="配置 marked"></a>配置 marked</h3><p>reveal.js 使用 <a href="https://github.com/chjj/marked" target="_blank" rel="noopener">marked</a> 来解析 Markdown,可在设置<a href="#configuration">reveal 配置</a> 时传入 marked 的配置:</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line">Reveal.initialize({</span><br><span class="line"> <span class="comment">// 传入 marked 的配置</span></span><br><span class="line"> <span class="comment">// 参考 https://github.com/chjj/marked#options-1</span></span><br><span class="line"> markdown: {</span><br><span class="line"> smartypants: <span class="literal">true</span></span><br><span class="line"> }</span><br><span class="line">});</span><br></pre></td></tr></table></figure>
<h2 id="配置"><a href="#配置" class="headerlink" title="配置"></a>配置</h2><p>需在页面底部初始化 reveal,所有配置项均为可选,默认值如下:</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line">Reveal.initialize({</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 在右下角显示控制面板</span></span><br><span class="line"> controls: <span class="literal">true</span>,</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 显示演示进度条</span></span><br><span class="line"> progress: <span class="literal">true</span>,</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 显示幻灯片页码</span></span><br><span class="line"> <span class="comment">// 可使用代码 slideNumber: 'c/t',表示 '当前页/总页数'</span></span><br><span class="line"> slideNumber: <span class="literal">false</span>,</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 幻灯片切换时写入浏览器历史记录</span></span><br><span class="line"> history: <span class="literal">false</span>,</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 启用键盘快捷键</span></span><br><span class="line"> keyboard: <span class="literal">true</span>,</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 启用幻灯片概览</span></span><br><span class="line"> overview: <span class="literal">true</span>,</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 幻灯片垂直居中</span></span><br><span class="line"> center: <span class="literal">true</span>,</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 在触屏设备上启用触摸滑动切换</span></span><br><span class="line"> touch: <span class="literal">true</span>,</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 循环演示</span></span><br><span class="line"> loop: <span class="literal">false</span>,</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 演示方向为右往左,即向左切换为下一张,向右切换为上一张</span></span><br><span class="line"> rtl: <span class="literal">false</span>,</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 打乱幻灯片顺序</span></span><br><span class="line"> shuffle: <span class="literal">false</span>,</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 启用幻灯片分段</span></span><br><span class="line"> fragments: <span class="literal">true</span>,</span><br><span class="line"></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">// false:所有在演示文稿上触发的 "touchmove" 的默认行为都会被阻止</span></span><br><span class="line"> <span class="comment">// true:只有在 "touchmove" 触发了演示文稿事件时才会阻止默认行为</span></span><br><span class="line"> embedded: <span class="literal">false</span>,</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 是否在按下 ? 键时显示快捷键帮助面板</span></span><br><span class="line"> help: <span class="literal">true</span>,</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 演讲备注是否对所有人可见</span></span><br><span class="line"> showNotes: <span class="literal">false</span>,</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 两个幻灯片之间自动播放的时间间隔(毫秒),当设置为 0 时,则禁止自动播放。</span></span><br><span class="line"> <span class="comment">// 该值可以被幻灯片上的 `data-autoslide` 属性覆盖</span></span><br><span class="line"> autoSlide: <span class="number">0</span>,</span><br><span class="line"></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">// 按 a 键暂停或恢复自动播放</span></span><br><span class="line"> autoSlideStoppable: <span class="literal">true</span>,</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 使用该函数执行自动播放操作</span></span><br><span class="line"> autoSlideMethod: Reveal.navigateNext,</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 启用鼠标滚轮切换幻灯片,作用与 SPACE 相同</span></span><br><span class="line"> mouseWheel: <span class="literal">false</span>,</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 在移动设备上隐藏地址栏</span></span><br><span class="line"> hideAddressBar: <span class="literal">true</span>,</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 在 iframe 预览弹框中打开链接</span></span><br><span class="line"> previewLinks: <span class="literal">false</span>,</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 切换过渡效果</span></span><br><span class="line"> <span class="comment">// none-无/fade-渐变/slide-飞入/convex-凸面/concave-凹面/zoom-缩放</span></span><br><span class="line"> transition: <span class="string">'slide'</span>, <span class="comment">// none/fade/slide/convex/concave/zoom</span></span><br><span class="line"></span><br><span class="line"> <span class="comment">// 切换过渡速度</span></span><br><span class="line"> <span class="comment">// default-中速/fast-快速/slow-慢速</span></span><br><span class="line"> transitionSpeed: <span class="string">'default'</span>, <span class="comment">// default/fast/slow</span></span><br><span class="line"></span><br><span class="line"> <span class="comment">// 背景切换过渡效果</span></span><br><span class="line"> backgroundTransition: <span class="string">'fade'</span>, <span class="comment">// none/fade/slide/convex/concave/zoom</span></span><br><span class="line"></span><br><span class="line"> <span class="comment">// 预加载幻灯片数</span></span><br><span class="line"> viewDistance: <span class="number">3</span>,</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 视差背景图</span></span><br><span class="line"> parallaxBackgroundImage: <span class="string">''</span>, <span class="comment">// 示例:"'https://s3.amazonaws.com/hakim-static/reveal-js/reveal-parallax-1.jpg'"</span></span><br><span class="line"></span><br><span class="line"> <span class="comment">// 视察背景图尺寸</span></span><br><span class="line"> parallaxBackgroundSize: <span class="string">''</span>, <span class="comment">// CSS 写法,示例:"2100px 900px"(目前只支持像素值,不支持 % 和 auto)</span></span><br><span class="line"></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">// - 当设置为 0 时,则禁止视差动画</span></span><br><span class="line"> parallaxBackgroundHorizontal: <span class="literal">null</span>,</span><br><span class="line"> parallaxBackgroundVertical: <span class="literal">null</span></span><br><span class="line"></span><br><span class="line">});</span><br></pre></td></tr></table></figure>
<p>在执行初始化后,可通过 configure 方法来更新配置:</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="comment">// 关闭自动播放</span></span><br><span class="line">Reveal.configure({ <span class="attr">autoSlide</span>: <span class="number">0</span> });</span><br><span class="line"></span><br><span class="line"><span class="comment">// 开启自动播放(时间间隔为 5 秒)</span></span><br><span class="line">Reveal.configure({ <span class="attr">autoSlide</span>: <span class="number">5000</span> });</span><br></pre></td></tr></table></figure>
<h2 id="演示文稿尺寸"><a href="#演示文稿尺寸" class="headerlink" title="演示文稿尺寸"></a>演示文稿尺寸</h2><p>演示文稿有一个标准尺寸,框架会在其基础上自动缩放以适应各种分辨率。</p>
<p>尺寸相关的配置项及其默认值如下:<br><figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line">Reveal.initialize({</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 class="comment">// 可使用百分比,如:'200%'</span></span><br><span class="line"> width: <span class="number">960</span>,</span><br><span class="line"> height: <span class="number">700</span>,</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 内容外边距</span></span><br><span class="line"> margin: <span class="number">0.1</span>,</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 内容缩放比例的最小值/最大值</span></span><br><span class="line"> minScale: <span class="number">0.2</span>,</span><br><span class="line"> maxScale: <span class="number">1.5</span></span><br><span class="line"></span><br><span class="line">});</span><br></pre></td></tr></table></figure></p>
<p>如果想要使用自定义的缩放方式(如使用媒体查询),可通过下面的设置来禁用自动缩放:<br><figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line">Reveal.initialize({</span><br><span class="line"></span><br><span class="line"> ...</span><br><span class="line"></span><br><span class="line"> width: <span class="string">"100%"</span>,</span><br><span class="line"> height: <span class="string">"100%"</span>,</span><br><span class="line"> margin: <span class="number">0</span>,</span><br><span class="line"> minScale: <span class="number">1</span>,</span><br><span class="line"> maxScale: <span class="number">1</span></span><br><span class="line">});</span><br></pre></td></tr></table></figure></p>
<h2 id="依赖"><a href="#依赖" class="headerlink" title="依赖"></a>依赖</h2><p>Reveal.js 的部分功能需要引入自带的第三方库,可在初始化时传入依赖项,运行时会自动加载。</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line">Reveal.initialize({</span><br><span class="line"> dependencies: [</span><br><span class="line"> <span class="comment">// classList 跨浏览器支持 - https://github.com/eligrey/classList.js/</span></span><br><span class="line"> { <span class="attr">src</span>: <span class="string">'lib/js/classList.js'</span>, <span class="attr">condition</span>: <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>{ <span class="keyword">return</span> !<span class="built_in">document</span>.body.classList; } },</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 解析 <section> 元素里的 Markdown 内容</span></span><br><span class="line"> { <span class="attr">src</span>: <span class="string">'plugin/markdown/marked.js'</span>, <span class="attr">condition</span>: <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>{ <span class="keyword">return</span> !!<span class="built_in">document</span>.querySelector( <span class="string">'[data-markdown]'</span> ); } },</span><br><span class="line"> { <span class="attr">src</span>: <span class="string">'plugin/markdown/markdown.js'</span>, <span class="attr">condition</span>: <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>{ <span class="keyword">return</span> !!<span class="built_in">document</span>.querySelector( <span class="string">'[data-markdown]'</span> ); } },</span><br><span class="line"></span><br><span class="line"> <span class="comment">// <code> 元素语法高亮</span></span><br><span class="line"> { <span class="attr">src</span>: <span class="string">'plugin/highlight/highlight.js'</span>, <span class="attr">async</span>: <span class="literal">true</span>, <span class="attr">callback</span>: <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>{ hljs.initHighlightingOnLoad(); } },</span><br><span class="line"></span><br><span class="line"> <span class="comment">// Alt+click 缩放点击元素</span></span><br><span class="line"> { <span class="attr">src</span>: <span class="string">'plugin/zoom-js/zoom.js'</span>, <span class="attr">async</span>: <span class="literal">true</span> },</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 演讲备注</span></span><br><span class="line"> { <span class="attr">src</span>: <span class="string">'plugin/notes/notes.js'</span>, <span class="attr">async</span>: <span class="literal">true</span> },</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 数学公式</span></span><br><span class="line"> { <span class="attr">src</span>: <span class="string">'plugin/math/math.js'</span>, <span class="attr">async</span>: <span class="literal">true</span> }</span><br><span class="line"> ]</span><br><span class="line">});</span><br></pre></td></tr></table></figure>
<p>自定义库也可以使用该方式加载。<br>依赖项属性:</p>
<ul>
<li><strong>src</strong>: 脚本路径</li>
<li><strong>async</strong>: [可选] 异步,是否允许 reveal.js 执行后再加载脚本,默认值为 false</li>
<li><strong>callback</strong>: [可选] 回调函数,脚本加载完成后执行</li>
<li><strong>condition</strong>: [可选] 条件函数,返回 true 时才会加载脚本</li>
</ul>
<p>要使用该方式来加载依赖项,需在引入 reveal.js 之前引入 <a href="http://headjs.com/" target="_blank" rel="noopener">head.js</a> <em>(提供加载脚本功能的库)</em>。</p>
<h2 id="Ready事件"><a href="#Ready事件" class="headerlink" title="Ready事件"></a>Ready事件</h2><p>reveal.js 在所有非异步依赖加载完成,准备播放时,会广播 ‘ready’ 事件。<br>可调用 <code>Reveal.isReady()</code> 函数来检查 reveal.js 是否已准备完成。</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line">Reveal.addEventListener( <span class="string">'ready'</span>, <span class="function"><span class="keyword">function</span>(<span class="params"> event </span>) </span>{</span><br><span class="line"> <span class="comment">// event.currentSlide, event.indexh, event.indexv</span></span><br><span class="line">} );</span><br></pre></td></tr></table></figure>
<p>reveal.js 准备完成时会给 <code>.reveal</code> 元素增加 <code>.ready</code> 类,也可以此来判断是否已准备完成。</p>
<h2 id="自动播放"><a href="#自动播放" class="headerlink" title="自动播放"></a>自动播放</h2><p>演示文稿可以设置为自动播放,只需告诉框架自动切换的时间间隔(毫秒):</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="comment">// 每 5 秒自动切换下一张幻灯片</span></span><br><span class="line">Reveal.configure({</span><br><span class="line"> autoSlide: <span class="number">5000</span></span><br><span class="line">});</span><br></pre></td></tr></table></figure>
<p>在手动切换分段或幻灯片后会暂停自动播放,也可以按 a 键来暂停或恢复自动播放。<br>设置 <figure class="highlight plain"><figcaption><span>false``` 后,用户操作则不会打断自动播放。</span></figcaption><table><tr><td class="code"><pre><span class="line"></span><br><span class="line">也可以通过 ```data-autoslide``` 属性来给个别幻灯片或分段重新设置时间间隔:</span><br><span class="line"></span><br><span class="line">```html</span><br><span class="line"><section data-autoslide="2000"></span><br><span class="line"> <p class="fragment"> 2 秒后第一个分段会自动显示 </p></span><br><span class="line"> <p class="fragment" data-autoslide="10000"> 10 秒后下一个分段会自动显示 </p></span><br><span class="line"> <p class="fragment"> 2 秒后会自动切换到下一张幻灯片 </p></span><br><span class="line"></section></span><br></pre></td></tr></table></figure></p>
<p>通过设置 <figure class="highlight plain"><figcaption><span>指定自动播放的方式,如设置为 ```Reveal.navigateRight```,则自动播放时纵向幻灯片只会播放主幻灯片,其它纵向幻灯片会被忽略。</span></figcaption><table><tr><td class="code"><pre><span class="line"></span><br><span class="line">自动播放被暂停和恢复时,会广播 ```autoslidepaused``` 和 ```autoslideresumed``` 事件。</span><br><span class="line"></span><br><span class="line">## 自定义快捷键</span><br><span class="line"></span><br><span class="line">如果不喜欢默认的快捷键,可通过 ```keyboard``` 配置项来自定义:</span><br><span class="line"></span><br><span class="line">```javascript</span><br><span class="line">Reveal.configure({</span><br><span class="line"> keyboard: {</span><br><span class="line"> 13: 'next', // 按 ENTER 键切换到下一个分段或幻灯片</span><br><span class="line"> 27: function() {}, // 按 ESC 键时触发自定义行为</span><br><span class="line"> 32: null // 按 SPACE 时不做任何处理(可用于禁用 reveal.js 的默认快捷键)</span><br><span class="line"> }</span><br><span class="line">});</span><br></pre></td></tr></table></figure></p>
<h2 id="触屏操作"><a href="#触屏操作" class="headerlink" title="触屏操作"></a>触屏操作</h2><p>在触屏设备上可以通过滑动来操作幻灯片,水平滑动切换横向幻灯片,垂直滑动切换纵向幻灯片。<br>设置 <figure class="highlight plain"><figcaption><span>false`` 可禁用触屏操作。</span></figcaption><table><tr><td class="code"><pre><span class="line"></span><br><span class="line">如果幻灯片内容本身带有滑动操作(比如滚动内容),需要给元素添加 `data-prevent-swipe` 属性来阻止默认的滑动行为。</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">当演示文稿中带有大量的多媒体或 iframe 内容时,延迟加载就显得尤为重要,即只提前加载当前幻灯片最近的几张幻灯片中的内容。</span><br><span class="line">预加载的幻灯片数量由 `viewDistance` 配置项决定。</span><br><span class="line"></span><br><span class="line">延迟加载支持 image、video、audio 和 iframe 元素,只需把 "src" 属性改为 "data-src" 即可。</span><br><span class="line">幻灯片中延迟加载的 iframe,会在切换到其它幻灯片时自动卸载。</span><br><span class="line"></span><br><span class="line">```html</span><br><span class="line"><section></span><br><span class="line"> <img data-src="图片.png"></span><br><span class="line"> <iframe data-src="http://hakim.se"></iframe></span><br><span class="line"> <video></span><br><span class="line"> <source data-src="视频.webm" type="video/webm" /></span><br><span class="line"> <source data-src="视频.mp4" type="video/mp4" /></span><br><span class="line"> </video></span><br><span class="line"></section></span><br></pre></td></tr></table></figure></p>
<h2 id="API中文"><a href="#API中文" class="headerlink" title="API中文"></a>API中文</h2><p><code>Reveal</code> 对象提供了一套控制演示进度和管理演示状态的 JavaScript API:</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="comment">// 演示进度控制</span></span><br><span class="line">Reveal.slide( indexh, indexv, indexf );</span><br><span class="line">Reveal.left();</span><br><span class="line">Reveal.right();</span><br><span class="line">Reveal.up();</span><br><span class="line">Reveal.down();</span><br><span class="line">Reveal.prev();</span><br><span class="line">Reveal.next();</span><br><span class="line">Reveal.prevFragment();</span><br><span class="line">Reveal.nextFragment();</span><br><span class="line"></span><br><span class="line"><span class="comment">// 打乱幻灯片顺序</span></span><br><span class="line">Reveal.shuffle();</span><br><span class="line"></span><br><span class="line"><span class="comment">// 显示快捷键帮助面板</span></span><br><span class="line">Reveal.showHelp();</span><br><span class="line"></span><br><span class="line"><span class="comment">// 管理演示文稿状态,传入 true/false 对应 on/off 状态</span></span><br><span class="line">Reveal.toggleOverview();</span><br><span class="line">Reveal.togglePause();</span><br><span class="line">Reveal.toggleAutoSlide();</span><br><span class="line"></span><br><span class="line"><span class="comment">// 改变配置项设置</span></span><br><span class="line">Reveal.configure({ <span class="attr">controls</span>: <span class="literal">true</span> });</span><br><span class="line"></span><br><span class="line"><span class="comment">// 获取当前的配置项设置</span></span><br><span class="line">Reveal.getConfig();</span><br><span class="line"></span><br><span class="line"><span class="comment">// 获取当前演示文稿的缩放比例</span></span><br><span class="line">Reveal.getScale();</span><br><span class="line"></span><br><span class="line"><span class="comment">// 获取上一个/当前幻灯片节点</span></span><br><span class="line">Reveal.getPreviousSlide();</span><br><span class="line">Reveal.getCurrentSlide();</span><br><span class="line"></span><br><span class="line"><span class="comment">// 获取当前演示状态</span></span><br><span class="line"><span class="comment">// h-横向幻灯片索引,v-纵向幻灯片索引,f-分段索引</span></span><br><span class="line">Reveal.getIndices(); <span class="comment">// { h: 0, v: 0, f: 0 }</span></span><br><span class="line"><span class="comment">// 获取当前演示进度</span></span><br><span class="line">Reveal.getProgress(); <span class="comment">// 0-1</span></span><br><span class="line"><span class="comment">// 获取幻灯片总数(包括横向幻灯片和纵向幻灯片)</span></span><br><span class="line">Reveal.getTotalSlides();</span><br><span class="line"></span><br><span class="line"><span class="comment">// 获取当前幻灯片的演讲备注</span></span><br><span class="line">Reveal.getSlideNotes();</span><br><span class="line"></span><br><span class="line"><span class="comment">// 状态检查</span></span><br><span class="line">Reveal.isFirstSlide();</span><br><span class="line">Reveal.isLastSlide();</span><br><span class="line">Reveal.isOverview();</span><br><span class="line">Reveal.isPaused();</span><br><span class="line">Reveal.isAutoSliding();</span><br></pre></td></tr></table></figure>
<h3 id="幻灯片切换事件"><a href="#幻灯片切换事件" class="headerlink" title="幻灯片切换事件"></a>幻灯片切换事件</h3><p>幻灯片切换时会广播 ‘slidechanged’ 事件。event 对象保存了当前幻灯片的横向索引和纵向索引、上一张幻灯片和当前幻灯片的节点引用。</p>
<p>部分第三方库,如 MathJax(见 <a href="https://github.com/hellobugme/reveal.js/issues/226#issuecomment-10261609" target="_blank" rel="noopener">#226</a>),会受到幻灯片变形和显示状态的影响,此时可以尝试在该事件的回调函数中重新计算和渲染来进行修复。</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line">Reveal.addEventListener( <span class="string">'slidechanged'</span>, <span class="function"><span class="keyword">function</span>(<span class="params"> event </span>) </span>{</span><br><span class="line"> <span class="comment">// event.previousSlide, event.currentSlide, event.indexh, event.indexv</span></span><br><span class="line">} );</span><br></pre></td></tr></table></figure>
<h3 id="演示状态"><a href="#演示状态" class="headerlink" title="演示状态"></a>演示状态</h3><p><code>getState</code> 方法可以获取演示文稿的当前状态,使用这个快照,可以非常方便地返回到记录的演示进度。</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="comment">// 切换到幻灯片 1</span></span><br><span class="line">Reveal.slide( <span class="number">1</span> );</span><br><span class="line"></span><br><span class="line"><span class="comment">// 获取当前状态</span></span><br><span class="line"><span class="keyword">var</span> state = Reveal.getState();</span><br><span class="line"></span><br><span class="line"><span class="comment">// 切换到幻灯片 3</span></span><br><span class="line">Reveal.slide( <span class="number">3</span> );</span><br><span class="line"></span><br><span class="line"><span class="comment">// 切回幻灯片 1</span></span><br><span class="line">Reveal.setState( state );</span><br></pre></td></tr></table></figure>
<h3 id="幻灯片状态"><a href="#幻灯片状态" class="headerlink" title="幻灯片状态"></a>幻灯片状态</h3><p>如果给幻灯片 <code><section></code> 设置了 <code>data-state="somestate"</code> 属性,则当播放到该幻灯片时,”somestate” 将会出现在文档元素 <code><html></code> 的类里,可以很方便地给各个幻灯片设置不同的页面样式。</p>
<p>此外,还可以在 JavaScript 中侦听这个状态:</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line">Reveal.addEventListener( <span class="string">'somestate'</span>, <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>{</span><br><span class="line"> <span class="comment">// <span class="doctag">TODO:</span> somestate 出现了,做些啥吧</span></span><br><span class="line">}, <span class="literal">false</span> );</span><br></pre></td></tr></table></figure>
<h3 id="幻灯片背景"><a href="#幻灯片背景" class="headerlink" title="幻灯片背景"></a>幻灯片背景</h3><figure class="highlight plain"><figcaption><span>元素的 ```data-background``` 属性可以设置一个覆盖整个幻灯片的背景。</span></figcaption><table><tr><td class="code"><pre><span class="line">支持 4 种类型的背景:颜色,图像,视频和 iframe。</span><br><span class="line"></span><br><span class="line">#### 颜色背景</span><br><span class="line">支持所有 CSS 颜色格式,如 rgba() 或 hsl()。</span><br><span class="line">```html</span><br><span class="line"><section data-background-color="#ff0000"></span><br><span class="line"> <h2> 颜色背景 </h2></span><br><span class="line"></section></span><br></pre></td></tr></table></figure>
<h4 id="图像背景"><a href="#图像背景" class="headerlink" title="图像背景"></a>图像背景</h4><p>背景图像默认会自动调整大小以覆盖整个幻灯片,可设置的选项:</p>
<table>
<thead>
<tr>
<th style="text-align:left">属性</th>
<th style="text-align:left">默认值</th>
<th style="text-align:left">说明</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left">data-background-image</td>
<td style="text-align:left"></td>
<td style="text-align:left">图片 URL(GIF 动图会在幻灯片显示时重新播放)</td>
</tr>
<tr>
<td style="text-align:left">data-background-size</td>
<td style="text-align:left">cover</td>
<td style="text-align:left">见 MDN <a href="https://developer.mozilla.org/docs/Web/CSS/background-size" target="_blank" rel="noopener">background-size</a></td>
</tr>
<tr>
<td style="text-align:left">data-background-position</td>
<td style="text-align:left">center</td>
<td style="text-align:left">见 MDN <a href="https://developer.mozilla.org/docs/Web/CSS/background-position" target="_blank" rel="noopener">background-position</a></td>
</tr>
<tr>
<td style="text-align:left">data-background-repeat</td>
<td style="text-align:left">no-repeat</td>
<td style="text-align:left">见 MDN <a href="https://developer.mozilla.org/docs/Web/CSS/background-repeat" target="_blank" rel="noopener">background-repeat</a></td>
</tr>
</tbody>
</table>
<figure class="highlight html"><table><tr><td class="code"><pre><span class="line"><span class="tag"><<span class="name">section</span> <span class="attr">data-background-image</span>=<span class="string">"http://example.com/image.png"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">h2</span>></span> 图像背景 <span class="tag"></<span class="name">h2</span>></span></span><br><span class="line"><span class="tag"></<span class="name">section</span>></span></span><br><span class="line"><span class="tag"><<span class="name">section</span> <span class="attr">data-background-image</span>=<span class="string">"http://example.com/image.png"</span> <span class="attr">data-background-size</span>=<span class="string">"100px"</span> <span class="attr">data-background-repeat</span>=<span class="string">"repeat"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">h2</span>></span> 背景图像尺寸为 100 像素,且平铺模式为重复 <span class="tag"></<span class="name">h2</span>></span></span><br><span class="line"><span class="tag"></<span class="name">section</span>></span></span><br></pre></td></tr></table></figure>
<h4 id="视频背景"><a href="#视频背景" class="headerlink" title="视频背景"></a>视频背景</h4><p>在幻灯片后面自动播放一个撑满页面的视频。</p>
<table>
<thead>
<tr>
<th style="text-align:left">属性</th>
<th style="text-align:left">默认值</th>
<th style="text-align:left">说明</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left">data-background-video</td>
<td style="text-align:left"></td>
<td style="text-align:left">单个视频地址,或由半角逗号 ‘,’ 分隔的视频地址列表。</td>
</tr>
<tr>
<td style="text-align:left">data-background-video-loop</td>
<td style="text-align:left">false</td>
<td style="text-align:left">是否循环播放</td>
</tr>
<tr>
<td style="text-align:left">data-background-video-muted</td>
<td style="text-align:left">false</td>
<td style="text-align:left">是否静音</td>
</tr>
</tbody>
</table>
<figure class="highlight html"><table><tr><td class="code"><pre><span class="line"><span class="tag"><<span class="name">section</span> <span class="attr">data-background-video</span>=<span class="string">"https://s3.amazonaws.com/static.slid.es/site/homepage/v1/homepage-video-editor.mp4,https://s3.amazonaws.com/static.slid.es/site/homepage/v1/homepage-video-editor.webm"</span> <span class="attr">data-background-video-loop</span> <span class="attr">data-background-video-muted</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">h2</span>></span> 视频背景 <span class="tag"></<span class="name">h2</span>></span></span><br><span class="line"><span class="tag"></<span class="name">section</span>></span></span><br></pre></td></tr></table></figure>
<h4 id="Iframe-背景"><a href="#Iframe-背景" class="headerlink" title="Iframe 背景"></a>Iframe 背景</h4><p>嵌入一个网页作为背景,该网页位于幻灯片后面的背景层,无法进行交互。<br><figure class="highlight html"><table><tr><td class="code"><pre><span class="line"><span class="tag"><<span class="name">section</span> <span class="attr">data-background-iframe</span>=<span class="string">"https://slides.com"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">h2</span>></span> Iframe <span class="tag"></<span class="name">h2</span>></span></span><br><span class="line"><span class="tag"></<span class="name">section</span>></span></span><br></pre></td></tr></table></figure></p>
<h4 id="背景切换过渡效果"><a href="#背景切换过渡效果" class="headerlink" title="背景切换过渡效果"></a>背景切换过渡效果</h4><p>背景切换的默认过渡效果为 fade(渐变),可在初始化 <figure class="highlight plain"><figcaption><span>时传入 ```backgroundTransition``` 配置项来修改,也可给 `<section>` 添加 ```data-background-transition``` 属性来给个别幻灯片单独设置。</section></span></figcaption><table><tr><td class="code"><pre><span class="line"></span><br><span class="line">#### 视差背景</span><br><span class="line"></span><br><span class="line">要使用视差滚动背景,需要在初始化 reveal.js 时设置下面的前两个配置项(后两个为可选项)。</span><br><span class="line"></span><br><span class="line">```javascript</span><br><span class="line">Reveal.initialize({</span><br><span class="line"></span><br><span class="line"> // 视差背景图</span><br><span class="line"> parallaxBackgroundImage: '', // 示例:"'https://s3.amazonaws.com/hakim-static/reveal-js/reveal-parallax-1.jpg'"</span><br><span class="line"></span><br><span class="line"> // 视察背景图尺寸</span><br><span class="line"> parallaxBackgroundSize: '', // CSS 写法,示例:"2100px 900px"(目前只支持像素值,不支持 % 和 auto)</span><br><span class="line"></span><br><span class="line"> // 相邻两张幻灯片间,视差背景移动的像素值</span><br><span class="line"> // - 如果不设置则自动计算</span><br><span class="line"> // - 当设置为 0 时,则禁止视差动画</span><br><span class="line"> parallaxBackgroundHorizontal: 200,</span><br><span class="line"> parallaxBackgroundVertical: 50</span><br><span class="line"></span><br><span class="line">});</span><br></pre></td></tr></table></figure></p>
<p>视差背景图尺寸必须大于幻灯片尺寸,否则切换幻灯片时无法滚动。<a href="http://lab.hakim.se/reveal-js/?parallaxBackgroundImage=https%3A%2F%2Fs3.amazonaws.com%2Fhakim-static%2Freveal-js%2Freveal-parallax-1.jpg&parallaxBackgroundSize=2100px%20900px" target="_blank" rel="noopener">查看示例</a></p>
<h3 id="切换过渡效果"><a href="#切换过渡效果" class="headerlink" title="切换过渡效果"></a>切换过渡效果</h3><p>幻灯片的切换过渡效果,默认使用配置项 <figure class="highlight plain"><figcaption><span>设置的值,可通过 ```data-transition``` 属性来给个别幻灯片单独指定过渡效果:</span></figcaption><table><tr><td class="code"><pre><span class="line"></span><br><span class="line">```html</span><br><span class="line"><section data-transition="zoom"></span><br><span class="line"> <h2> 该幻灯片不使用全局的切换过渡效果,而是单独指定的缩放! </h2></span><br><span class="line"></section></span><br><span class="line"></span><br><span class="line"><section data-transition-speed="fast"></span><br><span class="line"> <h2> 可供选择的切换过渡速度有:default-中速、fast-快速、slow-慢速! </h2></span><br><span class="line"></section></span><br></pre></td></tr></table></figure></p>
<p>甚至可以给同一张幻灯片指定不同的切入和切出过渡效果:</p>
<figure class="highlight html"><table><tr><td class="code"><pre><span class="line"><span class="tag"><<span class="name">section</span> <span class="attr">data-transition</span>=<span class="string">"slide"</span>></span></span><br><span class="line"> 没时间解释了快上车……</span><br><span class="line"><span class="tag"></<span class="name">section</span>></span></span><br><span class="line"><span class="tag"><<span class="name">section</span> <span class="attr">data-transition</span>=<span class="string">"slide"</span>></span></span><br><span class="line"> 继续前进……</span><br><span class="line"><span class="tag"></<span class="name">section</span>></span></span><br><span class="line"><span class="tag"><<span class="name">section</span> <span class="attr">data-transition</span>=<span class="string">"slide-in fade-out"</span>></span></span><br><span class="line"> 到站停车。</span><br><span class="line"><span class="tag"></<span class="name">section</span>></span></span><br><span class="line"><span class="tag"><<span class="name">section</span> <span class="attr">data-transition</span>=<span class="string">"fade-in slide-out"</span>></span></span><br><span class="line"> (乘客上车和下车)</span><br><span class="line"><span class="tag"></<span class="name">section</span>></span></span><br><span class="line"><span class="tag"><<span class="name">section</span> <span class="attr">data-transition</span>=<span class="string">"slide"</span>></span></span><br><span class="line"> 重新上路。</span><br><span class="line"><span class="tag"></<span class="name">section</span>></span></span><br></pre></td></tr></table></figure>
<h3 id="内部跳转"><a href="#内部跳转" class="headerlink" title="内部跳转"></a>内部跳转</h3><p>幻灯片间的跳转十分简单,下面第一个例子指定的是目标幻灯片的索引,第二个例子指定的是目标幻灯片的 ID 属性(<figure class="highlight plain"><figcaption><span>id</span></figcaption><table><tr><td class="code"><pre><span class="line"></span><br><span class="line">```html</span><br><span class="line"><a href="#/2/1"> 跳转到第 3 个横向幻灯片的第 2 个纵向幻灯片 </a></span><br><span class="line"><a href="#/some-slide"> 跳转到 ID 为 some-slide 的幻灯片 </a></span><br></pre></td></tr></table></figure></p>
<p>也可以给元素添加下面这些类,来指定一个相对地址,类似于 reveal.js 的控制面板。<br>如果指定的是一个有效的跳转地址,元素会自动附加 <figure class="highlight plain"><figcaption><span>类。</span></figcaption><table><tr><td class="code"><pre><span class="line"></span><br><span class="line">```html</span><br><span class="line"><a href="#" class="navigate-left"></span><br><span class="line"><a href="#" class="navigate-right"></span><br><span class="line"><a href="#" class="navigate-up"></span><br><span class="line"><a href="#" class="navigate-down"></span><br><span class="line"><a href="#" class="navigate-prev"> <!-- 上一张纵向幻灯片或横向幻灯片 --></span><br><span class="line"><a href="#" class="navigate-next"> <!-- 下一张纵向幻灯片或横向幻灯片 --></span><br></pre></td></tr></table></figure></p>
<h3 id="片段"><a href="#片段" class="headerlink" title="片段"></a>片段</h3><p>分段可用于强调幻灯片中的个别元素。演示文稿向前播放时,所有带有 <figure class="highlight plain"><figcaption><span>类的元素,会在切换下个幻灯片之前逐个触发。[查看示例](http://lab.hakim.se/reveal-js/#/fragments)</span></figcaption><table><tr><td class="code"><pre><span class="line"></span><br><span class="line">分段默认是初始隐藏,播放时渐显出现,可通过给分段追加类来修改这个效果:</span><br><span class="line"></span><br><span class="line">```html</span><br><span class="line"><section></span><br><span class="line"> <p class="fragment grow"> 放大:初始可见,播放时放大 </p></span><br><span class="line"> <p class="fragment shrink"> 缩小:初始可见,播放时缩小 </p></span><br><span class="line"> <p class="fragment fade-out"> 渐隐消失:初始可见,播放时渐隐消失 </p></span><br><span class="line"> <p class="fragment fade-up"> 渐显上升:初始隐藏,播放时渐显上升出现(down、left、right 类似) </p></span><br><span class="line"> <p class="fragment current-visible"> 显示一次:初始隐藏,播放时出现,继续播放则消失 </p></span><br><span class="line"> <p class="fragment highlight-current-blue"> 高亮蓝一次:初始可见,播放时变蓝,继续播放则恢复颜色 </p></span><br><span class="line"> <p class="fragment highlight-red"> 高亮红:初始可见,播放时变红 </p></span><br><span class="line"> <p class="fragment highlight-green"> 高亮绿:初始可见,播放时变绿 </p></span><br><span class="line"> <p class="fragment highlight-blue"> 高亮蓝:初始可见,播放时变蓝 </p></span><br><span class="line"></section></span><br></pre></td></tr></table></figure></p>
<p>嵌套分段会对包裹的内容逐个触发,在下面的例子中,播放时文本会先渐显出现,继续播放则文本渐隐消失。</p>
<figure class="highlight html"><table><tr><td class="code"><pre><span class="line"><span class="tag"><<span class="name">section</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">span</span> <span class="attr">class</span>=<span class="string">"fragment fade-in"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">span</span> <span class="attr">class</span>=<span class="string">"fragment fade-out"</span>></span> 我将渐显出现,然后渐隐消失 <span class="tag"></<span class="name">span</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">span</span>></span></span><br><span class="line"><span class="tag"></<span class="name">section</span>></span></span><br></pre></td></tr></table></figure>
<p>分段的播放顺序,可以通过 <figure class="highlight plain"><figcaption><span>属性来控制。</span></figcaption><table><tr><td class="code"><pre><span class="line"></span><br><span class="line">```html</span><br><span class="line"><section></span><br><span class="line"> <p class="fragment" data-fragment-index="3"> 最后播放 </p></span><br><span class="line"> <p class="fragment" data-fragment-index="1"> 最先播放 </p></span><br><span class="line"> <p class="fragment" data-fragment-index="2"> 第二个播放 </p></span><br><span class="line"></section></span><br></pre></td></tr></table></figure></p>
<h3 id="片段事件"><a href="#片段事件" class="headerlink" title="片段事件"></a>片段事件</h3><p>任意分段在出现和隐藏时,reveal.js 都会广播事件。</p>
<p>部分第三方库,如 MathJax(见 #505),会受到初始隐藏的分段元素的影响,此时可以尝试在这些事件的回调函数中重新计算和渲染来进行修复。</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line">Reveal.addEventListener( <span class="string">'fragmentshown'</span>, <span class="function"><span class="keyword">function</span>(<span class="params"> event </span>) </span>{</span><br><span class="line"> <span class="comment">// event.fragment = 分段元素节点</span></span><br><span class="line">} );</span><br><span class="line">Reveal.addEventListener( <span class="string">'fragmenthidden'</span>, <span class="function"><span class="keyword">function</span>(<span class="params"> event </span>) </span>{</span><br><span class="line"> <span class="comment">// event.fragment = 分段元素节点</span></span><br><span class="line">} );</span><br></pre></td></tr></table></figure>
<h3 id="代码语法高亮"><a href="#代码语法高亮" class="headerlink" title="代码语法高亮"></a>代码语法高亮</h3><p>Reveal 自带代码语法高亮插件 <a href="https://highlightjs.org/" target="_blank" rel="noopener">highlight.js</a>(需引入该依赖项)。<br>在下面的例子中, clojure 代码会自动语法高亮,指定 <code>data-trim</code> 属性可以自动删除多余空格。<br>HTML 默认会自动转义,要避免转义(如例子中的 <code><mark></code> 标签要显示出来),可以给 <code><code></code> 元素追加 <code>data-noescape</code> 属性。</p>
<figure class="highlight html"><table><tr><td class="code"><pre><span class="line"><span class="tag"><<span class="name">section</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">pre</span>></span><span class="tag"><<span class="name">code</span> <span class="attr">data-trim</span> <span class="attr">data-noescape</span>></span></span><br><span class="line">(def lazy-fib</span><br><span class="line"> (concat</span><br><span class="line"> [0 1]</span><br><span class="line"> <span class="tag"><<span class="name">mark</span>></span>((fn rfib [a b]<span class="tag"></<span class="name">mark</span>></span></span><br><span class="line"> (lazy-cons (+ a b) (rfib b (+ a b)))) 0 1)))</span><br><span class="line"> <span class="tag"></<span class="name">code</span>></span><span class="tag"></<span class="name">pre</span>></span></span><br><span class="line"><span class="tag"></<span class="name">section</span>></span></span><br></pre></td></tr></table></figure>
<h3 id="幻灯片页码"><a href="#幻灯片页码" class="headerlink" title="幻灯片页码"></a>幻灯片页码</h3><p>如果想显示幻灯片页码,可以设置 <figure class="highlight plain"><figcaption><span>配置项。</span></figcaption><table><tr><td class="code"><pre><span class="line"></span><br><span class="line">```javascript</span><br><span class="line">// 使用默认格式显示幻灯片页码</span><br><span class="line">Reveal.configure({ slideNumber: true });</span><br><span class="line"></span><br><span class="line">// 可供选择的幻灯片页码格式:</span><br><span class="line">// "h.v": 当前横向幻灯片页码 . 当前纵向幻灯片页码 (默认)</span><br><span class="line">// "h/v": 当前横向幻灯片页码 / 当前纵向幻灯片页码</span><br><span class="line">// "c": 当前幻灯片页码(包括横向幻灯片和纵向幻灯片)</span><br><span class="line">// "c/t": 当前幻灯片页码 / 幻灯片总数</span><br><span class="line">Reveal.configure({ slideNumber: 'c/t' });</span><br></pre></td></tr></table></figure></p>
<h3 id="概览模式"><a href="#概览模式" class="headerlink" title="概览模式"></a>概览模式</h3><p>按 “Esc” 或 “o” 键可以打开或关闭概览模式。在概览模式中,你仍然可以在幻灯片间切换,就好像位于演示文稿的上空,操作平铺开来的幻灯片。<br>与概览模式相关的 API:</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line">Reveal.addEventListener( <span class="string">'overviewshown'</span>, <span class="function"><span class="keyword">function</span>(<span class="params"> event </span>) </span>{ <span class="comment">/* ... */</span> } );</span><br><span class="line">Reveal.addEventListener( <span class="string">'overviewhidden'</span>, <span class="function"><span class="keyword">function</span>(<span class="params"> event </span>) </span>{ <span class="comment">/* ... */</span> } );</span><br><span class="line"></span><br><span class="line"><span class="comment">// 通过代码打开或关闭概览模式</span></span><br><span class="line">Reveal.toggleOverview();</span><br></pre></td></tr></table></figure>
<h3 id="全屏模式"><a href="#全屏模式" class="headerlink" title="全屏模式"></a>全屏模式</h3><p>按 »F« 键可以让演示文稿进入全屏模式,按 »ESC« 键退出全屏模式。</p>
<h3 id="嵌入媒体"><a href="#嵌入媒体" class="headerlink" title="嵌入媒体"></a>嵌入媒体</h3><p>嵌入的 HTML5 <code><video></code>/<code><audio></code> 和 YouTube iframe,会在幻灯片切出时自动暂停播放,通过给元素添加 <code>data-ignore</code> 属性可以禁止该行为。</p>
<p>给媒体元素添加 <code>data-autoplay</code> 属性,则在幻灯片显示时媒体将自动播放:</p>
<figure class="highlight html"><table><tr><td class="code"><pre><span class="line"><span class="tag"><<span class="name">video</span> <span class="attr">data-autoplay</span> <span class="attr">src</span>=<span class="string">"http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4"</span>></span><span class="tag"></<span class="name">video</span>></span></span><br></pre></td></tr></table></figure>
<p>此外,框架会自动发送两条消息(见 <a href="https://developer.mozilla.org/en-US/docs/Web/API/Window.postMessage" target="_blank" rel="noopener">发送消息</a>)给所有的 iframe。包含 iframe 的幻灯片,显示时会给其内部所有的 iframe 发送 <figure class="highlight plain"><figcaption><span>```slide:stop``` 消息。</span></figcaption><table><tr><td class="code"><pre><span class="line"></span><br><span class="line"></span><br><span class="line">### 拉伸元素</span><br><span class="line"></span><br><span class="line">有时我们希望元素(如图像或者视频)可以自动拉伸,尽可能多的占用幻灯片的空间,这时可以给元素添加 ```.stretch``` 类:</span><br><span class="line"></span><br><span class="line">```html</span><br><span class="line"><section></span><br><span class="line"> <h2> 这个视频将占用幻灯片的所有剩余空间 </h2></span><br><span class="line"> <video class="stretch" src="http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4"></video></span><br><span class="line"></section></span><br></pre></td></tr></table></figure></p>
<p>限制:</p>
<ul>
<li>只能用于幻灯片的直接子元素</li>
<li>每个幻灯片最多只能设置 1 个子元素</li>
</ul>
<h3 id="通信-API"><a href="#通信-API" class="headerlink" title="通信 API"></a>通信 API</h3><p>框架自带一个发送消息 API <figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">下面的例子展示了如何让指定窗口中的 reveal.js 实例切换到幻灯片 2:</span><br><span class="line"></span><br><span class="line">```javascript</span><br><span class="line"><window>.postMessage( JSON.stringify({ method: 'slide', args: [ 2 ] }), '*' );</span><br></pre></td></tr></table></figure></p>
<hr>
<p><strong>译者注</strong><br>示例可参考 <a href="https://github.com/icewind1991/reveal" target="_blank" rel="noopener">icewind1991</a> 的 <a href="https://github.com/icewind1991/reveal/blob/master/js/public/plugin/postmessage/example.html" target="_blank" rel="noopener">plugin/postmessage</a>。<br>reveal.js 已自带该特性,无需额外引入 postmessage.js 插件。<br><figure class="highlight html"><table><tr><td class="code"><pre><span class="line"><span class="tag"><<span class="name">html</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">iframe</span> <span class="attr">id</span>=<span class="string">"reveal"</span> <span class="attr">src</span>=<span class="string">"../../index.html"</span> <span class="attr">style</span>=<span class="string">"border: 0;"</span> <span class="attr">width</span>=<span class="string">"500"</span> <span class="attr">height</span>=<span class="string">"500"</span>></span><span class="tag"></<span class="name">iframe</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">input</span> <span class="attr">id</span>=<span class="string">"back"</span> <span class="attr">type</span>=<span class="string">"button"</span> <span class="attr">value</span>=<span class="string">"后退"</span>/></span></span><br><span class="line"> <span class="tag"><<span class="name">input</span> <span class="attr">id</span>=<span class="string">"ahead"</span> <span class="attr">type</span>=<span class="string">"button"</span> <span class="attr">value</span>=<span class="string">"前进"</span>/></span></span><br><span class="line"> <span class="tag"><<span class="name">input</span> <span class="attr">id</span>=<span class="string">"slideto"</span> <span class="attr">type</span>=<span class="string">"button"</span> <span class="attr">value</span>=<span class="string">"切换到 2-2"</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">script</span>></span></span><br><span class="line"><span class="javascript"> (<span class="function"><span class="keyword">function</span> (<span class="params"></span>)</span>{</span></span><br><span class="line"><span class="javascript"> <span class="keyword">var</span> back = <span class="built_in">document</span>.getElementById( <span class="string">'back'</span> ),</span></span><br><span class="line"><span class="javascript"> ahead = <span class="built_in">document</span>.getElementById( <span class="string">'ahead'</span> ),</span></span><br><span class="line"><span class="javascript"> slideto = <span class="built_in">document</span>.getElementById( <span class="string">'slideto'</span> ),</span></span><br><span class="line"><span class="javascript"> reveal = <span class="built_in">window</span>.frames[<span class="number">0</span>];</span></span><br><span class="line"><span class="javascript"> back.addEventListener( <span class="string">'click'</span>, <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>{</span></span><br><span class="line"><span class="javascript"> reveal.postMessage( <span class="built_in">JSON</span>.stringify({<span class="attr">method</span>: <span class="string">'prev'</span>, <span class="attr">args</span>: []}), <span class="string">'*'</span> );</span></span><br><span class="line"><span class="javascript"> }, <span class="literal">false</span> );</span></span><br><span class="line"><span class="javascript"> ahead.addEventListener( <span class="string">'click'</span>, <span class="function"><span class="keyword">function</span> (<span class="params"></span>)</span>{</span></span><br><span class="line"><span class="javascript"> reveal.postMessage( <span class="built_in">JSON</span>.stringify({<span class="attr">method</span>: <span class="string">'next'</span>, <span class="attr">args</span>: []}), <span class="string">'*'</span> );</span></span><br><span class="line"><span class="javascript"> }, <span class="literal">false</span> );</span></span><br><span class="line"><span class="javascript"> slideto.addEventListener( <span class="string">'click'</span>, <span class="function"><span class="keyword">function</span> (<span class="params"></span>)</span>{</span></span><br><span class="line"><span class="javascript"> reveal.postMessage( <span class="built_in">JSON</span>.stringify({<span class="attr">method</span>: <span class="string">'slide'</span>, <span class="attr">args</span>: [<span class="number">2</span>,<span class="number">2</span>]}), <span class="string">'*'</span> );</span></span><br><span class="line"><span class="javascript"> }, <span class="literal">false</span> );</span></span><br><span class="line"> }());</span><br><span class="line"> <span class="tag"></<span class="name">script</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">html</span>></span></span><br></pre></td></tr></table></figure></p>
<hr>
<p>reveal.js 在 iframe 中运行时,可选择是否将其所有事件冒泡给父窗口。冒泡的事件对象为一个 JSON 字符串,保存了 3 个字段:namespace-命名空间、eventName-事件名、state-状态。<br>下面的例子展示了父窗口如何向 reveal 订阅事件:</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="built_in">window</span>.addEventListener( <span class="string">'message'</span>, <span class="function"><span class="keyword">function</span>(<span class="params"> event </span>) </span>{</span><br><span class="line"> <span class="keyword">var</span> data = <span class="built_in">JSON</span>.parse( event.data );</span><br><span class="line"> <span class="keyword">if</span>( data.namespace === <span class="string">'reveal'</span> && data.eventName ===<span class="string">'slidechanged'</span> ) {</span><br><span class="line"> <span class="comment">// 幻灯片切换,可访问 data.state 来查看幻灯片页码</span></span><br><span class="line"> }</span><br><span class="line">} );</span><br></pre></td></tr></table></figure>
<p>跨窗口消息传递可通过配置项来打开或关闭。</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line">Reveal.initialize({</span><br><span class="line"> ...,</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 暴露 postMessage API</span></span><br><span class="line"> postMessage: <span class="literal">true</span>,</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 将演示文稿的所有事件冒泡给父窗口</span></span><br><span class="line"> postMessageEvents: <span class="literal">false</span></span><br><span class="line">});</span><br></pre></td></tr></table></figure>
<h2 id="导出-PDF"><a href="#导出-PDF" class="headerlink" title="导出 PDF"></a>导出 PDF</h2><p>演示文稿可以通过一个特殊的打印样式来导出 PDF。该特性需要使用 <a href="http://google.com/chrome" target="_blank" rel="noopener">Google Chrome</a> 或 <a href="https://www.chromium.org/Home" target="_blank" rel="noopener">Chromium</a>、且运行于 web 服务器上时,可以导出为 PDF。<br>这是一个演示文稿导出 PDF 并上传到 SlideShare 的例子:<a href="http://www.slideshare.net/hakimel/revealjs-300。" target="_blank" rel="noopener">http://www.slideshare.net/hakimel/revealjs-300。</a></p>
<h3 id="页面尺寸"><a href="#页面尺寸" class="headerlink" title="页面尺寸"></a>页面尺寸</h3><p>导出的 PDF 尺寸由 <a href="#演示文稿尺寸">演示文稿尺寸</a> 决定,如果幻灯片太高无法一页展示完,则会切分为多页,可通过 <code>pdfMaxPagesPerSlide</code> 配置项设置每张幻灯片最多可被切分为几数,如 <code>Reveal.configure({ pdfMaxPagesPerSlide: 1 })</code> 可确保幻灯片不会被切分。</p>
<h3 id="打印样式"><a href="#打印样式" class="headerlink" title="打印样式"></a>打印样式</h3><p>想要启用演示文稿的打印功能,需要加载一个用于打印的特殊样式 <a href="https://github.com/hakimel/reveal.js/blob/master/css/print/pdf.css" target="_blank" rel="noopener">/css/print/pdf.css</a>,默认的 index.html 文件已包含该逻辑,只要演示文稿的链接中带有 <code>print-pdf</code> 参数,就会自动加载。如果使用的是其它的 HTML 模板,可以在 HEAD 中插入以下代码:</p>
<figure class="highlight html"><table><tr><td class="code"><pre><span class="line"><span class="tag"><<span class="name">script</span>></span></span><br><span class="line"><span class="javascript"> <span class="keyword">var</span> link = <span class="built_in">document</span>.createElement( <span class="string">'link'</span> );</span></span><br><span class="line"><span class="javascript"> link.rel = <span class="string">'stylesheet'</span>;</span></span><br><span class="line"><span class="javascript"> link.type = <span class="string">'text/css'</span>;</span></span><br><span class="line"><span class="javascript"> link.href = <span class="built_in">window</span>.location.search.match( <span class="regexp">/print-pdf/gi</span> ) ? <span class="string">'css/print/pdf.css'</span> : <span class="string">'css/print/paper.css'</span>;</span></span><br><span class="line"><span class="javascript"> <span class="built_in">document</span>.getElementsByTagName( <span class="string">'head'</span> )[<span class="number">0</span>].appendChild( link );</span></span><br><span class="line"><span class="tag"></<span class="name">script</span>></span></span><br></pre></td></tr></table></figure>
<h3 id="步骤"><a href="#步骤" class="headerlink" title="步骤"></a>步骤</h3><ol>
<li>给演示文稿的 URL 加上 <code>print-pdf</code> 参数,如:<a href="http://localhost:8000/?print-pdf#/" target="_blank" rel="noopener">http://localhost:8000/?print-pdf#/</a> ,可以尝试这个例子 <a href="http://lab.hakim.se/reveal-js?print-pdf" target="_blank" rel="noopener">lab.hakim.se/reveal-js?print-pdf</a>。</li>
<li>打开浏览器的打印面板 (CTRL/CMD+P)。</li>
<li><strong>Destination(目标打印机)</strong> 修改为 <strong>Save as PDF(另存为 PDF)</strong>。</li>
<li><strong>Layout(布局)</strong> 修改为 <strong>Landscape(横向)</strong>。</li>
<li><strong>Margins(边距)</strong> 修改为 <strong>None(无)</strong>。</li>
<li>启用选项 <strong>Background graphics(背景图形)</strong>。</li>
<li>点击 <strong>Save(保存)</strong></li>
</ol>
<p><img src="https://s3.amazonaws.com/hakim-static/reveal-js/pdf-print-settings-2.png" alt="谷歌浏览器打印设置"></p>
<p>也可使用 <a href="https://github.com/astefanutti/decktape" target="_blank" rel="noopener">decktape</a>(一个将 HTML5 演示文稿导出为高质量 PDF 的框架)项目代替。</p>
<h2 id="主题"><a href="#主题" class="headerlink" title="主题"></a>主题</h2><p>框架带有几个不同的主题:</p>
<ul>
<li>black:黑色背景,白色文本,蓝色链接(默认主题)</li>
<li>white:白色背景,黑色文本,蓝色链接</li>
<li>league:灰色背景,白色文本,蓝色链接(reveal.js 3.0.0 之前版本的默认主题)</li>
<li>beige:米黄色背景,暗色(#333)文本,棕色链接</li>
<li>sky:蓝色背景,暗色文本,蓝色链接</li>
<li>night:黑色背景,亮色(#eee)文本,橙色链接</li>
<li>serif:咖啡色背景,灰色文本,褐色链接</li>
<li>simple:白色背景,黑色文本,蓝色链接</li>
<li>solarized:奶油色背景,深绿色文本,蓝色链接</li>
</ul>
<p>每个主题都是一个单独的样式文件,修改主题只需把 index.html 的主题样式中的 <strong>black</strong> 替换为想要的主题名即可:</p>
<figure class="highlight html"><table><tr><td class="code"><pre><span class="line"><span class="tag"><<span class="name">link</span> <span class="attr">rel</span>=<span class="string">"stylesheet"</span> <span class="attr">href</span>=<span class="string">"css/theme/black.css"</span> <span class="attr">id</span>=<span class="string">"theme"</span>></span></span><br></pre></td></tr></table></figure>
<p>如果要增加自定义主题,请参考:<a href="https://github.com/hellobugme/reveal.js/blob/master/css/theme/README.md" target="_blank" rel="noopener">/css/theme/README.md</a>。</p>
<h2 id="演讲备注"><a href="#演讲备注" class="headerlink" title="演讲备注"></a>演讲备注</h2><p>reveal.js 自带演讲备注插件,可以在一个单独的浏览器窗口中为每张幻灯片提供备注,同时预览下一张幻灯片。<br>按 ‘s’ 键来打开备注窗口。</p>
<p>演讲计时器会在备注窗口打开时启动,点击时间可以重置为 00:00:00。</p>
<p>给幻灯片追加一个 <figure class="highlight plain"><figcaption><span>元素来添加备注,如果想用 Markdown 编写备注内容,可以给 aside 元素添加 ```data-markdown``` 属性。</span></figcaption><table><tr><td class="code"><pre><span class="line"></span><br><span class="line">也可以通过幻灯片的 `data-notes` 属性来添加简单的备注,如 `<section data-notes="一些简单的备注"></section>`。</span><br><span class="line"></span><br><span class="line">如果是在本地打开演示文稿,想要使用演讲备注,需要 reveal.js [运行于一个本地 web 服务器](#完整安装).</span><br><span class="line"></span><br><span class="line">```html</span><br><span class="line"><section></span><br><span class="line"> <h2> 我是幻灯片 </h2></span><br><span class="line"></span><br><span class="line"> <aside class="notes"></span><br><span class="line"> 大家好,我是这张幻灯片的备注,在演示文稿上是看不到,不过可以按 's' 键打开备注窗口来找我哦,么么哒~</span><br><span class="line"> </aside></span><br><span class="line"></section></span><br></pre></td></tr></table></figure></p>
<p>对于幻灯片引入的外部 Markdown 文件,可以在指定的分隔符后面添加备注:</p>
<figure class="highlight html"><table><tr><td class="code"><pre><span class="line"><span class="tag"><<span class="name">section</span> <span class="attr">data-markdown</span>=<span class="string">"example.md"</span> <span class="attr">data-separator</span>=<span class="string">"^\n\n\n"</span> <span class="attr">data-separator-vertical</span>=<span class="string">"^\n\n"</span> <span class="attr">data-separator-notes</span>=<span class="string">"^Note:"</span>></span><span class="tag"></<span class="name">section</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">幻灯片内容……</span><br><span class="line"></span><br><span class="line">Note:</span><br><span class="line">只会在备注窗口显示的内容……</span><br></pre></td></tr></table></figure>
<h3 id="分享和打印演讲备注"><a href="#分享和打印演讲备注" class="headerlink" title="分享和打印演讲备注"></a>分享和打印演讲备注</h3><p>备注只对演讲者可见,如果想让其他人也能看到,可以在初始化 reveal.js 时,把 <code>showNotes</code> 配置项设为 <code>true</code>,则备注会显示在演示文稿的底部。</p>
<p>如果启用了 <code>showNotes</code>,在 <a href="#导出-pdf">导出 PDF</a> 时也会包含备注。<br>备注默认打印在一个半透明的浮窗中,覆盖于幻灯片底部,如果想在该幻灯片后面单独新建一页打印备注,可以把 <code>showNotes</code> 设置为 <code>"separate-page"</code>。</p>
<h3 id="服务器端演讲备注"><a href="#服务器端演讲备注" class="headerlink" title="服务器端演讲备注"></a>服务器端演讲备注</h3><p>基于 Node.js 的演讲备注插件,让你可以在其它设备上运行你正在控制的演讲备注,就像客户端演讲备注的副本,会相互同步操作。<br>需要引入以下依赖项:</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line">Reveal.initialize({</span><br><span class="line"> ...</span><br><span class="line"></span><br><span class="line"> dependencies: [</span><br><span class="line"> { <span class="attr">src</span>: <span class="string">'socket.io/socket.io.js'</span>, <span class="attr">async</span>: <span class="literal">true</span> },</span><br><span class="line"> { <span class="attr">src</span>: <span class="string">'plugin/notes-server/client.js'</span>, <span class="attr">async</span>: <span class="literal">true</span> }</span><br><span class="line"> ]</span><br><span class="line">});</span><br></pre></td></tr></table></figure>
<p>然后:</p>
<ol>
<li>安装 <a href="http://nodejs.org/" target="_blank" rel="noopener">Node.js</a>(4.0.0 或更新版本)</li>
<li>执行 <figure class="highlight plain"><figcaption><span>install```</span></figcaption><table><tr><td class="code"><pre><span class="line">3. 执行 ```node plugin/notes-server</span><br></pre></td></tr></table></figure></li>
</ol>
<h3 id="多路复用"><a href="#多路复用" class="headerlink" title="多路复用"></a>多路复用</h3><p>多路复用插件让你的听众可以在自己的手机、平板电脑或笔记本电脑上观看你正在控制的演示文稿,当你操作主演示文稿时,所有的客户端演示文稿将实时同步更新。查看示例:<a href="https://reveal-js-multiplex-ccjbegmaii.now.sh/" target="_blank" rel="noopener">https://reveal-js-multiplex-ccjbegmaii.now.sh/</a>。</p>
<p>多路复用插件需要以下 3 个部分:</p>
<ol>
<li>可以控制的主演示文稿</li>
<li>同步更新的客户端演示文稿</li>
<li>用于广播主演示文稿事件给客户端演示文稿的 Socket.io 服务器</li>
</ol>
<p>更多说明:</p>
<h3 id="主演示文稿"><a href="#主演示文稿" class="headerlink" title="主演示文稿"></a>主演示文稿</h3><p>存放于只有演讲者可以访问(最好)的静态文件服务器(存放在演讲者的电脑上即可,在演讲者的电脑上运行主演示文稿会更加保险,即使会场断网,也不会打断演示。)。<br>在主演示文稿目录中执行以下命令:</p>
<ol>
<li><figure class="highlight plain"><figcaption><span>install node-static```</span></figcaption><table><tr><td class="code"><pre><span class="line">2. ```static</span><br></pre></td></tr></table></figure>
</li>
</ol>
<p>如果想在主演示文稿上使用演讲备注,需要先配置演讲备注插件,然后在主演示文稿目录中执行 <figure class="highlight plain"><figcaption><span>plugin/notes-server``` 命令。</span></figcaption><table><tr><td class="code"><pre><span class="line"></span><br><span class="line">运行演讲备注/静态文件服务器,作为主控端连接 socket.io 服务器。</span><br><span class="line"></span><br><span class="line">通过 ```http://localhost:1947``` 访问主演示文稿。</span><br><span class="line"></span><br><span class="line">配置示例:</span><br><span class="line">```javascript</span><br><span class="line">Reveal.initialize({</span><br><span class="line"> // 其它配置项……</span><br><span class="line"></span><br><span class="line"> multiplex: {</span><br><span class="line"> // 示例值,使用时请自己生成,具体参考 socket.io 说明。</span><br><span class="line"> secret: '13652805320794272084', // 从 socket.io 服务器获得,允许演示文稿可以被控制</span><br><span class="line"> id: '1ea875674b17ca76', // 从 socket.io 服务器获得</span><br><span class="line"> url: 'https://reveal-js-multiplex-ccjbegmaii.now.sh' // socket.io 服务器地址</span><br><span class="line"> },</span><br><span class="line"></span><br><span class="line"> // 依赖项</span><br><span class="line"> dependencies: [</span><br><span class="line"> { src: '//cdn.socket.io/socket.io-1.3.5.js', async: true },</span><br><span class="line"> { src: 'plugin/multiplex/master.js', async: true },</span><br><span class="line"></span><br><span class="line"> // 演讲备注</span><br><span class="line"> { src: 'plugin/notes-server/client.js', async: true }</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>
<h3 id="客户端演示文稿"><a href="#客户端演示文稿" class="headerlink" title="客户端演示文稿"></a>客户端演示文稿</h3><p>存放于可以公开访问的静态文件服务器,如 GitHub Pages、Amazon S3、Dreamhost、Akamai 等。</p>
<p>使用下面的配置,当听众通过 <figure class="highlight plain"><figcaption><span>访问演示文稿时,将作为被控端连接 socket.io 服务器。</span></figcaption><table><tr><td class="code"><pre><span class="line"></span><br><span class="line">配置示例:</span><br><span class="line">```javascript</span><br><span class="line">Reveal.initialize({</span><br><span class="line"> // 其它配置项……</span><br><span class="line"></span><br><span class="line"> multiplex: {</span><br><span class="line"> // 示例值,使用时请自己生成,具体参考 socket.io 说明。</span><br><span class="line"> secret: null, // 设置为 null,演示文稿将不能被控制,而是同步 socket.io 服务器上相同 id 的主演示文稿的操作</span><br><span class="line"> id: '1ea875674b17ca76', // 从 socket.io 服务器获得</span><br><span class="line"> url: 'https://reveal-js-multiplex-ccjbegmaii.now.sh' // socket.io 服务器地址</span><br><span class="line"> },</span><br><span class="line"></span><br><span class="line"> // 依赖项</span><br><span class="line"> dependencies: [</span><br><span class="line"> { src: '//cdn.socket.io/socket.io-1.3.5.js', async: true },</span><br><span class="line"> { src: 'plugin/multiplex/client.js', async: true }</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>
<h2 id="MathJax"><a href="#MathJax" class="headerlink" title="_MathJax"></a>_MathJax</h2><p>如果想在演示文稿中更好的显示数学公式,可以使用基于 <a href="http://www.mathjax.org/" target="_blank" rel="noopener">MathJax</a> 库封装的这个小插件。</p>
<p>插件默认使用 <a href="http://en.wikipedia.org/wiki/LaTeX" target="_blank" rel="noopener">LaTeX</a> 格式(一种基于ΤΕΧ的排版系统),可通过 <figure class="highlight plain"><figcaption><span>配置项来修改。</span></figcaption><table><tr><td class="code"><pre><span class="line"></span><br><span class="line">MathJax 是从远程服务器加载的,如果想离线使用,需自行下载该库,并修改 ```mathjax``` 配置项。</span><br><span class="line"></span><br><span class="line">下面是 MathJax 的配置示例(使用默认配置时,```math``` 配置项可省略):</span><br><span class="line"></span><br><span class="line">```js</span><br><span class="line">Reveal.initialize({</span><br><span class="line"> // 其它配置项……</span><br><span class="line"></span><br><span class="line"> math: {</span><br><span class="line"> mathjax: 'https://cdn.mathjax.org/mathjax/latest/MathJax.js',</span><br><span class="line"> config: 'TeX-AMS_HTML-full' // 参考 http://docs.mathjax.org/en/latest/config-files.html</span><br><span class="line"> },</span><br><span class="line"></span><br><span class="line"> dependencies: [</span><br><span class="line"> { src: 'plugin/math/math.js', async: true }</span><br><span class="line"> ]</span><br><span class="line"></span><br><span class="line">});</span><br></pre></td></tr></table></figure></p>
<p>如果想了解 MathJax 的 <a href="http://docs.mathjax.org/en/latest/start.html#secure-access-to-the-cdn" target="_blank" rel="noopener">HTTPS 传输</a>方式,或为了稳定性需要使用<a href="http://docs.mathjax.org/en/latest/configuration.html#loading-mathjax-from-the-cdn" target="_blank" rel="noopener">特定版本</a>,请参考 MathJax 的说明文档。</p>
<h2 id="工程安装"><a href="#工程安装" class="headerlink" title="工程安装"></a>工程安装</h2><p><strong>基础安装</strong> 适用于创建简单的演讲文稿,<strong>完整安装</strong> 可以使用 reveal.js 的所有特性和插件(如演讲备注)。</p>
<h3 id="基础安装"><a href="#基础安装" class="headerlink" title="基础安装"></a>基础安装</h3><p>reveal.js 基础功能的安装十分简单,只需下载框架包,然后直接在浏览器中打开 index.html 文件即可。</p>
<ol>
<li><p>在 <a href="https://github.com/hakimel/reveal.js/releases" target="_blank" rel="noopener">https://github.com/hakimel/reveal.js/releases</a> 上下载 reveal.js 的最新版本</p>
</li>
<li><p>解压缩,然后将 index.html 里的示例内容修改为自己的内容</p>
</li>
<li><p>在浏览器中打开 index.html</p>
</li>
</ol>
<h3 id="完整安装"><a href="#完整安装" class="headerlink" title="完整安装"></a>完整安装</h3><p>部分 reveal.js 特性(如 Markdown 和演讲备注)需要演示文稿运行于一个本地 web 服务器。<br>按照下面的步骤,可以创建一个完整的 reveal.js 开发和运行环境:</p>
<ol>
<li><p>安装 <a href="http://nodejs.org/" target="_blank" rel="noopener">Node.js</a> (4.0.0 或更新版本)</p>
</li>
<li><p>克隆 reveal.js 仓库</p>
<figure class="highlight sh"><table><tr><td class="code"><pre><span class="line">$ git <span class="built_in">clone</span> https://github.com/palmerye/demos-Reveal.js.git</span><br></pre></td></tr></table></figure>
</li>
<li><p>进入 reveal.js 目录</p>
<figure class="highlight sh"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">cd</span> reveal.js</span><br></pre></td></tr></table></figure>
</li>
<li><p>安装依赖</p>
<figure class="highlight sh"><table><tr><td class="code"><pre><span class="line">$ npm install</span><br></pre></td></tr></table></figure>
</li>
<li><p>启动演示文稿并监控文件变更</p>
<figure class="highlight sh"><table><tr><td class="code"><pre><span class="line">$ npm start</span><br></pre></td></tr></table></figure>
</li>
<li><p>打开 <a href="http://localhost:8000" target="_blank" rel="noopener">http://localhost:8000</a> 查看演示文稿</p>
</li>
</ol>
<p>通过 <code>npm start -- --port=8001</code> 指令可修改端口号</p>
<h3 id="目录结构"><a href="#目录结构" class="headerlink" title="目录结构"></a>目录结构</h3><ul>
<li><strong>css/</strong> 框架样式</li>
<li><strong>js/</strong> 框架 JavaScript </li>
<li><strong>plugin/</strong> 用于扩展 reveal.js 的组件</li>
<li><strong>lib/</strong> 第三方库(JavaScript、样式、字体)</li>
</ul>
<h2 id="许可"><a href="#许可" class="headerlink" title="许可"></a>许可</h2><p>遵循 MIT 开源协议</p>
<p>Copyright (C) 2016 Hakim El Hattab, <a href="http://hakim.se" target="_blank" rel="noopener">http://hakim.se</a></p>
]]></content>
<tags>
<tag>reveal.js</tag>
<tag>slides</tag>
</tags>
</entry>
<entry>
<title>Rokid(全栈语音开发套件)评测---优雅篇</title>
<url>/2018/01/Rokid%EF%BC%88%E5%85%A8%E6%A0%88%E8%AF%AD%E9%9F%B3%E5%BC%80%E5%8F%91%E5%A5%97%E4%BB%B6%EF%BC%89%E8%AF%84%E6%B5%8B-%E4%BC%98%E9%9B%85%E7%AF%87/</url>
<content><![CDATA[<blockquote>
<p>元旦宅在家chuang里shang,刚好收到了Rokid寄来的开发板,激动的去公司拿回快递,动手拆拆拆。</p>
</blockquote>
<a id="more"></a>
<p>首先感谢SF和Rokid平台,想想自己申请的时候脸皮真的是厚,现在看评论真的不堪入目。看了几篇其他人的评测,感觉需要从另一个角度来看Rokid这块开发板,那就先从优duo雅tu的角度看吧。</p>
<h2 id="全家桶"><a href="#全家桶" class="headerlink" title="全家桶"></a>全家桶</h2><p><img src="https://github.com/palmerye/pictureBed/raw/master/rokid/WechatIMG3841514985737_.pic_hd.jpg" alt></p>
<p>从左至右依次为:</p>
<ul>
<li>开发板外盒</li>
<li>Type-C数据线(供电: 应该是正常1.5A~3A都能带动,还没仔细去看电源模块)</li>
<li>Debug板</li>
<li>核心板</li>
</ul>
<p>如果想正常体验Rokid的功能,其实只需要核心板就可以,USB Type-C供电,结合Rokid App。</p>
<h2 id="拆拆拆"><a href="#拆拆拆" class="headerlink" title="拆拆拆"></a>拆拆拆</h2><blockquote>
<p>作为一名曾经的硬件工程师,看到螺丝这种东西,都想不自觉地拧一拧</p>
</blockquote>
<p><img src="https://github.com/palmerye/pictureBed/raw/master/rokid/WechatIMG3831514985731_.pic_hd.jpg" alt></p>
<p>拆下所有螺丝螺母,铜制,Rokid还是良心呀。</p>
<p><img src="https://github.com/palmerye/pictureBed/raw/master/rokid/WechatIMG3821514985724_.pic_hd.jpg" alt></p>
<p>很快就将能拆的都拆了,两块圆形透明塑料板子让开发板线路很直观,很极客。但如果需要把debug板子集成进去的话,还需要再加三根铜柱来支撑。</p>
<h2 id="套件细节"><a href="#套件细节" class="headerlink" title="套件细节"></a>套件细节</h2><blockquote>
<p>从工程角度看这块开发板的做工,无论是焊锡点,还是PCB布线材质,都很漂亮,想起了自己以前手焊电路板的日子,尤其是那种芝麻大的电容,想想还是。。。快忘了很多硬件的工艺知识了,跑工厂的时候,解决现场问题尤其头疼。</p>
</blockquote>
<h3 id="核心板"><a href="#核心板" class="headerlink" title="核心板"></a>核心板</h3><p><img src="https://github.com/palmerye/pictureBed/raw/master/rokid/WechatIMG3801514985704_.pic_hd.jpg" alt></p>
<p><img src="https://github.com/palmerye/pictureBed/raw/master/rokid/WechatIMG3791514985666_.pic_hd.jpg" alt></p>
<p><img src="https://github.com/palmerye/pictureBed/raw/master/rokid/WechatIMG3811514985715_.pic_hd.jpg" alt></p>
<h3 id="Debug板"><a href="#Debug板" class="headerlink" title="Debug板"></a>Debug板</h3><p><img src="https://github.com/palmerye/pictureBed/raw/master/rokid/WechatIMG3771514985640_.pic_hd.jpg" alt></p>
<p><img src="https://github.com/palmerye/pictureBed/raw/master/rokid/WechatIMG3761514985619_.pic_hd.jpg" alt></p>
<p><img src="https://github.com/palmerye/pictureBed/raw/master/rokid/WechatIMG3751514985603_.pic_hd.jpg" alt></p>
<p>躺在盒子是这个样子的。</p>
<h3 id="PCB收尾"><a href="#PCB收尾" class="headerlink" title="PCB收尾"></a>PCB收尾</h3><p><img src="https://github.com/palmerye/pictureBed/raw/master/rokid/WechatIMG3781514985655_.pic_hd.jpg" alt></p>
<h2 id="一言不合开个机看看"><a href="#一言不合开个机看看" class="headerlink" title="一言不合开个机看看"></a>一言不合开个机看看</h2><p>USB口接上普通手机电源,我是直接插到笔记本边上了,也能带得动。</p>
<p><img src="https://github.com/palmerye/pictureBed/raw/master/rokid/WechatIMG3741514985594_.pic_hd.jpg" alt></p>
<p>刚开机的时候,外圈交替闪烁四盏LED(白)。3.5mm接口插上耳机(开发套件默认不配备扬声器),可以听到开发套件的语音反馈。</p>
<p><img src="https://github.com/palmerye/pictureBed/raw/master/rokid/WechatIMG3711514985578_.pic_hd.jpg" alt></p>
<p><img src="https://github.com/palmerye/pictureBed/raw/master/rokid/WechatIMG3731514985589_.pic_hd.jpg" alt></p>
<p><img src="https://github.com/palmerye/pictureBed/raw/master/rokid/WechatIMG3721514985584_.pic_hd.jpg" alt></p>
<p><img src="https://github.com/palmerye/pictureBed/raw/master/rokid/WechatIMG370.jpeg" alt></p>
<p>这里我就跳过了App网络蓝牙配置阶段了。</p>
<ul>
<li>配置成功后亮起一圈LED(绿)</li>
<li>对它说“若琪”,在你声音的方向会亮起一盏LED(白)</li>
<li>“明天天气如何?”,识别语音,亮起若干LED(白)转圈显示</li>
<li>”xxxx“耳机可以听到相应的语音反馈,期间整圈LED(白)同时闪烁</li>
</ul>
<h2 id="最后"><a href="#最后" class="headerlink" title="最后"></a>最后</h2><p>还没怎么去折腾开发功能,不过目前想解决的问题是,让套件连接蓝牙音箱,代替它的麦克风输出。有时间再玩耍吧。</p>
<p>生命不息,折腾不止。</p>
<blockquote>
<p>本文参与了 SegmentFault<a href="https://segmentfault.com/a/1190000012425295" target="_blank" rel="noopener">「Rokid 开发板试用,开启你的嵌入式开发之旅」</a>活动,欢迎正在阅读的你申请试用,一起交流开发心得。</p>
</blockquote>
]]></content>
<tags>
<tag>rokid</tag>
<tag>硬件</tag>
</tags>
</entry>
<entry>
<title>Travis CI助力Blog持续输出</title>
<url>/2018/01/Travis%20CI%E5%8A%A9%E5%8A%9BBlog%E6%8C%81%E7%BB%AD%E8%BE%93%E5%87%BA/</url>
<content><![CDATA[<blockquote>
<p>之前更新blog要这样:本地安装hexo环境,还需要敲几个命令:<code>hexo clean && hexo g && hexo d</code>,构建部署还有点浪费时间。其实每次更新blog的时候,只需要增删改几个Markdown文件。懒~干脆上CI吧。</p>
</blockquote>
<a id="more"></a>
<h2 id="CI-为何物"><a href="#CI-为何物" class="headerlink" title="CI 为何物"></a>CI 为何物</h2><blockquote>
<p>CI(Continuous Integration)—— 持续集成。</p>
</blockquote>
<p>其实光从名字其实能大致知道CI做了什么事情。硬件领域有集成模块、集成电路,软件领域也有集成概念:项目构建、自动化测试、部署等等。我的理解,每个成熟的产品从零散到成型到出品(上线)的过程,就是集成(Integration)。那么CI做的事情,就是让这个工程自动化,持续进行(Continuous)。</p>
<h3 id="好处:"><a href="#好处:" class="headerlink" title="好处:"></a>好处:</h3><ul>
<li>快速发现错误</li>
<li>保持分支与主干相对集中</li>
</ul>
<blockquote>
<p>“持续集成并不能消除Bug,而是让它们非常容易发现和改正。” – Martin Fowler</p>
</blockquote>
<h3 id="流程:"><a href="#流程:" class="headerlink" title="流程:"></a>流程:</h3><blockquote>
<p>其实应该将这几个概念揉在一起:持续集成、持续部署、持续交付、持续发布。</p>
</blockquote>
<p><img src="https://github.com/palmerye/pictureBed/raw/master/blog/2403013470-5a708bdde14ce_articlex.jpeg?fromMac" alt></p>
<p>1.代码提交:commit<br>2.测试(第一轮):hook相应的commit动作,自动化测试<br>3.构建:build,相当于是编译可用的代码<br>4.测试(第二轮):包含单元测试和集成测试<br>5.部署:打包至生产环境<br>6.回滚:若最新版本发生异常,则回滚到上一版本</p>
<h2 id="Travis-CI-又为何物"><a href="#Travis-CI-又为何物" class="headerlink" title="Travis CI 又为何物"></a>Travis CI 又为何物</h2><p><img src="http://www.ruanyifeng.com/blogimg/asset/2017/bg2017121901.png" alt="image"></p>
<blockquote>
<p>Travis CI: 在线托管的CI服务,最重要的事情,它对开源项目是免费的!!!(重要的感叹号加三个!!!)</p>
</blockquote>
<p><a href="https://travis-ci.org/" target="_blank" rel="noopener">Travis CI</a> 官网上醒目的大字:<br>Test and Deploy with Confidence<br>Easily sync your <strong>GitHub</strong> projects with Travis CI and you’ll be testing your code in minutes!</p>
<blockquote>
<p>赤裸裸的表白,果然和Github是一对好基友。</p>
</blockquote>
<p>这意味着,我们在Github的 Public Repository都可以利用Travis CI 进行免费的持续集成,当然,Personal Repository也可以用它,不过挺贵的。之前用Github Pages 搭的<a href="http://palmer.arkstack.cn/">Blog</a>刚好可以用Travis CI来持续构建,将偷懒进行到底吧!</p>
<h2 id="只需几步,快速体验CI"><a href="#只需几步,快速体验CI" class="headerlink" title="只需几步,快速体验CI"></a>只需几步,快速体验CI</h2><h3 id="1-GitHub账号直接登录"><a href="#1-GitHub账号直接登录" class="headerlink" title="1.GitHub账号直接登录"></a>1.GitHub账号直接登录</h3><p>打开<a href="https://travis-ci.org/" target="_blank" rel="noopener">Travis CI</a> ,使用 GitHub 第三方授权登录,不要问为什么,好丽友,好基友。</p>
<h3 id="2-打开Repo-CI配置"><a href="#2-打开Repo-CI配置" class="headerlink" title="2.打开Repo CI配置"></a>2.打开Repo CI配置</h3><p><img src="https://github.com/palmerye/pictureBed/raw/master/travisCI/index.png" alt="image"></p>
<p>勾上你的blog repo (这里我勾上了<code>palmerye.github.io</code>),点击小齿轮,进入配置页。</p>
<p><img src="https://github.com/palmerye/pictureBed/raw/master/travisCI/index2.png" alt="image"></p>
<p>打开最上方两个开关,其它默认就行了:<br><code>Build only if .travis.yml is present</code><br><code>Build pushed branches</code></p>
<p>其实官方也有教程,只要三步:</p>
<p><img src="https://github.com/palmerye/pictureBed/raw/master/travisCI/index6.png" alt="image"></p>
<h3 id="3-添加-travis-yml"><a href="#3-添加-travis-yml" class="headerlink" title="3.添加 .travis.yml"></a>3.添加 .travis.yml</h3><blockquote>
<p>划重点了!</p>
</blockquote>
<p>1.新建一个source分支,将原来本地的Hexo工程,gitignore外的那些目录,切到source分支。(最终我们只需要推这个分支到origin)</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="comment">// .gitignore</span></span><br><span class="line"></span><br><span class="line">.DS_Store</span><br><span class="line">Thumbs.db</span><br><span class="line">db.json</span><br><span class="line">*.log</span><br><span class="line">node_modules/</span><br><span class="line">public/</span><br><span class="line">.deploy*<span class="regexp">/</span></span><br></pre></td></tr></table></figure>
<p><img src="https://github.com/palmerye/pictureBed/raw/master/travisCI/index3.png" alt="image"></p>
<p>2.为Travis CI 新建Token</p>
<p>这一步很关键,为什么Travis有权限帮你推GitHub?所以你要给它钥匙,就是Token。</p>
<p>在GitHub个人账户 <code>Setting/ Developer settings/ Personal access tokens</code>下,新建一个Token,然后在Travis CI配置中,Environment Variables,添加生成的Token。</p>
<p><img src="https://github.com/palmerye/pictureBed/raw/master/travisCI/index4.png" alt="image"></p>
<p>3.source分支下新建.travis.yml</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line">language: node_js</span><br><span class="line">node_js: stable</span><br><span class="line">cache:</span><br><span class="line"> directories:</span><br><span class="line"> - node_modules</span><br><span class="line"></span><br><span class="line"># S: Build Lifecycle</span><br><span class="line">install:</span><br><span class="line"> - npm install</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">#before_script:</span><br><span class="line"> # - npm install -g gulp</span><br><span class="line"></span><br><span class="line">script:</span><br><span class="line"> - hexo clean && hexo g</span><br><span class="line"></span><br><span class="line">after_script:</span><br><span class="line"> - git clone https:<span class="comment">//${GH_REF} .deploy_git</span></span><br><span class="line"> - cd .deploy_git</span><br><span class="line"> - git checkout master</span><br><span class="line"> - cd ../</span><br><span class="line"> - mv .deploy_git/.git/ ./public/</span><br><span class="line"> - cd ./public</span><br><span class="line"> - git init</span><br><span class="line"> - git config user.name <span class="string">"palmerye"</span></span><br><span class="line"> - git config user.email <span class="string">"[email protected]"</span></span><br><span class="line"> - git add .</span><br><span class="line"> - git commit -m <span class="string">":memo:\ Update docs by CI"</span></span><br><span class="line"> - git push --force --quiet <span class="string">"https://${CI_TOKEN}@${GH_REF}"</span> master:master <span class="comment">// CI_TOKEN为上一步在github上生成的Token。</span></span><br><span class="line"># E: Build LifeCycle</span><br><span class="line"></span><br><span class="line">branches:</span><br><span class="line"> only:</span><br><span class="line"> - source</span><br><span class="line">env:</span><br><span class="line"> global:</span><br><span class="line"> - GH_REF: github.com/palmerye/palmerye.github.io.git</span><br></pre></td></tr></table></figure>
<p>其实看这个配置文件就大致能知道这个流程,在Travis 服务器上<code>install</code>相应的依赖,然后执行<code>hexo clean && hexo g</code>等一系列之前需要在本地跑的命令,最后将生成的静态资源blog(在<code>./public</code>目录下),推到master分支。</p>
<p>4.将source分支推到远端,Travis 监听到有动作就会跑上面我们配置的脚本。</p>
<h2 id="可以愉快写Blog了"><a href="#可以愉快写Blog了" class="headerlink" title="可以愉快写Blog了"></a>可以愉快写Blog了</h2><p>现在,我们可以把本地那些hexo臃肿的依赖删了(这意味着,你在任意的电脑上都能快速更新blog了,不需要安装hexo依赖),每次只需要增删改<code>/source/_posts/</code>下的markdown文件就可以了,轻轻push一下,其他交给Travis CI吧,你可以在Travis / Current<br>看到实时的构建状态,包括构建时间和成功与否。</p>
<p>最后,为了提高Blog的档bi次ge,在readme加个build passing 标签吧。</p>
<p><img src="https://github.com/palmerye/pictureBed/raw/master/travisCI/index5.png" alt="image"></p>
<h2 id="最后的最后"><a href="#最后的最后" class="headerlink" title="最后的最后"></a>最后的最后</h2><p>其实前面只是最简单粗暴的用了Travis CI,它还有很多强大的功能,比如一些 Cron Jobs,都是比较傻瓜式的,有时间继续搞吧。干巴爹💪!继续写blog了。</p>
<p>PS:<br>Blog in Github:<a href="https://github.com/palmerye/palmerye.github.io/" target="_blank" rel="noopener">https://github.com/palmerye/palmerye.github.io/</a></p>
<hr>
<p>参考:<br><a href="http://www.ruanyifeng.com/blog/2015/09/continuous-integration.html" target="_blank" rel="noopener">持续集成是什么?– 阮大大</a><br><a href="https://www.liaoxuefeng.com/article/0014631488240837e3633d3d180476cb684ba7c10fda6f6000" target="_blank" rel="noopener">使用Travis进行持续集成 – 廖大大</a></p>
]]></content>
<tags>
<tag>CI</tag>
</tags>
</entry>
<entry>
<title>Web + Log = Blog</title>
<url>/2017/01/Web-Log-Blog/</url>
<content><![CDATA[<h2 id="Blog原来是这样来的"><a href="#Blog原来是这样来的" class="headerlink" title="Blog原来是这样来的"></a>Blog原来是这样来的</h2><blockquote>
<p>博客(英语:Blog,为Web Log的混成词),意指log on the web意即在网络上纪录,是一种由个人管理、张贴新的文章、图片或视频的网站或在线日记,用来纪录、抒发情感或分享信息。 From Wiki.</p>
</blockquote>
<a id="more"></a>
<h2 id="我为什么要写博客"><a href="#我为什么要写博客" class="headerlink" title="我为什么要写博客"></a>我为什么要写博客</h2><h3 id="For-生存"><a href="#For-生存" class="headerlink" title="For 生存"></a>For 生存</h3><blockquote>
<p>自从看了阮一峰老师的<a href="http://www.ruanyifeng.com/blog/" target="_blank" rel="noopener">Blog</a>,我才知道什么叫全能;频繁的浏览他的Blog,我才意识到全能的背后是文章的高产。</p>
</blockquote>
<ol>
<li>*知识梳理,才知道自己哪里缺胳膊少腿 </li>
<li>给别人一个爱<del>批评</del>你的机会</li>
<li>一不小心能帮到同行呢</li>
<li>信息整合,也许有一天,不需要再这里Google那里Baidu了,Local Search就能找到信息</li>
<li>扩大在圈子里的影响力 <del>(打这几个字我都有点手抖)</del></li>
</ol>
<h3 id="For-生活"><a href="#For-生活" class="headerlink" title="For 生活"></a>For 生活</h3><blockquote>
<p>有没有发现,年级大了,QQ空间没什么动态更新了,朋友圈发得少了,不易悲,也不易喜。</p>
</blockquote>
<ol>
<li>写一些经历和想法,也许能和visitors产生一些共鸣</li>
<li>用文字和图片记录下一些生活,常常翻翻,听说这样不会抑郁</li>
<li>我挺喜欢拍照,拿blog当个web相册也不错</li>
</ol>
<h2 id="关于这个博客一些东西"><a href="#关于这个博客一些东西" class="headerlink" title="关于这个博客一些东西"></a>关于这个博客一些东西</h2><ul>
<li>暂时搭建在github良心的Pages上(<a href="https://github.com/palmerye/palmer-blog" target="_blank" rel="noopener">Repository</a>)<blockquote>
<p>如果你手滑点进去了,那就手滑star下吧</p>
</blockquote>
</li>
<li>搭建于gh-pages分支。为什么不用<a href="https://github.com/palmerye/palmerye.github.io" target="_blank" rel="noopener">palmerye.github.io</a>?另有他用,其实没多大区别</li>
<li>Blog工具用的Hexo,主题是Next,自己稍做了一点修改</li>
<li>首页的封面图是用AI画的矢量图,从PCB到Code,也表示自己从硬件转型到软件的历程,每一段经历都很宝贵,值得珍惜。</li>
<li>该加的功能都加了,包括站点底下的PV和UV统计</li>
<li>或许上面👆这条是假的,我们的工作就是不断否定自己</li>
<li>日子如何,力量也如何。这句话出于《圣经·申命记》33:25</li>
</ul>
<p><strong>关于博客的目的,说到底还是一句话,利人利己 <del>因为我觉得这样很酷</del></strong>。</p>
]]></content>
<tags>
<tag>blog</tag>
</tags>
</entry>
<entry>
<title>从setTimeout/setInterval看JS线程</title>
<url>/2017/12/%E4%BB%8EsetTimeout-setInterval%E7%9C%8BJS%E7%BA%BF%E7%A8%8B/</url>
<content><![CDATA[<blockquote>
<p>最近项目中遇到了一个场景,其实很常见,就是定时获取接口刷新数据。那么问题来了,假设我设置的定时时间为1s,而数据接口返回大于1s,应该用同步阻塞还是异步?我们先整理下js中定时器的相关知识,再来看这个问题。</p>
</blockquote>
<a id="more"></a>
<h2 id="初识setTimeout-与-setInterval"><a href="#初识setTimeout-与-setInterval" class="headerlink" title="初识setTimeout 与 setInterval"></a>初识setTimeout 与 setInterval</h2><blockquote>
<p>先来简单认识,后面我们试试用setTimeout 实现 setInterval 的功能</p>
</blockquote>
<ul>
<li>setTimeout 延迟一段时间执行一次 <strong>(Only one)</strong></li>
</ul>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line">setTimeout(<span class="function"><span class="keyword">function</span>, <span class="title">milliseconds</span>, <span class="title">param1</span>, <span class="title">param2</span>, ...)</span></span><br><span class="line"><span class="function"><span class="title">clearTimeout</span>(<span class="params"></span>) // 阻止定时器运行</span></span><br><span class="line"><span class="function"></span></span><br><span class="line"><span class="function"><span class="title">e</span>.<span class="title">g</span>.</span></span><br><span class="line"><span class="function"><span class="title">setTimeout</span>(<span class="params">function(</span>)</span>{ alert(<span class="string">"Hello"</span>); }, <span class="number">3000</span>); <span class="comment">// 3s后弹出</span></span><br></pre></td></tr></table></figure>
<ul>
<li>setInterval 每隔一段时间执行一次 <strong>(Many times)</strong></li>
</ul>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line">setInterval(<span class="function"><span class="keyword">function</span>, <span class="title">milliseconds</span>, <span class="title">param1</span>, <span class="title">param2</span>, ...)</span></span><br><span class="line"><span class="function"></span></span><br><span class="line"><span class="function"><span class="title">e</span>.<span class="title">g</span>.</span></span><br><span class="line"><span class="function"><span class="title">setInterval</span>(<span class="params">function(</span>)</span>{ alert(<span class="string">"Hello"</span>); }, <span class="number">3000</span>); <span class="comment">// 每隔3s弹出</span></span><br></pre></td></tr></table></figure>
<blockquote>
<p>setTimeout和setInterval的延时最小间隔是4ms(W3C在HTML标准中规定);在JavaScript中没有任何代码是立刻执行的,但一旦进程空闲就尽快执行。这意味着无论是setTimeout还是setInterval,所设置的时间都只是n毫秒被添加到队列中,而不是过n毫秒后立即执行。</p>
</blockquote>
<h2 id="进程与线程,傻傻分不清楚"><a href="#进程与线程,傻傻分不清楚" class="headerlink" title="进程与线程,傻傻分不清楚"></a>进程与线程,傻傻分不清楚</h2><p>为了讲清楚这两个抽象的概念,我们借用阮大大借用的比喻,先来模拟一个场景:</p>
<ul>
<li>这里有一个大型工厂</li>
<li>工厂里有若干车间,每次只能有一个车间在作业</li>
<li>每个车间里有若干房间,有若干工人在流水线作业</li>
</ul>
<p>那么:</p>
<ul>
<li>一个工厂对应的就是计算机的一个CPU,平时讲的多核就代表多个工厂</li>
<li>每个工厂里的车间,就是<strong>进程</strong>,意味着同一时刻一个CPU只运行一个<strong>进程</strong>,其余<strong>进程</strong>在怠工</li>
<li>这个运行的车间(<strong>进程</strong>)里的工人,就是<strong>线程</strong>,可以有多个工人(<strong>线程</strong>)协同完成一个任务</li>
<li>车间(<strong>进程</strong>)里的房间,代表内存。</li>
</ul>
<p>再深入点:</p>
<ul>
<li>车间(<strong>进程</strong>)里工人可以随意在多个房间(内存)之间走动,意味着一个<strong>进程</strong>里,多个<strong>线程</strong>可以共享内存</li>
<li>部分房间(内存)有限,只允许一个工人(<strong>线程</strong>)使用,此时其他工人(<strong>线程</strong>)要等待</li>
<li>房间里有工人进去后上锁,其他工人需要等房间(内存)里的工人(<strong>线程</strong>)开锁出来后,才能才进去,这就是<strong>互斥锁</strong>(Mutual exclusion,缩写 Mutex)</li>
<li>有些房间只能容纳部分的人,意味着部分内存只能给有限的<strong>线程</strong></li>
</ul>
<p>再再深入:</p>
<ul>
<li>如果同时有多个车间作业,就是<strong>多进程</strong></li>
<li>如果一个车间里有多个工人协同作业,就是<strong>多线程</strong></li>
<li>当然不同车间之间的工人也可以有相互协作,就需要协调机制</li>
</ul>
<h2 id="JavaScript-单线程"><a href="#JavaScript-单线程" class="headerlink" title="JavaScript 单线程"></a>JavaScript 单线程</h2><p>总所周知,JavaScript 这门语言的核心特征,就是单线程(是指在<strong>JS引擎</strong>中负责解释和执行JavaScript代码的线程只有一个)。这和 JavaScript 最初设计是作为一门 GUI 编程语言有关,最初用于浏览器端,单一线程控制 GUI 是很普遍的做法。但这里特别要划个重点,虽然JavaScript是单线程,但<strong>浏览器是多线程的!!!</strong>例如Webkit或是Gecko引擎,可能有javascript引擎线程、界面渲染线程、浏览器事件触发线程、Http请求线程,读写文件的线程(例如在Node.js中)。ps:可能要总结一篇浏览器渲染的文章了。</p>
<blockquote>
<p>HTML5提出Web Worker标准,允许JavaScript脚本创建多个线程,但是子线程完全受主线程控制,且不得操作DOM。所以,这个新标准并没有改变JavaScript单线程的本质。</p>
</blockquote>