-
Notifications
You must be signed in to change notification settings - Fork 1
/
atom.xml
1637 lines (1376 loc) · 213 KB
/
atom.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"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>清风轩</title>
<subtitle>清风轩居 - 引仙阁</subtitle>
<link href="/atom.xml" rel="self"/>
<link href="https://xovel.cn/"/>
<updated>2021-02-10T05:38:59.847Z</updated>
<id>https://xovel.cn/</id>
<author>
<name>xovel</name>
<email>xovel@vip.qq.com</email>
</author>
<generator uri="http://hexo.io/">Hexo</generator>
<entry>
<title>2020 年回顾</title>
<link href="https://xovel.cn/article/summary-2020.html"/>
<id>https://xovel.cn/article/summary-2020.html</id>
<published>2021-02-10T03:04:19.000Z</published>
<updated>2021-02-10T05:38:59.847Z</updated>
<content type="html"><![CDATA[<blockquote>
<p>转眼就快到春节了,是时候来一个不大不小的总结了。</p>
</blockquote>
<p>今年发生的事情比较多,也没有想过要去逐个去进行记录。</p>
<p>说起年度总结,已经有很长一段时间没有进行记录了。</p>
<p>还是按照上一次的总结的提纲来进行简单记录吧。</p>
<h3 id="公司项目"><a href="#公司项目" class="headerlink" title="公司项目"></a>公司项目</h3><p>回顾之下,2020 年做的项目太少了。公司项目只有一个,已经够了。个人项目有点散乱,在之前的项目维护的基础上进行了一番修订。</p>
<p>负责参与的项目为公司内部的核心 A 级项目,本人将负责的内容分阶段进行阐述。</p>
<h4 id="第一季度"><a href="#第一季度" class="headerlink" title="第一季度"></a>第一季度</h4><p>刚入职,那个时候刚巧碰上疫情,在家里远程办公,持续到 3 月份才返回职场。远程的效率其实远远没有现场高,诸多权限限制,得到无法顺利进行编译代码,开发效率不可谓不低。饶是如此,还是取得了不少的进展。</p>
<p>内部几个迭代之后发布的效果还算令人不错,我在其中负责多个模块的管理与开发,包括“企业信用管理”,“任企付”(后改名叫“易企发”),“疫情减息活动”,“数字证”,“数字保管箱”,“数字融资”(涉及到中小企业贷款),“企业资讯”等。</p>
<h4 id="第二季度"><a href="#第二季度" class="headerlink" title="第二季度"></a>第二季度</h4><p>由于公司高层的战略调整,我们的 APP 的功能点与公司内另外一个 APP 的功能点高度重合,于是有了项目合并的操作。合并之后还是叫数字口袋,内部叫法只是在前面加了一个新字以示区别。</p>
<p>新 APP 的功能略有调整,“易企发”由于有高度重合的现有产品,被裁撤。数字融资为两边都有的功能,进行合并。“企业信用管理”由于对接的第三方存在诸多问题,被无限期挂起。“企业资讯”改名叫“企业头条”(后定名为“数字头条”)。</p>
<p>可以看到,数字化运作是我们项目的一大亮点,也是一种运营手段。</p>
<p>期间,“数字证”,“数字保管箱”,“数字头条”是本人核心负责的模块,也参与“数字融资”的部分开发与管理工作。同时发挥自己的技术优势,开始对前端 WEB 开发进行规范性指导,解决开发团队面对的重点和难点问题。</p>
<h4 id="第三季度"><a href="#第三季度" class="headerlink" title="第三季度"></a>第三季度</h4><p>是的,大概从第二季度结尾期间,业务侧准备搞一点大事件,做营销活动。我被指派为营销活动的前端开发负责人。</p>
<p>之前原本计划负责的数字头条内部 CMS 系统建设由于本人的技术重心变更,业务也放弃了这方面的规划。</p>
<p>整个团队之前从未进行过营销活动方面的开发,可以说是毫无经验,我持有的部分经验无法带动带现有体系当中,所以做起来也多半是吃力不讨好的。</p>
<p>经过一番苦战,我主要负责新客大礼包的相关开发和管理,这也是业务准备重点推广的拉新活动。截止到 11 月份,新客大礼包的活动取得的效果卓著,拉新效果远远高出其他所有活动的总和。这一点也是令我们感到荣幸的。</p>
<p>部分开发人员由于合约到期,不能再进行驻场,也是经历几波迎来送往。</p>
<h4 id="第四季度"><a href="#第四季度" class="headerlink" title="第四季度"></a>第四季度</h4><p>团队内部对模块的管理出现了严重的分歧,管理层商议之下之后,决定将几个可以分离的模块分离出去以进行单独管理,以达到快速发版迭代的要求。于是本人被授命担任营销活动模块整体分离的负责人。由于分离需要进行全功能覆盖范围和迁移相关的兼容性测试,工作量较大,好在整个迁移过程平稳并未出现问题。迁移期间由于开发人员和测试人员配合到位,新客大礼包的营销效果一如既往的卓越。</p>
<p>迁移完成之后,由于当时的前端开发体系混乱(甚至有提到前端不需要架构、没有架构可言),本人被指派为前端架构优化整改的负责人之一。虽然说之一,但实际上之一可以拿掉的,另外几个负责人实际上由于各种各样的原因,并没有参与到其中。</p>
<p>在这期间,本人利用自己的技术优势,提供了大量的通用方法,也综合考虑不同的前端页面场景,着重探索了原生 APP 与 HTML5 页面之间的交互问题。提出的一些建议很快得到落实,给团队的整理开发能力上升了一个台阶。</p>
<p>另外,对于部分开发人员的代码风格混乱的场景,将之前建议的 lint 校验工具升级为强制校验。本质上是利用了 <code>git hooks</code> 在提交代码的时候进行代码检测。也算是自己对 Git 工程化辅助能力的一种很好的使用。</p>
<h4 id="综合回顾"><a href="#综合回顾" class="headerlink" title="综合回顾"></a>综合回顾</h4><p>在梳理和整合前端体系的时候,出现了很多令我捉摸不透的问题。这可能跟团队的性质有关。之前我们的团队的主要工作内容是创新性质的,而之后团队整合,变成了求稳。也或许是因为这样,诸多优秀的技术无法得到顺利的落地,在提升效率的道路上遇到了极为严重的阻碍。</p>
<p>在既有资源的支撑下,本人不遗余力的将诸多优秀的工具引入团队中,其中不乏包括优秀的 <code>webpack</code> 插件,极具指导性的风格指导,<code>eslint</code>,<code>shelljs</code>,<code>git hooks</code>,<code>stylus</code> 等。</p>
<p>核心依赖在确保不会出现重大问题的前提之下进行了升级,比如 <code>axios</code>,<code>core-js</code>,<code>vuex</code> 等工具,解决了一些已经被公开的安全漏洞。</p>
<p>期间也发现了团队内部的开发人员的水平普遍具有鲜明的个性,团队建设很多时候变成了一句空谈。可能心还是比较散漫吧,据说是被惯的。</p>
<h4 id="关于敏捷不得不说的一些事"><a href="#关于敏捷不得不说的一些事" class="headerlink" title="关于敏捷不得不说的一些事"></a>关于敏捷不得不说的一些事</h4><p>从我入职的时候开始,团队里面是有一个敏捷教练协助我们进行敏捷化转型。抛开敏捷转型的必要性和可执行性不谈,团队内部对于敏捷教练的态度是令我感到最为困惑的地方。</p>
<p>之前在拥有敏捷教练的团队里面待过,教练拥有非常高的权限,基本上是没有人敢顶撞教练的。然而在我们团队中间,敏捷教练仿佛成为了一个摆设,令不行,禁不止,转型过程谈不上成功。敏捷教练后半年退场,之后团队继续陷入混沌状态。</p>
<p>有一说一,在面对如此的一个团队的时候,可能没有人敢跳出来指正和纠偏吧。</p>
<p>本人对于敏捷的理解可能跟很多人的并不一致,我内心从来没有赞同过敏捷机制,但我尊重这个机制,毕竟在没有找到更加有效地方式之前,敏捷机制给团队带来的效果是显著的。</p>
<h3 id="个人项目"><a href="#个人项目" class="headerlink" title="个人项目"></a>个人项目</h3><h4 id="zob"><a href="#zob" class="headerlink" title="zob"></a><code>zob</code></h4><p>得益于团队内部开发团队能力的建设,我将搁置许久的 <code>zob</code> 项目捡了起来,并且更新了 <code>eslint</code> 插件,添加了一些规则。</p>
<h4 id="zmin"><a href="#zmin" class="headerlink" title="zmin"></a><code>zmin</code></h4><p>尚未整理和进行发布的执行压缩的工具,借助于 <code>image-min</code> 的能力,对常见图片 <code>jpg</code> 和 <code>png</code> 进行压缩,以减少其体积。</p>
<h3 id="人来人往"><a href="#人来人往" class="headerlink" title="人来人往"></a>人来人往</h3><h4 id="有人来"><a href="#有人来" class="headerlink" title="有人来"></a>有人来</h4><p>是的,新冠疫情缠绕我们一整年的时候,到目前为止还并未有丝毫退散之意,这足以令人唏嘘。在疫情笼罩一下,本人有幸能陪伴自己的爱人一路走来,并在 6 月份喜结连理,从此生命中多了一个至关重要的人。9 月份的婚宴,虽然不大,但已然是生命中美好的记忆点了。</p>
<h4 id="有人走"><a href="#有人走" class="headerlink" title="有人走"></a>有人走</h4><blockquote>
<p>逝者已去,生者不息。</p>
</blockquote>
<p>舅舅因疾病救治无效离开人世,给家族带来了悲伤难以挥去。文字太过悲伤,就不再对其进行描述了。</p>
<h3 id="吃喝玩乐"><a href="#吃喝玩乐" class="headerlink" title="吃喝玩乐"></a>吃喝玩乐</h3><h4 id="再回母校"><a href="#再回母校" class="headerlink" title="再回母校"></a>再回母校</h4><p>受限于疫情,妻子不太方便离深,故而并未去其他地方游玩。非要说一个,那就是我的母校湖南大学了。因为自己的身体原因,需要去大医院进行诊治,请了一个礼拜的假,带妻子一起去了长沙。在湘雅医院看病完成之后,便带她去了湖南大学。</p>
<p>彼时,地铁已经开通,可以直达我的母校。</p>
<h4 id="云南之行"><a href="#云南之行" class="headerlink" title="云南之行"></a>云南之行</h4><p>已经好几年没有出去旅游了,这一次,我们携手去往了云南,游玩了丽江古城,嬉戏于泸沽湖之上,还特意去探索了木府,本来应该有一篇游记进行记录的,奈何那个时候自己的重点压根不在文字上面,所以也就没有及时进行记录。等到后续有空,自己的记忆还没有淡去,进行添补也未尝不好。</p>
<h4 id="其他散点"><a href="#其他散点" class="headerlink" title="其他散点"></a>其他散点</h4><p>像洪湖公园,锦绣文化村,玫瑰海岸,大梅沙,海景公园此类市内景点,也是去游玩了一番的。只可惜莲花山的勒杜鹃画展妻子没有能够赶上,翻看单反随手拍的一些照片也算是一种参与方式吧。</p>
<h4 id="厨艺"><a href="#厨艺" class="headerlink" title="厨艺"></a>厨艺</h4><p>没错,因为要照顾妻子的缘故,我将多年搁置的厨艺捡了起来,也尝试许多不同的菜式。以前从来没有做过大菜的我,也进行了尝试。好在效果还算不错,味道也不是那么差,可以继续加油呢。</p>
<h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h3><p>已经很久没有进行总结和展望了,或许混沌的前两年给自己带来的改变,或许是抑郁抗争从未停止,我已经不太愿意去跟其他人谈论自己的总结和梦想,甚至连自我总结也不会再轻易提及。</p>
<p>随风来,随风去。</p>
<hr>
<p>最后,总要说点什么新年愿望的,那么我的愿望很简单,就是希望她们母女平安健康,这也是我接下来很长一段时间的核心任务。</p>
<p>至于自我成长,太过遥远,我们先放一放,能将自己的博客或者 <code>camphor</code> 项目捡起来就已经是对自己最大的回报了。</p>
<p>加油!</p>
]]></content>
<summary type="html">
2020 年的一些得失,一些故事,一些感悟。
</summary>
<category term="生活" scheme="https://xovel.cn/categories/life/"/>
<category term="经历" scheme="https://xovel.cn/tags/%E7%BB%8F%E5%8E%86/"/>
<category term="2020" scheme="https://xovel.cn/tags/2020/"/>
<category term="2021" scheme="https://xovel.cn/tags/2021/"/>
<category term="回顾" scheme="https://xovel.cn/tags/%E5%9B%9E%E9%A1%BE/"/>
</entry>
<entry>
<title>北京旅游攻略</title>
<link href="https://xovel.cn/article/travel-in-beijing.html"/>
<id>https://xovel.cn/article/travel-in-beijing.html</id>
<published>2019-04-14T15:37:56.000Z</published>
<updated>2021-02-10T06:01:42.422Z</updated>
<content type="html"><![CDATA[<p>场景描述:在北京国际会议中心下榻,晚上出游。</p>
<ol>
<li>天安门及周围</li>
</ol>
<p>天安门广场附近是夜北京最美的地方之一。白日里端庄威严的天安门城楼此时被灯光映衬晶莹剔透,仿佛一处玉雕殿堂。城楼前高低起伏的硕大喷泉,仿佛随歌起舞的仙子,轻灵、飘逸潇洒自如,引得无数游人驻足,甚至有不少年轻人走到喷泉近前,伸出双手去迎接那一朵朵四溅开来的珠花。</p>
<blockquote>
<p>前门大街可以考虑去逛逛。</p>
</blockquote>
<p>前门大街是北京著名商业街。位于京城中轴线,北起前门月亮湾,南至天桥路口,与天桥南大街相连。明嘉靖二十九年(1550)建外城前是皇帝出城赴天坛、山川坛的御路,建外城后为外城主要南北街道。</p>
<p>前门大街悠久的历史,造就了这里的许多中华老字号,如六必居酱园、同仁堂药店、瑞蚨祥绸布店、长春堂药店、内联升鞋店、张一元茶庄,还有月盛斋的酱肉店、都一处的烧卖店等16处老字号分列道路两侧。</p>
<blockquote>
<p>长安街也是绝佳的去处。</p>
</blockquote>
<p>长安街在北京,以致全国的的地位十分重要,中国的象征——天安门和天安门广场,就在长安街上,长安街两侧还有人民大会堂、中南海和公安部、商务部等其他中央政府的机关。</p>
<blockquote>
<p>东单/西单</p>
</blockquote>
<p>位于天安门广场的两侧。西单有商业街,东单有很值得一逛的银街小店。东单离王府井不远,可以一并逛逛。</p>
<ol start="2">
<li>什刹海</li>
</ol>
<blockquote>
<p>强烈推荐。可以去看看钟楼和南锣鼓巷,还有一个很有意思的烟袋斜街。</p>
</blockquote>
<p>这里风光优美,而且人文积淀深厚,既有南国水乡的清幽秀丽,又兼具北方皇家的雍容气度,既能感受普通百姓的生活气息,亦能寻访帝王将相昔日的烙印与足迹,是了解老北京历史与文化的绝佳之地,也是目前北京城内老北京风貌保存最完好的地方。</p>
<p>什刹海景区包括前海、后海、西海等水域以及沿岸众多名胜古迹和胡同民居,这里有宋庆龄故居、郭沫若故居、恭王府花园、广化寺、火神庙、钟鼓楼和银锭桥等古迹。</p>
<p>什刹海的夜,层次丰富、韵味浓厚,什刹海的夜,五彩斑斓、光怪陆离。这里可以乘船游览、赏花、游胡同、享美食,街边的小店更是藏满了神秘与诱惑。夏夜,灯火通明的酒吧一条街人头涌动,中外游人云集,古典与现代在这里完美交融,传统与前卫在这里激情碰撞,品酒眺湖,微风扑面,湖光粼粼,游船杨柳,窃窃私语,别有一番风味。</p>
<p>什刹海景区具有大量典型的胡同和四合院,如金丝套地区的大、小金丝胡同,南、北官房胡同和后海北沿的鸦儿胡同以及白米斜街、烟袋斜街等。</p>
<p>依托胡同和四合院,什刹海地区自古以来就有许多富有特色的民裕活动,如放荷灯、泛舟游湖、宴饮赏荷、冰床围酌、大阅冰鞋等。至今,一些有生命力的民俗活动仍然在什刹海地区大量存在,如钓鱼、游泳、划船、赛艇、下棋、弹唱、消夏舞会等。</p>
<ol start="3">
<li>簋街</li>
</ol>
<p>北京簋街的美食一条街可谓是不容错过。嘉陵楼馋嘴城、两岸一家、哈哈镜鸭脖子、宽板凳老灶火锅、胡大饭馆、金簋簋街小山城、俞家小院猪脚巷、兰溪小馆、江边城外烤全鱼等店子都可以去逛逛。</p>
<ol start="4">
<li>三里屯</li>
</ol>
<p>全北京的时尚中心之一、文化中心之一,世界各地的艺术、戏剧、音乐、商务、时尚、餐饮和购物在三里屯融汇。可以在户外的商业街区随心漫步,也可以享受室内餐饮和娱乐的空间。花园、庭院和小巷点缀其间,格局开阔,整体设计凸现空间无界的概念,让人漫步其中,体会无穷乐趣。从经典到前卫,三里屯带给人的感觉是持续变幻出新的,体验也是多方位的。夜色中的三里屯,是潮人的天堂。</p>
<ol start="5">
<li>鸟巢</li>
</ol>
<p>夜幕降临,灯光自鸟巢那盘根错节的无数钢柱中透射出来,加上水中的倒影,柔和之美与力量之美完美融合。而水立方那透亮的蓝光,让人仿佛到了塞班、马尔代夫,置身于清澈的海水中,感受海天一色的美,感受洁白的浪花打在身上时的凉爽。</p>
<p>鸟巢与水立方,一静一动,一刚一柔,相互烘托又相互映衬,加之国家体育场的身份,成为北京夜色的经典。</p>
<ol start="6">
<li>世贸天阶</li>
</ol>
<p>世贸天阶地处首都CBD区域,非常适合下班后休闲或谈事。</p>
<p>晚上通常会放映一些灯光秀或设计秀,这里周末都会聚集一大批文艺青年,来拍照摄影。</p>
<ol start="7">
<li>朝阳公园/蓝色港湾国际商区</li>
</ol>
<p>一个充满了灿烂阳光、幽静湖水、优雅建筑、浪漫小径的购物公园,一个位于亚洲最大的城市公园——朝阳公园西北湖岸的欧式商业小镇。</p>
<ol start="8">
<li>中央广播电视塔/玉渊潭</li>
</ol>
<p>中央广播电视塔是集广播电视发射和旅游观光、餐饮娱乐为一体的综合性建筑,是北京现代化的一个重要标志。中央广播电视塔共分20余层。塔的设计充分考虑首都北京的特殊地理环境,力图表现塔的中国属性和北京特色。中央广播电视塔的夜景照明也是一绝,曾被评为首都夜景照明工作一等奖。在晚上,仰视中央电视塔,如同一个大灯笼一样挂在空中。</p>
<p>玉渊潭公园樱花节,有机会可以去看看。不过鉴于是晚上,估计看不清,另外,要门票 10 块。</p>
<ol start="9">
<li>清华/北大</li>
</ol>
<p>凑数的。</p>
]]></content>
<summary type="html">
搜集的一篇关于北京旅游的文章,仅供参考。
</summary>
<category term="生活" scheme="https://xovel.cn/categories/life/"/>
<category term="旅游" scheme="https://xovel.cn/tags/%E6%97%85%E6%B8%B8/"/>
<category term="北京" scheme="https://xovel.cn/tags/%E5%8C%97%E4%BA%AC/"/>
</entry>
<entry>
<title>2018 年总结</title>
<link href="https://xovel.cn/article/summary-2018.html"/>
<id>https://xovel.cn/article/summary-2018.html</id>
<published>2018-12-31T08:53:15.000Z</published>
<updated>2019-01-04T16:41:41.251Z</updated>
<content type="html"><![CDATA[<blockquote>
<p>转眼已经是 2018 年的最后一天了,是时候来好好做一个全面的总结了。</p>
</blockquote>
<p>以上这段文字是<del>抄袭</del>自去年的总结。</p>
<p>不知道该写点什么,后面再说。</p>
<hr>
<p>元旦前后,忙于事务,未能更新本篇文章。思来想去,一个象征性的总结还是需要的,所以又回来写点什么吧。</p>
<p>今年(应该叫做去年了,仍然还有中恍惚感)在这个博客上面发布的文章数量竟未过十,想来自己的重心确实已经不在文字创作上面了吧。包括对《圣血记》的创作,停滞的状态从来没有变过。</p>
<hr>
<p>回顾一下 2018 年,令人唏嘘的事情太多,经历的波折也可以专门拎出来写一篇传记了。</p>
<hr>
<blockquote>
<p>其实本篇文章并不是真正意义的总结,真正的总结不在这里。</p>
</blockquote>
<!--
### 走马观花般的回顾
- 1 月,在中电那边的公司出了点不大不小的问题,但也只能迎难而上。同时,筹划新公司的成立。
- 2 月,过年了,我经历了心态上的一个极大的变化,并由此创造出了《圣血记·外传》的章节。核心角色叫做张青荷(后来才改的名),原本叫做轩辕青荷,是张青姿(也就是轩辕青姿)的胞妹。个中细节,因为故事的《圣血记》的整体搁置,也没有继续创作下去了。算是一个新坑。
- 3 月,风风火火的小创业项目开张进入开发期,具体的内容会在后面详述。
- 4 月,诸君不知吾心碎,奈何桥头顾影怜。
- 5 月,参加了童年好友的婚礼,放纵骄狂的队伍又少了一员主力。
- 6 月,火热的年华,终于与中电宣告离别,也临近了内心第二次巨大的波动期。
- 7 月,充满灰暗的下半年由此拉开序幕,首先,工作离我而去;其次,理想逐渐失色;更有萧非玉的出现,宣告了自己人生的失败。关于萧非玉如何出现,又映射的是谁,我想我大概不会再愿意去提起了。
- 8 月,总会有一些人和事,让自己的内心无比煎熬,我开始了堕落之旅,害怕晚上入睡。很长时间以来,只要我一闭上眼,就出现了萧非玉的形象,我的潜意思告诫我,疏远之,疏远之,可终究逃不过。这个时候,有另一个人出现,但并没有缓解多少,我依然还是失落。
- 9 月,上个月成功“劝退”的家伙,遇到了一些问题。我并没有那么足够有耐心,但是还是有了那样的耐心。或许麻痹的我早已经忘记了,努力让自己沉浸于工作之中,并以此为乐。
- 10 月,逐渐的开始发现,即使是背靠大山,躲进山洞,一样会受到风雨侵袭。
- 11 月,内心真正的第一次开始让自己有了转型的念头,但这并不够强烈。已经迷失方向的自己犹如漂泊在大海中的一搜小木船,不知该随波逐流还是逆浪而上。
- 12 月,突然想亲力亲为做一个系统,但这也仅仅是一个念头一闪而过。更多实质性的操作还有待细化。在命名的时候又陷入了困境,正所谓最困难的两件事就是命名和缓存,真真。最终以非常严肃的 `TMD` 作为项目的设定名称,嗯,嗯嗯。
### 关于张青荷
> 这个人跟下面要讲述的萧非玉,可谓是 2018 年最能扼杀我整个人生激情的角色了。~~这里说到扼杀确实是有些过激了~~。
在大学年代,我构思过一部小说,是讲述大学时光,青春懵懂情怀。男主角没有名字,有一个代号叫做“断无忌”,也就是后来我用的一个网名。女主角是许欣羽,但我已经忘记了这个角色原本的人设了,另一个重要的女角色是张青姿。
张青姿有着与众不同的魅力,虽然只是一个年纪轻轻的学生,却有着洞穿世人内心的能力,也数次拯救断无忌于水火,两人结下了深厚的友谊。当初创作这个角色的目的也只是想表示男女之间的友谊本可以纯净无暇。
而这种性格设定,刚好与《圣血记》中的另一个幕后人物极为相似,于是就将其迁移了过期,也是叫做张青姿,身份变更为轩辕家族的后人,也就是轩辕青姿。
当然,这个设定是因为轩辕青荷的原因。这个角色的出现表示我的心已经倒下,将其作为故事角色进行创作意味着我准备将其放下。虽然后来没能够成功,但也是一种尝试,当然,这些都是后话了。
我曾经很喜欢跟她聊天的状态,就算是她不回复,我也能找到内心的静谧。我很希望这种状态能够持续下去,就如同 2017 年我的生日愿望那样。终究是现实残酷,本身条件和资质都不是那么优秀的我,并没有得到伊人的芳心,她最终并不是选择我,我也只好将对她的一片算不上真心的真心掩藏起来,不再轻易告诉任何人,包括我自己。
蓦然一看,我确实已经深陷内心的囹圄。轩辕青荷角色雏形构建出来之后,我开始对其进行打磨和塑造,我妄图将其塑造成一个尽善尽美的角色,可终究太悲苦。为了不让轩辕青荷的角色显得孤单,我给她加了一个姐姐,因为这个世界,可能只有姐姐才最懂得疼惜人了——于是轩辕青姿就是这么出现了。
由于轩辕青荷行走时间的名称叫做张青姿,所以轩辕青荷自然就变成了张青荷。这个这个角色名称和原型的由来。然而,最终,我选择跟另外一个小伙伴一起开创了一家公司,创作之路就此中断。
可叹这世间多少悲欢离合,挡不住人们前进的步伐。我们创业的故事不在本次的总结范围之内,就不过多言明了。
### 关于萧非玉
> 这可能又是一段令人唏嘘的往事。
我的人生,可能早就已经注定跟萧姓分不开关系了,我甚至怀疑我上辈子是不是欠了萧姓什么?
《圣血记》一开始的女主角设定就是萧姓,或许就是冥冥之中天注定吧。
原本我跟她相识于 2016 年,当年的我是那么的血性、年少轻狂又不懂爱恨情仇,所以才放任了她许久。直到 2018 年年初,心灰意冷的我发表了为数不多的消极朋友圈,却被她安慰到。
虽然后来得知并非是她主动,但这一点安慰对于我来说却意味着重生之光(或许换一个“救命稻草”更为贴切)。
但我并没有表现出什么,只当作是曾经的一个朋友的日常互动。直到姐姐跟我提起,她有意撮合我跟她。那个时候,我才明白,这世间的确存在轮回一说,毕竟,能在两年之后再相识,通过这样奇怪的方式,也是一种莫大的机缘。
我开始慌了阵脚,不知道该如何相处。可能是创业公司的一堆事情让我感觉龃龉难行,自己的很多想法得不到肯定,所以一贯选择避世和随和的我选择妥协,磨平菱角的我最终独自承担了前端技术开发的所有工作。
我曾经将压力告诉她,但是她似乎并没有什么举动。或许还是因为我自身的条件太差劲,根本就不够入她的法眼。平下心来,但想,换做是我,我也嫌弃着自己。
此情可待成追忆,只是当时已惘然,这句话是对我跟她很好的总结吧。所以,在 7 月的某个不知道是下着雨还是吹着风的日子,我最困难的阶段,她选择弃我而去。
决然。
我想,我本身确实不够优秀,即便是拥有能俯瞰这个社会阶层的收入跟地位,也不能走进她的心。自那以后,我灰暗的下半年才刚刚开始。
我曾想过自己的过失,对她造成的困惑与影响。很抱歉了,我的出现已经对她造成了诸多的困扰。
萧非玉的角色大概就是在那个时候诞生的吧。为什么叫做萧非玉呢?
因为,她确实是她原本的姓氏,我逃不出这个怪圈,我不会埋怨任何人。毕竟,学会接受现实也是一种成长,说起来我还要感谢她。她若不告诉我她本性萧,或许萧非玉这个角色就永远不会存在。
玉这个字原本就是《圣血记》核心角色萧玉的名字,至于中间的“非”字,其实是一个双关:
- 人间四月芳菲尽中的“芳菲”,取另一半“菲”,没有草丛,没有树林,没有绿色,所以将其部首草字头移除,就是“非”字了。
- “非”本意就是不是(最初的意向字,鸟的双翅展开,表示相背),既然最终她选择离开,自然就不是我所追寻的萧玉。
> 三个字拼起来,感觉有点那么一丝丝的韵味了。
然而,从那以后,我的精神世界开始变得不再正常,我总是在梦里恍惚出现了她和萧非玉的形象,我已经分不清谁是谁了。难道机缘害我如斯?
我不想去辩驳这个问题,有些事情,不要弄清楚或许是最好的状态。
-->
<h3 id="接手的项目"><a href="#接手的项目" class="headerlink" title="接手的项目"></a>接手的项目</h3><p>回顾之下,发现,2018 年做的项目有点多,容我梳理梳理。</p>
<p>嗯,捡重要的简单罗列一下吧。</p>
<h4 id="空港出行管理后台"><a href="#空港出行管理后台" class="headerlink" title="空港出行管理后台"></a>空港出行管理后台</h4><p>这个是 2017 年开始接手的项目,2018 年将其做了一番深入开发,重构了页面框架,支持了大部分网约车相关的后台管理场景。</p>
<h4 id="空港专车"><a href="#空港专车" class="headerlink" title="空港专车"></a>空港专车</h4><p>一个微信小程序,来实现微信端呼叫网约车的功能。接手之后对齐进行了完全重构,但也是使用的原生的方式进行开发,贴近官方的语法。</p>
<h4 id="车享智能"><a href="#车享智能" class="headerlink" title="车享智能"></a>车享智能</h4><p>这个就是 2018 年我们的创业项目,一个妄图赶上共享经济时代的产品。从产品规划到技术实现,包括硬件和软件,我们都深度参与其中,最终做出了一个能面市的小规模产品。</p>
<h4 id="先导客服平台"><a href="#先导客服平台" class="headerlink" title="先导客服平台"></a>先导客服平台</h4><p>这是 7 月份加入新公司新团队之后负责的一款产品,该产品分为三个端,前端均由我进行主力开发。解决在 APP 端没有客服系统的尴尬并对数据、订单、投诉反馈进行统一的管理。</p>
<h4 id="先导约车管理后台"><a href="#先导约车管理后台" class="headerlink" title="先导约车管理后台"></a>先导约车管理后台</h4><p>从单独扒取 API 到重建系统页面,一个标准的从传统开发模式(即以 jQuery 为核心的一套框架)转向三大框架之一的 Vue 的迁移例子。百分之百的还原了出去按钮权限控制(后台并没有直接给出相应接口)之外的所有功能,并对大部分业务场景做了抽象化封装。</p>
<h4 id="先导约车微信端"><a href="#先导约车微信端" class="headerlink" title="先导约车微信端"></a>先导约车微信端</h4><p>类似上面的方式,使用 Vue 技术栈重构微信公众号页面,并解决了诸多之前存在的问题。目前的叫车体验比之前精进的不止一两点。</p>
<h4 id="先导运维管理系统"><a href="#先导运维管理系统" class="headerlink" title="先导运维管理系统"></a>先导运维管理系统</h4><p>辅助进行问题跟踪和页面调试。</p>
<h4 id="先导企业用车管理端"><a href="#先导企业用车管理端" class="headerlink" title="先导企业用车管理端"></a>先导企业用车管理端</h4><p>可以单独拎出来作为子系统的约车子系统,实现了企业用车的 WEB 操作界面独立化。</p>
<h3 id="个人项目"><a href="#个人项目" class="headerlink" title="个人项目"></a>个人项目</h3><h4 id="trademark-classification"><a href="#trademark-classification" class="headerlink" title="trademark-classification"></a><code>trademark-classification</code></h4><p>出于学习的目的,构建了本项目,用于快速查询商标。</p>
<h4 id="node-wxpay-test"><a href="#node-wxpay-test" class="headerlink" title="node-wxpay-test"></a><code>node-wxpay-test</code></h4><p>同样也是出于学习的目的,也是为了更好的实现车享智能项目,制作了这个项目,实践微信公众号支付。</p>
<h4 id="draw-io"><a href="#draw-io" class="headerlink" title="draw.io"></a><code>draw.io</code></h4><p>这个项目是在 2018 年年底萌生的转型想法的雏形项目,是利用在线项目 <code>draw.io</code> 构建流程图的项目载体。</p>
<h4 id="api-test"><a href="#api-test" class="headerlink" title="api-test"></a><code>api-test</code></h4><p>一个简单版本的 API 测试工具,非常简单,简单到我已经将它给删了。</p>
<h4 id="vue-cli3-demo"><a href="#vue-cli3-demo" class="headerlink" title="vue-cli3-demo"></a><code>vue-cli3-demo</code></h4><p>听说 <code>Vue CLI 3</code> 更新了新版本,所以就有了这么一个演示版本。</p>
<h4 id="gank"><a href="#gank" class="headerlink" title="gank"></a><code>gank</code></h4><p>根据干货集中营提供的开放接口,使用 <code>vue</code> 构建了一个 WEB 端。</p>
<h4 id="garden"><a href="#garden" class="headerlink" title="garden"></a><code>garden</code></h4><p>之前位于博客的花园项目,独立出来了。主要是用来展示一些简单的工具和在线文档的。</p>
<h3 id="新增的技术栈"><a href="#新增的技术栈" class="headerlink" title="新增的技术栈"></a>新增的技术栈</h3><p>很惭愧,2018 年在技术栈可谓是毫无建树,并没有追加什么新技术栈。只是稳固了这么久以来使用到的一些技术和知识,特别是 <code>vue</code>,目前已经逐渐变成一个重度使用者了。</p>
<p><code>node</code> 是用的逐渐多了起来,但很多也只是停留在个人实验性阶段,并没有实际的应用,顶多也只是做一个中间件或者转发请求,这些原本使用 <code>nginx</code> 就可以轻松做到。</p>
<h3 id="尝试过的技术"><a href="#尝试过的技术" class="headerlink" title="尝试过的技术"></a>尝试过的技术</h3><ul>
<li><code>react</code></li>
<li><code>dart</code></li>
<li><code>flutter</code></li>
<li><code>redis</code></li>
<li><code>docker</code></li>
</ul>
<blockquote>
<p>仅仅是尝试,挺有意思的,学无止境,大概说的就是这个吧。</p>
</blockquote>
<h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h3><p>去年提出的展望是这个:</p>
<blockquote>
<ul>
<li>遇见更好的自己。</li>
<li>让自己内心更加平静。</li>
<li>努力提升自己的情商和魅力值。</li>
</ul>
</blockquote>
<p>很遗憾,只有第二条算做到了。第一条勉强也算,但是第三条的话,因为 7 月份的时候一些事情的发生,苗头被迅速抹杀,同时也直接造就了《圣血记外传之萧非玉》的萌芽。相关细节由于过于悲苦,过往不愿再被提起,就此长久搁置。</p>
<p>回顾整个 2018 年,上半年我是阳光灿烂的存在,但是 7 月份的转机过大,灰霾阴郁持续笼罩。经历了长达半年的失眠抑郁,我却依然没有倒下,充满希望的我收拾自己的行囊,重新踏上征程。灰暗存在,或许只是为了衬托光明的存在。</p>
<h3 id="展望-2019"><a href="#展望-2019" class="headerlink" title="展望 2019"></a>展望 2019</h3><p>没什么,只有一点:继续让自己更加平静。</p>
<p>加油!</p>
<hr>
<p>其实,可以看得出来,我已经不太愿意去写博客了,很多东西其实在我的日志项目中已经做了记录,大部分的技术攻略或者资料均做了简单总结。</p>
<p>前路漫漫,珍重。</p>
]]></content>
<summary type="html">
2018 年年末大总结。
</summary>
<category term="生活" scheme="https://xovel.cn/categories/life/"/>
<category term="总结" scheme="https://xovel.cn/tags/%E6%80%BB%E7%BB%93/"/>
<category term="经历" scheme="https://xovel.cn/tags/%E7%BB%8F%E5%8E%86/"/>
<category term="2018" scheme="https://xovel.cn/tags/2018/"/>
<category term="2019" scheme="https://xovel.cn/tags/2019/"/>
</entry>
<entry>
<title>VSCode 扩展</title>
<link href="https://xovel.cn/article/vscode-extensions.html"/>
<id>https://xovel.cn/article/vscode-extensions.html</id>
<published>2018-10-26T16:05:43.000Z</published>
<updated>2018-10-26T16:47:02.304Z</updated>
<content type="html"><![CDATA[<blockquote>
<p>之前曾经介绍过一个跟扩展相关的文章,那已经是 18 个月前的事情了:<a href="/article/brackets-emmet.html">Brackets</a>。</p>
<p>近日将再记录两篇文章,一个是跟 <code>VSCode</code> 的扩展,另一个是 <code>Chrome</code> 浏览器的扩展。列出的扩展是本人<strong>使用过</strong>的。本文讲述 <code>VSCode</code> 的扩展。</p>
</blockquote>
<p>话不多说,直接进入正题,本次列举的扩展如下:</p>
<h3 id="Auto-Close-Tag-和-Auto-Rename-Tag"><a href="#Auto-Close-Tag-和-Auto-Rename-Tag" class="headerlink" title="Auto Close Tag 和 Auto Rename Tag"></a>Auto Close Tag 和 Auto Rename Tag</h3><p>这两个扩展通常会放在一起,前者是自动闭合 HTML 标签的,后者是自动重命名 HTML 标签的。</p>
<h3 id="Beautify"><a href="#Beautify" class="headerlink" title="Beautify"></a>Beautify</h3><p>代码格式化工具。</p>
<h3 id="Bracket-Pair-Colorizer"><a href="#Bracket-Pair-Colorizer" class="headerlink" title="Bracket Pair Colorizer"></a>Bracket Pair Colorizer</h3><p>括号匹配高亮。非常实用的一个扩展。</p>
<h3 id="Color-Picker"><a href="#Color-Picker" class="headerlink" title="Color Picker"></a>Color Picker</h3><p>CSS 颜色选择器。</p>
<h3 id="Debugger-for-Chrome"><a href="#Debugger-for-Chrome" class="headerlink" title="Debugger for Chrome"></a>Debugger for Chrome</h3><p>调试神器。</p>
<h3 id="Document-This"><a href="#Document-This" class="headerlink" title="Document This"></a>Document This</h3><p>自动对代码进行智能注释,兼容 <code>JSDoc</code>,可以作用域 <code>function</code>、<code>class</code> 等地方。默认快捷键为<strong>按两次</strong> <code>Ctrl+Alt+D</code>。</p>
<h3 id="ESLint"><a href="#ESLint" class="headerlink" title="ESLint"></a>ESLint</h3><p><code>ESLint</code> 在 <code>VSCode</code> 中的应用。</p>
<h3 id="Git-History"><a href="#Git-History" class="headerlink" title="Git History"></a>Git History</h3><p>管理 Git 提交记录的工具。在多项目中也表现优异。</p>
<h3 id="Guides"><a href="#Guides" class="headerlink" title="Guides"></a>Guides</h3><p>空白换行等的可视化标示。</p>
<h3 id="Markdown-PDF"><a href="#Markdown-PDF" class="headerlink" title="Markdown PDF"></a>Markdown PDF</h3><p>将 markdown 文件转换为 PDF,同时支持转换为 html、jpeg 和 png。</p>
<h3 id="Markdown-TOC"><a href="#Markdown-TOC" class="headerlink" title="Markdown TOC"></a>Markdown TOC</h3><p>给 markdown 生成目录并自动更新。</p>
<h3 id="Material-Icon-Theme"><a href="#Material-Icon-Theme" class="headerlink" title="Material Icon Theme"></a>Material Icon Theme</h3><p>一套 Material Design 风格的文件图标。</p>
<h3 id="Polacode"><a href="#Polacode" class="headerlink" title="Polacode"></a>Polacode</h3><p>将指定代码生成一张看起来挺不错的图片。</p>
<h3 id="RegExp-Preview-and-Editor"><a href="#RegExp-Preview-and-Editor" class="headerlink" title="RegExp Preview and Editor"></a>RegExp Preview and Editor</h3><p>正则表达式的可视化工具。</p>
<h3 id="Sublime-Text-Keymap-and-Settings-Importer"><a href="#Sublime-Text-Keymap-and-Settings-Importer" class="headerlink" title="Sublime Text Keymap and Settings Importer"></a>Sublime Text Keymap and Settings Importer</h3><p>使用 Sublime 的快捷键。之前习惯使用 Sublime,所以也将几个常用的快捷键搬了过来。</p>
<h3 id="SVG-Viewer"><a href="#SVG-Viewer" class="headerlink" title="SVG Viewer"></a>SVG Viewer</h3><p><code>svg</code> 图片直接查看工具。</p>
<h3 id="Toggle-Quotes"><a href="#Toggle-Quotes" class="headerlink" title="Toggle Quotes"></a>Toggle Quotes</h3><p>切换引号。引号组是 <code>"</code>、<code>'</code>、<code>`</code>。</p>
<h3 id="Vetur"><a href="#Vetur" class="headerlink" title="Vetur"></a>Vetur</h3><p>是的,就是 <code>vue</code>。</p>
<hr>
<p>介绍完毕。</p>
<p><del>下一篇的走起了。</del></p>
]]></content>
<summary type="html">
本文简单介绍本人在实际开发中使用到的几个 VSCode 扩展。
</summary>
<category term="随笔" scheme="https://xovel.cn/categories/essay/"/>
<category term="VSCode" scheme="https://xovel.cn/tags/vscode/"/>
<category term="扩展" scheme="https://xovel.cn/tags/extension/"/>
</entry>
<entry>
<title>Chrome 扩展</title>
<link href="https://xovel.cn/article/chrome-extensions.html"/>
<id>https://xovel.cn/article/chrome-extensions.html</id>
<published>2018-10-26T16:05:43.000Z</published>
<updated>2018-10-26T17:16:31.303Z</updated>
<content type="html"><![CDATA[<blockquote>
<p>之前曾经介绍过一个跟扩展相关的文章,那已经是 18 个月前的事情了:<a href="/article/brackets-emmet.html">Brackets</a>。</p>
<p>近日将再记录两篇文章,一个是跟 <code>VSCode</code> 的扩展,另一个是 <code>Chrome</code> 浏览器的扩展。列出的扩展是本人<strong>使用过</strong>的。本文讲述 <code>Chrome</code> 的扩展。</p>
</blockquote>
<p>话不多说,直接进入正题,本次列举的扩展如下:</p>
<h3 id="AdBlock"><a href="#AdBlock" class="headerlink" title="AdBlock"></a>AdBlock</h3><p>广告拦截插件,实力拦截不入眼的东西。</p>
<h3 id="Axure-RP-Extension-for-Chrome"><a href="#Axure-RP-Extension-for-Chrome" class="headerlink" title="Axure RP Extension for Chrome"></a>Axure RP Extension for Chrome</h3><p>Axure 原型图工具导出的 HTML 文档的查看工具,直接通过 file 协议查看的话会有所限制,使用该插件之后就可以愉快的浏览 Axure 的制作的原型图了。</p>
<blockquote>
<p>目前已经转战墨刀。</p>
</blockquote>
<h3 id="GitHub-Hovercard"><a href="#GitHub-Hovercard" class="headerlink" title="GitHub Hovercard"></a>GitHub Hovercard</h3><p><code>GitHub</code> 辅助工具,鼠标悬浮上去的时候拉取关键信息并进行显示。</p>
<h3 id="Isometric-Contributions"><a href="#Isometric-Contributions" class="headerlink" title="Isometric Contributions"></a>Isometric Contributions</h3><p>在 <code>GitHub</code> 首页,将贡献记录渲染成 <code>3D</code> 视图,更加立体的展现。</p>
<h3 id="JSONView"><a href="#JSONView" class="headerlink" title="JSONView"></a>JSONView</h3><p>格式化 <code>JSON</code> 文件。</p>
<h3 id="OctoLinker"><a href="#OctoLinker" class="headerlink" title="OctoLinker"></a>OctoLinker</h3><p>快速查看代码中引用的文件或类库。</p>
<h3 id="Octotree"><a href="#Octotree" class="headerlink" title="Octotree"></a>Octotree</h3><p><code>GitHub</code> 项目查看时使用 Code tree 模式进行查看和管理。</p>
<h3 id="Vue-js-devtools"><a href="#Vue-js-devtools" class="headerlink" title="Vue.js devtools"></a>Vue.js devtools</h3><p><code>Vue</code> 开发工具。</p>
<h3 id="Wappalyzer"><a href="#Wappalyzer" class="headerlink" title="Wappalyzer"></a>Wappalyzer</h3><p>检测当前访问的网站所使用到的技术,包含服务器、使用到的工具、框架等等。</p>
<hr>
<blockquote>
<p>以下部分安装在非 <code>Chrome</code> 浏览器上,但是也是在 <code>Chromium</code> 内核的浏览器运行的扩展/插件。</p>
</blockquote>
<h3 id="CSSViewer"><a href="#CSSViewer" class="headerlink" title="CSSViewer"></a>CSSViewer</h3><p>CSS 查看工具。</p>
<h3 id="Fiddler"><a href="#Fiddler" class="headerlink" title="Fiddler"></a>Fiddler</h3><p>简单的 API 侦听工具。</p>
<h3 id="Frameworks"><a href="#Frameworks" class="headerlink" title="Frameworks"></a>Frameworks</h3><p>跟上面的 <code>Wappalyzer</code> 的功能类似,但只检测使用到的框架和类库。</p>
<h3 id="Page-Ruler"><a href="#Page-Ruler" class="headerlink" title="Page Ruler"></a>Page Ruler</h3><p>页面尺寸丈量工具。</p>
<h3 id="Postman-Interceptor"><a href="#Postman-Interceptor" class="headerlink" title="Postman Interceptor"></a>Postman Interceptor</h3><p>Postman 拦截器工具。</p>
<blockquote>
<p>依然不能愉快的解决跨域问题,所以直接弃用了,采用了客户端软件。浏览器的自己编写了超级简单的一个<a href="https://hdk4.com/garden/tools/api-test.html" target="_blank" rel="noopener">工具</a>。</p>
</blockquote>
<h3 id="QQ空间放大"><a href="#QQ空间放大" class="headerlink" title="QQ空间放大"></a>QQ空间放大</h3><p>专门用于放大 <code>QQ空间</code> 里面的图片的一个工具。<del>现在已经基本不逛了</del>。</p>
<h3 id="Redirector"><a href="#Redirector" class="headerlink" title="Redirector"></a>Redirector</h3><p>伪装重定向工具,通过某种设置可以做出翻墙工具的效果,但有效性堪忧。</p>
<h3 id="Responsive-Web-Design-Tester"><a href="#Responsive-Web-Design-Tester" class="headerlink" title="Responsive Web Design Tester"></a>Responsive Web Design Tester</h3><p>快速切换浏览器大小。</p>
<h3 id="Web-Developer"><a href="#Web-Developer" class="headerlink" title="Web Developer"></a>Web Developer</h3><p>很实用的一套 WEB 开发工具组合。</p>
<h3 id="WhatFont"><a href="#WhatFont" class="headerlink" title="WhatFont"></a>WhatFont</h3><p>快速查看 CSS 字体。</p>
<h3 id="好声音"><a href="#好声音" class="headerlink" title="好声音"></a>好声音</h3><p>获取当前网页中的音效和音乐的实际地址。</p>
<h3 id="眼不见心不烦(新浪微博)"><a href="#眼不见心不烦(新浪微博)" class="headerlink" title="眼不见心不烦(新浪微博)"></a>眼不见心不烦(新浪微博)</h3><p>新浪微博美化工具。</p>
<h3 id="草料二维码"><a href="#草料二维码" class="headerlink" title="草料二维码"></a>草料二维码</h3><p>二维码管理工具。</p>
]]></content>
<summary type="html">
本文简单介绍本人在实际开发中使用到的几个 Chrome 扩展。
</summary>
<category term="随笔" scheme="https://xovel.cn/categories/essay/"/>
<category term="扩展" scheme="https://xovel.cn/tags/extension/"/>
<category term="Chrome" scheme="https://xovel.cn/tags/chrome/"/>
</entry>
<entry>
<title>Buffer 简介</title>
<link href="https://xovel.cn/article/node-buffer.html"/>
<id>https://xovel.cn/article/node-buffer.html</id>
<published>2018-10-07T14:05:26.000Z</published>
<updated>2018-10-07T15:13:42.490Z</updated>
<content type="html"><![CDATA[<p><code>Buffer</code> 是 <code>node</code> 中的一个全局对象,用来读取或者操作二进制数据流。</p>
<a id="more"></a>
<blockquote>
<p>本文直接使用 <code>Buffer</code> 讲述这个对象,该对象翻译成中文,可以叫做“缓冲区对象”。</p>
</blockquote>
<p><a href="https://nodejs.org/api/buffer.html" target="_blank" rel="noopener"><strong>官方文档</strong></a>的介绍如下:</p>
<blockquote>
<p>Prior to the introduction of <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray" target="_blank" rel="noopener">TypedArray</a>, the JavaScript language had no mechanism for reading or manipulating streams of binary data. The Buffer class was introduced as part of the Node.js API to enable interaction with octet streams in TCP streams, file system operations, and other contexts.</p>
</blockquote>
<p>在 <code>ECMAScript 2015</code> 引入 <code>TypedArray</code> 之后,<code>Buffer</code> 类使用了一种更优化、更适合 <code>Node.js</code> 用例的方式实现了 <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array" target="_blank" rel="noopener"><code>Uint8Array</code></a> API。</p>
<p><code>Buffer</code> 类可以视作一个跟 <code>Array</code> 类一样的对象,区别在于 <code>Buffer</code> 的大小是固定的,且在 <code>v8</code> <strong>堆外</strong>分配物理内存。<code>Buffer</code> 的大小在创建时就确定了,无法调整。</p>
<p>先来看一段官方文档提供的示例代码:</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Creates a zero-filled Buffer of length 10.</span></span><br><span class="line"><span class="keyword">const</span> buf1 = Buffer.alloc(<span class="number">10</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">// Creates a Buffer of length 10, filled with 0x1.</span></span><br><span class="line"><span class="keyword">const</span> buf2 = Buffer.alloc(<span class="number">10</span>, <span class="number">1</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">// Creates an uninitialized buffer of length 10.</span></span><br><span class="line"><span class="comment">// This is faster than calling Buffer.alloc() but the returned</span></span><br><span class="line"><span class="comment">// Buffer instance might contain old data that needs to be</span></span><br><span class="line"><span class="comment">// overwritten using either fill() or write().</span></span><br><span class="line"><span class="keyword">const</span> buf3 = Buffer.allocUnsafe(<span class="number">10</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">// Creates a Buffer containing [0x1, 0x2, 0x3].</span></span><br><span class="line"><span class="keyword">const</span> buf4 = Buffer.from([<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>]);</span><br><span class="line"></span><br><span class="line"><span class="comment">// Creates a Buffer containing UTF-8 bytes [0x74, 0xc3, 0xa9, 0x73, 0x74].</span></span><br><span class="line"><span class="keyword">const</span> buf5 = Buffer.from(<span class="string">'tést'</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">// Creates a Buffer containing Latin-1 bytes [0x74, 0xe9, 0x73, 0x74].</span></span><br><span class="line"><span class="keyword">const</span> buf6 = Buffer.from(<span class="string">'tést'</span>, <span class="string">'latin1'</span>);</span><br></pre></td></tr></table></figure>
<hr>
<p><code>Buffer</code> 实例一般用于表示编码字符的序列,用过指定字符编码,可以在 <code>Buffer</code> 实例与常规 <code>JavaScript</code> 字符串之间进行相互转换。</p>
<p>这样的描述,可能太过于抽象,直接上代码解释吧:</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">btoa</span>(<span class="params">str</span>) </span>{</span><br><span class="line"> <span class="keyword">const</span> buf = Buffer.from(str);</span><br><span class="line"> <span class="keyword">return</span> buf.toString(<span class="string">'base64'</span>);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">atob</span>(<span class="params">str</span>) </span>{</span><br><span class="line"> <span class="keyword">const</span> buf = Buffer.from(str, <span class="string">'base64'</span>);</span><br><span class="line"> <span class="keyword">return</span> buf.toString();</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>上面的代码,是 <code>node</code> 环境下关于浏览器 <a href="https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/atob" target="_blank" rel="noopener"><code>atob</code></a> 和 <a href="https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/btoa" target="_blank" rel="noopener"><code>btoa</code></a> 方法的实现。</p>
<p><code>Node.js</code> 目前支持的字符编码如下:</p>
<ul>
<li><code>ascii</code>,仅支持 7 位 ASCII 数据。</li>
<li><code>utf8</code>,多字节编码的 Unicode 字符。许多网页和其他文档格式都使用 <code>UTF-8</code>。</li>
<li><code>utf16le</code>,2 或 4 字节,<code>little-endian</code>(小字节序)编码的 Unicode 字符。支持 <code>U+10000</code> 到 <code>U+10FFFF</code> 的代理对。</li>
<li><code>usc2</code>,即 <code>utf16le</code>。</li>
<li><code>base64</code>,即 <code>Base64</code> 编码。</li>
<li><code>latin1</code>,即 <code>Latin-1</code> 编码,具体由 IANA 在 <a href="https://tools.ietf.org/html/rfc1345" target="_blank" rel="noopener">RFC1345</a> 中定义。</li>
<li><code>binary</code>,即 <code>latin1</code>。</li>
<li><code>hex</code>,将每个字节编码为两个十六进制字符。</li>
</ul>
<blockquote>
<p>注意,现代浏览器遵循 <a href="https://encoding.spec.whatwg.org/" target="_blank" rel="noopener">WHATWG 编码标准</a> 将 <code>latin1</code> 和 <code>ISO-8859-1</code> 别名为 <code>win-1252</code>。这意味着在进行例如 <code>http.get()</code> 获取到的字符编码在规范列表中,服务器可能返回 <code>win-1252</code> 编码的数据,此时如果使用 <code>latin1</code> 字符编码,可能会得到错误的解码数据。</p>
</blockquote>
<p><code>Buffer</code> 对象可以使用 <code>for...of</code> 进行内部迭代。同样的,实例对象的 <code>.values</code>、<code>.keys</code> 和 <code>.entries</code> 方法都可以创建迭代。</p>
<p>使用 <code>new</code> 操作符实例化一个 <code>Buffer</code> 的方法已经被弃用。注意,<strong>已经弃用的方法本文不做介绍</strong>。</p>
<p>创建 <code>Buffer</code> 实例的方法有下面几个:</p>
<ul>
<li><code>Buffer.from(array)</code>,从数组进行创建。</li>
<li><code>Buffer.from(arrayBuffer[, byteOffset[, length]])</code>,从 <code>arrayBuffer</code> 的实例进行创建。</li>
<li><code>Buffer.from(buffer)</code>,直接根据 <code>buffer</code> 创建。</li>
<li><code>Buffer.from(string[, encoding])</code>,根据字符串创建,<code>encoding</code> 即使用的编码方式。</li>
<li><code>Buffer.from(object[, offsetOrEncoding[, length]])</code>,根据对象创建,该对象需要支持 <code>Symbol.toPrimitive</code> 或者有 <code>valueOf()</code> 方法,比如 <code>Buffer.from(new String('this is a test'));</code>。</li>
<li><code>Buffer.alloc(size[, fill[, encoding]])</code>,创建一个指定长度的对象,<code>fill</code> 表示用来填充新建的 <code>Buffer</code> 的值,默认为 <code>0</code>。</li>
<li><code>Buffer.allocUnsafe(size)</code>,分配一个大小为 <code>size</code> 的对象。该方式创建的 <code>Buffer</code> 对象是未经过初始化的,内容未知,可能包含敏感数据。</li>
</ul>
<blockquote>
<p>更多的创建方式不在本文的记述范围之内。</p>
</blockquote>
<p>创建之后的实例,我们使用 <code>buf</code> 进行表示,<code>buf</code> 的特性跟数组类似。</p>
<p><code>buf.buffer</code> 指向了 <code>Buffer</code> 底层的 <code>ArrayBuffer</code> 对象。</p>
<p>可以使用 <code>fill</code> 方法进行填充,语法为 <code>buf.fill(value[, offset[, end]][, encoding])</code>。</p>
<p><code>toString</code> 可以将 <code>buf</code> 转为一个常规字符串,语法为 <code>buf.toString([encoding[, start[, end]]])</code>。</p>
<p>之前做了一个简单的获取网页源代码的方法,代码大概是这样的:</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> http = <span class="built_in">require</span>(<span class="string">'http'</span>);</span><br><span class="line"><span class="keyword">const</span> https = <span class="built_in">require</span>(<span class="string">'https'</span>);</span><br><span class="line"></span><br><span class="line"><span class="built_in">module</span>.exports = <span class="function"><span class="keyword">function</span> <span class="title">getHTML</span>(<span class="params">url</span>) </span>{</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function"><span class="keyword">function</span> (<span class="params">resolve, reject</span>) </span>{</span><br><span class="line"> (<span class="regexp">/^https/i</span>.test(url) ? https : http).get(url, <span class="function"><span class="keyword">function</span> (<span class="params">res</span>) </span>{</span><br><span class="line"> <span class="keyword">var</span> html = <span class="string">''</span>;</span><br><span class="line"></span><br><span class="line"> res.on(<span class="string">'data'</span>, <span class="function"><span class="keyword">function</span> (<span class="params">chunk</span>) </span>{</span><br><span class="line"> <span class="comment">// chunk is a Buffer instance, use the method toString to get the string</span></span><br><span class="line"> html += chunk;</span><br><span class="line"> });</span><br><span class="line"></span><br><span class="line"> res.on(<span class="string">'end'</span>, <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>{</span><br><span class="line"> resolve(html);</span><br><span class="line"> });</span><br><span class="line"> }).on(<span class="string">'error'</span>, <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>{</span><br><span class="line"> reject();</span><br><span class="line"> });</span><br><span class="line"> });</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>是的,这里面的 <code>chunk</code> 对象就是一个 <code>Buffer</code> 实例。</p>
<hr>
<p>真·简介。本文到此就结束了。</p>
]]></content>
<summary type="html">
<p><code>Buffer</code> 是 <code>node</code> 中的一个全局对象,用来读取或者操作二进制数据流。</p>
</summary>
<category term="Node" scheme="https://xovel.cn/categories/node/"/>
<category term="node" scheme="https://xovel.cn/tags/node/"/>
<category term="buffer" scheme="https://xovel.cn/tags/buffer/"/>
</entry>
<entry>
<title>ES6 模块</title>
<link href="https://xovel.cn/article/es6-modules.html"/>
<id>https://xovel.cn/article/es6-modules.html</id>
<published>2018-05-24T09:54:29.000Z</published>
<updated>2021-02-03T13:08:21.540Z</updated>
<content type="html"><![CDATA[<blockquote>
<p>阅读本文需要有一定的 ES6 基础。</p>
</blockquote>
<p>ES6 模块是 ES6 中的一个非常重要的特性,它收集了多年来各种模块化的优点,解决了其间的差异化,并期望能最终形成一个大家共同遵守的规范。</p>
<blockquote>
<p>关于 JS 的模块化历程,可以参考 <a href="https://appendto.com/2016/06/the-short-history-of-javascript-module-loaders/" target="_blank" rel="noopener">这篇文章</a>。</p>
</blockquote>
<p>本文从 <code>import</code> 和 <code>export</code> 两部分对 ES6 模块做一个基础的介绍,这两部分内容也就是 ES6 模块的全部了。</p>
<h3 id="import"><a href="#import" class="headerlink" title="import"></a>import</h3><p>来看一组现有的 <code>import</code> 语法:</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> defaultExport <span class="keyword">from</span> <span class="string">"module-name"</span>;</span><br><span class="line"><span class="keyword">import</span> * <span class="keyword">as</span> name <span class="keyword">from</span> <span class="string">"module-name"</span>;</span><br><span class="line"><span class="keyword">import</span> { <span class="keyword">export</span> } <span class="keyword">from</span> <span class="string">"module-name"</span>;</span><br><span class="line"><span class="keyword">import</span> { <span class="keyword">export</span> <span class="keyword">as</span> alias } <span class="keyword">from</span> <span class="string">"module-name"</span>;</span><br><span class="line"><span class="keyword">import</span> { export1 , export2 } <span class="keyword">from</span> <span class="string">"module-name"</span>;</span><br><span class="line"><span class="keyword">import</span> { export1 , export2 <span class="keyword">as</span> alias2 , [...] } <span class="keyword">from</span> <span class="string">"module-name"</span>;</span><br><span class="line"><span class="keyword">import</span> defaultExport, { <span class="keyword">export</span> [ , [...] ] } <span class="keyword">from</span> <span class="string">"module-name"</span>;</span><br><span class="line"><span class="keyword">import</span> defaultExport, * <span class="keyword">as</span> name <span class="keyword">from</span> <span class="string">"module-name"</span>;</span><br><span class="line"><span class="keyword">import</span> <span class="string">"module-name"</span>;</span><br></pre></td></tr></table></figure>
<blockquote>
<p>以上代码来自 MDN 上面关于 <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import" target="_blank" rel="noopener">import</a> 的介绍。</p>
</blockquote>
<p><code>import</code> 是模块导入语句的关键字,通过指定具体的导入方式,可以进行相应模块的导入操作。</p>
<p>以下是逐条说明:</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 导入默认模块</span></span><br><span class="line"><span class="keyword">import</span> defaultExport <span class="keyword">from</span> <span class="string">"module-name"</span>;</span><br><span class="line"><span class="comment">// 导入所有模块并指定一个新的名称,导入后的对象包含了所有具名模块</span></span><br><span class="line"><span class="keyword">import</span> * <span class="keyword">as</span> name <span class="keyword">from</span> <span class="string">"module-name"</span>;</span><br><span class="line"><span class="comment">// 导入指定模块</span></span><br><span class="line"><span class="keyword">import</span> { <span class="keyword">export</span> } <span class="keyword">from</span> <span class="string">"module-name"</span>;</span><br><span class="line"><span class="comment">// 导入指定的模块并指定一个新的名称,即直接进行重命名操作</span></span><br><span class="line"><span class="keyword">import</span> { <span class="keyword">export</span> <span class="keyword">as</span> alias } <span class="keyword">from</span> <span class="string">"module-name"</span>;</span><br><span class="line"><span class="comment">// 导入多个模块</span></span><br><span class="line"><span class="keyword">import</span> { export1 , export2 } <span class="keyword">from</span> <span class="string">"module-name"</span>;</span><br><span class="line"><span class="comment">// 导入多个模块,并对其中的某一部分进行重命名</span></span><br><span class="line"><span class="keyword">import</span> { export1 , export2 <span class="keyword">as</span> alias2 , [...] } <span class="keyword">from</span> <span class="string">"module-name"</span>;</span><br><span class="line"><span class="comment">// 同时导入默认模块和其他模块</span></span><br><span class="line"><span class="keyword">import</span> defaultExport, { <span class="keyword">export</span> [ , [...] ] } <span class="keyword">from</span> <span class="string">"module-name"</span>;</span><br><span class="line"><span class="comment">// 同时导入模块模块,并将所有模块以新名称进行导入</span></span><br><span class="line"><span class="keyword">import</span> defaultExport, * <span class="keyword">as</span> name <span class="keyword">from</span> <span class="string">"module-name"</span>;</span><br><span class="line"><span class="comment">// 直接引入模块,不导入任何东西</span></span><br><span class="line"><span class="keyword">import</span> <span class="string">"module-name"</span>;</span><br></pre></td></tr></table></figure>
<h3 id="export"><a href="#export" class="headerlink" title="export"></a>export</h3><p><code>export</code> 是模块导出语句的关键字,同样的,来看一组 <code>export</code> 的语法,代码来自 MDN 上面的 <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export" target="_blank" rel="noopener">export</a>:</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 导出指定模块</span></span><br><span class="line"><span class="keyword">export</span> { name1, name2, …, nameN };</span><br><span class="line"><span class="comment">// 导出指定模块,并进行重命名</span></span><br><span class="line"><span class="keyword">export</span> { variable1 <span class="keyword">as</span> name1, variable2 <span class="keyword">as</span> name2, …, nameN };</span><br><span class="line"><span class="comment">// 导出变量</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">let</span> name1, name2, …, nameN; <span class="comment">// also var</span></span><br><span class="line"><span class="comment">// 导出变量,并对变量直接进行定义</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">let</span> name1 = …, name2 = …, …, nameN; <span class="comment">// also var, const</span></span><br><span class="line"><span class="comment">// 导出函数</span></span><br><span class="line"><span class="keyword">export</span> <span class="function"><span class="keyword">function</span> <span class="title">FunctionName</span>(<span class="params"></span>)</span>{...}</span><br><span class="line"><span class="comment">// 导出类</span></span><br><span class="line"><span class="keyword">export</span> <span class="class"><span class="keyword">class</span> <span class="title">ClassName</span> </span>{...}</span><br><span class="line"></span><br><span class="line"><span class="comment">// 导出一个表达式作为默认模块</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> expression;</span><br><span class="line"><span class="comment">// 导出匿名函数作为默认模块,类和生成器函数亦可</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="function"><span class="keyword">function</span> (<span class="params">…</span>) </span>{ … } <span class="comment">// also class, function*</span></span><br><span class="line"><span class="comment">// 导出具名函数作为默认模块,类和生成器函数亦可</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="function"><span class="keyword">function</span> <span class="title">name1</span>(<span class="params">…</span>) </span>{ … } <span class="comment">// also class, function*</span></span><br><span class="line"><span class="comment">// 将指定模块作为默认模块进行导出</span></span><br><span class="line"><span class="keyword">export</span> { name1 <span class="keyword">as</span> <span class="keyword">default</span>, … };</span><br><span class="line"></span><br><span class="line"><span class="comment">// 从另一个模块提取所有模块进行导出</span></span><br><span class="line"><span class="keyword">export</span> * <span class="keyword">from</span> …;</span><br><span class="line"><span class="comment">// 从另一个模块提取指定模块进行导出</span></span><br><span class="line"><span class="keyword">export</span> { name1, name2, …, nameN } <span class="keyword">from</span> …;</span><br><span class="line"><span class="comment">// 从另一个模块提取指定的模块并进行重命名后再导出</span></span><br><span class="line"><span class="keyword">export</span> { import1 <span class="keyword">as</span> name1, import2 <span class="keyword">as</span> name2, …, nameN } <span class="keyword">from</span> …;</span><br><span class="line"><span class="comment">// 从另一个模块导出默认模块</span></span><br><span class="line"><span class="keyword">export</span> { <span class="keyword">default</span> } <span class="keyword">from</span> …;</span><br></pre></td></tr></table></figure>
<h3 id="一些说明"><a href="#一些说明" class="headerlink" title="一些说明"></a>一些说明</h3><ol>
<li>在进行 <code>import</code> 的时候,<code>import { export } from "module-name";</code> 中的 <code>{ export }</code> 语法并不等同于对象的解构,这是 <code>import</code> 专门的语法。</li>
<li><code>export</code> 和 <code>export default</code> 的区别是在后续进行引入的时候需要分别使用 <code>import { ... } from</code> 和 <code>import ... from</code> 进行操作。</li>
<li>作为默认模块进行导出时,匿名函数和具名函数在导出之后并无区分。</li>
<li>导出后的模块,如果存在变量,该变量对外是不可变的。可以通过模块内置的方法进行改变。</li>
</ol>
<hr>
<p>大体上就是这些内容了,ES6 的模块化给编程领域尤其是前端开发这一块,带来非常大的便利。</p>
<blockquote>
<p>由于市面上直接支持 ES6 模块的产品的覆盖率依然不够理想,所以需要通过一些转译工具进行转译之后再进行使用。</p>
<blockquote>
<p>目前,本人主要工作是在进行微信小程序的开发,好在小程序现在的开发环境已经基本支持 <code>import</code> 和 <code>export</code> 语法(除了 <code>export ... from</code>),所以可以放心无忧的进行现代化 ES6 代码的编写了。目前使用原生代码进行微信小程序的编写,感觉良好。至于 <code>wepy</code> 和 <code>mpvue</code> 之类的前瞻框架,由于未进行全面使用,所以不做过多评述。</p>
</blockquote>
</blockquote>
<hr>
<p>在撰写本文的时候,参考了大量的资料,但是提笔的时候却又感觉很词穷,所以只是简单的做了一个代码层次的注释说明,更多的参考资料罗列如下,请诸君自行参阅。</p>
<h3 id="参考资料与拓展阅读"><a href="#参考资料与拓展阅读" class="headerlink" title="参考资料与拓展阅读"></a>参考资料与拓展阅读</h3><ul>
<li><a href="http://2ality.com/2014/09/es6-modules-final.html" target="_blank" rel="noopener">ECMAScript 6 modules: the final syntax</a></li>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import" target="_blank" rel="noopener">import - JavaScript | MDN</a></li>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export" target="_blank" rel="noopener">export - JavaScript | MDN</a></li>
<li><a href="https://blogs.windows.com/msedgedev/2016/05/17/es6-modules-and-beyond/" target="_blank" rel="noopener">Previewing ES6 Modules and more from ES2015, ES2016 and beyond</a></li>
<li><a href="https://hacks.mozilla.org/2015/08/es6-in-depth-modules/" target="_blank" rel="noopener">ES6 In Depth: Modules</a></li>
<li><a href="https://hacks.mozilla.org/2018/03/es-modules-a-cartoon-deep-dive/" target="_blank" rel="noopener">ES modules: A cartoon deep-dive</a></li>
<li><a href="http://exploringjs.com/es6/ch_modules.html#_modules" target="_blank" rel="noopener">Exploring ES6 - 16. Modules</a></li>
<li><a href="https://github.com/eslint/espree/pull/43" target="_blank" rel="noopener">eslint/espree - #43 - adds module import and export grammar</a></li>
<li><a href="https://github.com/tc39/proposal-export-default-from" target="_blank" rel="noopener">tc39/proposal-export-default-from</a></li>
<li><a href="https://github.com/tc39/proposal-dynamic-import" target="_blank" rel="noopener">tc39/proposal-dynamic-import</a></li>
<li><a href="http://2ality.com/2015/07/es6-module-exports.html" target="_blank" rel="noopener">What do ES6 modules export?</a></li>
<li><a href="https://www.sitepoint.com/understanding-es6-modules/" target="_blank" rel="noopener">Understanding ES6 Modules</a></li>
<li><a href="http://www.commonjs.org/" target="_blank" rel="noopener">CommonJS</a></li>
<li><a href="http://jsmodules.io/" target="_blank" rel="noopener">JavaScript Modules</a></li>
<li><a href="https://developer.telerik.com/featured/choose-es6-modules-today/" target="_blank" rel="noopener">Choose ES6 modules Today!</a></li>
<li><a href="https://medium.freecodecamp.org/javascript-modules-a-beginner-s-guide-783f7d7a5fcc" target="_blank" rel="noopener">JavaScript Modules: A Beginner’s Guide</a></li>
<li><a href="https://appendto.com/2016/06/the-short-history-of-javascript-module-loaders/" target="_blank" rel="noopener">History and Background of JavaScript Module Loaders</a></li>
<li><a href="http://www.adequatelygood.com/JavaScript-Module-Pattern-In-Depth.html" target="_blank" rel="noopener">JavaScript Module Pattern: In-Depth</a></li>
</ul>
<p><本文完></p>
]]></content>
<summary type="html">
本文是对 ES6 模块化的简单介绍。
</summary>
<category term="WEB" scheme="https://xovel.cn/categories/web/"/>
<category term="文档" scheme="https://xovel.cn/categories/web/docs/"/>
<category term="es6" scheme="https://xovel.cn/tags/es6/"/>
<category term="module" scheme="https://xovel.cn/tags/module/"/>
<category term="import" scheme="https://xovel.cn/tags/import/"/>
<category term="export" scheme="https://xovel.cn/tags/export/"/>
<category term="javascript" scheme="https://xovel.cn/tags/javascript/"/>
</entry>
<entry>
<title>使用 nginx</title>
<link href="https://xovel.cn/article/use-nginx.html"/>
<id>https://xovel.cn/article/use-nginx.html</id>
<published>2018-03-26T01:07:00.000Z</published>
<updated>2018-03-31T04:47:25.294Z</updated>
<content type="html"><![CDATA[<p><img src="https://nginx.org/nginx.png" alt="nginx"></p>
<blockquote>
<p>本文根据个人日志中相关记录进行整理而成。</p>
<p>注意,这并不是一篇配置攻略或者是文档性质的,阅读时请不要以本篇文章描述的为主,请适当进行斟酌。</p>
</blockquote>
<p>导语中的文本来自于百度百科,不过根据官网的描述,<code>nginx</code> 是这样的一个东西:</p>
<blockquote>
<p>nginx [engine x] is an HTTP and reverse proxy server, a mail proxy server, and a generic TCP/UDP proxy server, originally written by Igor Sysoev.</p>
</blockquote>
<p>本文将一句个人日志项目中关于 <code>nginx</code> 的记载进行阐述。</p>
<p>最初,在去年 9 月份,我第一次记录了关于 <code>nginx</code> 的东西,是关于如何在 <code>nginx</code> 站点中开启文件目录的浏览:在 <code>location</code> 模块中使用 <code>autoindex on;</code> 指令即可。</p>
<p>然后没过多久,写了一篇关于开启指定域名访问的记录,即设置 <code>server_name</code> 指令。</p>
<p>在 12 月初,写了一篇重量级的文章,安装 <code>nginx</code>,这也是我第一次完全自己部署前端站点的一次尝试。</p>
<p><code>nginx</code> 的常规依赖:</p>
<ul>
<li><code>zlib</code>,用于开启 <code>gzip</code> 压缩。</li>
<li><code>pcre</code>,用于开启伪静态或者重定向。</li>
<li><code>openssh</code>,用于开启 <code>ssl</code>,或者换个说法,叫做 <code>https</code>。</li>
</ul>
<p>安装过程中需要 <code>gcc-c++</code> 运行库。</p>
<p>紧接着没多久,写了一篇如何配置 <code>nginx</code> 的日志,讲述了如何开启多配置文件模式,主要是 <code>include</code> 指令。顺便阐述了一下过滤非法域名访问的问题,<code>default_server</code> 关键字进行设置即可。</p>
<p>之后在一篇微信支付相关的记录中,提到了关于反向代理转发真实 IP 地址的方法。</p>
<p>过完年之后,由于等级保护评估测试相关的原因,针对前端全站开启了 <code>https</code> 模式。关键配置为 <code>listen 443 ssl;</code>,结合 <code>ssl_certificate</code> 和 <code>ssl_certificate_key</code> 进行相关文件的配置即可完成。</p>
<p>由于 <code>https</code> 的访问模式,页面不能直接使用 <code>http</code> 请求,于是针对之前提到的反向代理 <code>proxy_pass</code> 进行了再一次的阐述,并对负载均衡进行了说明。<code>nginx</code> 的负载均衡是一个非常强大的功能,主要依赖 <code>upstream</code> 来进行相关配置。</p>
<p>之后没多久,有需要页面重定向的需求,于是对 <code>rewrite</code> 指令做了简单的介绍。</p>
<p>因为某一次的服务器改版,转发 <code>https</code> 到 <code>http</code> 的时候,发现端口出现了稍稍的偏差。于是针对 <code>X-Forwarded-Proto</code> 之类的参数设置进行了相关的解释。</p>
<p>后来因个人项目,部署的时候想尝试一下路由的 <code>history</code> 模式,于是 <code>nginx</code> 的 <code>try_files</code> 指令被提上日程,但是目前我并没有进行日志记录。</p>
<p>至此,本人日志项目关于 <code>nginx</code> 的记录就回顾完毕,这大概也就是本篇文章的主要内容了。</p>
<p>另外,在阅读子项目中,曾经记录了一篇跟 <code>nginx</code> 密切相关的书籍《Nginx 开发从入门到精通》,该书是 <code>tengine</code> 开发团队主笔的。</p>
<hr>
<ul>
<li><a href="http://nginx.org/" target="_blank" rel="noopener">nginx 官网</a></li>
<li><a href="http://nginx.org/en/docs/" target="_blank" rel="noopener">nginx documentation</a></li>
<li><a href="http://nginx.org/en/docs/stream/ngx_stream_upstream_module.html" target="_blank" rel="noopener">Module ngx_stream_upstream_module</a></li>
<li><a href="https://trac.nginx.org/nginx/browser/nginx/src/http/modules/ngx_http_proxy_module.c" target="_blank" rel="noopener">ngx_http_proxy_module.c in nginx/src/http/modules – nginx</a></li>
<li><a href="https://www.nginx.com/resources/wiki/start/topics/depth/ifisevil/" target="_blank" rel="noopener">If Is Evil | NGINX</a></li>
<li><a href="http://tengine.taobao.org/book/index.html" target="_blank" rel="noopener">Nginx开发从入门到精通</a></li>
<li><a href="https://serverfault.com/questions/630413/nginx-apache-set-hsts-only-if-x-forwarded-proto-is-https" target="_blank" rel="noopener">Nginx/Apache: set HSTS only if X-Forwarded-Proto is https - Server Fault</a></li>
</ul>
]]></content>
<summary type="html">
Nginx (engine x) 是一个高性能的 HTTP 和反向代理服务器,也是一个 IMAP/POP3/SMTP 服务器。
</summary>
<category term="随笔" scheme="https://xovel.cn/categories/essay/"/>
<category term="nginx" scheme="https://xovel.cn/tags/nginx/"/>
</entry>
<entry>
<title>node 下的微信公众号支付初探</title>
<link href="https://xovel.cn/article/node-wxpay.html"/>
<id>https://xovel.cn/article/node-wxpay.html</id>
<published>2018-01-30T15:06:50.000Z</published>
<updated>2018-01-31T02:53:28.513Z</updated>
<content type="html"><![CDATA[<blockquote>
<p>那么,就直接开门见山呗。本篇博客根据个人日志记录整理而成。</p>
<p>项目地址:<a href="https://github.com/xovel/node-wxpay-test" target="_blank" rel="noopener">https://github.com/xovel/node-wxpay-test</a></p>
</blockquote>
<p>其实大部分的文档,微信官方开发文档里面都提供了,我们只需要按照其说明严格执行就可以达到目的。</p>
<p>注意,这里只讲述公众号支付相关的情形,其他的基本类似,本人未作深入实践,故此不敢多言。</p>
<p>这次的讲解,主要从四个方面进行说明:</p>
<ol>
<li>相关账户配置</li>
<li>后台的搭建</li>
<li>前端页面的展示</li>
<li>支付流程</li>
</ol>
<h3 id="账户"><a href="#账户" class="headerlink" title="账户"></a>账户</h3><p>首先,肯定是需要一个微信公众号的。公众号的性质需要满足开通商户号和微信支付,并且实际上已经开通好了。这次我用的账号是认证好了的服务号。</p>
<p>进入公众号设置界面,对相关的域名进行配置,本次调试,我使用的域名是 <code>z.hdk4.com</code>,故此在公众的管理页面的 <code>【设置】-【公众号设置】-【功能设置】</code> 中对 <code>业务域名</code>、<code>JS接口安全域名</code>、<code>网页授权域名</code> 全部进行了相应的设置。</p>
<blockquote>
<p>至于开发者的添加和公众号密钥和商户号密钥等数据的获取,属于入门级别,这里不再赘述。</p>
</blockquote>
<p>要做微信支付,需要事先对 <code>支付授权目录</code> 进行设置,在商户号管理页面就能够找得到,直接进行设置即可。注意这里是 <code>支付目录</code> 的设置,即浏览器访问下的 <code>location.pathname</code> 对应的访问路径,结尾必须以 <code>/</code> 结束且<strong>区分大小写</strong>。</p>
<h3 id="后台"><a href="#后台" class="headerlink" title="后台"></a>后台</h3><p>这一块最为重要也是核心所在,由于只是演示与测验,所以采用了简单粗暴的 <code>express</code> 来作为后台服务器。详情容后再禀。</p>
<h3 id="前端"><a href="#前端" class="headerlink" title="前端"></a>前端</h3><p>前端页面相对来说简单一些,在引入微信的官方 <code>js</code>,即 <a href="http://res.wx.qq.com/open/js/jweixin-1.2.0.js" target="_blank" rel="noopener">http://res.wx.qq.com/open/js/jweixin-1.2.0.js</a> 之后,调用 <code>WeixinJSBridge</code> 的 API,发起 <code>getBrandWCPayRequest</code> 请求即可。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">WeixinJSBridge.invoke(<span class="string">'getBrandWCPayRequest'</span>, {</span><br><span class="line"> appId: data.appId,</span><br><span class="line"> timeStamp: data.timeStamp,</span><br><span class="line"> nonceStr: data.nonceStr,</span><br><span class="line"> package: data.package,</span><br><span class="line"> signType: data.signType,</span><br><span class="line"> paySign: data.paySign</span><br><span class="line">}, <span class="function"><span class="keyword">function</span> (<span class="params">res</span>) </span>{</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line">});</span><br></pre></td></tr></table></figure>
<p>当然,在这里之前,需要先获取用户的 <code>openid</code>。</p>
<p>当然,在获取 <code>openid</code> 之前,还需要获取一下用户的访问 <code>code</code>。</p>
<p>那么,这个访问的 <code>code</code> 如何获取呢?</p>
<p>根据微信开发文档提供的链接 <a href="https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140842" target="_blank" rel="noopener">https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140842</a>,我们先判断链接是否有 <code>code</code> 字段,如果没有则跳转到微信的链接去进行获取。获取到了之后再进行 <code>openid</code> 的获取。文档方面的信息这里不详细展开,直接上代码进行说明吧!</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> code = getUrlParam(<span class="string">'code'</span>) || sessionStorage.code;</span><br><span class="line"><span class="keyword">var</span> openid = sessionStorage.openid;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 没有 openid 则尝试获取 code</span></span><br><span class="line"><span class="comment">// code 获取之后跳回原链接进行临时存储</span></span><br><span class="line"><span class="keyword">if</span> (!openid) {</span><br><span class="line"> <span class="keyword">if</span> (!code) {</span><br><span class="line"> <span class="keyword">var</span> redirect_uri = <span class="built_in">encodeURIComponent</span>(<span class="string">'http://z.hdk4.com/d.html'</span>);</span><br><span class="line"> <span class="built_in">window</span>.location.replace(<span class="string">'https://open.weixin.qq.com/connect/oauth2/authorize?appid=wxbce0a3daf503097c&redirect_uri='</span> + redirect_uri + <span class="string">'&response_type=code&scope=snsapi_base&state=7'</span>);</span><br><span class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (!sessionStorage.code) {</span><br><span class="line"> sessionStorage.code = code;</span><br><span class="line"> <span class="built_in">window</span>.location.replace(<span class="string">'http://z.hdk4.com/d.html'</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>几点说明:</p>
<ul>
<li><code>redirect_uri</code> 中的 <code>state=7</code> 是随便写的一个值。</li>
<li><code>window.location.replace</code> 用于直接替换,如果不想要替换效果,可以修改为 <code>window.location.href = '...'</code>。</li>
<li>采用 <code>sessionStorage</code> 进行数据的缓存。</li>
<li><code>getUrlParam</code> 为提取链接中的 <code>querystring</code>。</li>
<li><del>不要管 <code>yoda</code> 什么的了</del></li>
</ul>
<p>前端差不多能说的就这么多了。</p>
<h3 id="支付流程"><a href="#支付流程" class="headerlink" title="支付流程"></a>支付流程</h3><p>整个支付流程浓缩起来就是:</p>
<ol>
<li>获取 <code>code</code></li>
<li>获取 <code>openid</code></li>
<li>开始进行支付操作</li>
<li>后台发起预支付订单</li>
<li>后台将获取到的预支付信息返回给前端</li>
<li>前端尝试唤起微信支付</li>
<li>进行支付</li>
<li>前端/后台处理支付回调。是的,都进行处理。前端无所谓,后台必须处理,不然微信会发很多次请求。</li>
<li>支付完成</li>
<li>后续一些相关操作。由于本次只是演示与测验,就不做处理了。</li>
</ol>
<hr>
<p>现在来说一下核心的重点,即后台的相关逻辑处理与接口的设计。</p>
<h3 id="后台-1"><a href="#后台-1" class="headerlink" title="后台"></a>后台</h3><p>相关的库的引入与声明,这里就不赘述了。</p>
<h4 id="api-getopenid-接口"><a href="#api-getopenid-接口" class="headerlink" title="/api/getopenid 接口"></a><code>/api/getopenid</code> 接口</h4><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 获取 openid</span></span><br><span class="line">app.get(<span class="string">'/api/getopenid'</span>, <span class="function"><span class="keyword">function</span> (<span class="params">req, res</span>) </span>{</span><br><span class="line"> <span class="keyword">const</span> code = req.query.code;</span><br><span class="line"> <span class="keyword">const</span> access_token_url = <span class="string">`https://api.weixin.qq.com/sns/oauth2/access_token?appid=<span class="subst">${config.app_id}</span>&secret=<span class="subst">${config.app_secret}</span>&code=<span class="subst">${code}</span>&grant_type=authorization_code`</span>;</span><br><span class="line"></span><br><span class="line"> request.post({ <span class="attr">url</span>: access_token_url }, <span class="function"><span class="keyword">function</span> (<span class="params">error, response, body</span>) </span>{</span><br><span class="line"> wFile(<span class="string">'openid'</span>, body);</span><br><span class="line"> <span class="keyword">if</span> (error) {</span><br><span class="line"> res.json({ <span class="attr">error</span>: body });</span><br><span class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (response.statusCode === <span class="number">200</span>) {</span><br><span class="line"> <span class="keyword">if</span> (body.errcode === <span class="number">40029</span> ) {</span><br><span class="line"> res.json({ <span class="attr">error</span>: body });</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> body = <span class="built_in">JSON</span>.parse(body);</span><br><span class="line"> res.json({ <span class="attr">data</span>: body });</span><br><span class="line"> }</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> res.json({ <span class="attr">error</span>: <span class="number">-1</span> });</span><br><span class="line"> }</span><br><span class="line"> });</span><br><span class="line">});</span><br></pre></td></tr></table></figure>
<blockquote>
<p><code>wFile</code> 是日志记录相关操作,可以无视。</p>
</blockquote>
<p>该接口是用来获取用户的 <code>openid</code> 的,要求的东西是 <code>code</code>,这个 <code>code</code> 就是上面前端花费一番周折得到的东西。</p>
<p>前端调用方式:</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">getOpenId</span>(<span class="params"></span>) </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function"><span class="keyword">function</span> (<span class="params">resolve, reject</span>) </span>{</span><br><span class="line"> <span class="keyword">if</span> (sessionStorage.openid) {</span><br><span class="line"> resolve(sessionStorage.openid);</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> $.get(<span class="string">'/api/getopenid?code='</span> + sessionStorage.code).then(<span class="function"><span class="keyword">function</span> (<span class="params">res</span>) </span>{</span><br><span class="line"> <span class="keyword">var</span> data = res.data;</span><br><span class="line"> <span class="keyword">if</span> (data && data.openid) {</span><br><span class="line"> sessionStorage.openid = data.openid;</span><br><span class="line"> resolve(data.openid)</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> reject();</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></pre></td></tr></table></figure>
<ul>
<li>是的, <code>$</code> 就是大名鼎鼎的 <code>jQuery</code>。</li>
<li>采用了 <code>Promise</code> 对象。</li>
</ul>
<h4 id="api-unifiedorder-接口"><a href="#api-unifiedorder-接口" class="headerlink" title="/api/unifiedorder 接口"></a><code>/api/unifiedorder</code> 接口</h4><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 获取微信支付的统一下单相关数据</span></span><br><span class="line">app.get(<span class="string">'/api/unifiedorder'</span>, <span class="function"><span class="keyword">function</span> (<span class="params">req, res</span>) </span>{</span><br><span class="line"> <span class="keyword">const</span> openid = req.query.openid;</span><br><span class="line"> <span class="keyword">const</span> ip = getClientIp(req);</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 商户订单号</span></span><br><span class="line"> <span class="keyword">const</span> out_trade_no = <span class="string">'test'</span> + <span class="keyword">new</span> <span class="built_in">Date</span>().getTime();</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 统一下单的相关参数</span></span><br><span class="line"> <span class="keyword">const</span> paramUnifiedOrder = {</span><br><span class="line"> appid: config.app_id,</span><br><span class="line"> attach: <span class="string">'test'</span>,</span><br><span class="line"> body: <span class="string">'desc'</span>,</span><br><span class="line"> mch_id: config.mch_id,</span><br><span class="line"> nonce_str: createNonceStr(),</span><br><span class="line"> notify_url: config.notify_url, <span class="comment">// 微信付款后的回调地址</span></span><br><span class="line"> openid: openid,</span><br><span class="line"> out_trade_no: out_trade_no,</span><br><span class="line"> spbill_create_ip: ip,</span><br><span class="line"> total_fee: <span class="number">1</span>,</span><br><span class="line"> trade_type: <span class="string">'JSAPI'</span></span><br><span class="line"> };</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 签名</span></span><br><span class="line"> paramUnifiedOrder.sign = getSign(paramUnifiedOrder);</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 请求微信支付下单接口,获取预订单编号</span></span><br><span class="line"> request.post({ <span class="attr">url</span>: <span class="string">'https://api.mch.weixin.qq.com/pay/unifiedorder'</span>, <span class="attr">body</span>: <span class="built_in">JSON</span>.stringify(getUnifiedOrderXml(paramUnifiedOrder)) }, <span class="function"><span class="keyword">function</span> (<span class="params">error, response, body</span>) </span>{</span><br><span class="line"> wFile(<span class="string">'unifiedorder'</span>, body);</span><br><span class="line"> <span class="keyword">if</span> (error) {</span><br><span class="line"> res.json({ <span class="attr">error</span>: body });</span><br><span class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (response.statusCode === <span class="number">200</span>) {</span><br><span class="line"> <span class="keyword">let</span> prepay_id = <span class="string">''</span>; <span class="comment">// 预订单编号</span></span><br><span class="line"> <span class="comment">// 微信返回的数据为 xml 格式,需要进行解析</span></span><br><span class="line"> xml2jsparseString(body, { <span class="attr">async</span>: <span class="literal">true</span> }, <span class="function"><span class="keyword">function</span> (<span class="params">error, result</span>) </span>{</span><br><span class="line"> prepay_id = result.xml.prepay_id[<span class="number">0</span>]; <span class="comment">// 获取预订单编号</span></span><br><span class="line"> <span class="keyword">const</span> paramWCPay = {</span><br><span class="line"> appId: config.app_id,</span><br><span class="line"> timeStamp: <span class="built_in">parseInt</span>(<span class="keyword">new</span> <span class="built_in">Date</span>().getTime() / <span class="number">1000</span>).toString(),</span><br><span class="line"> nonceStr: createNonceStr(),</span><br><span class="line"> package: <span class="string">'prepay_id='</span> + prepay_id,</span><br><span class="line"> signType: <span class="string">'MD5'</span></span><br><span class="line"> };</span><br><span class="line"> paramWCPay.paySign = getSign(paramWCPay); <span class="comment">// 微信支付签名</span></span><br><span class="line"> res.json({ <span class="attr">data</span>: paramWCPay });</span><br><span class="line"> });</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> res.json({ <span class="attr">error</span>: <span class="number">-1</span> });</span><br><span class="line"> }</span><br><span class="line"> });</span><br><span class="line"></span><br><span class="line">});</span><br></pre></td></tr></table></figure>
<ul>
<li><code>getClientIp</code> 是获取客户端真实 IP 地址的方法。</li>
<li><code>createNonceStr</code> 是生成随机串的方式,非常简单粗暴。</li>
<li><code>out_trade_no</code> 是商户自定义的订单号。</li>
<li><code>getUnifiedOrderXml</code> 是用来拼接发送给微信支付统一下单接口的数据,要 <code>xml</code> 格式的,所以就给一个封装。</li>
<li><code>xml2jsparseString</code> 是解析 <code>xml</code> 文件的库。微信支付统一下单接口返回的数据是 <code>xml</code> 格式的,需要进行相应的解码。</li>
<li><code>getSign</code> 是生成签名的方法。</li>
</ul>
<hr>
<p>如果不出意外,下单接口会返回一个 <code>xml</code> 数据,然后我们就可以提取到 <code>prepay_id</code> 这个核心的信息了。</p>
<h4 id="api-wxresponse-接口"><a href="#api-wxresponse-接口" class="headerlink" title="/api/wxresponse 接口"></a><code>/api/wxresponse</code> 接口</h4><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 处理微信支付的回调</span></span><br><span class="line">app.post(<span class="string">'/api/wxresponse'</span>, <span class="function"><span class="keyword">function</span> (<span class="params">req, res</span>) </span>{</span><br><span class="line"> wFile(<span class="string">'response'</span>, req.body);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">let</span> xmlData = req.body.xml;</span><br><span class="line"> <span class="keyword">let</span> ret = <span class="string">''</span>;</span><br><span class="line"> <span class="keyword">if</span> (xmlData.sign === getSign(xmlData)) {</span><br><span class="line"> ret = <span class="string">`<xml></span></span><br><span class="line"><span class="string"> <return_code><![CDATA[SUCCESS]]></return_code></span></span><br><span class="line"><span class="string"> <return_msg><![CDATA[OK]]></return_msg></span></span><br><span class="line"><span class="string"></xml>`</span>;</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> ret = <span class="string">`<xml></span></span><br><span class="line"><span class="string"> <return_code><![CDATA[SIGNATRURE_ERROR]]></return_code></span></span><br><span class="line"><span class="string"> <return_msg><![CDATA[FAIL]]></return_msg></span></span><br><span class="line"><span class="string"></xml>`</span>;</span><br><span class="line"> }</span><br><span class="line"> res.send(ret);</span><br><span class="line"></span><br><span class="line">});</span><br></pre></td></tr></table></figure>
<p>该接口是用来处理 <code>notify_url</code> 指定的回调链接的相关数据的,本次用的具体值就是 <a href="http://z.hdk4.com/api/wxresponse" target="_blank" rel="noopener">http://z.hdk4.com/api/wxresponse</a>。</p>
<p>如果不对该接口做回应,微信支付会一直发请求,直至系统判定失败。</p>
<blockquote>
<p>注意,使用 <code>express</code> 进行开发时,会收不到 <code>req.body</code>,采用以下方法进行解决即可:</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> bodyParser = <span class="built_in">require</span>(<span class="string">'body-parser'</span>);</span><br><span class="line"><span class="built_in">require</span>(<span class="string">'body-parser-xml'</span>)(bodyParser);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 解决微信支付通知回调数据</span></span><br><span class="line">app.use(bodyParser.xml({</span><br><span class="line"> limit: <span class="string">'1MB'</span>, <span class="comment">// Reject payload bigger than 1 MB</span></span><br><span class="line"> xmlParseOptions: {</span><br><span class="line"> normalize: <span class="literal">true</span>, <span class="comment">// Trim whitespace inside text nodes</span></span><br><span class="line"> normalizeTags: <span class="literal">true</span>, <span class="comment">// Transform tags to lowercase</span></span><br><span class="line"> explicitArray: <span class="literal">false</span> <span class="comment">// Only put nodes in array if >1</span></span><br><span class="line"> }</span><br><span class="line">}));</span><br></pre></td></tr></table></figure>
<h4 id="签名算法"><a href="#签名算法" class="headerlink" title="签名算法"></a>签名算法</h4><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 签名算法</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">getSign</span>(<span class="params">paramSign</span>) </span>{</span><br><span class="line"> <span class="comment">// 按 key 值的 ascii 排序</span></span><br><span class="line"> <span class="keyword">const</span> keys = <span class="built_in">Object</span>.keys(paramSign).sort();</span><br><span class="line"> <span class="keyword">const</span> temp = [];</span><br><span class="line"> keys.forEach(<span class="function"><span class="params">v</span> =></span> {</span><br><span class="line"> <span class="keyword">if</span> (paramSign[v] && v !== <span class="string">'sign'</span>) {</span><br><span class="line"> temp.push(<span class="string">`<span class="subst">${v}</span>=<span class="subst">${paramSign[v]}</span>`</span>);</span><br><span class="line"> }</span><br><span class="line"> });</span><br><span class="line"> temp.push(<span class="string">`key=<span class="subst">${config.mch_key}</span>`</span>);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">const</span> ret = temp.join(<span class="string">'&'</span>);</span><br><span class="line"> <span class="comment">// 生成签名</span></span><br><span class="line"> <span class="keyword">return</span> crypto.createHash(<span class="string">'md5'</span>).update(ret, <span class="string">'utf8'</span>).digest(<span class="string">'hex'</span>).toUpperCase();</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>非常<del>简单粗暴</del>的算法,嗯,如上所示。如果是其他语言,在生成 <code>MD5</code> 值的时候方法可能会有所不同,使用对应的方法即可。</p>
<h4 id="随机字符串方法"><a href="#随机字符串方法" class="headerlink" title="随机字符串方法"></a>随机字符串方法</h4><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">createNonceStr</span>(<span class="params"></span>) </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="built_in">Math</span>.random().toString(<span class="number">36</span>).substr(<span class="number">2</span>, <span class="number">15</span>);</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p><del>是的,这一条是滥竽充数的</del>。</p>
<h3 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h3><ul>
<li><a href="https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=4_4" target="_blank" rel="noopener">获取openid</a></li>
<li><a href="https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140842" target="_blank" rel="noopener">微信网页授权</a></li>
<li><a href="https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_7&index=6" target="_blank" rel="noopener">微信内H5调起支付</a></li>
<li><a href="https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=4_3" target="_blank" rel="noopener">签名算法</a></li>
<li><a href="https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1" target="_blank" rel="noopener">统一下单</a></li>
<li><a href="https://github.com/wxpay/WXPay-SDK-Node.js" target="_blank" rel="noopener">wxpay/WXPay-SDK-Node.js</a></li>
<li><a href="https://gitee.com/anziguoer/wechatPay" target="_blank" rel="noopener">nodejs 微信公众号支付开发</a>,<em>大部分代码参考于此</em>。</li>
<li><a href="https://www.cnblogs.com/yimiyan/p/5603657.html" target="_blank" rel="noopener">微信公众号支付开发全过程 –JAVA</a></li>
<li><a href="http://blog.csdn.net/aofavx/article/details/52220394" target="_blank" rel="noopener">微信公众号支付详细步骤(整理)</a></li>
<li><a href="https://segmentfault.com/a/1190000005797170" target="_blank" rel="noopener">Nginx向ExpressJS转发真实IP地址</a></li>
<li><a href="https://www.jianshu.com/p/0496ef49b2a5" target="_blank" rel="noopener">Nodejs 部署到阿里云全过程</a></li>
<li><a href="http://www.expressjs.com.cn/starter/static-files.html" target="_blank" rel="noopener">利用 Express 托管静态文件</a></li>
<li><a href="http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_pass" target="_blank" rel="noopener">proxy_pass</a></li>
</ul>
]]></content>
<summary type="html">
本文记录一下关于 node/express 下的微信公众号支付测试小 demo 的开发过程。
</summary>
<category term="Node" scheme="https://xovel.cn/categories/node/"/>
<category term="node" scheme="https://xovel.cn/tags/node/"/>
<category term="wxpay" scheme="https://xovel.cn/tags/wxpay/"/>
<category term="公众号" scheme="https://xovel.cn/tags/%E5%85%AC%E4%BC%97%E5%8F%B7/"/>
</entry>
<entry>
<title>Gulp 4 已发布!</title>
<link href="https://xovel.cn/article/gulp-4.html"/>
<id>https://xovel.cn/article/gulp-4.html</id>
<published>2018-01-10T15:29:19.000Z</published>
<updated>2018-01-10T16:29:05.308Z</updated>
<content type="html"><![CDATA[<blockquote>
<p>千呼万唤始出来,犹抱琵琶半遮面。</p>
</blockquote>
<p>在这一天发布的日子里面,其实 <code>gulp</code> 一口气是出了四个版本的:</p>
<ul>
<li><code>v4.0.0-alpha.1</code></li>
<li><code>v4.0.0-alpha.2</code></li>
<li><code>v4.0.0-alpha.3</code></li>
<li><code>v4.0.0</code></li>
</ul>
<p>前面三个是打了 <code>pre-release</code> 的标签的。</p>
<p><a href="https://github.com/gulpjs/gulp/releases" target="_blank" rel="noopener">更新记录</a>这里就不赘述了,简单来说一下发布带来的新特性吧。</p>
<p>首先是 API 的变化,新增了两个非常重要的改进:<code>gulp.parallel</code> 和 <code>gulp.series</code>。这一点我之前在<a href="https://github.com/xovel/diary/blob/master/2017/10/2017-10-22-gulp-4.md" target="_blank" rel="noopener">个人日志项目</a>里面也进行过记录,当时的说明还是略显简陋的。</p>
<p><code>gulp.parallel</code> 是用于执行并联任务的,相对的 <code>gulp.series</code> 则用于执行串联任务。</p>
<p><code>gulp</code> 任务的处理内核由之前的 <a href="https://github.com/robrich/orchestrator" target="_blank" rel="noopener"><code>orchestrator</code></a> 迁移到为 <code>gulp</code> 而生的 <a href="https://github.com/gulpjs/undertaker" target="_blank" rel="noopener"><code>undertaker</code></a>。迁移之后的处理方式更加高效便捷。支持的任务命名方式也灵活许多。</p>
<p><code>gulp.task</code> 调整,删除之前第二个任务列表的参数,前置任务之类的全部并入到上面的两个 API 中进行处理,可以更好的控制 <code>gulp</code> 任务的执行顺序。</p>
<p><code>gulp.watch</code> 改进,在 <a href="https://github.com/paulmillr/chokidar" target="_blank" rel="noopener"><code>chokidar</code></a> 的基础上支持各种文件操作方式的监视。</p>
<p>另外新增了几个 API:</p>
<ul>
<li><code>gulp.symlink</code> 用于创建 <code>symlinks</code>。</li>
<li><code>gulp.lastRun</code> 用于获得指定任务上一次的执行时间。</li>
<li><code>gulp.tree</code> 用于获取当前任务的树形结构。</li>
<li><code>gulp.registry</code> 用于获取或者设置注册任务。</li>
</ul>
<p>所有 API 的详细说明可以在这里找到:<a href="https://github.com/gulpjs/gulp/blob/v4.0.0/docs/API.md" target="_blank" rel="noopener">https://github.com/gulpjs/gulp/blob/v4.0.0/docs/API.md</a>。</p>
<p>另外,对于命令行执行方式,也添加更加丰富的指令,详情可以参阅:<a href="https://github.com/gulpjs/gulp/blob/v4.0.0/docs/CLI.md" target="_blank" rel="noopener">https://github.com/gulpjs/gulp/blob/v4.0.0/docs/CLI.md</a></p>
<p>更新之后,对现有的生态系统影响不会太大,因为还是保留了 <code>v3.9.1</code> 的安装方式。要安装 <code>v4</code>,需要使用 <code>npm install gulp@next</code> 命令来进行安装和获取。这些也都在其 <code>README.md</code> 文件里面有详细说明。</p>
<hr>
<p>鉴于发布的太过于突然,我来不及反应,也暂时没有想法要将现有系统的构建脚本升级到适配 <code>gulp v4</code> 的版本。</p>
<p>前不久在 <code>parcel</code> 爆发之后,自己曾经说过,<code>gulp v4</code> 发布遥遥无期,这还不到一个月,我就被打脸了,想想也真是如梦如幻啊。</p>
]]></content>
<summary type="html">
是的,就在 2017 与 2018 交替的时间里面,gulp v4 发布了,发布时间为北京时间 2018 年 1 月 1 日 上午 9 点。
</summary>
<category term="随笔" scheme="https://xovel.cn/categories/essay/"/>
<category term="gulp" scheme="https://xovel.cn/tags/gulp/"/>
</entry>
<entry>
<title>2017 年总结</title>
<link href="https://xovel.cn/article/summary-2017.html"/>
<id>https://xovel.cn/article/summary-2017.html</id>
<published>2017-12-31T13:20:48.000Z</published>
<updated>2018-01-01T12:11:52.025Z</updated>
<content type="html"><![CDATA[<blockquote>
<p>转眼已经是 2017 年的最后一天了,是时候来好好做一个全面的总结了。</p>
</blockquote>
<p>以上这段文字是<del>抄袭</del>自去年的总结。</p>
<p>今年的总结就换一个方式吧。</p>
<h3 id="先做检讨"><a href="#先做检讨" class="headerlink" title="先做检讨"></a>先做检讨</h3><p>2017 年设定了许多的目标,但是很遗憾,基本上没有完成。最为痛心的是继续弃坑《圣血记》,这一部当初踌躇满志气势恢宏的小说,如今也只剩一声叹息。或许是现实生活与我的理念背道而驰,或许是自己的诸多想法不切实际过于天真,导致我没有太多的心思去创作。近期我每每念及此处,都不禁哀叹遗憾。</p>
<!--
《圣血记》是一部作者用来反应社会现实的玄幻浪漫主义小说,有些架空和修仙的成分。有三部曲,前两部分别为《鸣泉录》、《寻玉》,最后一部暂未进行构思(有强烈的依赖关系)。了解这个系列的人应该会知道我为什么没有给第三部定名。
《鸣泉录》是以作者自己为原型,用一种近乎自恋的手法来描述了一段荡气回肠的爱情故事。故事玄幻色彩很重,讲述了幽冥、驾驭魂魄的一些的现实生活中几乎不可能发生的事情,也在试图为幽魂之事正名,使其显得并不那么幽暗恐怖。《鸣泉录》因为故事中映射的女主角原型的人生经历变化,已被作者强行中止,整个故事的走向发生了剧变。在宏大场面还没有来得及展开的情况下强行中止,说起来也是一种遗憾。
《寻玉》讲述的是另一位与《鸣泉录》男主人公有密切联系(为表兄弟关系)的人物寻找失落宝物相关的故事,故事本身其实是一个很大的轮回。遍寻许久没有找到的东西,原来一直就在自己身边,这也是作者将“远在天边近在眼前”的种种擦肩错过进行艺术化处理的尝试。《鸣泉录》中未能叙述的故事也将在《寻玉》中进行补充。而正当进行到了补充的阶段,《寻玉》也难以继续下去。
我想这应该是一个我绕不过去的坎。总之,从 2016 年下半年开始,就一直搁置了《圣血记》的故事创作。原本打算 2017 年进行重构,但诸多之前的设定都发生了变化,我没有继续创作下去。整个 2017 年,只写了一部分关于《鸣泉录》男主角恢复神志的情节。如今,回过头看《寻玉》的创作,都快变成多主人公的设定了,有点模仿《天龙八部》和《海上牧云记》的节奏。
在阅读一些作品的评鉴的时候,得知一个这样的信息:所有的小说创作,其背景其实都是为了剧情和人物而服务。如果依赖背景去进行创作,除非是有一个非常统一并且经得起推敲的背景故事,否则往往会令人曲解了故事的本原。
*****************
好了,上面其实都是扯谈,意图分散诸君的注意力,也是在弱化自己的侧重点。
-->
<p>工作方面,没有能够稳定住现有的工作。是的,我在 11 月份的时候从上一家公司离职了。上一家公司对我很好,同事之间相处也非常融洽,领导也很是器重我。我选择离开,无论如何,都是工作不稳定的一种体现。原本自己是想打算在上一家公司静静打拼两年,积攒一些人脉,但是事实上我并没有这样去做。这也可能是促使我做出离职决定的一个重大原因吧。</p>
<p>生活方面,说来也甚是杯具。我依然在人生的道路上孤军奋战,我内心多么渴望能有一个人和我一起共同面对未知的旅途呀。说多了都是泪的节奏,归根结底都是因为自己自身的原因。所幸,2017 年,我到底还是学会了如何去勇敢面对。有时候内心面临崩溃,身边又孤立无援的时候,我不再像之前在杭州那般堕落消极,而是努力寻找解决方案。</p>
<h3 id="挖过的坑"><a href="#挖过的坑" class="headerlink" title="挖过的坑"></a>挖过的坑</h3><p>2017 年,我给自己是挖了很多的坑的。这里也稍作罗列,希望还能有时间和精力去填补。</p>
<ol>
<li><code>zob</code> 项目。该项目最初设定的是解决 <code>MVVM</code> 框架的问题,后来项目失败,项目的定位迁移成了代码和写作风格指导。</li>
<li><code>moonlight</code> 项目。该项目原本计划是在 2017 年产出至少两个的子项目,但是很遗憾,目前只有一个半成品的小项目。</li>
<li><code>lui</code> 项目。这个坑挖的太大了,导致项目直接崩盘。该项目的定位是用于解决终端之间的样式风格问题,而目前市面上的大多数 UI 库都致力于解决这个问题,并不是一朝一夕的事情。<del><code>L</code> 是法语单词 <code>libellule</code> 的首字母,意思为_蜻蜓_</del>。</li>
<li>创作系列之<strong>内心小剧场</strong>。这其实也算是一个不大不小的坑,最初的灵感来源是国庆假期的时候去见了她。一直想用一些文字来描述自己的内心世界,开设这个小项目,也是为了释放一下自己心中的情感。</li>
<li>代码风格统一化。这也算团队协作的一个组成部分吧,然而目前只是做到了自己编码风格的统一,并没有对团队成员做统一规范要求。</li>
</ol>
<h3 id="有过的想法"><a href="#有过的想法" class="headerlink" title="有过的想法"></a>有过的想法</h3><p>在 2017 年有过的想法,但是一直没有去执行的事情:</p>
<ol>
<li>日历项目。记录所有重要的日期。</li>
<li>运营一个微信公众号。</li>
<li>收集某一垂直领域的相关资料。拟定的方向有两个,分别为养生和建筑。</li>
<li>成为 <code>vue.js</code> 的贡献者。</li>
</ol>
<p>可以将理由统一定性为懒惰,不思进取。这些事情也逐渐让我明白了一个道理:一个人的精力毕竟还是有限的。</p>
<hr>
<p>下面来总结一下 2017 可圈可点的事情:</p>
<h3 id="接手的项目"><a href="#接手的项目" class="headerlink" title="接手的项目"></a>接手的项目</h3><h4 id="中小学装备管理系统"><a href="#中小学装备管理系统" class="headerlink" title="中小学装备管理系统"></a>中小学装备管理系统</h4><p>上一家公司拳头产品,我在其中负责前端的开发。</p>
<h4 id="集中采购系统"><a href="#集中采购系统" class="headerlink" title="集中采购系统"></a>集中采购系统</h4><p>上一家公司的另一款采购物品的管理后台产品,与装备管理系统密切相关。同样的,我也是前端主程。</p>
<h4 id="数据直报系统"><a href="#数据直报系统" class="headerlink" title="数据直报系统"></a>数据直报系统</h4><p>与上一个项目基本类似,用于学校端的数据填写上报,行管端的审批与汇总,方便管理系统进行数据的统一管理。</p>
<blockquote>
<p>以上各个项目的版本因为公司的战略计划,统一都是 <code>V9</code>。</p>
</blockquote>
<h4 id="实验教学平台"><a href="#实验教学平台" class="headerlink" title="实验教学平台"></a>实验教学平台</h4><p>该项目分为三个迭代阶段,我都参与了。第一个阶段为项目雏形时期,采用传统的 <code>jQuery/Bootstrap</code> 搭建,该阶段直接被第二个阶段替代。第二个阶段为采用 <code>angular.js</code> 进行搭建,我参与了主框架的搭建,并进行了路由配置以及懒加载方案的探索与实现。第三个阶段为 <code>vue.js</code> 阶段,此阶段为项目前端正式转型之后采用的框架,我只参与了部分主框架的搭建,之后因公司战略调整,我回到了装备开发团队。</p>
<h4 id="空港出行管理后台"><a href="#空港出行管理后台" class="headerlink" title="空港出行管理后台"></a>空港出行管理后台</h4><p>这便就是当前自己经手的核心项目。</p>
<h3 id="与工作相关的子项目"><a href="#与工作相关的子项目" class="headerlink" title="与工作相关的子项目"></a>与工作相关的子项目</h3><h4 id="sinput-js"><a href="#sinput-js" class="headerlink" title="sinput.js"></a><a href="https://github.com/xovel/sinput/tree/1.x" target="_blank" rel="noopener"><code>sinput.js</code></a></h4><p>一个用于列表模糊检索的 <code>jQuery</code> 插件。因前面提到的装备管理系统中,存在大量的模糊检索的需求,为了应对复杂的产品需求,在采用了诸多现有的插件之后,便有了这样一个子项目的诞生。主要目的是解决千奇百怪的需求。插件性能和效果表现均十分良好。</p>
<h4 id="dreport-xlsx"><a href="#dreport-xlsx" class="headerlink" title="dreport-xlsx"></a><code>dreport-xlsx</code></h4><p>因数据直报系统中使用到了大量的表格导入导出功能,后台人员在制作模板的过程中,需要面临大量重复冗余的操作,遂在 <code>node-xlsx</code> 的基础之上,为缩短人工操作的时间和避免操作失误,开发了这一款用于生成数据模板的子项目。</p>
<blockquote>
<p>不过,因为离职走的匆忙,相关的代码我没有带走。</p>
</blockquote>
<h4 id="util-js"><a href="#util-js" class="headerlink" title="util.js"></a><code>util.js</code></h4><p>单独将此拎出来是因为该文件的定位至关重要。该项目收集并整理了部分在前端开发中使用频率非常高的工具方法。在上一家公司之后,又加入诸多方法比如重新封装 <code>ajax</code> 方法,表格组件的支持更加丰富,加入了部分类似与 <code>vue</code> 和 <code>angular</code> 过滤器的概念方法等等。</p>
<h3 id="个人项目"><a href="#个人项目" class="headerlink" title="个人项目"></a>个人项目</h3><h4 id="htree"><a href="#htree" class="headerlink" title="htree"></a><a href="https://github.com/xovel/htree" target="_blank" rel="noopener"><code>htree</code></a></h4><p>一款用于 <code>node.js</code> 环境的类似于 <code>Linux</code> 系统的 <code>tree</code> 命令的命令行工具。更多介绍可以参考之前在博客中发表的这篇文章:<a href="/article/htree.html">htree,一款模仿 tree 命令的本地文件结构查看工具</a>。</p>
<h4 id="最合拍"><a href="#最合拍" class="headerlink" title="最合拍"></a>最合拍</h4><p>一款面向羽毛球运动的微信商城项目。<del>后该项目因为迭代升级原因,我个人退出下一个版本的开发</del>。</p>
<h4 id="第五空间文学网"><a href="#第五空间文学网" class="headerlink" title="第五空间文学网"></a>第五空间文学网</h4><p>一款面向小说后台管理的静态页面实现。</p>
<h3 id="新增的技术栈"><a href="#新增的技术栈" class="headerlink" title="新增的技术栈"></a>新增的技术栈</h3><ul>
<li><code>angular.js</code>。开始对大型应用的 <code>MVVM</code> 模式做深入的了解与应用。</li>
<li><code>jenkins</code> 的使用,本人的日志项目中有许多记录是关于 <code>jenkins</code> 这一款 <code>CI</code> 系统的。</li>
<li><code>gulp</code> 构建复杂的大型应用。配合简单的 <code>node</code> 命令完成各种场景需求。</li>
<li><code>node.js</code> 编写简单基础的应用。如上面提到的 <code>dreport-xlsx</code>,上一条提到的 <code>gulp</code> 生成 <code>config</code> 配置文件,均采用 <code>node</code> 执行文件来产出。</li>
<li><code>nginx</code> 搭建与配置,代理纯前端站点。多文件的配置模式。</li>
<li><code>xshell</code> 连接远程主机进行调试。主要是操作 <code>nginx</code> 和查看 <code>tomcat</code> 的后台日志记录文件。</li>
<li><code>webpack</code> 技术,使用 <code>vue</code> 进行项目的骨架搭建。</li>
<li><code>vue</code>,非常优秀的前端框架,算是入了门。组件库的使用这里就不赘述了。</li>
</ul>
<h3 id="阅读与写作"><a href="#阅读与写作" class="headerlink" title="阅读与写作"></a>阅读与写作</h3><p>说来惭愧,2017 年,自己的写作任务全面处于弃坑状态,所以这里就针对自己的阅读情况做一个简单的记录。</p>
<ul>
<li>《圣血记》的创作,持续搁置。“她”的原型再度丢失,我失去了创作的方向。</li>
<li>购买了一些技术方面的书籍,如《代码整洁之道》、《深入理解 ES6》、《HTTP 指南》等。基本上都是下半年购买的,远远没有达到年初既定的目标(<code>≥ 10</code>)。</li>
<li>图书馆去的次数大概在 20 次,每次借阅的书籍数量平均为两本。也是没有能够达到最初的目标的。书籍的范围大都是技术和哲学相关的。希望 2018 年能够借阅更多类型的书籍来拓展自己的知识视野。</li>
<li>各大博客和站点,以掘金、简书、开发者头条、干货集中营、前端之巅、前端日刊等为代表,几乎推送过来的文章,跟前端和 UI 相关的都进行了阅读,并针对部分文章做了收藏与整理记录。</li>
<li>个人博客的创作,2017 年的产出量不超过 10 篇,能拿得出手的其实只有两篇,一篇是介绍 <code>brackets</code> 插件的,另一篇是介绍 <code>htree</code> 的。</li>
<li>个人日志项目,坚持了下来。虽然每天都记录了,但是个人认为有效记录的比率在 60% 左右(即有大约 30% ~ 40% 是并没有什么实际意义的记录或者是流水账式的记录)。我会抽一个时间对 2017 年写下的日志做一个整理,看看自己的技术成长路线是个什么样子的。<del>嗯,这又算是给自己挖了一个坑</del>。</li>
</ul>
<h3 id="关于音乐"><a href="#关于音乐" class="headerlink" title="关于音乐"></a>关于音乐</h3><p>截止目前为止,我在网易云音乐上面的听歌总数达到了八千多首,主要类型可以分为两类,一类是纯音乐,包括史诗、空间、纯电音、新世纪等等;另一类是柔和舒缓类型的。</p>
<p>自己的音乐梦想,到目前为止,已经中断将近 20 年了。说起来也甚是滑稽可笑,我其实是有条件进一步接触音乐的,但我一直没有勇气将其拎起来。我并不知道何时才能重拾年幼时的梦想,也可能一辈子都不会再捡起来了吧。</p>
<p>自己的歌唱水平比以前好了很多很多。以前 100% 走调的我,现在也能逐渐掐准节奏了。深情,有故事,这是我得到的最多的评价。</p>
<h3 id="展望-2018"><a href="#展望-2018" class="headerlink" title="展望 2018"></a>展望 2018</h3><p>说了这么多,我其实也是在一直犹豫,对于 2018 年的规划是什么样子的,其实早在 2017 年 7 月份,我就已经做出了明确的规划。</p>
<p>有些事情,是不方便明说的。2017 年没有来得及完成的事情,2018 年也不会特意去处理,毕竟各有各的规划。若是刻意去完成某件事情,是否又偏离了原定计划呢?</p>
<p>简单粗暴的总结一下 2018 年的展望:</p>
<ul>
<li>遇见更好的自己。</li>
<li>让自己内心更加平静。</li>
<li>努力提升自己的情商和魅力值。</li>
</ul>
<blockquote>
<p>嗯,后面两点是<del>充数</del>的。</p>
</blockquote>
<hr>
<blockquote>
<p><em>知道的越多,就越发现自己不知道的其实更多</em>。<del>这句不是鲁迅说的,是古希腊大哲学家芝诺说的</del>。</p>
<p>因此而产生恐惧,那是万万不可取的。</p>
</blockquote>
<hr>
<p>2018 年,加油!</p>
]]></content>
<summary type="html">
2017 年年末大总结。
</summary>
<category term="生活" scheme="https://xovel.cn/categories/life/"/>
<category term="2017" scheme="https://xovel.cn/tags/2017/"/>
<category term="总结" scheme="https://xovel.cn/tags/%E6%80%BB%E7%BB%93/"/>
<category term="经历" scheme="https://xovel.cn/tags/%E7%BB%8F%E5%8E%86/"/>
<category term="2018" scheme="https://xovel.cn/tags/2018/"/>
</entry>
<entry>
<title>中国的商标分类</title>
<link href="https://xovel.cn/article/trademark-classification.html"/>
<id>https://xovel.cn/article/trademark-classification.html</id>
<published>2017-12-31T11:54:33.000Z</published>
<updated>2017-12-31T15:58:52.650Z</updated>
<content type="html"><![CDATA[<p>商标是区别商品或服务来源的一种标志,每一个注册商标都是指定用于某一商品或服务上的。</p>
<a id="more"></a>
<p>不想引述大段现有的资料。</p>
<p>打算设立一个项目,就是针对开启高强度的模糊搜索效果的商标范围在线搜索。</p>
<p>为什么不提供精确的商标查询效果?说来惭愧,没有能够顺利破解 <code>商标网</code> 提供的 <code>API</code>。前天听后台开发的同事讲解了一些开放平台和网关拦截的知识,我想我是碰到了。我没有找到合适的破解方案,时间一到就告知权限失效或者查无数据了。所以,暂时先提供一个商标范围的搜索项目,名字就叫做 <code>trademark-classification</code>。所有数据来源来自商标网的官方数据,采集时间为 <code>2017-10-31</code>。</p>
<p>部分参考资料:</p>
<ul>
<li><a href="http://sbj.saic.gov.cn/sbsq/sphfwfl/" target="_blank" rel="noopener">商标注册用商品和服务分类说明</a></li>
<li><a href="http://wsjs.saic.gov.cn" target="_blank" rel="noopener">中国商标网</a></li>