-
Notifications
You must be signed in to change notification settings - Fork 0
/
atom.xml
437 lines (267 loc) · 281 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
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>Sun with no word</title>
<subtitle>something about what I have learned and some interesting things</subtitle>
<link href="https://sunjinkang.github.io/atom.xml" rel="self"/>
<link href="https://sunjinkang.github.io/"/>
<updated>2024-03-28T07:35:50.263Z</updated>
<id>https://sunjinkang.github.io/</id>
<author>
<name>Sun Jinkang</name>
</author>
<generator uri="https://hexo.io/">Hexo</generator>
<entry>
<title>关于github个人博客使用giscus作为评论系统的操作说明</title>
<link href="https://sunjinkang.github.io/2024/03/28/62-about-giscus/"/>
<id>https://sunjinkang.github.io/2024/03/28/62-about-giscus/</id>
<published>2024-03-28T06:05:44.000Z</published>
<updated>2024-03-28T07:35:50.263Z</updated>
<content type="html"><![CDATA[<h4 id="说明"><a href="#说明" class="headerlink" title="说明"></a>说明</h4><p>本人使用github搭建个人博客,博客框架为Hexo(5.4.2),博客主题为Volantis(5.8.0)。为了便于使用,接入了Giscus作为评论系统。本篇文章主要说明接入Giscus的具体操作。</p><h4 id="步骤一"><a href="#步骤一" class="headerlink" title="步骤一"></a>步骤一</h4><ul><li>建一个公共库<br>由于Giscus使用github的discussion作为评论数据存放地,所以使用Giscus需要先建一个github的<em>公共仓库</em>,仓库名称可根据自己的需要进行设置。本文中评论的仓库名为comments。<br><img src="create-repo.png" class="lazyload" data-srcset="create-repo.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="create-repo"></li></ul><p><em>除了要求是个公共库之外,是否需要README、gitignore无具体要求</em></p><ul><li>开启公共库的discussion功能</li></ul><p>公共库 -> Settings -> General -> Features -> 勾选discussion<br><img src="check-discussion.png" class="lazyload" data-srcset="check-discussion.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="check-discussion"></p><h4 id="步骤二"><a href="#步骤二" class="headerlink" title="步骤二"></a>步骤二</h4><ul><li>公共库安装Giscus<br>前往<a href="https://github.com/apps/giscus">这里</a>,点击 <font color="red">Install</font> 安装Giscus<br><img src="install-giscus.png" class="lazyload" data-srcset="install-giscus.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="install-giscus"></li></ul><p>选择创建的公共库,将公共库与Giscus关联起来<br><img src="giscus-select-repo.png" class="lazyload" data-srcset="giscus-select-repo.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="giscus-select-repo"></p><h4 id="步骤三"><a href="#步骤三" class="headerlink" title="步骤三"></a>步骤三</h4><ul><li>Giscus官网配置<br>前往 <a href="https://giscus.app/">Giscus官网</a>,进行配置。<br><img src="giscus-config1.png" class="lazyload" data-srcset="giscus-config1.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="giscus-config1"><br>仓库名有三个前置条件,如果按照本文顺序进行安装,这里的检查会通过,否则会报错。如果报错了,请检查一下之前的配置是不是有哪里配置错了。</li></ul><p><img src="giscus-config2.png" class="lazyload" data-srcset="giscus-config2.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="giscus-config2"><br>可以根据自己的需要选择,本文默认选了第一个。</p><p><img src="giscus-config3.png" class="lazyload" data-srcset="giscus-config3.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="giscus-config3"><br>选择 Announcements 类型即可,官方也是这样推荐的,因为这样便于管理。</p><p>其他的配置使用默认配置就好。</p><p><img src="giscus-config4.png" class="lazyload" data-srcset="giscus-config4.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="giscus-config4"><br>在你想出现评论的位置添加上面的 <em></script/></em> 标签。但如果已经存在带有giscus类的元素,则评论会被放在那里。<br>将上面标签中的数据填入项目中giscus配置的对应位置。</p><figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">giscus:</span></span><br><span class="line"> <span class="comment"># 以下配置按照 yml 格式增删填写即可</span></span><br><span class="line"> <span class="attr">repo:</span> <span class="comment">#data-repo</span></span><br><span class="line"> <span class="attr">repo-id:</span> <span class="comment">#data-repo-id</span></span><br><span class="line"> <span class="attr">category:</span> <span class="comment">#data-category</span></span><br><span class="line"> <span class="attr">category-id:</span> <span class="comment">#data-category-id</span></span><br><span class="line"> <span class="attr">mapping:</span> <span class="string">"pathname"</span></span><br><span class="line"> <span class="attr">reactions-enabled:</span> <span class="string">"1"</span></span><br><span class="line"> <span class="attr">emit-metadata:</span> <span class="string">"0"</span></span><br><span class="line"> <span class="attr">lang:</span> <span class="string">"zh-CN"</span></span><br></pre></td></tr></table></figure><p>以上配置完成后,理论上项目中就可以使用评论系统了。</p><p>登录后,输入评论,可以查看公共库的discussion中是否有对应的评论<br><img src="giscus-comments.png" class="lazyload" data-srcset="giscus-comments.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="giscus-comments"><br><img src="github-comments.png" class="lazyload" data-srcset="github-comments.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="github-comments"><br>可以看到,博客中的评论在github的公共仓库中也存在,配置Giscus的评论系统成功!</p>]]></content>
<summary type="html"><h4 id="说明"><a href="#说明" class="headerlink" title="说明"></a>说明</h4><p>本人使用github搭建个人博客,博客框架为Hexo(5.4.2),博客主题为Volantis(5.8.0)。为了便于使用,接入了Giscus作为评论系统。本篇文章主要说明接入Giscus的具体操作。</p>
<h4 id="步骤一"><a href="#步骤一" class="headerlink" title="步骤一"></a>步骤一</h4><ul>
<li>建一个公共库<br>由于Giscus使用github的discussion作为评论数据存放地,所以使用Giscus需要先建一个github的<em>公共仓库</em>,仓库名称可根据自己的需要进行设置。本文中评论的仓库名为comments。<br><img src="create-repo.png" class="lazyload" data-srcset="create-repo.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="create-repo"></li>
</ul>
<p><em>除了要求是个公共库之外,是否需要README、gitignore无具体要求</em></p></summary>
<category term="blog, giscus" scheme="https://sunjinkang.github.io/tags/blog-giscus/"/>
</entry>
<entry>
<title>关于docker的使用问题</title>
<link href="https://sunjinkang.github.io/2024/01/29/61-about-docker-command/"/>
<id>https://sunjinkang.github.io/2024/01/29/61-about-docker-command/</id>
<published>2024-01-29T08:10:54.000Z</published>
<updated>2024-03-28T09:18:33.258Z</updated>
<content type="html"><![CDATA[<p><strong>问题:删除docker网络,报错存在active endpoints</strong><br>例如: while removing network: network docker_dms_net id ec0611ba3525 has active endpoints</p><p>解决方法:<br>第一种:<br>重启docker</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo service docker restart</span><br></pre></td></tr></table></figure><p>第二种:</p><ol><li><p>查看docker的网络</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker network ls</span><br></pre></td></tr></table></figure></li><li><p>查看网络的endpoint, 停止使用网络的container</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></pre></td><td class="code"><pre><span class="line">docker network inspect <network-id></span><br><span class="line"></span><br><span class="line"><span class="comment">// container-id 是Containers下对应的数据</span></span><br><span class="line"><span class="comment">// 例如:</span></span><br><span class="line"><span class="comment">// "Containers": {</span></span><br><span class="line"><span class="comment">// "6bcc2418b08f9e1446053ab2e95bda066ec79bcbb0bd200c5e5110dc9bc637a3": {</span></span><br><span class="line"><span class="comment">// "Name": "dms-mysql-2",</span></span><br><span class="line"><span class="comment">// "EndpointID": "75b980a5ad52734eccf237b9bcef0b5c1b2b1426274326eb317d006aceac3eff",</span></span><br><span class="line"><span class="comment">// "MacAddress": "02:42:ac:1f:86:03",</span></span><br><span class="line"><span class="comment">// "IPv4Address": "172.31.134.3/24",</span></span><br><span class="line"><span class="comment">// "IPv6Address": ""</span></span><br><span class="line"><span class="comment">// }</span></span><br><span class="line"><span class="comment">// }</span></span><br><span class="line"><span class="comment">// container-id为:6bcc2418b08f9e1446053ab2e95bda066ec79bcbb0bd200c5e5110dc9bc637a3</span></span><br><span class="line">docker container stop <container-id></span><br></pre></td></tr></table></figure></li></ol><p>停止所有使用network的container之后,删除network即可。如果存在其他报错,建议google一下</p>]]></content>
<summary type="html"><p><strong>问题:删除docker网络,报错存在active endpoints</strong><br>例如: while removing network: network docker_dms_net id ec0611ba3525 has active endpoints</p>
<p>解决方法:<br>第一种:<br>重启docker</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo service docker restart</span><br></pre></td></tr></table></figure>
<p>第二种:</p>
<ol>
<li><p>查看docker的网络</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker network ls</span><br></pre></td></tr></table></figure></li>
<li><p>查看网络的endpoint, 停止使用网络的container</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></pre></td><td class="code"><pre><span class="line">docker network inspect &lt;network-id&gt;</span><br><span class="line"></span><br><span class="line"><span class="comment">// container-id 是Containers下对应的数据</span></span><br><span class="line"><span class="comment">// 例如:</span></span><br><span class="line"><span class="comment">// &quot;Containers&quot;: &#123;</span></span><br><span class="line"><span class="comment">// &quot;6bcc2418b08f9e1446053ab2e95bda066ec79bcbb0bd200c5e5110dc9bc637a3&quot;: &#123;</span></span><br><span class="line"><span class="comment">// &quot;Name&quot;: &quot;dms-mysql-2&quot;,</span></span><br><span class="line"><span class="comment">// &quot;EndpointID&quot;: &quot;75b980a5ad52734eccf237b9bcef0b5c1b2b1426274326eb317d006aceac3eff&quot;,</span></span><br><span class="line"><span class="comment">// &quot;MacAddress&quot;: &quot;02:42:ac:1f:86:03&quot;,</span></span><br><span class="line"><span class="comment">// &quot;IPv4Address&quot;: &quot;172.31.134.3/24&quot;,</span></span><br><span class="line"><span class="comment">// &quot;IPv6Address&quot;: &quot;&quot;</span></span><br><span class="line"><span class="comment">// &#125;</span></span><br><span class="line"><span class="comment">// &#125;</span></span><br><span class="line"><span class="comment">// container-id为:6bcc2418b08f9e1446053ab2e95bda066ec79bcbb0bd200c5e5110dc9bc637a3</span></span><br><span class="line">docker container stop &lt;container-id&gt;</span><br></pre></td></tr></table></figure></li>
</ol></summary>
<category term="docker" scheme="https://sunjinkang.github.io/tags/docker/"/>
</entry>
<entry>
<title>关于shadow dom及如何创建一个shadow dom</title>
<link href="https://sunjinkang.github.io/2024/01/06/60-about-shadow-dom/"/>
<id>https://sunjinkang.github.io/2024/01/06/60-about-shadow-dom/</id>
<published>2024-01-06T03:20:34.000Z</published>
<updated>2024-01-26T01:42:14.058Z</updated>
<content type="html"><![CDATA[<h4 id="什么是Shadow-Dom?"><a href="#什么是Shadow-Dom?" class="headerlink" title="什么是Shadow Dom?"></a>什么是Shadow Dom?</h4><blockquote><p>一种连接节点的树状结构,代表标记文档(通常是在 web 文档中的 HTML 文档)中出现的不同元素和文本字符串。</p></blockquote><p>浏览器渲染文档的时候会给指定的DOM结构插入编写好的DOM元素,但是插入的Shadow DOM 会与主文档的DOM保持分离,也就是说Shadow DOM不存在于主DOM树上。并且Shadow DOM封装出来的DOM元素是独立的,外部的配置不会影响到内部,内部的配置也不会影响外部。</p><p><strong>Chrome中查看Shadow Dom</strong><br>1.打开浏览器控制台的设置选项<br>2.找到Preference -> Elements,把show user anent shadow dom勾上<br><img src="chrome-setting.png" class="lazyload" data-srcset="chrome-setting.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="chrome-setting"><br><img src="shadow-dom.png" class="lazyload" data-srcset="shadow-dom.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="shadow-dom"></p><h4 id="Shadow-Dom的结构"><a href="#Shadow-Dom的结构" class="headerlink" title="Shadow Dom的结构"></a>Shadow Dom的结构</h4><p><img src="shadow-dom-structure.png" class="lazyload" data-srcset="shadow-dom-structure.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="shadow-dom-structure"></p><p>Shadow DOM术语<br>Shadow host: Shadow DOM 附加到的常规 DOM 节点。<br>Shadow tree: Shadow DOM 内部的 DOM 树。<br>Shadow boundary: Shadow DOM 终止,常规 DOM 开始的地方。<br>Shadow root: Shadow tree的根节点。</p><h4 id="Shadow-DOM的作用及如何创建Shadow-DOM?"><a href="#Shadow-DOM的作用及如何创建Shadow-DOM?" class="headerlink" title="Shadow DOM的作用及如何创建Shadow DOM?"></a>Shadow DOM的作用及如何创建Shadow DOM?</h4><p><em>作用</em><br>Shadow DOM是独立于DOM树的,外部的样式不会影响到Shadow DOM的内部,并且使用一般的javascript操作dom的方式去操作Shadow DOM,都是不生效的。这种良好的密封性,使得Shadow DOM可以用于创建类似video这类的标签,方便开发。</p><p><em>如何创建Shadow DOM?</em></p><p>使用attachShadow给指定元素挂载一个shadow dom,并且返回对shadow root的引用。</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"><span class="comment">// html</span></span><br><span class="line"><div id=<span class="string">"first"</span>></div></span><br><span class="line"><span class="language-xml"><span class="tag"><<span class="name">span</span>></span>第一个例子<span class="tag"></<span class="name">span</span>></span></span></span><br><span class="line"><span class="language-xml"><span class="tag"><<span class="name">div</span> <span class="attr">id</span>=<span class="string">"total"</span>></span><span class="tag"></<span class="name">div</span>></span></span></span><br><span class="line"><span class="comment">// js</span></span><br><span class="line"><span class="keyword">const</span> firstParent = <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">'first'</span>);</span><br><span class="line"><span class="keyword">const</span> shadow = firstParent.<span class="title function_">attachShadow</span>({ <span class="attr">mode</span>: <span class="string">'open'</span> });</span><br><span class="line"><span class="keyword">const</span> span = <span class="variable language_">document</span>.<span class="title function_">createElement</span>(<span class="string">'span'</span>);</span><br><span class="line">span.<span class="property">textContent</span> = <span class="string">'Shadow DOM'</span>;</span><br><span class="line">shadow.<span class="title function_">appendChild</span>(span);</span><br></pre></td></tr></table></figure><p><em>Shadow DOM mode</em><br>使用attachShadow()方法,必须传递一个对象作为参数来指定shadow DOM树的封装模式,否则将会抛出一个TypeError。该对象必须具有mode属性,值为 open 或 closed。</p><ul><li><p>open<br>shadow root 元素可以从 js 外部访问根节点,例如使用 shadowRoot:</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> shadowSpan = firstParent.<span class="property">shadowRoot</span>?.<span class="title function_">querySelectorAll</span>(<span class="string">'span'</span>);</span><br><span class="line"><span class="comment">// shadowRoot 返回一个 ShadowRoot 对象</span></span><br></pre></td></tr></table></figure></li><li><p>closed<br>拒绝从 js 外部访问关闭的 shadow root 节点, shadowRoot 返回 null</p></li></ul><p><img src="open-closed.png" class="lazyload" data-srcset="open-closed.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="open-closed"></p><p><em>可以挂载Shadow DOM的标签</em></p><p><img src="mount-tag.png" class="lazyload" data-srcset="mount-tag.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="mount-tag"></p><p>注意:如果将Shadow DOM挂载到不可挂载标签上,挂载会失败,控制台会报错。<br><img src="mount-tag-error.png" class="lazyload" data-srcset="mount-tag-error.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="mount-tag-error"></p><h4 id="Shadow-DOM特点"><a href="#Shadow-DOM特点" class="headerlink" title="Shadow DOM特点"></a>Shadow DOM特点</h4><ul><li>外部的样式不影响Shadow DOM内部<br>Shadow DOM是游离在 DOM 树之外的节点树,所以文档上的CSS不会作用在他身上<br><img src="normal-css.png" class="lazyload" data-srcset="normal-css.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="normal-css"></li></ul><p>在MDN上提到了两种方式可以修改Shadow DOM的样式,感兴趣的可以自己去看看:<br><a href="https://developer.mozilla.org/zh-CN/docs/Web/API/Web_components/Using_shadow_DOM#%E5%9C%A8%E5%BD%B1%E5%AD%90_dom_%E5%86%85%E5%BA%94%E7%94%A8%E6%A0%B7%E5%BC%8F">https://developer.mozilla.org/zh-CN/docs/Web/API/Web_components/Using_shadow_DOM#%E5%9C%A8%E5%BD%B1%E5%AD%90_dom_%E5%86%85%E5%BA%94%E7%94%A8%E6%A0%B7%E5%BC%8F</a></p><p>这里给Shadow DOM添加样式使用的是第二种:</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><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// html</span></span><br><span class="line"><div id=<span class="string">"third"</span>></div></span><br><span class="line"><span class="language-xml"><span class="tag"><<span class="name">span</span>></span>第三个例子<span class="tag"></<span class="name">span</span>></span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">// js</span></span><br><span class="line"><span class="keyword">const</span> thirdParent = <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">'third'</span>);</span><br><span class="line"><span class="keyword">const</span> shadow3 = thirdParent.<span class="title function_">attachShadow</span>({ <span class="attr">mode</span>: <span class="string">'open'</span> });</span><br><span class="line"><span class="keyword">const</span> span3 = <span class="variable language_">document</span>.<span class="title function_">createElement</span>(<span class="string">'span'</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 使用class的方式设置样式</span></span><br><span class="line">span3.<span class="property">innerHTML</span> = <span class="string">`</span></span><br><span class="line"><span class="string"> <div class="text">Shadow DOM3</div></span></span><br><span class="line"><span class="string"> <style></span></span><br><span class="line"><span class="string"> .text {</span></span><br><span class="line"><span class="string"> border: 1px solid #ccc;</span></span><br><span class="line"><span class="string"> color: pink;</span></span><br><span class="line"><span class="string"> }</span></span><br><span class="line"><span class="string"> </style></span></span><br><span class="line"><span class="string">`</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 使用伪类host设置样式</span></span><br><span class="line">span3.<span class="property">innerHTML</span> = <span class="string">`</span></span><br><span class="line"><span class="string"> <div>Shadow DOM3</div></span></span><br><span class="line"><span class="string"> <style></span></span><br><span class="line"><span class="string"> :host {</span></span><br><span class="line"><span class="string"> border: 1px solid #ccc;</span></span><br><span class="line"><span class="string"> color: pink;</span></span><br><span class="line"><span class="string"> }</span></span><br><span class="line"><span class="string"> </style></span></span><br><span class="line"><span class="string">`</span>;</span><br><span class="line">shadow3.<span class="title function_">appendChild</span>(span3);</span><br></pre></td></tr></table></figure><p><img src="css-class.png" class="lazyload" data-srcset="css-class.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="css-class"><br><img src="css-host.png" class="lazyload" data-srcset="css-host.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="css-host"></p><ul><li><p>样式钩子<br>shadow dom还有一个非常重要的一个特点就是可以使用CSS自定义属性来创建样式占位符,并允许用户填充。</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// html</span></span><br><span class="line"><div id=<span class="string">"third"</span>></div></span><br><span class="line"><span class="language-xml"><span class="tag"><<span class="name">span</span>></span>第三个例子<span class="tag"></<span class="name">span</span>></span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">// style</span></span><br><span class="line">#third {</span><br><span class="line"> --<span class="attr">color</span>: red;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// js</span></span><br><span class="line"><span class="keyword">const</span> thirdParent = <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">'third'</span>);</span><br><span class="line"><span class="keyword">const</span> shadow3 = thirdParent.<span class="title function_">attachShadow</span>({ <span class="attr">mode</span>: <span class="string">'open'</span> });</span><br><span class="line"><span class="keyword">const</span> span3 = <span class="variable language_">document</span>.<span class="title function_">createElement</span>(<span class="string">'span'</span>);</span><br><span class="line"></span><br><span class="line">span3.<span class="property">innerHTML</span> = <span class="string">`</span></span><br><span class="line"><span class="string"> <div class="text">Shadow DOM3</div></span></span><br><span class="line"><span class="string"> <style></span></span><br><span class="line"><span class="string"> .text {</span></span><br><span class="line"><span class="string"> border: 1px solid #ccc;</span></span><br><span class="line"><span class="string"> color: var(--color);</span></span><br><span class="line"><span class="string"> }</span></span><br><span class="line"><span class="string"> </style></span></span><br><span class="line"><span class="string">`</span>;</span><br></pre></td></tr></table></figure><p><img src="css-hook.png" class="lazyload" data-srcset="css-hook.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="css-hook"></p></li><li><p>使用伪类修改Shadow DOM的内部样式</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="comment">// style</span></span><br><span class="line">input[placeholder=<span class="string">'user'</span>]::-webkit-input-placeholder {</span><br><span class="line"> <span class="attr">color</span>: red;</span><br><span class="line"> font-<span class="attr">size</span>: 18px;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// html</span></span><br><span class="line"><input placeholder=<span class="string">"user"</span> <span class="keyword">class</span>=<span class="string">"user"</span> name=<span class="string">"user"</span> type=<span class="string">"text"</span> /></span><br><span class="line"><span class="language-xml"><span class="tag"><<span class="name">input</span></span></span></span><br><span class="line"><span class="tag"><span class="language-xml"> <span class="attr">placeholder</span>=<span class="string">"password"</span></span></span></span><br><span class="line"><span class="tag"><span class="language-xml"> <span class="attr">class</span>=<span class="string">"password"</span></span></span></span><br><span class="line"><span class="tag"><span class="language-xml"> <span class="attr">name</span>=<span class="string">"password"</span></span></span></span><br><span class="line"><span class="tag"><span class="language-xml"> <span class="attr">type</span>=<span class="string">"text"</span></span></span></span><br><span class="line"><span class="tag"><span class="language-xml">/></span></span></span><br></pre></td></tr></table></figure></li></ul><p><img src="fake-class.png" class="lazyload" data-srcset="fake-class.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="fake-class"></p>]]></content>
<summary type="html"><h4 id="什么是Shadow-Dom?"><a href="#什么是Shadow-Dom?" class="headerlink" title="什么是Shadow Dom?"></a>什么是Shadow Dom?</h4><blockquote>
<p>一种连接节点的树状结构,代表标记文档(通常是在 web 文档中的 HTML 文档)中出现的不同元素和文本字符串。</p>
</blockquote>
<p>浏览器渲染文档的时候会给指定的DOM结构插入编写好的DOM元素,但是插入的Shadow DOM 会与主文档的DOM保持分离,也就是说Shadow DOM不存在于主DOM树上。并且Shadow DOM封装出来的DOM元素是独立的,外部的配置不会影响到内部,内部的配置也不会影响外部。</p>
<p><strong>Chrome中查看Shadow Dom</strong><br>1.打开浏览器控制台的设置选项<br>2.找到Preference -&gt; Elements,把show user anent shadow dom勾上<br><img src="chrome-setting.png" class="lazyload" data-srcset="chrome-setting.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="chrome-setting"><br><img src="shadow-dom.png" class="lazyload" data-srcset="shadow-dom.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="shadow-dom"></p>
<h4 id="Shadow-Dom的结构"><a href="#Shadow-Dom的结构" class="headerlink" title="Shadow Dom的结构"></a>Shadow Dom的结构</h4></summary>
</entry>
<entry>
<title>关于原子CSS引擎 -- unocss</title>
<link href="https://sunjinkang.github.io/2024/01/06/59-about-unocss/"/>
<id>https://sunjinkang.github.io/2024/01/06/59-about-unocss/</id>
<published>2024-01-06T02:23:11.000Z</published>
<updated>2024-01-19T06:51:05.910Z</updated>
<content type="html"><![CDATA[<h4 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h4><p>unocss是一个即时的原子CSS引擎,它可以让你用简短的类名来控制元素的样式,而不需要写复杂的CSS代码。<br>之前有分享提到过Tailwind,不知道大家是否还记得,Tailwind就是一种原子化的CSS框架。</p><blockquote><p>原子化CSS是一种CSS架构方式,其支持小型、单一用途的类,其名称基于视觉功能。更加通俗的来讲,原子化CSS是一种新的CSS编程思路,它倾向于创建小巧且单一用途的class,并且以视觉效果进行命名。</p></blockquote><h4 id="优点"><a href="#优点" class="headerlink" title="优点"></a>优点</h4><p>它可以让你快速地开发和原型设计,而不需要考虑CSS的细节。<br>它可以让你的CSS文件更小,因为它只生成你用到的工具类。<br>它可以让你的CSS更一致,因为它遵循一套预设的规则和变量。<br>它可以让你的CSS更灵活,因为它支持自定义工具类,变体,指令和图标。<br>它可以让你的CSS更易于维护,因为它避免了样式冲突和重复代码。</p><h4 id="unocss的安装和使用"><a href="#unocss的安装和使用" class="headerlink" title="unocss的安装和使用"></a>unocss的安装和使用</h4><p>unocss官网:<a href="https://unocss.dev/">https://unocss.dev/</a></p><p>unocss的安装(支持pnpm/yarn/npm):</p><blockquote><p>pnpm add -D unocss</p></blockquote><p><strong>在Vite中使用unocss</strong><br>unocss支持多种打包工具,这里仅以vite进行介绍,其他的方式可以查看官方文档。</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">// 在vite配置文件中引入unocss</span></span><br><span class="line"><span class="comment">// vite.config.ts</span></span><br><span class="line"><span class="keyword">import</span> <span class="title class_">UnoCSS</span> <span class="keyword">from</span> <span class="string">'unocss/vite'</span></span><br><span class="line"><span class="keyword">import</span> { defineConfig } <span class="keyword">from</span> <span class="string">'vite'</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="title function_">defineConfig</span>({</span><br><span class="line"> <span class="attr">plugins</span>: [</span><br><span class="line"> <span class="title class_">UnoCSS</span>(),</span><br><span class="line"> ],</span><br><span class="line">})</span><br><span class="line"></span><br><span class="line"><span class="comment">// 新建 uno.config.ts 文件</span></span><br><span class="line"><span class="keyword">import</span> { defineConfig } <span class="keyword">from</span> <span class="string">'unocss'</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="title function_">defineConfig</span>({</span><br><span class="line"> <span class="comment">// ...UnoCSS options</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"><span class="keyword">import</span> <span class="string">'virtual:uno.css'</span></span><br></pre></td></tr></table></figure><p>在Vite中使用unocss时,支持设置不同的mode:</p><ul><li>global(默认)<br>在这种模式下,需要在项目入口文件中添加 uno.css 的引入,同时这种模式支持热更新,生成的css样式会注入到index.html文件中。</li><li>vue-scoped<br>将生成的css注入<style scoped></li><li>svelte-scoped<br>g该模式已移入对应的svelte-scoped包中</li><li>shadow-dom</li><li>per-module (实验性的)<br>为每个模块生成对应的css样式</li><li>dist-chunk (实验性的)<br>为每个build的chunk文件生成css,对多页面应用更友好</li></ul><p><strong>react+unocss</strong></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"><span class="comment">// vite.config.js</span></span><br><span class="line"><span class="keyword">import</span> <span class="title class_">UnoCSS</span> <span class="keyword">from</span> <span class="string">'unocss/vite'</span></span><br><span class="line"><span class="keyword">import</span> <span class="title class_">React</span> <span class="keyword">from</span> <span class="string">'@vitejs/plugin-react'</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> {</span><br><span class="line"> <span class="attr">plugins</span>: [</span><br><span class="line"> <span class="title class_">React</span>(),</span><br><span class="line"> <span class="title class_">UnoCSS</span>(),</span><br><span class="line"> ],</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>注意:</p><ul><li>如果项目中使用了 <em>@unocss/preset-attributify</em>,需要把 tsc 从build命令中去除</li><li>如果项目中同时使用了 <em>@vitejs/plugin-react</em> 和 <em>@unocss/preset-attributify</em>,引入unocss插件的位置要放在 <em>@vitejs/plugin-react</em> 前面<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"><span class="comment">// vite.config.js</span></span><br><span class="line"><span class="keyword">import</span> <span class="title class_">UnoCSS</span> <span class="keyword">from</span> <span class="string">'unocss/vite'</span></span><br><span class="line"><span class="keyword">import</span> <span class="title class_">React</span> <span class="keyword">from</span> <span class="string">'@vitejs/plugin-react'</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> {</span><br><span class="line"> <span class="attr">plugins</span>: [</span><br><span class="line"> <span class="title class_">UnoCSS</span>(),</span><br><span class="line"> <span class="title class_">React</span>(),</span><br><span class="line"> ],</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li></ul><p><strong>preset</strong></p><p>Presets是UnoCSS的核心功能,能够让开发更便利</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"><span class="comment">// uno.config.ts</span></span><br><span class="line"><span class="keyword">import</span> { defineConfig, presetAttributify, presetUno } <span class="keyword">from</span> <span class="string">'unocss'</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="title function_">defineConfig</span>({</span><br><span class="line"> <span class="attr">presets</span>: [</span><br><span class="line"> <span class="title function_">presetAttributify</span>({ <span class="comment">/* preset options */</span>}),</span><br><span class="line"> <span class="title function_">presetUno</span>(),</span><br><span class="line"> <span class="comment">// ...custom presets</span></span><br><span class="line"> ],</span><br><span class="line">})</span><br></pre></td></tr></table></figure><p>注意:<br>如果presets的选项设置了具体值,默认preset会自动忽略。同时可以通过空数组的方式禁用默认preset。</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="comment">// uno.config.ts</span></span><br><span class="line"><span class="keyword">import</span> { defineConfig } <span class="keyword">from</span> <span class="string">'unocss'</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="title function_">defineConfig</span>({</span><br><span class="line"> <span class="attr">presets</span>: [], <span class="comment">// disable default preset</span></span><br><span class="line"> <span class="attr">rules</span>: [</span><br><span class="line"> <span class="comment">// your custom rules</span></span><br><span class="line"> ],</span><br><span class="line">})</span><br></pre></td></tr></table></figure><p>官方提供的preset包:<a href="https://unocss.dev/presets/">https://unocss.dev/presets/</a><br>设置提供的preset包:<a href="https://unocss.dev/presets/community">https://unocss.dev/presets/community</a></p><p><em>定义自己的preset</em></p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> { <span class="title class_">Preset</span>, definePreset } <span class="keyword">from</span> <span class="string">'unocss'</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="title function_">definePreset</span>(<span class="function">(<span class="params">options?: MyPresetOptions</span>) =></span> {</span><br><span class="line"> <span class="keyword">return</span> {</span><br><span class="line"> <span class="attr">name</span>: <span class="string">'my-preset'</span>,</span><br><span class="line"> <span class="attr">rules</span>: [</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line"> ],</span><br><span class="line"> <span class="attr">variants</span>: [</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line"> ],</span><br><span class="line"> }</span><br><span class="line">})</span><br><span class="line"></span><br><span class="line"><span class="comment">// uno.config.ts</span></span><br><span class="line"><span class="keyword">import</span> { defineConfig } <span class="keyword">from</span> <span class="string">'unocss'</span></span><br><span class="line"><span class="keyword">import</span> myPreset <span class="keyword">from</span> <span class="string">'./my-preset'</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="title function_">defineConfig</span>({</span><br><span class="line"> <span class="attr">presets</span>: [</span><br><span class="line"> <span class="title function_">myPreset</span>({ <span class="comment">/* preset options */</span> }),</span><br><span class="line"> ],</span><br><span class="line">})</span><br></pre></td></tr></table></figure><p>注意:规则名相同时,后面的会覆盖前面的规则。</p><h4 id="具体使用"><a href="#具体使用" class="headerlink" title="具体使用"></a>具体使用</h4><p>刚入手 unocss 不知道怎么写规则,可以参考官方(大佬 antfu)给出的 交互式文档,输入你想要的css样式,就可以获得对应的class名称</p><blockquote><p><a href="https://unocss.dev/interactive/">https://unocss.dev/interactive/</a></p></blockquote><p><img src="unocss.png" class="lazyload" data-srcset="unocss.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="unocss"></p><p><em>用法</em><br>基础使用:<br>可以依据自身需要,添加对应的class<br><img src="base.png" class="lazyload" data-srcset="base.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="base"></p><p>自定义规则:</p><ul><li>自定义类<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> { defineConfig } <span class="keyword">from</span> <span class="string">'unocss'</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="title function_">defineConfig</span>({</span><br><span class="line"> <span class="attr">rules</span>: [</span><br><span class="line"> [<span class="string">'w-10'</span>, { <span class="attr">width</span>: <span class="string">'10px'</span> }]</span><br><span class="line"> [<span class="regexp">/^h-(\d)$/</span>, <span class="function">(<span class="params">[, d]</span>) =></span> ({ <span class="attr">height</span>: <span class="string">`<span class="subst">${d}</span>px`</span> })],</span><br><span class="line"> ],</span><br><span class="line">});</span><br><span class="line"></span><br></pre></td></tr></table></figure></li><li>静态快捷方式<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> { defineConfig } <span class="keyword">from</span> <span class="string">'unocss'</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="title function_">defineConfig</span>({</span><br><span class="line"> <span class="attr">shortcuts</span>: [</span><br><span class="line"> { <span class="string">'flex-center'</span>: <span class="string">'flex items-center justify-center'</span> },</span><br><span class="line"> ],</span><br><span class="line">});</span><br><span class="line"></span><br></pre></td></tr></table></figure></li><li>动态快捷方式<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> { defineConfig } <span class="keyword">from</span> <span class="string">'unocss'</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="title function_">defineConfig</span>({</span><br><span class="line"> <span class="attr">shortcuts</span>: [</span><br><span class="line"> [</span><br><span class="line"> <span class="regexp">/^base-border-(.*)$/</span>,</span><br><span class="line"> <span class="function">(<span class="params">match</span>) =></span> <span class="string">`border-1 border-style-dashed border-<span class="subst">${match[<span class="number">1</span>]}</span>`</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></li></ul><h4 id="vscode插件"><a href="#vscode插件" class="headerlink" title="vscode插件"></a>vscode插件</h4><p>unocss有自己的vscode插件:UnoCSS<br><img src="unocss-vscode.png" class="lazyload" data-srcset="unocss-vscode.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="unocss-vscode"></p><p>unocss插件支持提示<br><img src="vscode-1.png" class="lazyload" data-srcset="vscode-1.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="vscode-1"></p><p>页面上使用 unocss 提供的 class 带有虚线,并且能显示类名对应的样式内容<br><img src="vscode-2.png" class="lazyload" data-srcset="vscode-2.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="vscode-2"></p>]]></content>
<summary type="html"><h4 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h4><p>unocss是一个即时的原子CSS引擎,它可以让你用简短的类名来控制元素的样式,而不需要写复杂的CSS代码。<br>之前有分享提到过Tailwind,不知道大家是否还记得,Tailwind就是一种原子化的CSS框架。</p>
<blockquote>
<p>原子化CSS是一种CSS架构方式,其支持小型、单一用途的类,其名称基于视觉功能。更加通俗的来讲,原子化CSS是一种新的CSS编程思路,它倾向于创建小巧且单一用途的class,并且以视觉效果进行命名。</p>
</blockquote>
<h4 id="优点"><a href="#优点" class="headerlink" title="优点"></a>优点</h4><p>它可以让你快速地开发和原型设计,而不需要考虑CSS的细节。<br>它可以让你的CSS文件更小,因为它只生成你用到的工具类。<br>它可以让你的CSS更一致,因为它遵循一套预设的规则和变量。<br>它可以让你的CSS更灵活,因为它支持自定义工具类,变体,指令和图标。<br>它可以让你的CSS更易于维护,因为它避免了样式冲突和重复代码。</p></summary>
</entry>
<entry>
<title>diff算法 -- 快速对比</title>
<link href="https://sunjinkang.github.io/2023/11/14/58-quick-contrast/"/>
<id>https://sunjinkang.github.io/2023/11/14/58-quick-contrast/</id>
<published>2023-11-14T11:51:24.000Z</published>
<updated>2023-12-25T03:01:08.678Z</updated>
<content type="html"><![CDATA[<h4 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h4><p> 前面我们说了diff算法里面的双端对比,主要是在vue2中使用。但在vue3中,使用了另一种比双端diff更快的算法 – 快速diff,今天我们来看一下快速diff的使用方式。</p><h4 id="快速diff的使用场景"><a href="#快速diff的使用场景" class="headerlink" title="快速diff的使用场景"></a>快速diff的使用场景</h4><ul><li>预处理前置节点</li><li>预处理后置节点</li><li>仅有新增节点</li><li>仅有卸载节点</li><li>新增、卸载、移动节点</li></ul><p>仅从上面这五种场景的字面意思上面我们大概能看出它们对应的处理情况,下面我们来看一下,每种场景具体的处理逻辑是怎么样的。(PS:为了便于理解,本文中的节点仅用数字表示)</p><h5 id="预处理前置节点与预处理后置节点"><a href="#预处理前置节点与预处理后置节点" class="headerlink" title="预处理前置节点与预处理后置节点"></a>预处理前置节点与预处理后置节点</h5><p><img src="pre-handle.jpg" class="lazyload" data-srcset="pre-handle.jpg" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="pre-handle"></p><p>从上图我们可以看到,分别有一个新子节点的组和一个旧子节点的组,我们指定一个变量j来代表当前的索引值。</p><ul><li>预处理前置节点就是表示j从0开始处理当前的两个子节点组,从索引0开始分别对比新旧子节点组,相同的时候不做处理(本文中由于节点元素均为数字所以不做处理,实际使用算法时,根据情况做处理,比如更新旧节点)。索引加1,对比下一索引的节点,从上图里面看,下一索引位置的节点不同,所以前置节点的预处理结束。</li><li>预处理前置节点对比完之后进行预处理后置节点的对比,我们设置newEndIdx和oldEndIdx分别对应新旧子节点组的末尾索引,获取对应位置的子节点进行对比,如果相同,newEndIdx和oldEndIdx就减1,指向前一位继续对比,直到对应位置的子节点不相同。</li></ul><p>从上面这个图可以看出来,当我们经过预处理前置节点和预处理后置节点这两步之后,明显新节点组还剩余一个4,旧节点组已经对比完了,所以我们引入下一种场景:仅有新增节点.</p><p>vue3源码</p><h5 id="仅有新增节点"><a href="#仅有新增节点" class="headerlink" title="仅有新增节点"></a>仅有新增节点</h5><p>仅有新增的节点,我们实际上只需要把节点添加到对应位置去即可,从上一步来看,就是新节点组最后对比的不相同的节点的位置,也就是说放在newEndIdx的位置。对应到真实场景中,比如dom的处理时,是需要把新的节点挂载到newEndIdx+1上去,即newEndIdx+1的位置作为锚点。</p><p>上图中就是新节点组中的4,把它加到旧节点组的对应位置之后,对比就完成了,新旧两个节点组就一样了。</p><h5 id="仅有卸载节点"><a href="#仅有卸载节点" class="headerlink" title="仅有卸载节点"></a>仅有卸载节点</h5><p>仅有卸载节点,就是指,新节点组对比结束了,没有剩余未对比的元素,而旧节点组还有为对比的节点,即剩余的节点在新节点组中不存在,所以直接删除即可,即卸载dom节点。</p><h5 id="新增、卸载、移动节点"><a href="#新增、卸载、移动节点" class="headerlink" title="新增、卸载、移动节点"></a>新增、卸载、移动节点</h5><p><img src="map-element.jpg" class="lazyload" data-srcset="map-element.jpg" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="map-element"><br>这种场景较为复杂,我们先从容易的动手,先删除后续不会用到的旧虚拟节点,比如上图的6,下面我们看一下怎么找到6这个位置的节点。</p><p>做法是构建一个新虚拟节点的key与其下标的映射,然后遍历未处理的旧虚拟节点数组,使其每一项访问前面映射的key得出其value,如果value是undefined就证明该虚拟节点在新虚拟节点数组中没有出现,需要删除。</p><p>删除用不到的节点之后,剩下可能的就是“移动”和“创建”两种操作。</p><p>vue3是利用“最长递增算法”求出最长递增序列,不满足最长递增子序列的节点就是需要移动的节点。<br>下面我们来看一下什么是最长递增子序列以及应该怎么使用达到我们的目的。</p><h4 id="最长递增子序列"><a href="#最长递增子序列" class="headerlink" title="最长递增子序列"></a>最长递增子序列</h4><h5 id="什么是最长递增子序列"><a href="#什么是最长递增子序列" class="headerlink" title="什么是最长递增子序列?"></a>什么是最长递增子序列?</h5><p>以数组每一项为开头,在数组中从前往后对比,前一项要比后一项小(即呈递增趋势),相等也不行,把找到的数拿出来构建的数组叫递增子序列,而“最长递增子序列”则是这些子序列中最长的那个。我们假定有数组【5,1,6,8,10】,那么它的最长递增子序列就是【5,6,8,10】和【1,6,8,10】</p><h5 id="查找最长递增子序列"><a href="#查找最长递增子序列" class="headerlink" title="查找最长递增子序列"></a>查找最长递增子序列</h5><p>查找最长递增子序列的方法有很多种,比如从后往前查找,前一项比当前项小时,子序列长度加1,如果前一项比当前项大或等于当前项时,再将前一项与当前项之后的每一项进行比较,直到数组比较结束。</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><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> seq = [<span class="number">5</span>, <span class="number">1</span>, <span class="number">6</span>, <span class="number">8</span>, <span class="number">10</span>]</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">lis</span>(<span class="params">seq</span>) {</span><br><span class="line"><span class="keyword">const</span> valueToMax = {}</span><br><span class="line"><span class="keyword">let</span> len = seq.<span class="property">length</span></span><br><span class="line"><span class="comment">// 先构建格子,1填充</span></span><br><span class="line"><span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i < len; i++) {</span><br><span class="line">valueToMax[seq[i]] = <span class="number">1</span></span><br><span class="line">}</span><br><span class="line"> </span><br><span class="line"><span class="keyword">let</span> i = len - <span class="number">1</span> <span class="comment">//最后</span></span><br><span class="line"><span class="keyword">let</span> last = seq[i]</span><br><span class="line"><span class="keyword">let</span> prev = seq[i - <span class="number">1</span>] <span class="comment">// prev才是当前比较基值。 跳过最后一个,直接从倒数第二个开始比较,因为最后一个一定是1</span></span><br><span class="line"> </span><br><span class="line"><span class="keyword">while</span> (<span class="keyword">typeof</span> prev !== <span class="string">'undefined'</span>) {</span><br><span class="line"><span class="comment">// 从后往前,两两比较</span></span><br><span class="line"><span class="keyword">let</span> j = i <span class="comment">// 后值的下标</span></span><br><span class="line"><span class="keyword">while</span> (j < len) {</span><br><span class="line">last = seq[j]</span><br><span class="line"><span class="keyword">if</span> (prev < last) {</span><br><span class="line"><span class="comment">// 当前值比后面的值小</span></span><br><span class="line"><span class="keyword">const</span> currentMax = valueToMax[last] + <span class="number">1</span> <span class="comment">// 记录此时比较下的最大值,即后面值的最长子序列长度+1</span></span><br><span class="line"><span class="keyword">if</span> (currentMax > valueToMax[prev]) {</span><br><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment">比较两个值的最长子序列长度,</span></span><br><span class="line"><span class="comment">如果 “后面值的子序列长度+1” 后比 当前值的子序列 长,</span></span><br><span class="line"><span class="comment">那么当前子序列长度重新赋值,取大的。</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line">valueToMax[prev] = currentMax</span><br><span class="line">}</span><br><span class="line"><span class="comment">// valueToMax[prev] =valueToMax[prev] !== 1 ? valueToMax[prev] > currentMax ? valueToMax[prev] : currentMax : currentMax</span></span><br><span class="line">}</span><br><span class="line">j++</span><br><span class="line">}</span><br><span class="line">i--</span><br><span class="line">last = seq[i]</span><br><span class="line">prev = seq[i - <span class="number">1</span>]</span><br><span class="line">}</span><br><span class="line"> </span><br><span class="line"><span class="keyword">const</span> lis = []</span><br><span class="line">i = <span class="number">1</span></span><br><span class="line"><span class="keyword">while</span> (--len >= <span class="number">0</span>) {</span><br><span class="line"><span class="comment">// 从后往前找,1 -> 2 -> 3...</span></span><br><span class="line"><span class="keyword">const</span> n = seq[len]</span><br><span class="line"><span class="keyword">if</span> (valueToMax[n] === i) {</span><br><span class="line">i++</span><br><span class="line">lis.<span class="title function_">unshift</span>(len)</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"> </span><br><span class="line"><span class="keyword">return</span> lis</span><br><span class="line">}</span><br><span class="line"> </span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title function_">lis</span>(seq)) <span class="comment">//得到的序列中的位置索引</span></span><br></pre></td></tr></table></figure><h5 id="最长递增子序列的使用"><a href="#最长递增子序列的使用" class="headerlink" title="最长递增子序列的使用"></a>最长递增子序列的使用</h5><p>我们为了便于说明,拿上面的第二张图来举例,上述四种场景的比较之后,我们得到了一个新旧节点之间的映射关系,目前新节点的元素是【6,4,5,8】,我们可以得到映射关系是【6,4,5,0】这个新数组的最长递增子序列是【1,2】,接下来,我们只需要从后往前一次做对比即可。</p><p>我们定义变量 i 记录位置,定义变量 j,记录最长递增子序列的位置,初始化为 1,</p><p>当 i = 3 时,位置值为 0,对应节点为 8,说明 8 是新增节点,直接挂载;</p><p>当 i = 2 时,位置值为 5,对应节点为 5,i = 2 处于最长递增子序列 j = 1 处, 因此无需移动直接跳过。一旦找到最长递增子序列元素,i 和 j 需同时往上移动;</p><p>当 i = 1 时,位置值为 4,对应节点为 5,i = 1 处于最长递增子序列当中 j = 0 处,因此无需移动直接跳过。i 和 j 同时再往上移动;</p><p>当 i = 0 时,位置值为 6,对应节点为 6,i = 0 不处于最长递增子序列中,因此该节点需要移动。</p><p>上述步骤执行结束后,可以看到旧节点已变更为新节点,变更结束。</p>]]></content>
<summary type="html"><h4 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h4><p> 前面我们说了diff算法里面的双端对比,主要是在vue2中使用。但在vue3中,使用了另一种比双端diff更快的算法 – 快速diff,今天我们来看一下快速diff的使用方式。</p>
<h4 id="快速diff的使用场景"><a href="#快速diff的使用场景" class="headerlink" title="快速diff的使用场景"></a>快速diff的使用场景</h4><ul>
<li>预处理前置节点</li>
<li>预处理后置节点</li>
<li>仅有新增节点</li>
<li>仅有卸载节点</li>
<li>新增、卸载、移动节点</li>
</ul>
<p>仅从上面这五种场景的字面意思上面我们大概能看出它们对应的处理情况,下面我们来看一下,每种场景具体的处理逻辑是怎么样的。(PS:为了便于理解,本文中的节点仅用数字表示)</p></summary>
</entry>
<entry>
<title>diff算法 -- 双端对比</title>
<link href="https://sunjinkang.github.io/2023/11/09/57-double-end-contrast/"/>
<id>https://sunjinkang.github.io/2023/11/09/57-double-end-contrast/</id>
<published>2023-11-09T05:27:17.000Z</published>
<updated>2023-12-25T03:01:08.678Z</updated>
<content type="html"><![CDATA[<h4 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h4><p> diff算法,全称为difference算法,是一种用于比较和查找文本、源代码或任何字符串之间差异的算法。前端中在react、vue等中使用diff算法对比虚拟DOM树,进行虚拟DOM树的更新,进而完成真实DOM的更新,达到更新页面的效果。在vue2中使用的就是双端diff算法。</p><h4 id="什么是双端对比?"><a href="#什么是双端对比?" class="headerlink" title="什么是双端对比?"></a>什么是双端对比?</h4><blockquote><p>双端对比,即双端diff算法,一种同时对新旧两组子节点的两个端点进行比较的算法。<br>但就从上面这句话来看,可能有点抽象,可参考下面这张图片<br><img src="double-end-contrast.png" class="lazyload" data-srcset="double-end-contrast.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="double-end-contrast"></p></blockquote><h4 id="双端对比的简单实现"><a href="#双端对比的简单实现" class="headerlink" title="双端对比的简单实现"></a>双端对比的简单实现</h4><h6 id="理想情况下的实现"><a href="#理想情况下的实现" class="headerlink" title="理想情况下的实现"></a>理想情况下的实现</h6><p>为了便于理解,我们先从理想情况下看怎么实现双端对比。上面提到了,双端对比需要从新旧两组子节点进行对比,所以需要四个索引值来分别指向新旧两组子节点的端点。本文中将其分别命名为newStartIdx, newEndIdx, oldStartIdx, oldEndIdx,由于本文仅是为了说明双端算法,为了便于理解说明,假定所有的节点均为数字数组中的元素,并进行比较,从代码层实现如下:</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="comment">// newStartIdx 新数组的起始索引</span></span><br><span class="line"><span class="comment">// newEndIdx 新数组的结束索引</span></span><br><span class="line"><span class="comment">// newArray 新数组</span></span><br><span class="line"><span class="comment">// oldStartIdx 旧数组的起始索引</span></span><br><span class="line"><span class="comment">// oldEndIdx 旧数组的结束索引</span></span><br><span class="line"><span class="comment">// oldArray 旧数组</span></span><br><span class="line"><span class="keyword">let</span> oldStartIdx = <span class="number">0</span>, newStartIdx = <span class="number">0</span></span><br><span class="line"><span class="keyword">let</span> oldEndIdx = oldArray.<span class="property">length</span> - <span class="number">1</span>, newEndIdx = newArray.<span class="property">length</span> - <span class="number">1</span></span><br><span class="line"><span class="keyword">let</span> oldStart = oldArray[oldStartIdx], newStart = newArray[newStartIdx]</span><br><span class="line"><span class="keyword">let</span> oldEnd = oldArray[oldEndIdx], newEnd = newArray[newEndIdx]</span><br><span class="line"><span class="keyword">if</span> (oldStart === newStart) {} </span><br><span class="line"><span class="keyword">else</span> <span class="keyword">if</span> (oldEnd === newEnd) {} </span><br><span class="line"><span class="keyword">else</span> <span class="keyword">if</span> (oldStart === newEnd) {}</span><br><span class="line"><span class="keyword">else</span> <span class="keyword">if</span> (oldEnd === newStart) {}</span><br></pre></td></tr></table></figure><p>那么下面我们来看一下双端算法的具体实现,根据上面的图片,我们将对应数组元素转化为数字:</p><blockquote><p>[1, 2, 3, 4]<br>[4, 2, 1, 3]<br>按照图片中标识的先后顺序,我们可以得出下面的步骤:</p></blockquote><ol><li>比较<em>oldStartIdx</em>和<em>newStartIdx</em>指向的元素,元素不同,不可复用,什么都不用做</li><li>比较<em>oldEndIdx</em>和<em>newEndIdx</em>指向的元素,元素不同,不可复用,什么都不用做</li><li>比较<em>oldStartIdx</em>和<em>newEndIdx</em>指向的元素,元素不同,不可复用,什么都不用做</li><li>比较<em>oldEndIdx</em>和<em>newStartIdx</em>指向的元素,元素相同,可复用,需要移动元素</li></ol><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> oldStartIdx = <span class="number">0</span>, newStartIdx = <span class="number">0</span></span><br><span class="line"><span class="keyword">let</span> oldEndIdx = oldArray.<span class="property">length</span> - <span class="number">1</span>, newEndIdx = newArray.<span class="property">length</span> - <span class="number">1</span></span><br><span class="line"><span class="keyword">let</span> oldStart = oldArray[oldStartIdx], newStart = newArray[newStartIdx]</span><br><span class="line"><span class="keyword">let</span> oldEnd = oldArray[oldEndIdx], newEnd = newArray[newEndIdx]</span><br><span class="line"><span class="keyword">if</span> (oldStart === newStart) {} </span><br><span class="line"><span class="keyword">else</span> <span class="keyword">if</span> (oldEnd === newEnd) {} </span><br><span class="line"><span class="keyword">else</span> <span class="keyword">if</span> (oldStart === newEnd) {}</span><br><span class="line"><span class="keyword">else</span> <span class="keyword">if</span> (oldEnd === newStart) {</span><br><span class="line"> <span class="comment">// 省略移动元素的代码。。。</span></span><br><span class="line"> <span class="comment">// 更新索引值,指向下一个位置</span></span><br><span class="line"> oldEnd = oldArray[--oldEndIdx];</span><br><span class="line"> newStart = newArray[++newStartIdx];</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>进行上面的操作之后,数组变更为:</p><blockquote><p>[4, 1, 2, 3]<br>[4, 2, 1, 3]<br>这时,oldArray的起始指向1,结束指向3;newArray的起始指向2,结束指向3。接下来重复进行上面的比对过程即可,由于是重复进行的逻辑,所以把对比的过程封装到一个while循环中:<br>这里需要注意,while循环的判断条件是起始索引小于结束索引,表明数组还没对比完,但这里会引申出其他问题,具体什么问题等一下再说,先往下看</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><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> oldStartIdx = <span class="number">0</span>, newStartIdx = <span class="number">0</span></span><br><span class="line"><span class="keyword">let</span> oldEndIdx = oldArray.<span class="property">length</span> - <span class="number">1</span>, newEndIdx = newArray.<span class="property">length</span> - <span class="number">1</span></span><br><span class="line"><span class="keyword">let</span> oldStart = oldArray[oldStartIdx], newStart = newArray[newStartIdx]</span><br><span class="line"><span class="keyword">let</span> oldEnd = oldArray[oldEndIdx], newEnd = newArray[newEndIdx]</span><br><span class="line"><span class="keyword">while</span>(oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx) {</span><br><span class="line"> <span class="keyword">if</span> (oldStart === newStart) {} </span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span> (oldEnd === newEnd) {} </span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span> (oldStart === newEnd) {}</span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span> (oldEnd === newStart) {</span><br><span class="line"> <span class="comment">// 省略移动元素的代码。。。</span></span><br><span class="line"> <span class="comment">// 更新索引值,指向下一个位置</span></span><br><span class="line"> oldEnd = oldArray[--oldEndIdx];</span><br><span class="line"> newStart = newArray[++newStartIdx];</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>上面的数组经过一轮对比之后,重复双端对比的顺序:</p><ol><li>比较<em>oldStartId</em>x和<em>newStartIdx</em>指向的元素,元素不同,不可复用,什么都不用做</li><li>比较<em>oldEndIdx</em>x和<em>newEndIdx</em>指向的元素,元素相同,但由于都处于数组尾部,不需要移动,所以仅更新索引值即可(PS:在具体的代码处理中根据需要自己添加处理,本文仅作双端对比的说明)</li></ol><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> oldStartIdx = <span class="number">0</span>, newStartIdx = <span class="number">0</span></span><br><span class="line"><span class="keyword">let</span> oldEndIdx = oldArray.<span class="property">length</span> - <span class="number">1</span>, newEndIdx = newArray.<span class="property">length</span> - <span class="number">1</span></span><br><span class="line"><span class="keyword">let</span> oldStart = oldArray[oldStartIdx], newStart = newArray[newStartIdx]</span><br><span class="line"><span class="keyword">let</span> oldEnd = oldArray[oldEndIdx], newEnd = newArray[newEndIdx]</span><br><span class="line"><span class="keyword">while</span>(oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx) {</span><br><span class="line"> <span class="keyword">if</span> (oldStart === newStart) {} </span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span> (oldEnd === newEnd) {</span><br><span class="line"> <span class="comment">// 省略需要添加的处理代码</span></span><br><span class="line"> oldEnd = oldArray[--oldEndIdx];</span><br><span class="line"> newEnd = newArray[--newEndIdx];</span><br><span class="line"> } </span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span> (oldStart === newEnd) {}</span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span> (oldEnd === newStart) {</span><br><span class="line"> <span class="comment">// 省略移动元素的代码。。。</span></span><br><span class="line"> <span class="comment">// 更新索引值,指向下一个位置</span></span><br><span class="line"> oldEnd = oldArray[--oldEndIdx];</span><br><span class="line"> newStart = newArray[++newStartIdx];</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>这时,oldArray的起始指向1,结束指向2;newArray的起始指向2,结束指向1。接下来,进行剩余部分的对比:</p><ol><li>比较<em>oldStartId</em>x和<em>newStartIdx</em>指向的元素,元素不同,不可复用,什么都不用做</li><li>比较<em>oldEndIdx</em>x和<em>newEndIdx</em>指向的元素,元素不同,不可复用,什么都不用做</li><li>比较<em>oldStartId</em>x和<em>newEndIdx</em>指向的元素,元素相同,可复用,需要更新索引和移动元素</li></ol><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="comment">// ....</span></span><br><span class="line"><span class="keyword">while</span>(oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx) {</span><br><span class="line"> <span class="keyword">if</span> (oldStart === newStart) {} </span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span> (oldEnd === newEnd) {</span><br><span class="line"> <span class="comment">// 省略需要添加的处理代码</span></span><br><span class="line"> <span class="comment">// 更新索引值,指向下一个位置</span></span><br><span class="line"> oldEnd = oldArray[--oldEndIdx];</span><br><span class="line"> newEnd = newArray[--newEndIdx];</span><br><span class="line"> } </span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span> (oldStart === newEnd) {</span><br><span class="line"> <span class="comment">// 省略移动元素的代码。。。</span></span><br><span class="line"> <span class="comment">// 更新索引值,指向下一个位置</span></span><br><span class="line"> oldStart = oldArray[++oldStartIdx];</span><br><span class="line"> newEnd = newArray[--newEndIdx];</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span> (oldEnd === newStart) {</span><br><span class="line"> <span class="comment">// 省略移动元素的代码。。。</span></span><br><span class="line"> <span class="comment">// 更新索引值,指向下一个位置</span></span><br><span class="line"> oldEnd = oldArray[--oldEndIdx];</span><br><span class="line"> newStart = newArray[++newStartIdx];</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>上面对比结束之后,仅剩余一个位置需要对比,由于该位置的元素相同,所以仅需要更新索引即可</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// ....</span></span><br><span class="line"><span class="keyword">while</span>(oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx) {</span><br><span class="line"> <span class="keyword">if</span> (oldStart === newStart) {</span><br><span class="line"> oldStart = oldArray[++oldStartIdx];</span><br><span class="line"> newStart = newArray[++newStartIdx];</span><br><span class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (oldEnd === newEnd) {</span><br><span class="line"> <span class="comment">// 省略需要添加的处理代码</span></span><br><span class="line"> <span class="comment">// 更新索引值,指向下一个位置</span></span><br><span class="line"> oldEnd = oldArray[--oldEndIdx];</span><br><span class="line"> newEnd = newArray[--newEndIdx];</span><br><span class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (oldStart === newEnd) {</span><br><span class="line"> <span class="comment">// 省略移动元素的代码。。。</span></span><br><span class="line"> <span class="comment">// 更新索引值,指向下一个位置</span></span><br><span class="line"> oldStart = oldArray[++oldStartIdx];</span><br><span class="line"> newEnd = newArray[--newEndIdx];</span><br><span class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (oldEnd === newStart) {</span><br><span class="line"> <span class="comment">// 省略移动元素的代码。。。</span></span><br><span class="line"> <span class="comment">// 更新索引值,指向下一个位置</span></span><br><span class="line"> oldEnd = oldArray[--oldEndIdx];</span><br><span class="line"> newStart = newArray[++newStartIdx];</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>经过上面的对比之后,新旧两组数组已经变为拥有相同元素的数组。同时相信大家经过上面这个对比的过程之后,已经对双端对比的过程有了一个基本的了解,但是上面的例子中使用的数组实际上是有一定特殊性的,新旧两个数组拥有相同的元素,只是顺序不一样而已,而且数组的四个索引位置的数据刚好能满足将这个对比进行下去的条件,这只是一种理想情况,但在实际使用中,这种情况可能很少见,比如四个索引位置的元素各不相同怎么办?下面我们来看一下非理想情况下时,双端对比的处理</p><p>和上面类似,我们也用例子进行说明:<br>现有两个较多元素的新旧数组:</p><blockquote><p>[6, 8, 1, 2, 3, 4, 5, 7]<br>[4, 2, 7, 1, 4, 3, 5, 8]<br>从上面的例子可以看出初始时的四个索引位置对应的元素都不相同,针对这种情况,双端对比的处理方式是:查找新元素的首位在旧数组中的对应位置</p></blockquote><ol><li>能够找到新元素的首位在旧数组中的对应位置</li><li>找不到新元素的首位在旧数组中的对应位置<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> index = oldArray.<span class="title function_">findIndex</span>(<span class="function"><span class="params">item</span> =></span> item === newStart);</span><br><span class="line"><span class="comment">// 能够找到新元素的首位在旧数组中的对应位置</span></span><br><span class="line"><span class="keyword">if</span> (index > -<span class="number">1</span>) {</span><br><span class="line"> <span class="comment">// ......</span></span><br><span class="line"> <span class="comment">// 为了保证后续不在对该元素进行对比,将其设置为null</span></span><br><span class="line"> oldArray[index] = <span class="literal">null</span>;</span><br><span class="line"> newStart = newArray[++newStartIdx];</span><br><span class="line">} <span class="keyword">else</span> {</span><br><span class="line"> <span class="comment">// 找不到新元素的首位在旧数组中的对应位置</span></span><br><span class="line"> <span class="comment">// 因为oldArray中没有newStart对应的元素,因此需要自己创建一个新的元素然后将元素添加到数组中,具体代码不在添加,可根据实际需要添加</span></span><br><span class="line"> newStart = newArray[++newStartIdx];</span><br><span class="line">}</span><br></pre></td></tr></table></figure>根据上面针对元素的查找,代码变更为:<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></pre></td><td class="code"><pre><span class="line"><span class="keyword">while</span>(oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx) {</span><br><span class="line"> <span class="keyword">if</span> (oldStart === <span class="literal">null</span>) {</span><br><span class="line"> oldStart = oldQueue[++oldStartIdx];</span><br><span class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (oldEnd === <span class="literal">null</span>) {</span><br><span class="line"> oldEnd = oldQueue[--oldEndIdx];</span><br><span class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (oldStart === newStart) {</span><br><span class="line"> oldStart = oldArray[++oldStartIdx];</span><br><span class="line"> newStart = newArray[++newStartIdx];</span><br><span class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (oldEnd === newEnd) {</span><br><span class="line"> oldEnd = oldArray[--oldEndIdx];</span><br><span class="line"> newEnd = newArray[--newEndIdx];</span><br><span class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (oldStart === newEnd) {</span><br><span class="line"> oldStart = oldArray[++oldStartIdx];</span><br><span class="line"> newEnd = newArray[--newEndIdx];</span><br><span class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (oldEnd === newStart) {</span><br><span class="line"> oldEnd = oldArray[--oldEndIdx];</span><br><span class="line"> newStart = newArray[++newStartIdx];</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">const</span> index = oldArray.<span class="title function_">findIndex</span>(<span class="function"><span class="params">item</span> =></span> item === newStart);</span><br><span class="line"> <span class="keyword">if</span> (index > -<span class="number">1</span>) {</span><br><span class="line"> <span class="comment">// ......</span></span><br><span class="line"> oldArray[index] = <span class="literal">null</span>;</span><br><span class="line"> newStart = newArray[++newStartIdx];</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="comment">// ......</span></span><br><span class="line"> newStart = newArray[++newStartIdx];</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>上面的代码保证了非理想情况下的双端对比能够进行对比处理,但是我们在实际应用双端对比进行处理时,上面的while条件往往会产生问题,如果新旧数组的长度不一致,比如下面这种,那么当短数组对比结束时,长数组还没对比完成,但上面的代码根据while条件实际上已经不能再继续执行,这时候就需要做针对处理,保证对比的正确性</li></ol><blockquote><p>[6, 13, 8, 1, 2, 10, 9, 11, 12, 3, 4, 5, 7]<br>[4, 2, 7, 1, 4, 3, 5, 8]</p></blockquote><p>从while的条件中可以看出,实际上可以分为两种情况进行处理:</p><ol><li>旧数组对比结束,新数组未结束<br>将新数组中剩余未对比的元素移动到新数组的最新结束元素后</li><li>新数组对比结束,旧数组未结束<br>将旧数组中剩余元素删除</li></ol><p>使用双端对比的前提是需要双端连续可持续跳跃,所以双向链表可用</p>]]></content>
<summary type="html"><h4 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h4><p> diff算法,全称为difference算法,是一种用于比较和查找文本、源代码或任何字符串之间差异的算法。前端中在react、vue等中使用diff算法对比虚拟DOM树,进行虚拟DOM树的更新,进而完成真实DOM的更新,达到更新页面的效果。在vue2中使用的就是双端diff算法。</p>
<h4 id="什么是双端对比?"><a href="#什么是双端对比?" class="headerlink" title="什么是双端对比?"></a>什么是双端对比?</h4><blockquote>
<p>双端对比,即双端diff算法,一种同时对新旧两组子节点的两个端点进行比较的算法。<br>但就从上面这句话来看,可能有点抽象,可参考下面这张图片<br><img src="double-end-contrast.png" class="lazyload" data-srcset="double-end-contrast.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="double-end-contrast"></p>
</blockquote>
<h4 id="双端对比的简单实现"><a href="#双端对比的简单实现" class="headerlink" title="双端对比的简单实现"></a>双端对比的简单实现</h4></summary>
</entry>
<entry>
<title>微信小游戏制作</title>
<link href="https://sunjinkang.github.io/2023/09/04/56-weixin-mini-game/"/>
<id>https://sunjinkang.github.io/2023/09/04/56-weixin-mini-game/</id>
<published>2023-09-04T06:21:41.000Z</published>
<updated>2023-12-25T03:01:08.671Z</updated>
<content type="html"><![CDATA[<h4 id="概览"><a href="#概览" class="headerlink" title="概览"></a>概览</h4><h6 id="工具"><a href="#工具" class="headerlink" title="工具"></a>工具</h6><p>微信小游戏使用《小游戏可视化制作工具》进行制作开发。<a href="https://gamemaker.weixin.qq.com/#/">《小游戏可视化制作工具》</a>是一款web应用,可用于开发微信小游戏。以可视化的操作方式编辑游戏场景,使用积木作为脚本设计精灵的行为逻辑。</p><blockquote><p>《小游戏可视化制作工具》推荐使用Chrome浏览器或者最新的QQ浏览器打开。</p></blockquote><p>《小游戏可视化制作工具》支持微信扫码登录,创建的小游戏项目为开发者私人所有,无法跟他人共享或共同编辑。<br>《小游戏可视化制作工具》的账号密码登录为团队开发登录使用,暂未开放注册。</p><h6 id="小游戏编辑器介绍"><a href="#小游戏编辑器介绍" class="headerlink" title="小游戏编辑器介绍"></a>小游戏编辑器介绍</h6><p><img src="weixin_idea.png" class="lazyload" data-srcset="weixin_idea.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="weixin_idea"></p><p>概览编辑器,可分为8个区域,分别是:</p><ul><li>工具栏:添加素材,运行游戏,预览发布,搜索,保存退出等功能入口;</li><li>场景面板:添加/切换不同场景,如果游戏复杂可能存在多个场景,比如:不同关卡、开始界面、结束界面等等;</li><li>资源面板:管理当前项目的所有资源(包括精灵/声音/函数),资源管理器中的精灵可拖拽进入编辑区域生成一个新的图层精灵实例;</li><li>积木面板:用于控制精灵实例的积木脚本,积木是与资源一一对应的,一个资源的多个实例图层都会公用一套积木;</li><li>图层面板:管理当前场景中的精灵实例,已经在编辑区域有实例的精灵都是一个图层,在图层面板可以拖拽调整图层顺序,也可以打组成为容器(Ctrl+G);</li><li>编辑区域:这里就是所见即所得的游戏界面!编辑区域与图层是一一对应的,我们可以选中区域中的精灵实例进行拖拽位置,调整大小等;</li><li>属性面板:由两块组成,当我们选择资源时,只显示资源属性,当我们选择图层时,同时显示图层属性和资源属性。每个图层都有自己的属性互不影响;</li><li>数据面板:对(全局/精灵私有)的变量/列表/表格/通知等数据进行管理</li></ul><h6 id="制作流程"><a href="#制作流程" class="headerlink" title="制作流程"></a>制作流程</h6><ol><li>在浏览器中打开制作工具</li><li>通过 [新建小游戏/复制示例/改编他人作品] 等方式创建一个游戏项目</li><li>导入素材,编辑场景,拖入积木,完善游戏</li><li>在电脑上运行调试</li><li>在移动端预览调试,也可以分享给他人体验</li><li>发布到MP平台,完成小游戏</li></ol><h6 id="游戏世界"><a href="#游戏世界" class="headerlink" title="游戏世界"></a>游戏世界</h6><p><em>精灵</em><br>在计算机图形学中,当一张二维图像集成进场景中,成为整个游戏的一部分时,这张图就被称为精灵(英:Sprite)</p><p><em>数字</em><br>数字也是一类特殊的精灵,它是由 “0-9” 十个数字及“-”和“.”组合形成的一个整体。使用也非常方便,可以通过以下这组积木进行实时动态修改。</p><blockquote><p>外观-「修改[?]的值为(n)」<br>外观-「将[?]的值增加(1)」</p></blockquote><p><em>文字</em><br>文字也是一类特殊的精灵,添加之后可以在图层属性面板修改:对齐方式、字体大小、行高、文字颜色。只能通过以下积木修改内容。</p><blockquote><p>外观-「修改[?]的内容为(你好)」</p></blockquote><h6 id="编辑器"><a href="#编辑器" class="headerlink" title="编辑器"></a>编辑器</h6><ul><li><p>工具栏</p><ul><li><p>作品设置<br><img src="work_setting.png" class="lazyload" data-srcset="work_setting.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="work_setting"><br>[适配模式] 我们可以调整在移动端的适配模式,推荐竖屏游戏使用宽度适配,横屏游戏使用高度适配<br>[使用默认资源进度条] 是否显示默认资源加载中的提示<br>[资源加载方式] 如果项目非常大并且多个场景,建议选择切换场景时加载,并且搭配[资源管理]插件一起使用,建议默认选择全部加载后启动<br>[分享标题] 设置一个好的分享标题可以吸引别人玩你的游戏,出现在小游戏分享给好友的卡片中,如不设置默认显示项目名<br>[分享缩略图] 分享图非常关键,无论是在预览时分享给好友,还是在社区,还是发布成独立小游戏,分享作品时该图片是给人的第一印象<br>[游戏说明] 游戏说明会出现在社区的项目页中,只有需要分享时才有必要设置该项</p></li><li><p>游戏适配<br>1、设计尺寸<br>目前通过可视化工具制作的游戏只能运行在微信小游戏端。官方设定的设计尺寸是:750<em>1334,也就是iPhone 7的尺寸。因此在iPhone 7的手机中,可以完美的展示制作工具中看到界面,不会有任何裁剪或者黑边。也会依照此比例,在其他设备上进行等比缩放。</em>循环滚动逻辑会改造为插件模式。*<br>2、适配方案</p><blockquote><p>设置背景图片的高度设计更高一点,为iPhone X的高度。或者将背景精灵纹理进行拉伸处理,这样能把黑边填充满。<br>设置适配模式为适配高度,将游戏等比缩放,假如iPhone X的高度是iPhone 7 的1.2倍,结果是将游戏等比放大1.2倍。但这种方法带来的问题是水平方向会裁剪,左右会失去一部分细节。<br>通过开启相对于场景布局来调整精灵在不同屏幕尺寸中的适配情况,无需过多的操作,只需要在场景中摆放完后选择开启想要的布局模式即可</p></blockquote></li></ul></li><li><p>资源管理<br>游戏素材是游戏的“原材料”,通常包含图片、文本、音频。图片又可分为:单图、帧动画等。</p></li></ul><p>在《小游戏可视化制作工具》中,游戏资源有以下几类</p><blockquote><p>[精灵] 最常用的资源,用途广泛甚至可以替代背景<br>[文字] 特殊的精灵,有两种文字类型,基础文字和带气泡背景的文字,常用于标题,按钮和提示等展示<br>[数字] 特殊的精灵,由0-9和.-两个符号组成,相当于特殊字体,常用于展示得分和其他数值变化<br>[背景] 特殊的精灵,每个场景只有一个且自动生成,并且不会超出屏幕区域,只适用于快速搭建小场景游戏<br>[容器] 多个精灵的组合层,本身也是独立的空精灵<br>[UI插件] 特殊的资源,自带一些行为属性,较为独立,部分积木无法影响到UI插件<br>[声音] 可以被积木引用并播放<br>[函数] 多个积木的合集,适用于需要在不同精灵多次使用相同积木组合的场合<br>游戏资源 = 素材 + 积木。换句话说可视化制作工具中的资源是具有积木逻辑的素材</p></blockquote><ul><li>系统素材<br>素材库包含:系统素材/我的素材/UI插件三个部分,官方提供了多个拥有自主版权的主题素材,如:《积木小Y》、《彩色飞机大战》等。</li></ul><p><em>素材库中的积木小Y是主要 文本/数字 等素材的导入入口,其中 [基础文字] 最为常用</em></p><ul><li><p>上传素材<br><img src="upload.png" class="lazyload" data-srcset="upload.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="upload"><br>使用上传素材需要切换到[我的素材]Tab页,同时针对上传的素材有特殊要求:</p></li><li><p>单图和音频:将素材拖拽扔进我的素材或者上传素材的上传区域即可</p></li><li><p>帧动画组:打开上传素材界面,并将帧动画组的素材名称规范命名为:xx1.png、xx2.png、xx3.png、xx4.png、xx5.png…,然后选中整个帧动画组整体拖拽扔进上传区域,即可自动生成帧动画组素材</p></li><li><p>数字:打开上传素材界面,将数字以规范命名为:xx1.png、xx2.png、xx3.png等,即可自动填充到对应的位置,也可以手动点击单个窗口上传对应的数字和字符,只有上传了负号和小数点的数字精灵,才支持负数和显示小数,否则只能显示正整数</p></li><li><p>文本框:打开上传素材界面,上传一张图片作为文本框的背景,还可以调整文本有效区域和真实图片之间的间距</p><ul><li><p>绘图:开发者可以自行对素材进行编辑修改或者创作一些简单的素材</p></li><li><p>录音:开发者可以创作个性的录音素材,并对素材进行剪辑等操作</p></li><li><p>绑定积木脚本:资源是和积木逻辑绑定的,每一个素材资源对应一套积木,关于积木脚本的详细信息可参考后续文章</p></li><li><p>资源的复用<br>除了从素材库添加资源时默认创建在当前场景中的图层实例,还可以从资源管理器直接拖拽“精灵素材”至当前的编辑区域,即可在当前“场景”添加一个精灵实例,并同时会生成一个对应的“图层”。<br>该实例是“精灵素材”资源的引用,将完全继承“精灵素材”的所有积木脚本。其属性会复制原始的“精灵素材”,可以在图层属性面板修改这些属性。</p></li><li><p>声音和音效<br>声音资源也是从素材库添加,声音分为 [音效] 和 [背景音乐] 两类,在资源库中他们名并没有实际的区别,上传声音素材时,时间过长的会被分类为背景音乐,较短的被分类为音效,可以通过选择全部主题,点击音效来播放预览系统提供的一些音效</p></li></ul></li></ul><p><em>声音是咖啡色的积木,总共只有5个相关的积木,我们推荐音效使用播放,背景音乐使用循环播放,在一些手机系统导致的声音暂停的情况下,我们会在重新进入小游戏时把背景音乐自动重启</em><br><em>在编辑游戏的过程中往往会反复调试音效,记得多使用资源面板中的替换音效功能而不是直接删除再添加,会省力的多</em></p><ul><li>场景管理<br>可以添加多个场景,并设置某一个场景为主场景,主场景并不一定是第一个场景,场景之间是通过积木「切换场景到XX」来互相跳转的,目前暂不支持场景的排序<br>和场景相关的积木:</li></ul><ol><li>「事件-当场景启动时」</li><li>「控制-切换场景到XX」</li><li>「控制-销毁XX」</li><li>「控制-重启当前场景」</li></ol><p>主场景<br>游戏首次加载的场景我们称为主场景(左上角有房子标识)。<br>在主场景中我们可以使用「当游戏开始时」积木作为启动事件,此事件只会触发一次。其他场景可通过「当场景启动时」作为启动事件。<br>这里推荐所有入口都用「当场景启动时」作为启动场景的入口事件,「当游戏开始时」这个积木使用限制较多,只推荐在做简单的demo时使用</p><ul><li>图层管理</li></ul><p>层级<br>图层的顺序影响精灵实例渲染的顺序,以及影响该实例对应的资源积木逻辑执行的顺序,所以管理好图层顺序也很重要,可以通过拖拽来调整图层层级顺序(不能拖动到背景层下方)</p><p>隐藏和锁定<br>图层面板选中图层后右键或者点右侧的菜单按钮会出现 [隐藏/锁定/删除] 三个操作:<br>[锁定] 图层的层级在编辑区域也会影响到下一层精灵的选中,我们可以暂时锁定上层的精灵,方便我们选中下一层,这里的锁定只会影响编辑,并不会对游戏运行过程产生影响<br>[隐藏] 我们也可以直接在图层面板隐藏对应的图层,也可以影响编辑区域中的选中关系,注意这里的隐藏会影响到游戏逻辑,隐藏是一个非常重的操作,如果该精灵是隐藏的,那么他将无法参与碰撞和被用户点击到<br>[删除] 删除图层操作只是将当前图层实例从当前场景中删除,并不会删除代码和对应的资源</p><p>摄像机<br>[设置XX为摄像机的世界区域] 摄像机的边界,摄像机不会移出超出该区域的部分,一般使用方法为在场景中放置一个大正方形作为区域并添加该积木,流程较为麻烦后续会优化该积木<br>[将XX移出摄像机镜头] 一般用于UI设置,需要成为UI的资源才有必要添加该积木<br>[设置摄像机的跟随对象为XX] 使用摄像机的主要目的,我们在制作RPG类型的游戏时有时候会需要把摄像机对准主角,主角始终会在游戏的中间<br>[设置摄像机的缩放比例] 设置摄像机缩放的比例,用于特写<br>[设置摄像机的缩放比例增加] 设置摄像机缩放的比例增减,常用于镜头抖动<br>[设置摄像机的偏移] 设置摄像机缩放的偏移,根据具体场景例如其他角色对话时使用<br>[设置摄像机的偏移增加] 设置摄像机缩放的偏移增减,常用于镜头抖动和来回移动对话</p><ul><li>属性<br>属性是精灵在画布上表现的数据体现,属性是和编辑区域看到的是一一对应的,在可视化制作工具里,属性分为图层属性和资源属性</li></ul><p>资源属性<br>当我们选中资源面板的资源时,我们就会显示资源属性,工具弱化了资源属性的功能和展示<br>大部分情况下,资源能设置的只有宽高和造型</p><p>通用属性<br><img src="normal.png" class="lazyload" data-srcset="normal.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="normal"></p><p>精灵特有属性<br><img src="jingling.png" class="lazyload" data-srcset="jingling.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="jingling"></p><p>数字特有属性<br><img src="number.png" class="lazyload" data-srcset="number.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="number"></p><p>文本特有属性<br>纯文本不支持部分属性如宽高或翻转,对话框文本由两个部分组成,修改宽高会修改对话框部分<br><img src="text.png" class="lazyload" data-srcset="text.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="text"></p><p>容器特有属性<br><img src="wrapper.png" class="lazyload" data-srcset="wrapper.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="wrapper"></p><p>插件特有属性<br>每个插件都有自己定义的属性,各不同用</p><ul><li>数据管理<br>数据面板总共有4种类型,变量/列表/表格/通知,其中 [变量/列表/表格] 是一类,都分别有全局的和私有的两种类型,对应积木列表中的积木标签,而通知相关的积木则在控制和事件标签中。<br>[变量/列表/表格] 都有格子对应的取值积木,分别对应 [红色/橙色/黄色]<br>新建时需要选择是私有变量还是全局变量,<br>全部变量在整个游戏中是唯一的,一旦改变,任何读取全局变量的积木都会拿到最新的值。<br>局部变量局部变量是属于某个精灵个体的,并且精灵的克隆体也拥有其自己的局部变量。</li></ul><p><em>在大部分情况下我们都推荐使用全局变量,只有在当前精灵对象存在克隆体时,为了让每个克隆体单独拥有一份变量才需要设置</em></p><p>列表<br>建议只使用全局列表,除非克隆体需要使用</p><p>表格<br>表格通常是我们用来定义初始化参数用的,例如答题游戏的题目和选项,关卡的配置等</p><ul><li>积木脚本</li></ul><p>积木是可视化制作工具中承担非常重要的逻辑关联的一部分,我们采用事件头触发的模式竖向排列拼接积木,每个事件头被触发后才会执行内部的积木,如果是散落的积木则不会执行<br>这里有几个通用概念,大部分积木都会有主语的选择,当我们选主语为其他精灵时,我们就可以在当前精灵控制其他精灵<br>还有几个固定的选项:<br>自己: 指精灵自己,常用主语,一般积木都默认操作自己,也可以用来在克隆体启动时指代克隆体本身<br>创建者: 特指克隆体的创建者,在当克隆体被创建时使用,用于找到创建该克隆体的对象<br>随机: 只会在屏幕内随机,而不是真正的无限随机<br>手指: 指用户操作屏幕的触发坐标点<br>被碰撞者: 在发生碰撞时使用,在监听碰撞的事件里找到被碰撞的对象<br>X: 横坐标<br>Y: 纵坐标<br>边缘: 特指场景的边缘,通常就是屏幕看到的区域<br>子精灵: 容器特有的选项,通常用于控制被克隆的容器<br>阻塞动画: 部分动画积木具有等待的效果,必须等待动画完成才会往下执行</p><p>事件<br>丰富的事件钩子积木能快速简单的控制游戏流程,监听状态和输入<br>启动事件都是“头部积木”,只有启动事件被触发,其中包含的积木队列才会被依次执行。<br><img src="event.png" class="lazyload" data-srcset="event.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="event"></p><p>逻辑<br><img src="logic.png" class="lazyload" data-srcset="logic.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="logic"></p><p>控制<br><img src="control.png" class="lazyload" data-srcset="control.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="control"></p><p>运动<br><img src="move.png" class="lazyload" data-srcset="move.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="move"></p><p>函数<br>函数是一系列积木的组合,由开发者自己创建,在当前项目使用<br>如果我们需要多次在不同的精灵里使用同一批积木时,例如敌人和主角的碰撞逻辑,敌人的销毁逻辑等,我们就需要自己创建一些函数来节省我们的积木,提高开发效率<br>并且函数具有传递参数的功能,当我们给函数增加参数并命名后,我们在调用函数时就可以给函数传递对应的参数来达到不同的效果</p><ul><li>碰撞系统</li></ul><p>碰撞描边<br>为了游戏性能,实际的计算不会去判断精灵的像素点是否相交,而是把它们简化为更简单的几个图形。这样做的目的是在碰撞性能与准确性之间保持一个平衡。另外值得注意的一个问题:是越复杂的图形碰撞计算越耗时,也意味着游戏可能会卡顿,所以在制作游戏的时候需要注意。为此编辑器提供了一个设置碰撞图形的功能。<br>系统默认是采用多边形的轮廓,程序会自动计算出来。如果想改变它。<br>往场景里面添加一个精灵,然后选中,在右侧的属性面板可以看到“调整碰撞轮廓”,可以手动去调整描边的类型与大小。<br><em>轮廓是跟随图层实例的,它的描边数据是保存在实例上,而不是对象上。</em></p><p>碰撞积木<br>在积木编辑区域,添加事件列表如下,在列表中选择“当精灵发生碰撞”事件<br>碰到边缘<br>碰到边缘比较简单,就是画布的边界。当这个条件满足的时候就会会触发这个事件的逻辑。<br>碰到精灵<br>当前精灵与其他精灵发生碰撞,也可以选择某一类精灵<br><em>下拉列表,可以跨场景选择到其他场景的精灵,但实际是不生效的。</em></p><p>碰撞与相交<br>相交:两个精灵的碰撞轮廓一直是有重叠区。<br>碰撞:如果两个精灵,从相离到相交,则记录为一次碰撞事件。碰撞事件触发后,两个精灵一直处于相交状态,则不会再次触发碰撞事件。直到两个精灵相离后再次相交。</p><ul><li>插件<br>插件分为两种,全局的和非全局的。像轮盘组件,可以在游戏场景中实例化多次的。而数据缓存,只能有一个全局实例,更像是一个库,只要打开一个开关,就可以使用它提供的功能。不像轮盘还要拖入到画布中实例化才可以使用。插件有两个入口,系统全局的在顶部菜单栏。另一种是在资源库中</li></ul><p><em>注意:不能给UI插件添加物理行为、碰撞事件监听等逻辑,会导致程序异常。</em></p><ul><li><p>固体行为<br>当给精灵添加固体行为的时候,就不能被穿透,可以当做地板或者墙壁使用。假如给A加上固体行为,B碰到A时会被挡住。但是这个行为使用是有场景限制的,必须配合其他行为一起使用。<br>固体行为使其他行为对对象产生反应,就好像它是不可逾越的障碍一样。具有这种行为的对象称为固体。它影响以下行为:<br>方向控制。被固体阻挡<br>平台角色。平台角色无法从下方跳至固体上方</p></li><li><p>跳跃穿透行为<br>当给精灵添加跳跃行为的时候,只能被单向穿透,可以当做特殊地板使用。假如给A加上跳跃穿透行为,B添加了平台角色行为,B跳跃或者横向跑动的时候可以穿过A,但B从高度下落碰到A时,则无法穿透A。这个行为使用有场景限制,必须配合平台角色行为一起使用。</p></li></ul><p><em>单独使用这个行为是没有任何意义,必须配合其他行为使用。</em></p><ul><li><p>平台角色行为<br>当给精灵添加平台角色行为的时候,添加此行为后,精灵可以在平台上跳跃、跑动,配合”固体”和”跳跃穿透”一起使用。<br>平台角色行为实现了侧视图“跳跃并运行”样式的移动。它支持斜坡,移动平台,“跳跃式”平台和任意重力角。<br>平台角色行为将落在具有“固体”或“跳跃穿透”的任何对象上。不同之处在于,平台角色可以从“跳跃穿透”下面跳到上面去,而从固体下跳会使角色反弹,穿透不了。</p></li><li><p>物理行为<br>物理从原来单纯的积木模式,切换行为插件模式。只有给精灵添加了物理行为才能使用物理相关的积木。 物理行为模拟现实的对象物理。它由Box2D驱动。<br>物理行为是相对复杂的。建议使用以下教程,以基本了解如何使用物理行为以及在开始使用物理行为之前要了解的一些要点:<br>物理:基础知识<br>物理:力,脉冲,扭矩和关节</p></li></ul><p><em>强烈建议完全通过物理行为(通过设置力,脉冲,转矩等)来控制物理对象,而不是尝试通过“设置位置”,“设置角度”等来操纵对象。</em></p><ul><li>方向控制行为<br>方向控制行为允许对象在默认情况下由箭头键控制的对角线上,下,左,右和对角线移动。在自顶向下视图游戏中控制玩家通常很有用。也可以将其设置为4个方向,或者简单地向上/向下或向左/向右移动,这对于拨片或滑块很有用。</li></ul><p><em>方向控制行为被具有固体行为的任何对象阻止。</em></p><ul><li><p>遮罩行为<br>遮罩用于规定精灵可渲染的范围,带有遮罩行为的精灵会使用约束框(也就是属性中遮罩类型的Size规定的范围创建一个渲染遮罩,该精灵的所有子精灵(容器的子元素)都会依据这个遮罩进行裁剪,遮罩范围外的将不会渲染。<br>简而言之,就是只绘制精灵的局部。</p></li><li><p>弹出行为<br>利用缓动(允许你以平滑的方式更改对象的属性)做的一个弹出特效行为,模拟游戏常用的动画弹窗。</p></li><li><p>缓动动画行为<br>“缓动动画”行为支持将精灵以特定缓动动画的方式移动到某个位置。它还支持以缓动动画的方式对精灵进行透明度修改、宽高调整以及比例缩放等功能。</p></li></ul><h4 id="发布流程"><a href="#发布流程" class="headerlink" title="发布流程"></a>发布流程</h4><ul><li>预览和体验:有50人上限的限制,但是最快速便捷,你可以选择下载二维码或者直接在微信右上角拉起分享给他人</li><li>发布到社区</li><li><a href="https://gamemaker.weixin.qq.com/doc/minigame/release.html#%E5%8F%91%E5%B8%83%E5%88%B0%E7%8B%AC%E7%AB%8B%E5%B0%8F%E6%B8%B8%E6%88%8F">发布到独立小游戏</a></li></ul><h4 id="优化建议"><a href="#优化建议" class="headerlink" title="优化建议"></a>优化建议</h4><p><a href="https://gamemaker.weixin.qq.com/doc/minigame/optimize.html">https://gamemaker.weixin.qq.com/doc/minigame/optimize.html</a></p><p>RPG类型的游戏:rpg游戏是角色扮演游戏类型,rpg是英文Role-Playing Game的缩写简称</p>]]></content>
<summary type="html"><h4 id="概览"><a href="#概览" class="headerlink" title="概览"></a>概览</h4><h6 id="工具"><a href="#工具" class="headerlink" title="工具"></a>工具</h6><p>微信小游戏使用《小游戏可视化制作工具》进行制作开发。<a href="https://gamemaker.weixin.qq.com/#/">《小游戏可视化制作工具》</a>是一款web应用,可用于开发微信小游戏。以可视化的操作方式编辑游戏场景,使用积木作为脚本设计精灵的行为逻辑。</p>
<blockquote>
<p>《小游戏可视化制作工具》推荐使用Chrome浏览器或者最新的QQ浏览器打开。</p>
</blockquote>
<p>《小游戏可视化制作工具》支持微信扫码登录,创建的小游戏项目为开发者私人所有,无法跟他人共享或共同编辑。<br>《小游戏可视化制作工具》的账号密码登录为团队开发登录使用,暂未开放注册。</p></summary>
</entry>
<entry>
<title>关于埋点</title>
<link href="https://sunjinkang.github.io/2023/08/09/55-burying-point/"/>
<id>https://sunjinkang.github.io/2023/08/09/55-burying-point/</id>
<published>2023-08-09T08:39:45.000Z</published>
<updated>2023-08-11T06:15:13.563Z</updated>
<content type="html"><![CDATA[<h6 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h6><p>假设你所在的公司有一个购物网站,想要分析不同用户的喜好偏向,预测商品销售情况等一些情况,这时就需要收集线上活动的用户行为的数据,并结合具体的指标进行分析。那么这些数据怎么收集?通常就可以通过埋点的方式解决类似的问题。</p><h6 id="什么是埋点?"><a href="#什么是埋点?" class="headerlink" title="什么是埋点?"></a>什么是埋点?</h6><p>埋点是一种常用的数据采集方法,是收集并记录用户行为数据的过程。</p><p>通过埋点收集用户行为的有效信息,用作统计页面加载和事件行为的数据支撑,比如访问量、点击率、跳出率等,同时埋点为数据运营提供基础,为未来的业务发展提供有力支持。</p><h6 id="埋点原则:"><a href="#埋点原则:" class="headerlink" title="埋点原则:"></a>埋点原则:</h6><p>1、获取目标数据;<br>2、获取当前版本情况;<br> 1)新功能使用情况是否符合预期;<br> 2)新功能对其他功能、整体是否有积极影响;<br> 3)运营活动目标群体特征获取;<br> 4)新增商业化目标监测。<br>3、为后续版本做数据支持。<br> 1)规划方向的用户行为分析;<br> 2)画像特征分析;<br>常见沟通过程以埋点文档为载体,以数据埋点评审为终结。</p><h6 id="埋点方式"><a href="#埋点方式" class="headerlink" title="埋点方式"></a>埋点方式</h6><p>埋点方式可以分为前端埋点和后端埋点,目前比较常见的前端埋点有:前端代码埋点、全埋点和可视化埋点。后端埋点通常指的就是后端代码埋点。</p><p>1、代码埋点:<br>实施人员:代码开发人员<br>优点:可以详细的设置某一个事件自定义属性,数据较为准确,比如:约定的id等属性;<br>缺点:时间、人力成本大,需要确定上传的数据,需要开发人员对代码进行修改;数据传输的时效性较差,因为涉及网络,甚至可能出现因为断网等原因导致数据无法上报。</p><p>2、可视化埋点:在可视化界面,点击具体点位做埋点配置;<br>实施人员:数据产品、数据分析师<br>优点:埋点只需业务同学接入,无需开发支持;<br>缺点:仅支持客户端行为。</p><p>可视化埋点的具体流程:</p><ul><li>手机APP嵌入开启可视化功能的SDK,通过WebSocket的方式和服务器、前端进行相互通信,SDK会定时收到服务器下发的页面请求;</li><li>然后会上报页面快照和界面因子信息到服务器,服务器收到信息后会根据界面因子信息对页面的每个元素进行分析,根据控件的类型来标记哪些页面元素是可以被埋点的;</li><li>最后将可埋点信息交给前端渲染,此时,前端Web页面上展示就的就是可以埋点的页面。</li><li>埋点人员在渲染出来的前端Web页面上进行框选,标记事件属性等进行埋点。</li><li>前端Web页面会将对应的埋点信息传递给服务器保存,SDK则会通过策略定时从服务器获取埋点信息。</li></ul><p>3、无埋点:又叫做全埋点,应用集成SDK,SDK自动监测用户所有行为。<br>定义:开发集成SDK后,SDK直接开始捕捉和检测用户在应用中的所有行为。<br>实施人员:数据产品、数据分析师<br>优点:<br> 1)无需开发,业务人员埋点即可;<br> 2)支持先上报数据,后进行埋点。<br>缺点:<br> 1)数据量大;<br> 2)多数有清空机制,超过n天,清空数据,无法追溯;<br> 3)仅仅支持客户端。<br><em>注:无埋点不是不埋点</em></p><p>注意:<br>全埋点和可视化埋点很像。从实际的实现上看,二者的区别就是:可视化埋点先通过界面配置哪些控件的操作数据需要收集;“无埋点”则是先尽可能收集所有的控件的操作数据,然后再通过界面配置哪些数据需要在系统里面进行分析。</p><p>“无埋点”相比可视化埋点的优点:<br>1、解决了数据“回溯”的问题,可视化埋点方案,只能从这一时刻向后收集数据,“无埋点”则从部署 SDK 的时候数据就一直都在收集了;<br>2、“无埋点”方案也可以自动获取很多启发性的信息,例如,“无埋点”可以告诉使用者这个界面上每个控件分别被点击的概率是多大,哪些控件值得做更进一步的分析等等。</p><p><img src="bury_point_type.jpg" class="lazyload" data-srcset="bury_point_type.jpg" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="bury-point-type"></p><h6 id="一些埋点工具"><a href="#一些埋点工具" class="headerlink" title="一些埋点工具"></a>一些埋点工具</h6><ul><li>百度统计</li><li>神策数据</li><li>FireBase</li><li>TalkingData</li></ul><h6 id="埋点数据采集遇到的问题:"><a href="#埋点数据采集遇到的问题:" class="headerlink" title="埋点数据采集遇到的问题:"></a>埋点数据采集遇到的问题:</h6><p>实时性:无网条件下产生的数据,无法实时上报;<br>完整性:部分数据无法采集,根据《用户隐私协议》和《欧盟通用数据保护条例》<br>异常:部分埋点,随版本升级变化,无法获取。</p>]]></content>
<summary type="html"><h6 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h6><p>假设你所在的公司有一个购物网站,想要分析不同用户的喜好偏向,预测商品销售情况等一些情况,这时就需要收集线上活动的用户行为的数据,并结合具体的指标进行分析。那么这些数据怎么收集?通常就可以通过埋点的方式解决类似的问题。</p>
<h6 id="什么是埋点?"><a href="#什么是埋点?" class="headerlink" title="什么是埋点?"></a>什么是埋点?</h6><p>埋点是一种常用的数据采集方法,是收集并记录用户行为数据的过程。</p>
<p>通过埋点收集用户行为的有效信息,用作统计页面加载和事件行为的数据支撑,比如访问量、点击率、跳出率等,同时埋点为数据运营提供基础,为未来的业务发展提供有力支持。</p></summary>
</entry>
<entry>
<title>进度条中同一文字颜色反差的实现</title>
<link href="https://sunjinkang.github.io/2023/08/03/54-render-progress-text/"/>
<id>https://sunjinkang.github.io/2023/08/03/54-render-progress-text/</id>
<published>2023-08-03T07:19:59.000Z</published>
<updated>2023-08-08T02:51:30.754Z</updated>
<content type="html"><![CDATA[<h6 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h6><p>生活中,大家应该都遇到过进度条,有时候进度条的文字在进度条内部,当进度覆盖到文字的时候,会有一种反差,比如:同一个文字被进度覆盖的部分是白色字体,未被进度覆盖的是黑色字体,本文即是针对这种效果的实现。</p><span id="more"></span><h6 id="实现一:使用伪类"><a href="#实现一:使用伪类" class="headerlink" title="实现一:使用伪类"></a>实现一:使用伪类</h6><p><em>预置说明</em><br>content与attr(PS: 本文仅针对需要的使用方式进行说明,不做详细说明,感兴趣的可以前往<a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/attr">mdn的attr</a>进行查看)</p><p>content<br>CSS 的 content CSS 属性用于在元素的 ::before 和 ::after 伪元素中插入内容。使用 content 属性插入的内容都是匿名的可替换元素。</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"><a href=<span class="string">"http://www.mozilla.org/en-US/"</span>><span class="title class_">Home</span> <span class="title class_">Page</span></a></span><br><span class="line"></span><br><span class="line"><span class="attr">a</span>::before {</span><br><span class="line"> <span class="attr">content</span>: <span class="title function_">url</span>(<span class="attr">http</span>:<span class="comment">//www.mozilla.org/favicon.ico) " MOZILLA: ";</span></span><br><span class="line"> <span class="attr">font</span>:</span><br><span class="line"> x-small <span class="title class_">Arial</span>,</span><br><span class="line"> freeSans,</span><br><span class="line"> sans-serif;</span><br><span class="line"> <span class="attr">color</span>: gray;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>常见用法:</p><blockquote><p>content: attr(属性名);</p></blockquote><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></pre></td><td class="code"><pre><span class="line"><span class="comment">// html code</span></span><br><span class="line"><p data-foo=<span class="string">"hello"</span>>world</p></span><br><span class="line"><span class="comment">// css code</span></span><br><span class="line"><span class="attr">p</span>:before {</span><br><span class="line"> <span class="attr">content</span>: <span class="title function_">attr</span>(data-foo) <span class="string">" "</span>;</span><br><span class="line">}</span><br><span class="line"><span class="comment">// result</span></span><br><span class="line"><span class="comment">// hello world</span></span><br></pre></td></tr></table></figure><p>注意:attr理论上可以单独使用,但由于浏览器兼容性问题,目前最好不要使用,本文中attr是与content一起使用,限制较小。<br><img src="content_attr.png" class="lazyload" data-srcset="content_attr.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="content_attr"></p><p>方案:使用content和attr可以获取标签中的属性,将进度条的文字同时放在标签的属性里面,再通过伪类和content、attr搭配,根据进度显示不同宽度,将新的文字覆盖到原有的底层文字之上,实现进度条文字反差的效果。</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"progress-bar"</span> <span class="attr">data-content</span>=<span class="string">"当前进度:18%"</span>></span>当前进度:18%<span class="tag"></<span class="name">div</span>></span></span><br></pre></td></tr></table></figure><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-class">.progress-bar</span> {</span><br><span class="line"> <span class="attribute">display</span>: inline-block;</span><br><span class="line"> <span class="attribute">font-size</span>: <span class="number">16px</span>;</span><br><span class="line"> <span class="attribute">line-height</span>: <span class="number">20px</span>;</span><br><span class="line"> <span class="attribute">color</span>: lightblue;</span><br><span class="line"> <span class="attribute">position</span>: relative;</span><br><span class="line"> <span class="attribute">overflow</span>: hidden;</span><br><span class="line"> <span class="attribute">white-space</span>: pre;</span><br><span class="line"> <span class="attribute">width</span>: <span class="number">300px</span>;</span><br><span class="line"> <span class="attribute">height</span>: <span class="number">20px</span>;</span><br><span class="line"> <span class="attribute">border</span>: <span class="number">1px</span> solid <span class="number">#333</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="selector-class">.progress-bar</span><span class="selector-pseudo">:before</span> {</span><br><span class="line"> <span class="attribute">position</span>: absolute;</span><br><span class="line"> <span class="attribute">top</span>: <span class="number">0</span>;</span><br><span class="line"> <span class="attribute">color</span>: <span class="number">#fff</span>;</span><br><span class="line"> <span class="attribute">display</span>: block;</span><br><span class="line"> <span class="attribute">width</span>: <span class="number">18%</span>;</span><br><span class="line"> <span class="attribute">content</span>: <span class="built_in">attr</span>(data-content);</span><br><span class="line"> <span class="attribute">overflow</span>: hidden;</span><br><span class="line"> <span class="attribute">background-color</span>: lightblue;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>效果如下:<br><img src="content-progress.png" class="lazyload" data-srcset="content-progress.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="content进度条"></p><p><em>说明</em><br>该方案中的文字好像只能处于默认的左侧位置,使用伪类获取的内容文字无法位于中间,暂未找到解决办法</p><h6 id="方案二:使用双层元素层叠"><a href="#方案二:使用双层元素层叠" class="headerlink" title="方案二:使用双层元素层叠"></a>方案二:使用双层元素层叠</h6><p>方案:本质与方案一类似,只不过方案二是把两个元素叠在一起,元素内容相同</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"progress-wrapper"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"progress-bottom"</span>></span>当前进度:18%<span class="tag"></<span class="name">div</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"progress-top"</span>></span>当前进度:18%<span class="tag"></<span class="name">div</span>></span></span><br><span class="line"><span class="tag"></<span class="name">div</span>></span></span><br></pre></td></tr></table></figure><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-tag">body</span> {</span><br><span class="line"> <span class="attribute">margin</span>: <span class="number">0</span>;</span><br><span class="line">}</span><br><span class="line"><span class="selector-class">.progress-wrapper</span> {</span><br><span class="line"> <span class="attribute">overflow</span>: hidden;</span><br><span class="line"> <span class="attribute">white-space</span>: pre;</span><br><span class="line"> <span class="attribute">width</span>: <span class="number">300px</span>;</span><br><span class="line"> <span class="attribute">height</span>: <span class="number">20px</span>;</span><br><span class="line"> <span class="attribute">line-height</span>: <span class="number">20px</span>;</span><br><span class="line"> <span class="attribute">font-size</span>: <span class="number">16px</span>;</span><br><span class="line"> <span class="attribute">border</span>: <span class="number">1px</span> solid <span class="number">#333</span>;</span><br><span class="line"> <span class="attribute">position</span>: relative;</span><br><span class="line">}</span><br><span class="line"><span class="selector-class">.progress-bottom</span> {</span><br><span class="line"> <span class="attribute">display</span>: inline-block;</span><br><span class="line"> <span class="attribute">color</span>: lightblue;</span><br><span class="line"> <span class="attribute">position</span>: absolute;</span><br><span class="line"> <span class="attribute">top</span>: <span class="number">0</span>;</span><br><span class="line"> <span class="attribute">left</span>: <span class="number">0</span>;</span><br><span class="line"> <span class="attribute">width</span>: <span class="number">100%</span>;</span><br><span class="line">}</span><br><span class="line"><span class="selector-class">.progress-top</span> {</span><br><span class="line"> <span class="attribute">background-color</span>: lightblue;</span><br><span class="line"> <span class="attribute">color</span>: <span class="number">#fff</span>;</span><br><span class="line"> <span class="attribute">width</span>: <span class="number">18%</span>;</span><br><span class="line"> <span class="attribute">position</span>: absolute;</span><br><span class="line"> <span class="attribute">top</span>: <span class="number">0</span>;</span><br><span class="line"> <span class="attribute">overflow</span>: hidden;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>效果与方案一相同</p><p><em>说明</em><br>方案二同样存在方案一的缺陷,文字只能位于左侧</p><p>上面两种方案都存在文字只能位于左侧的问题,但实际使用中往往文字是位于中间的,进而出现了方案三</p><h6 id="方案三:使用三层元素层叠-js计算"><a href="#方案三:使用三层元素层叠-js计算" class="headerlink" title="方案三:使用三层元素层叠+js计算"></a>方案三:使用三层元素层叠+js计算</h6><p>方案:实现方式与方案二类似,不过文字都位于进度条中间,并在两层元素之间又加了一层元素,新加的这层元素仅用于进度的渲染,同时通过js计算最上层的元素与进度区域的重合部分宽度,修改最上层元素的宽度,展示不同颜色的文字。<br>ps: 本文中未实现具体的js计算逻辑,可根据进度条总长度,文字区域长度等进行计算。</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"progress-wrapper"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"progress-bottom"</span>></span>当前进度:18%<span class="tag"></<span class="name">div</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"progress-bar"</span>></span><span class="tag"></<span class="name">div</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"progress-top"</span>></span>当前进度:18%<span class="tag"></<span class="name">div</span>></span></span><br><span class="line"><span class="tag"></<span class="name">div</span>></span></span><br></pre></td></tr></table></figure><figure class="highlight css"><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></pre></td><td class="code"><pre><span class="line"><span class="selector-tag">body</span> {</span><br><span class="line"> <span class="attribute">margin</span>: <span class="number">0</span>;</span><br><span class="line">}</span><br><span class="line"><span class="selector-class">.progress-wrapper</span> {</span><br><span class="line"> <span class="attribute">overflow</span>: hidden;</span><br><span class="line"> <span class="attribute">white-space</span>: pre;</span><br><span class="line"> <span class="attribute">width</span>: <span class="number">300px</span>;</span><br><span class="line"> <span class="attribute">height</span>: <span class="number">20px</span>;</span><br><span class="line"> <span class="attribute">line-height</span>: <span class="number">20px</span>;</span><br><span class="line"> <span class="attribute">font-size</span>: <span class="number">16px</span>;</span><br><span class="line"> <span class="attribute">border</span>: <span class="number">1px</span> solid <span class="number">#333</span>;</span><br><span class="line"> <span class="attribute">position</span>: relative;</span><br><span class="line"> <span class="attribute">text-align</span>: center;</span><br><span class="line">}</span><br><span class="line"><span class="selector-class">.progress-bottom</span> {</span><br><span class="line"> <span class="attribute">display</span>: inline-block;</span><br><span class="line"> <span class="attribute">color</span>: lightblue;</span><br><span class="line"> <span class="attribute">position</span>: absolute;</span><br><span class="line"> <span class="attribute">top</span>: <span class="number">0</span>;</span><br><span class="line"> <span class="attribute">left</span>: <span class="number">0</span>;</span><br><span class="line"> <span class="attribute">width</span>: <span class="number">100%</span>;</span><br><span class="line">}</span><br><span class="line"><span class="selector-class">.progress-top</span> {</span><br><span class="line"> <span class="attribute">background-color</span>: lightblue;</span><br><span class="line"> <span class="attribute">color</span>: <span class="number">#fff</span>;</span><br><span class="line"> <span class="attribute">width</span>: <span class="number">19%</span>;</span><br><span class="line"> <span class="attribute">position</span>: absolute;</span><br><span class="line"> <span class="attribute">top</span>: <span class="number">0</span>;</span><br><span class="line"> <span class="attribute">overflow</span>: hidden;</span><br><span class="line"> <span class="attribute">left</span>: <span class="number">50%</span>;</span><br><span class="line"> <span class="attribute">margin-left</span>: -<span class="number">56px</span>;</span><br><span class="line">}</span><br><span class="line"><span class="selector-class">.progress-bar</span> {</span><br><span class="line"> <span class="attribute">background-color</span>: lightblue;</span><br><span class="line"> <span class="attribute">color</span>: <span class="number">#fff</span>;</span><br><span class="line"> <span class="attribute">width</span>: <span class="number">50%</span>;</span><br><span class="line"> <span class="attribute">position</span>: absolute;</span><br><span class="line"> <span class="attribute">top</span>: <span class="number">0</span>;</span><br><span class="line"> <span class="attribute">overflow</span>: hidden;</span><br><span class="line"> <span class="attribute">height</span>: <span class="number">20px</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>方案三通过js的计算,在实现文字颜色反差的基础上进一步实现了文字的居中</p><h6 id="进度条插件的实现方案"><a href="#进度条插件的实现方案" class="headerlink" title="进度条插件的实现方案"></a>进度条插件的实现方案</h6><p>暂未发现。。。</p>]]></content>
<summary type="html"><h6 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h6><p>生活中,大家应该都遇到过进度条,有时候进度条的文字在进度条内部,当进度覆盖到文字的时候,会有一种反差,比如:同一个文字被进度覆盖的部分是白色字体,未被进度覆盖的是黑色字体,本文即是针对这种效果的实现。</p></summary>
</entry>
<entry>
<title>js中的void运算符</title>
<link href="https://sunjinkang.github.io/2023/08/03/53-about-void/"/>
<id>https://sunjinkang.github.io/2023/08/03/53-about-void/</id>
<published>2023-08-03T05:42:02.000Z</published>
<updated>2023-08-04T01:54:01.852Z</updated>
<content type="html"><![CDATA[<h6 id="void运算符的作用"><a href="#void运算符的作用" class="headerlink" title="void运算符的作用"></a>void运算符的作用</h6><blockquote><p>void 运算符对给定的表达式进行求值,然后返回 undefined。</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></pre></td><td class="code"><pre><span class="line"><span class="comment">// 语法</span></span><br><span class="line"><span class="keyword">void</span> expression</span><br><span class="line"><span class="comment">// or</span></span><br><span class="line"><span class="title function_">void</span>(expression)</span><br></pre></td></tr></table></figure><p>同时需要注意考虑 void 运算符的优先级(void优先级较高),以下加括号的表达式的例子可以帮助你清楚地理解 void 操作符的优先级:</p>]]></content>
<summary type="html"><h6 id="void运算符的作用"><a href="#void运算符的作用" class="headerlink" title="void运算符的作用"></a>void运算符的作用</h6><blockquote>
<p>void 运算符对给定的表达式进行求值,然后返回 </summary>
</entry>
<entry>
<title>Hello World</title>
<link href="https://sunjinkang.github.io/2023/07/24/1-hello-world/"/>
<id>https://sunjinkang.github.io/2023/07/24/1-hello-world/</id>
<published>2023-07-24T09:24:46.208Z</published>
<updated>2023-08-03T02:54:29.832Z</updated>
<content type="html"><![CDATA[<p>Welcome to <a href="https://hexo.io/">Hexo</a>! This is your very first post. Check <a href="https://hexo.io/docs/">documentation</a> for more info. If you get any problems when using Hexo, you can find the answer in <a href="https://hexo.io/docs/troubleshooting.html">troubleshooting</a> or you can ask me on <a href="https://github.com/hexojs/hexo/issues">GitHub</a>.</p><span id="more"></span><h2 id="Quick-Start"><a href="#Quick-Start" class="headerlink" title="Quick Start"></a>Quick Start</h2><h3 id="Create-a-new-post"><a href="#Create-a-new-post" class="headerlink" title="Create a new post"></a>Create a new post</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ hexo new <span class="string">"My New Post"</span></span><br></pre></td></tr></table></figure><p>More info: <a href="https://hexo.io/docs/writing.html">Writing</a></p><h3 id="Run-server"><a href="#Run-server" class="headerlink" title="Run server"></a>Run server</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ hexo server</span><br></pre></td></tr></table></figure><p>More info: <a href="https://hexo.io/docs/server.html">Server</a></p><h3 id="Generate-static-files"><a href="#Generate-static-files" class="headerlink" title="Generate static files"></a>Generate static files</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ hexo generate</span><br></pre></td></tr></table></figure><p>More info: <a href="https://hexo.io/docs/generating.html">Generating</a></p><h3 id="Deploy-to-remote-sites"><a href="#Deploy-to-remote-sites" class="headerlink" title="Deploy to remote sites"></a>Deploy to remote sites</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ hexo deploy</span><br></pre></td></tr></table></figure><p>More info: <a href="https://hexo.io/docs/one-command-deployment.html">Deployment</a></p><h3 id="deploy产生如下错误的解决方法"><a href="#deploy产生如下错误的解决方法" class="headerlink" title="deploy产生如下错误的解决方法"></a>deploy产生如下错误的解决方法</h3><p>(1)使用hexo部署报错Error: Spawn failed<br>解决办法:删除.deploy_git文件夹 -> 修改_config.yml文件中deploy的repository地址,修改为SSH方式 -> 按顺序执行命令hexo clean、hexo generate、hexo deploy</p>]]></content>
<summary type="html"><p>Welcome to <a href="https://hexo.io/">Hexo</a>! This is your very first post. Check <a href="https://hexo.io/docs/">documentation</a> for more info. If you get any problems when using Hexo, you can find the answer in <a href="https://hexo.io/docs/troubleshooting.html">troubleshooting</a> or you can ask me on <a href="https://github.com/hexojs/hexo/issues">GitHub</a>.</p></summary>
</entry>
<entry>
<title>Vite 插件</title>
<link href="https://sunjinkang.github.io/2023/06/15/52-vite-plugin/"/>
<id>https://sunjinkang.github.io/2023/06/15/52-vite-plugin/</id>
<published>2023-06-15T13:13:24.000Z</published>
<updated>2023-08-04T01:54:01.850Z</updated>
<content type="html"><![CDATA[<h4 id="vite插件"><a href="#vite插件" class="headerlink" title="vite插件"></a>vite插件</h4><h6 id="什么是vite插件"><a href="#什么是vite插件" class="headerlink" title="什么是vite插件"></a>什么是vite插件</h6><p>vite 其实就是一个由原生 ES Module 驱动的新型 Web 开发前端构建工具。<br>vite 插件 就可以很好的扩展 vite 自身不能做到的事情,比如一些打包的数据展示,开发中或者打包中的数据处理等等。</p><h6 id="插件-API"><a href="#插件-API" class="headerlink" title="插件 API"></a>插件 API</h6><p>Vite 插件扩展了设计出色的 Rollup 接口,带有一些 Vite 独有的配置项。因此,你只需要编写一个 Vite 插件,就可以同时为开发环境和生产环境工作。</p><p>注意:了解vite插件之前,建议先阅读 Rollup 插件文档。</p><h6 id="注意事项"><a href="#注意事项" class="headerlink" title="注意事项"></a>注意事项</h6><p>对于 Vite 专属的插件:</p><ul><li>Vite 插件应该有一个带 vite-plugin- 前缀、语义清晰的名称。</li><li>在 package.json 中包含 vite-plugin 关键字。</li><li>在插件文档增加一部分关于为什么本插件是一个 Vite 专属插件的详细说明(如,本插件使用了 Vite 特有的插件钩子)。</li></ul><p>如果你的插件只适用于特定的框架,它的名字应该遵循以下前缀格式:</p><ul><li>vite-plugin-vue- 前缀作为 Vue 插件</li><li>vite-plugin-react- 前缀作为 React 插件</li><li>vite-plugin-svelte- 前缀作为 Svelte 插件</li></ul><blockquote><p>通常的惯例是创建一个 Vite/Rollup 插件作为一个返回实际插件对象的工厂函数。该函数可以接受允许用户自定义插件行为的选项。</p></blockquote><h6 id="通用钩子"><a href="#通用钩子" class="headerlink" title="通用钩子"></a>通用钩子</h6><p>以下钩子在构建阶段被调用:</p><ul><li>options(options) :在服务器启动时被调用:获取、操纵Rollup选项,严格意义上来讲,它执行于属于构建阶段之前;</li><li>buildStart(options):在每次开始构建时调用;</li><li>resolveId(source, importer, options):在每个传入模块请求时被调用,创建自定义确认函数,可以用来定位第三方依赖;</li><li>load(id):在每个传入模块请求时被调用,可以自定义加载器,可用来返回自定义的内容;</li><li>transform(code, id):在每个传入模块请求时被调用,主要是用来转换单个模块;</li><li>buildEnd(error?: Error):在构建阶段结束后被调用,此处构建结束只是代表所有模块转义完成;</li></ul><p>以下钩子在输出阶段被调用:</p><ul><li>outputOptions(options):接受输出参数;</li><li>renderStart(outputOptions, inputOptions):每次 bundle.generate 和 bundle.write 调用时都会被触发;</li><li>augmentChunkHash(chunkInfo):用来给 chunk 增加 hash;</li><li>renderChunk(code, chunk, options):转译单个的chunk时触发。rollup 输出每一个chunk文件的时候都会调用;</li><li>generateBundle(options, bundle, isWrite):在调用 bundle.write 之前立即触发这个 hook;</li><li>writeBundle(options, bundle):在调用 bundle.write后,所有的chunk都写入文件后,最后会调用一次 writeBundle;</li><li>closeBundle():在服务器关闭时被调用</li></ul><blockquote><p>请注意 moduleParsed 钩子在开发中是 不会 被调用的,因为 Vite 为了性能会避免完整的 AST 解析。<br>Output Generation Hooks(除了 closeBundle) 在开发中是 不会 被调用的。你可以认为 Vite 的开发服务器只调用了 rollup.rollup() 而没有调用 bundle.generate()。</p></blockquote><h6 id="vite-独有钩子"><a href="#vite-独有钩子" class="headerlink" title="vite 独有钩子"></a>vite 独有钩子</h6><blockquote><p>这些钩子会被rollup忽略</p></blockquote><ul><li><p>enforce<br>值可以是pre 或 post , pre 会较于 post 先执行</p></li><li><p>apply<br>值可以是 build 或 serve 亦可以是一个函数,指明它们仅在 build 或 serve 模式时调用;</p></li><li><p>config</p></li></ul><p>在解析 Vite 配置前调用。钩子接收原始用户配置(命令行选项指定的会与配置文件合并)和一个描述配置环境的变量,包含正在使用的 mode 和 command。它可以返回一个将被深度合并到现有配置中的部分配置对象,或者直接改变配置(如果默认的合并不能达到预期的结果)</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> <span class="title function_">mutateConfigPlugin</span> = (<span class="params"></span>) => ({</span><br><span class="line"> <span class="attr">name</span>: <span class="string">'mutate-config'</span>,</span><br><span class="line"> <span class="title function_">config</span>(<span class="params">config, { command }</span>) {</span><br><span class="line"> <span class="keyword">if</span> (command === <span class="string">'build'</span>) {</span><br><span class="line"> config.<span class="property">root</span> = __dirname</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">});</span><br></pre></td></tr></table></figure><p><em>用户插件在运行这个钩子之前会被解析,因此在 config 钩子中注入其他插件不会有任何效果。</em></p><ul><li>configResolved</li></ul><p>在解析 Vite 配置后调用。使用这个钩子读取和存储最终解析的配置。当插件需要根据运行的命令做一些不同的事情时,它也很有用。</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> <span class="title function_">exmaplePlugin</span> = (<span class="params"></span>) => {</span><br><span class="line"> <span class="keyword">let</span> config</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> {</span><br><span class="line"> <span class="attr">name</span>: <span class="string">'read-config'</span>,</span><br><span class="line"></span><br><span class="line"> <span class="title function_">configResolved</span>(<span class="params">resolvedConfig</span>) {</span><br><span class="line"> <span class="comment">// 存储最终解析的配置</span></span><br><span class="line"> config = resolvedConfig</span><br><span class="line"> },</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 在其他钩子中使用存储的配置</span></span><br><span class="line"> <span class="title function_">transform</span>(<span class="params">code, id</span>) {</span><br><span class="line"> <span class="keyword">if</span> (config.<span class="property">command</span> === <span class="string">'serve'</span>) {</span><br><span class="line"> <span class="comment">// serve: 由开发服务器调用的插件</span></span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="comment">// build: 由 Rollup 调用的插件</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>configureServer</li></ul><p>是用于配置开发服务器的钩子。最常见的用例是在内部 connect 应用程序中添加自定义中间件:</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> <span class="title function_">myPlugin</span> = (<span class="params"></span>) => ({</span><br><span class="line"> <span class="attr">name</span>: <span class="string">'configure-server'</span>,</span><br><span class="line"> <span class="title function_">configureServer</span>(<span class="params">server</span>) {</span><br><span class="line"> server.<span class="property">middlewares</span>.<span class="title function_">use</span>(<span class="function">(<span class="params">req, res, next</span>) =></span> {</span><br><span class="line"> <span class="comment">// 自定义请求处理...</span></span><br><span class="line"> })</span><br><span class="line"> }</span><br><span class="line">})</span><br></pre></td></tr></table></figure><p><em>注入后置中间件</em><br>configureServer 钩子将在内部中间件被安装前调用,所以自定义的中间件将会默认会比内部中间件早运行。如果你想注入一个在内部中间件 之后 运行的中间件,你可以从 configureServer 返回一个函数,将会在内部中间件安装后被调用:</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> <span class="title function_">myPlugin</span> = (<span class="params"></span>) => ({</span><br><span class="line"> <span class="attr">name</span>: <span class="string">'configure-server'</span>,</span><br><span class="line"> <span class="title function_">configureServer</span>(<span class="params">server</span>) {</span><br><span class="line"> <span class="comment">// 返回一个在内部中间件安装后</span></span><br><span class="line"> <span class="comment">// 被调用的后置钩子</span></span><br><span class="line"> <span class="keyword">return</span> <span class="function">() =></span> {</span><br><span class="line"> server.<span class="property">middlewares</span>.<span class="title function_">use</span>(<span class="function">(<span class="params">req, res, next</span>) =></span> {</span><br><span class="line"> <span class="comment">// 自定义请求处理...</span></span><br><span class="line"> })</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">})</span><br></pre></td></tr></table></figure><p><em>存储服务器访问</em><br>在某些情况下,其他插件钩子可能需要访问开发服务器实例(例如访问 websocket 服务器、文件系统监视程序或模块图)。这个钩子也可以用来存储服务器实例以供其他钩子访问:</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">const</span> <span class="title function_">myPlugin</span> = (<span class="params"></span>) => {</span><br><span class="line"> <span class="keyword">let</span> server</span><br><span class="line"> <span class="keyword">return</span> {</span><br><span class="line"> <span class="attr">name</span>: <span class="string">'configure-server'</span>,</span><br><span class="line"> <span class="title function_">configureServer</span>(<span class="params">_server</span>) {</span><br><span class="line"> server = _server</span><br><span class="line"> },</span><br><span class="line"> <span class="title function_">transform</span>(<span class="params">code, id</span>) {</span><br><span class="line"> <span class="keyword">if</span> (server) {</span><br><span class="line"> <span class="comment">// 使用 server...</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><p><em>注意 configureServer 在运行生产版本时不会被调用,所以其他钩子需要防范它缺失。</em></p><ul><li><p>transformIndexHtml<br>转换 index.html 的专用钩子。钩子接收当前的 HTML 字符串和转换上下文。上下文在开发期间暴露ViteDevServer实例,在构建期间暴露 Rollup 输出的包。<br>这个钩子可以是异步的,并且可以返回以下其中之一:</p></li><li><p>经过转换的 HTML 字符串</p></li><li><p>注入到现有 HTML 中的标签描述符对象数组({ tag, attrs, children })。每个标签也可以指定它应该被注入到哪里(默认是在 <head> 之前)</p></li><li><p>一个包含 { html, tags } 的对象</p></li><li><p>handleHotUpdate<br>执行自定义 HMR 更新处理。钩子接收一个带有以下签名的上下文对象:</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></pre></td><td class="code"><pre><span class="line">interface <span class="title class_">HmrContext</span> {</span><br><span class="line"> <span class="attr">file</span>: string</span><br><span class="line"> <span class="attr">timestamp</span>: number</span><br><span class="line"> <span class="attr">modules</span>: <span class="title class_">Array</span><<span class="title class_">ModuleNode</span>></span><br><span class="line"> <span class="attr">read</span>: <span class="function">() =></span> string | <span class="title class_">Promise</span><string></span><br><span class="line"> <span class="attr">server</span>: <span class="title class_">ViteDevServer</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure></li><li><p>modules 是受更改文件影响的模块数组。它是一个数组,因为单个文件可能映射到多个服务模块(例如 Vue 单文件组件)。</p></li><li><p>read 这是一个异步读函数,它返回文件的内容。之所以这样做,是因为在某些系统上,文件更改的回调函数可能会在编辑器完成文件更新之前过快地触发,并 fs.readFile 直接会返回空内容。传入的 read 函数规范了这种行为。</p></li></ul><p>钩子可以选择:</p><ul><li>过滤和缩小受影响的模块列表,使 HMR 更准确。</li><li>返回一个空数组,并通过向客户端发送自定义事件来执行完整的自定义 HMR 处理:<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="title function_">handleHotUpdate</span>(<span class="params">{ server }</span>) {</span><br><span class="line"> server.<span class="property">ws</span>.<span class="title function_">send</span>({</span><br><span class="line"> <span class="attr">type</span>: <span class="string">'custom'</span>,</span><br><span class="line"> <span class="attr">event</span>: <span class="string">'special-update'</span>,</span><br><span class="line"> <span class="attr">data</span>: {}</span><br><span class="line"> })</span><br><span class="line"> <span class="keyword">return</span> []</span><br><span class="line">}</span><br></pre></td></tr></table></figure>客户端代码应该使用 HMR API 注册相应的处理器(这应该被相同插件的 transform 钩子注入):<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></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span> (<span class="keyword">import</span>.<span class="property">meta</span>.<span class="property">hot</span>) {</span><br><span class="line"> <span class="keyword">import</span>.<span class="property">meta</span>.<span class="property">hot</span>.<span class="title function_">on</span>(<span class="string">'special-update'</span>, <span class="function">(<span class="params">data</span>) =></span> {</span><br><span class="line"> <span class="comment">// 执行自定义更新</span></span><br><span class="line"> })</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li></ul><h6 id="插件顺序"><a href="#插件顺序" class="headerlink" title="插件顺序"></a>插件顺序</h6><p>一个 Vite 插件可以额外指定一个 enforce 属性(类似于 webpack 加载器)来调整它的应用顺序。enforce 的值可以是pre 或 post。解析后的插件将按照以下顺序排列:</p><ul><li>Alias</li><li>带有 enforce: ‘pre’ 的用户插件</li><li>Vite 核心插件</li><li>没有 enforce 值的用户插件</li><li>Vite 构建用的插件</li><li>带有 enforce: ‘post’ 的用户插件</li><li>Vite 后置构建插件(最小化,manifest,报告)</li></ul><h6 id="情景应用"><a href="#情景应用" class="headerlink" title="情景应用"></a>情景应用</h6><p>默认情况下插件在开发(serve)和构建(build)模式中都会调用。如果插件只需要在预览或构建期间有条件地应用,请使用 apply 属性指明它们仅在 ‘build’ 或 ‘serve’ 模式时调用:</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">myPlugin</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="keyword">return</span> {</span><br><span class="line"> <span class="attr">name</span>: <span class="string">'build-only'</span>,</span><br><span class="line"> <span class="attr">apply</span>: <span class="string">'build'</span> <span class="comment">// 或 'serve'</span></span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// 还可以使用函数来进行更精准的控制</span></span><br><span class="line"><span class="title function_">apply</span>(<span class="params">config, { command }</span>) {</span><br><span class="line"> <span class="comment">// 非 SSR 情况下的 build</span></span><br><span class="line"> <span class="keyword">return</span> command === <span class="string">'build'</span> && !config.<span class="property">build</span>.<span class="property">ssr</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><h6 id="Rollup-插件兼容性"><a href="#Rollup-插件兼容性" class="headerlink" title="Rollup 插件兼容性"></a>Rollup 插件兼容性</h6><p>有一些rollup插件可以直接作为vite插件使用,但是有些不行,一般来说,需要满足以下条件:</p><ul><li>没有使用 moduleParsed 钩子。</li><li>它在打包钩子和输出钩子之间没有很强的耦合。</li></ul><p><em>如果一个 Rollup 插件只在构建阶段有意义,则在 build.rollupOptions.plugins 下指定即可。</em></p><p>你也可以用 Vite 独有的属性来扩展现有的 Rollup 插件:</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></pre></td><td class="code"><pre><span class="line"><span class="comment">// vite.config.js</span></span><br><span class="line"><span class="keyword">import</span> example <span class="keyword">from</span> <span class="string">'rollup-plugin-example'</span></span><br><span class="line"><span class="keyword">import</span> { defineConfig } <span class="keyword">from</span> <span class="string">'vite'</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="title function_">defineConfig</span>({</span><br><span class="line"> <span class="attr">plugins</span>: [</span><br><span class="line"> {</span><br><span class="line"> ...<span class="title function_">example</span>(),</span><br><span class="line"> <span class="attr">enforce</span>: <span class="string">'post'</span>,</span><br><span class="line"> <span class="attr">apply</span>: <span class="string">'build'</span></span><br><span class="line"> }</span><br><span class="line"> ]</span><br><span class="line">})</span><br></pre></td></tr></table></figure><p>查看 <a href="https://vite-rollup-plugins.patak.dev/">Vite Rollup 插件</a> 获取兼容的官方 Rollup 插件列表及其使用指南。</p><h6 id="路径规范化"><a href="#路径规范化" class="headerlink" title="路径规范化"></a>路径规范化</h6><p>Vite 对路径进行了规范化处理,在解析路径时使用 POSIX 分隔符( / ),同时保留了 Windows 中的卷名。而另一方面,Rollup 在默认情况下保持解析的路径不变,因此解析的路径在 Windows 中会使用 win32 分隔符( \ )。然而,Rollup 插件会使用 @rollup/pluginutils 内部的 normalizePath 工具函数,它在执行比较之前将分隔符转换为 POSIX。所以意味着当这些插件在 Vite 中使用时,include 和 exclude 两个配置模式,以及与已解析路径比较相似的路径会正常工作。</p><p>所以对于 Vite 插件来说,在将路径与已解析的路径进行比较时,首先规范化路径以使用 POSIX 分隔符是很重要的。从 vite 模块中也导出了一个等效的 normalizePath 工具函数。</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> { normalizePath } <span class="keyword">from</span> <span class="string">'vite'</span></span><br><span class="line"></span><br><span class="line"><span class="title function_">normalizePath</span>(<span class="string">'foo\\bar'</span>) <span class="comment">// 'foo/bar'</span></span><br><span class="line"><span class="title function_">normalizePath</span>(<span class="string">'foo/bar'</span>) <span class="comment">// 'foo/bar'</span></span><br></pre></td></tr></table></figure><p>vite kooks的渲染顺序<br><a href="./52-vite-plugin/vite-hooks.jpg">hooks</a></p><p>vite插件顺序????<br>有些插件钩子在非构建式的开发服务器上下文中没有意义????</p>]]></content>
<summary type="html"><h4 id="vite插件"><a href="#vite插件" class="headerlink" title="vite插件"></a>vite插件</h4><h6 id="什么是vite插件"><a href="#什么是vite插件" class="headerlink" title="什么是vite插件"></a>什么是vite插件</h6><p>vite 其实就是一个由原生 ES Module 驱动的新型 Web 开发前端构建工具。<br>vite 插件 就可以很好的扩展 vite 自身不能做到的事情,比如一些打包的数据展示,开发中或者打包中的数据处理等等。</p>
<h6 id="插件-API"><a href="#插件-API" class="headerlink" title="插件 API"></a>插件 API</h6><p>Vite 插件扩展了设计出色的 Rollup 接口,带有一些 Vite 独有的配置项。因此,你只需要编写一个 Vite 插件,就可以同时为开发环境和生产环境工作。</p></summary>
</entry>
<entry>
<title>Thunk函数</title>
<link href="https://sunjinkang.github.io/2023/04/19/51-about-thunk-function/"/>
<id>https://sunjinkang.github.io/2023/04/19/51-about-thunk-function/</id>
<published>2023-04-19T09:00:23.000Z</published>
<updated>2023-08-08T02:53:12.775Z</updated>
<content type="html"><![CDATA[<h6 id="求值策略"><a href="#求值策略" class="headerlink" title="求值策略"></a>求值策略</h6><p>在介绍Thunk函数之前,需要先介绍一下什么叫做求值策略,即函数的参数应该什么时候求值。</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">test</span>(<span class="params">num</span>) {</span><br><span class="line"> <span class="keyword">return</span> num+<span class="number">1</span>;</span><br><span class="line">}</span><br><span class="line"><span class="title function_">test</span>(<span class="number">2</span>+<span class="number">3</span>);</span><br></pre></td></tr></table></figure><p>类似上面这样将一个表达式作为参数传入函数,表达式应该什么时候计算?实际上可以分为两种情况:</p><ul><li>一种是**传值调用(call by value)**,即表达式在传入函数之前就已经进行了计算,test(2+3)就相当于test(5),js、C语言、JAVA等语言使用的是这种策略。</li><li>一种是**传名调用(call by name)**,即直接将表达式传入函数,只在需要的时候进行表达式的运算,Haskell(哈斯克尔)使用的是这种策略。<br>传值调用比较简单和便于理解,但是在没有用到的时候,先进行了计算,可能造成性能浪费。<span id="more"></span><h6 id="什么是Thunk函数"><a href="#什么是Thunk函数" class="headerlink" title="什么是Thunk函数"></a>什么是Thunk函数</h6><blockquote><p>将表达式参数放到一个临时函数之中,再将这个临时函数传入函数体。这个临时函数就叫做 Thunk 函数。<br>它是”传名调用”的一种实现策略,用来替换某个表达式。</p></blockquote></li></ul><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">test</span>(<span class="params">num</span>) {</span><br><span class="line"> <span class="keyword">return</span> num+<span class="number">1</span>;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">testValue</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="keyword">return</span> <span class="number">2</span>+<span class="number">3</span>;</span><br><span class="line">}</span><br><span class="line"><span class="title function_">test</span>(<span class="title function_">testValue</span>());</span><br><span class="line"><span class="comment">// testValue 函数就是Thunk函数</span></span><br></pre></td></tr></table></figure><h6 id="JavaScript中的Thunk函数"><a href="#JavaScript中的Thunk函数" class="headerlink" title="JavaScript中的Thunk函数"></a>JavaScript中的Thunk函数</h6><p>在 JavaScript 语言中,Thunk 函数替换的不是表达式,而是多参数函数,将其替换成单参数的版本,且只接受回调函数作为参数。</p><p>要点:多参数函数</p><ul><li>函数接受多个参数</li><li>函数的最后一个参数是回调函数</li></ul><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">test</span>(<span class="params">a, b, callback</span>) {...}</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> testThunk = <span class="title class_">Thunk</span>(a, b);</span><br><span class="line"><span class="title function_">testThunk</span>(callback);</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> <span class="title class_">Thunk</span> = <span class="keyword">function</span> (<span class="params">a, b</span>){</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">function</span> (<span class="params">callback</span>){</span><br><span class="line"> <span class="keyword">return</span> <span class="title function_">test</span>(a, b, callback);</span><br><span class="line"> };</span><br><span class="line">};</span><br></pre></td></tr></table></figure><p>上面的函数经过转换器处理,它变成了一个单参数函数,只接受回调函数作为参数。这个单参数版本,就叫做 Thunk 函数。<br>任何函数,只要参数有回调函数,就能写成 Thunk 函数的形式。下面是一个简单的 Thunk 函数转换器。</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> toThunk = <span class="keyword">function</span>(<span class="params">fn</span>){</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">function</span> (<span class="params"></span>){</span><br><span class="line"> <span class="keyword">var</span> args = <span class="title class_">Array</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">slice</span>.<span class="title function_">call</span>(<span class="variable language_">arguments</span>);</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">function</span> (<span class="params">callback</span>){</span><br><span class="line"> args.<span class="title function_">push</span>(callback);</span><br><span class="line"> <span class="keyword">return</span> fn.<span class="title function_">apply</span>(<span class="variable language_">this</span>, args);</span><br><span class="line"> }</span><br><span class="line"> };</span><br><span class="line">};</span><br></pre></td></tr></table></figure><p>使用上面的转换器之后,可将上述的例子修改为</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> testThunk = <span class="title function_">toThunk</span>(test);</span><br><span class="line"><span class="title function_">testThunk</span>(a, b)(callback)</span><br></pre></td></tr></table></figure><h6 id="Thunkify模块"><a href="#Thunkify模块" class="headerlink" title="Thunkify模块"></a>Thunkify模块</h6><p>下载地址:<a href="https://github.com/tj/node-thunkify">https://github.com/tj/node-thunkify</a><br>使用举例</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> thunkify = <span class="built_in">require</span>(<span class="string">'thunkify'</span>);</span><br><span class="line"><span class="keyword">var</span> fs = <span class="built_in">require</span>(<span class="string">'fs'</span>);</span><br><span class="line"><span class="keyword">var</span> read = <span class="title function_">thunkify</span>(fs.<span class="property">readFile</span>);</span><br><span class="line"><span class="title function_">read</span>(<span class="string">'package.json'</span>, <span class="string">'utf8'</span>)(<span class="keyword">function</span>(<span class="params">err, str</span>){</span><br><span class="line"> ...</span><br><span class="line">});</span><br></pre></td></tr></table></figure><p><em>注意:thunkify中存在一个检查机制,回调函数只运行一次。</em><br><img src="thunkify.png" class="lazyload" data-srcset="thunkify.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="thunkify源码"></p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> thunkify <span class="keyword">from</span> <span class="string">'thunkify'</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">test</span>(<span class="params">a, b, callback</span>) {</span><br><span class="line"> <span class="keyword">const</span> result = a + b;</span><br><span class="line"> <span class="title function_">callback</span>(result);</span><br><span class="line"> <span class="title function_">callback</span>(result);</span><br><span class="line"> <span class="title function_">callback</span>(result);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> thunkTest = <span class="title function_">thunkify</span>(test);</span><br><span class="line"><span class="title function_">thunkTest</span>(<span class="number">1</span>, <span class="number">2</span>)(<span class="variable language_">console</span>.<span class="property">log</span>);</span><br><span class="line"><span class="comment">// 3</span></span><br></pre></td></tr></table></figure><h6 id="Thunk函数的用途"><a href="#Thunk函数的用途" class="headerlink" title="Thunk函数的用途"></a>Thunk函数的用途</h6><p>Thunk函数可以和Generator结合使用,Thunk 函数作为在 Generator 中要迭代的值,通过 co 来对 Generator 进行流程控制。<br>Generator函数中可以使用yield将程序的执行权移出,然后通过Thunk函数的回调函数,再将执行权还给Generator函数。</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> thunkify <span class="keyword">from</span> <span class="string">'thunkify'</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">test</span>(<span class="params">a, b, callback</span>) {</span><br><span class="line"> <span class="keyword">const</span> result = a + b;</span><br><span class="line"> <span class="title function_">callback</span>(result);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> thunkTest = <span class="title function_">thunkify</span>(test);</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span>* <span class="title function_">gen</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="keyword">yield</span> <span class="title function_">thunkTest</span>(<span class="number">1</span>, <span class="number">2</span>);</span><br><span class="line"> <span class="keyword">yield</span> <span class="title function_">thunkTest</span>(<span class="number">3</span>, <span class="number">4</span>);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// 使用Thunk函数处理</span></span><br><span class="line"><span class="keyword">const</span> genTest = <span class="title function_">gen</span>();</span><br><span class="line"><span class="keyword">const</span> genValue = genTest.<span class="title function_">next</span>();</span><br><span class="line">genValue.<span class="title function_">value</span>(<span class="keyword">function</span> (<span class="params">data</span>) {</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(data);</span><br><span class="line"> <span class="keyword">const</span> genValue1 = genTest.<span class="title function_">next</span>(data);</span><br><span class="line"> genValue1.<span class="title function_">value</span>(<span class="keyword">function</span> (<span class="params">data1</span>) {</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(data1);</span><br><span class="line"> });</span><br><span class="line">});</span><br><span class="line"></span><br><span class="line"><span class="comment">// 修改为递归方式调用</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">genFn</span>(<span class="params">fn</span>) {</span><br><span class="line"> <span class="keyword">const</span> gen = <span class="title function_">fn</span>();</span><br><span class="line"> <span class="keyword">function</span> <span class="title function_">next</span>(<span class="params">data</span>) {</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(data);</span><br><span class="line"> <span class="keyword">const</span> genValue = gen.<span class="title function_">next</span>(data);</span><br><span class="line"> <span class="keyword">if</span> (genValue.<span class="property">done</span>) <span class="keyword">return</span>;</span><br><span class="line"> genValue.<span class="title function_">value</span>(next);</span><br><span class="line"> }</span><br><span class="line"> <span class="title function_">next</span>();</span><br><span class="line">}</span><br><span class="line"><span class="title function_">genFn</span>(gen);</span><br></pre></td></tr></table></figure><h6 id="co-Generator-Thunk"><a href="#co-Generator-Thunk" class="headerlink" title="co+Generator+Thunk"></a>co+Generator+Thunk</h6><p>可以通过co控制Generator函数中的Thunk函数的执行流程<br>co地址:<a href="https://github.com/tj/co">https://github.com/tj/co</a></p><p><em>注意:co从4.0.0开始返回的是promise,之前返回的是thunk函数,4.0.0之前会把promise转成thunk函数</em></p><p><img src="promiseToThunk.png" class="lazyload" data-srcset="promiseToThunk.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="promiseToThunk"></p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> co = <span class="built_in">require</span>(<span class="string">'co'</span>);</span><br><span class="line"><span class="comment">// 这里的thunk函数也可以自己实现</span></span><br><span class="line"><span class="keyword">var</span> thunkify = <span class="built_in">require</span>(<span class="string">'thunkify'</span>);</span><br><span class="line"><span class="keyword">var</span> request = <span class="built_in">require</span>(<span class="string">'request'</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> get = <span class="title function_">thunkify</span>(request.<span class="property">get</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> *<span class="title function_">results</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="keyword">var</span> a = <span class="title function_">get</span>(<span class="string">'http://google.com'</span>)</span><br><span class="line"> <span class="keyword">var</span> b = <span class="title function_">get</span>(<span class="string">'http://yahoo.com'</span>)</span><br><span class="line"> <span class="keyword">var</span> c = <span class="title function_">get</span>(<span class="string">'http://ign.com'</span>)</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">yield</span> [a, b, c]</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="title function_">co</span>(<span class="keyword">function</span> *(){</span><br><span class="line"> <span class="comment">// 3 concurrent requests at a time</span></span><br><span class="line"> <span class="keyword">var</span> a = <span class="keyword">yield</span> results;</span><br><span class="line"> <span class="keyword">var</span> b = <span class="keyword">yield</span> results;</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(a, b);</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 6 concurrent requests</span></span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="keyword">yield</span> [results, results]);</span><br><span class="line">})()</span><br></pre></td></tr></table></figure><p><img src="thunkToPromise.png" class="lazyload" data-srcset="thunkToPromise.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="thunkToPromise"></p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> co <span class="keyword">from</span> <span class="string">'co'</span>;</span><br><span class="line"><span class="title function_">co</span>(<span class="keyword">function</span>* () {</span><br><span class="line"> <span class="keyword">var</span> result = <span class="keyword">yield</span> <span class="title class_">Promise</span>.<span class="title function_">resolve</span>(<span class="literal">true</span>);</span><br><span class="line"> <span class="comment">// var result = yield Promise.reject('errorInfo');</span></span><br><span class="line"> <span class="keyword">return</span> result;</span><br><span class="line">})</span><br><span class="line"> .<span class="title function_">then</span>(<span class="keyword">function</span> (<span class="params">value</span>) {</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">`then: <span class="subst">${value}</span>`</span>);</span><br><span class="line"> })</span><br><span class="line"> .<span class="title function_">catch</span>(<span class="keyword">function</span> (<span class="params">err</span>) {</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">error</span>(err);</span><br><span class="line"> });</span><br></pre></td></tr></table></figure><p>comment:<br>一些简单的传值调用,会在编译阶段就被优化掉。<br>如果将简单的表达式放到一个函数中return返回,将函数作为参数传入处理函数中,这个参数函数是否会被编译优化处理??</p>]]></content>
<summary type="html"><h6 id="求值策略"><a href="#求值策略" class="headerlink" title="求值策略"></a>求值策略</h6><p>在介绍Thunk函数之前,需要先介绍一下什么叫做求值策略,即函数的参数应该什么时候求值。</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">test</span>(<span class="params">num</span>) &#123;</span><br><span class="line"> <span class="keyword">return</span> num+<span class="number">1</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="title function_">test</span>(<span class="number">2</span>+<span class="number">3</span>);</span><br></pre></td></tr></table></figure>
<p>类似上面这样将一个表达式作为参数传入函数,表达式应该什么时候计算?实际上可以分为两种情况:</p>
<ul>
<li>一种是**传值调用(call by value)**,即表达式在传入函数之前就已经进行了计算,test(2+3)就相当于test(5),js、C语言、JAVA等语言使用的是这种策略。</li>
<li>一种是**传名调用(call by name)**,即直接将表达式传入函数,只在需要的时候进行表达式的运算,Haskell(哈斯克尔)使用的是这种策略。<br>传值调用比较简单和便于理解,但是在没有用到的时候,先进行了计算,可能造成性能浪费。</summary>
</entry>
<entry>
<title>try...catch和return</title>
<link href="https://sunjinkang.github.io/2023/04/19/50-try-catch-return/"/>
<id>https://sunjinkang.github.io/2023/04/19/50-try-catch-return/</id>
<published>2023-04-19T02:42:04.000Z</published>
<updated>2023-08-03T03:05:54.178Z</updated>
<content type="html"><![CDATA[<h6 id="关于return"><a href="#关于return" class="headerlink" title="关于return"></a>关于return</h6><blockquote><p>return 语句终止函数的执行,并返回一个指定的值给函数调用者</p></blockquote><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">test</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i < <span class="number">4</span>; i++) {</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">`before: <span class="subst">${i}</span>`</span>);</span><br><span class="line"> <span class="keyword">if</span> (i === <span class="number">2</span>) <span class="keyword">return</span>;</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">`after: <span class="subst">${i}</span>`</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">`result`</span>);</span><br><span class="line">}</span><br><span class="line"><span class="title function_">test</span>();</span><br><span class="line"><span class="comment">// before: 0</span></span><br><span class="line"><span class="comment">// after: 0</span></span><br><span class="line"><span class="comment">// before: 1</span></span><br><span class="line"><span class="comment">// after: 1</span></span><br><span class="line"><span class="comment">// before: 2</span></span><br></pre></td></tr></table></figure><p>注意:自动分号补全规则会影响 return 语句。在 return 关键字和被返回的表达式之间不允许使用换行符。</p><span id="more"></span><p><em>自动分号补全(ASI)</em><br>在JavaScript中,行尾的分号有一种自动插入机制,如果新起了一行,并且这新的一行不能追加到当前语句时,会自动追加一个分号</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">return</span></span><br><span class="line"><span class="number">1</span>;</span><br><span class="line"><span class="comment">// return会因为自动分号补全自动添加一个分号</span></span><br></pre></td></tr></table></figure><h6 id="关于try…catch"><a href="#关于try…catch" class="headerlink" title="关于try…catch"></a>关于try…catch</h6><blockquote><p>try…catch 语句标记要尝试的语句块,并指定一个出现异常时抛出的响应。</p></blockquote><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">try</span> {</span><br><span class="line"> a + <span class="number">3</span>;</span><br><span class="line">} <span class="keyword">catch</span> (error) {</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(error);</span><br><span class="line">}</span><br><span class="line"><span class="comment">// ReferenceError: a is not defined</span></span><br></pre></td></tr></table></figure><ul><li>try…catch语法<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">try</span> {</span><br><span class="line"> try_statements</span><br><span class="line">}</span><br><span class="line">[<span class="keyword">catch</span> (exception_var_1 <span class="keyword">if</span> condition_1) { <span class="comment">// non-standard</span></span><br><span class="line"> catch_statements_1</span><br><span class="line">}]</span><br><span class="line">...</span><br><span class="line">[<span class="keyword">catch</span> (exception_var_2) {</span><br><span class="line"> catch_statements_2</span><br><span class="line">}]</span><br><span class="line">[<span class="keyword">finally</span> {</span><br><span class="line"> finally_statements</span><br><span class="line">}]</span><br></pre></td></tr></table></figure></li><li>使用方式<ul><li>try…catch</li><li>try…finally</li><li>try…catch…finally<br>catch子句包含try块中抛出异常时要执行的语句。如果在try块中有任何一个语句(或者从try块中调用的函数)抛出异常,控制立即转向catch子句。如果在try块中没有异常抛出,会跳过catch子句。</li></ul></li></ul><p>finally子句在try块和catch块之后执行但是在下一个try声明之前执行。无论是否有异常抛出或捕获它总是执行。</p><p><em>你可以嵌套一个或者更多的try语句。如果内部的try语句没有catch子句,那么将会进入包裹它的try语句的catch子句。</em></p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">try</span> {</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> a + <span class="number">3</span>;</span><br><span class="line"> } <span class="keyword">catch</span> (err) {</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">`inner: <span class="subst">${err}</span>`</span>);</span><br><span class="line"> }</span><br><span class="line">} <span class="keyword">catch</span> (err) {</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">`outer: <span class="subst">${err}</span>`</span>);</span><br><span class="line">}</span><br><span class="line"><span class="comment">// inner: ReferenceError: a is not defined</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">try</span> {</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> a + <span class="number">3</span>;</span><br><span class="line"> } <span class="keyword">finally</span>{}</span><br><span class="line">} <span class="keyword">catch</span> (err) {</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">`outer: <span class="subst">${err}</span>`</span>);</span><br><span class="line">}</span><br><span class="line"><span class="comment">// outer: ReferenceError: a is not defined</span></span><br></pre></td></tr></table></figure><ul><li>无条件的catch语句<br>即catch捕获错误,进行处理,常用的一般是这种,不再赘述</li><li>有条件的catch语句<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">try</span> {</span><br><span class="line"> a + <span class="number">3</span>;</span><br><span class="line">} <span class="keyword">catch</span> (err) {</span><br><span class="line"> <span class="keyword">if</span> (err.<span class="title function_">toString</span>().<span class="title function_">includes</span>(<span class="string">'not defined'</span>)) {</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">`not defined error: <span class="subst">${err}</span>`</span>);</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(err);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="comment">// not defined error: ReferenceError: a is not defined</span></span><br></pre></td></tr></table></figure><h6 id="try…catch中使用return"><a href="#try…catch中使用return" class="headerlink" title="try…catch中使用return"></a>try…catch中使用return</h6></li></ul><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">test</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> a+<span class="number">3</span>;</span><br><span class="line"> } <span class="keyword">catch</span> (err) {</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">`inner error: <span class="subst">${err}</span>`</span>);</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> }</span><br><span class="line"> } <span class="keyword">finally</span> {</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">`finally`</span>)</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="title function_">test</span>();</span><br><span class="line"><span class="comment">// inner error: ReferenceError: a is not defined</span></span><br><span class="line"><span class="comment">// finally</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">test</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> a + <span class="number">3</span>;</span><br><span class="line"> } <span class="keyword">catch</span> (err) {</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">`inner error: <span class="subst">${err}</span>`</span>);</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> } <span class="keyword">finally</span> {</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">`inner finally`</span>);</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> }</span><br><span class="line"> } <span class="keyword">finally</span> {</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">`finally`</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="title function_">test</span>();</span><br><span class="line"><span class="comment">// inner error: ReferenceError: a is not defined</span></span><br><span class="line"><span class="comment">// inner finally</span></span><br><span class="line"><span class="comment">// finally</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">test</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="keyword">return</span> <span class="number">3</span>;</span><br><span class="line"> } <span class="keyword">catch</span> (err) {</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">`inner error: <span class="subst">${err}</span>`</span>);</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> } <span class="keyword">finally</span> {</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">`inner finally`</span>);</span><br><span class="line"> <span class="comment">// return 'finally';</span></span><br><span class="line"> }</span><br><span class="line"> } <span class="keyword">finally</span> {</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">`outer finally`</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="keyword">const</span> result = <span class="title function_">test</span>();</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(result);</span><br><span class="line"><span class="comment">// inner finally</span></span><br><span class="line"><span class="comment">// outer finally</span></span><br><span class="line"><span class="comment">// if inner finally not return something, result is 3, else result is the inner finally return.</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">test</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="keyword">return</span> <span class="number">3</span>;</span><br><span class="line"> } <span class="keyword">catch</span> (err) {</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">`inner error: <span class="subst">${err}</span>`</span>);</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> } <span class="keyword">finally</span> {</span><br><span class="line"> <span class="keyword">return</span> <span class="string">'finally'</span>;</span><br><span class="line"> }</span><br><span class="line"> } <span class="keyword">finally</span> {</span><br><span class="line"> <span class="keyword">return</span> <span class="string">'outer finally'</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="keyword">const</span> result = <span class="title function_">test</span>();</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(result);</span><br><span class="line"><span class="comment">// outer finally</span></span><br></pre></td></tr></table></figure><p><em>如果从finally块中返回一个值,那么这个值将会成为整个try-catch-finally的返回值,无论是否有return语句在try和catch中。这包括在catch块里抛出的异常。</em></p>]]></content>
<summary type="html"><h6 id="关于return"><a href="#关于return" class="headerlink" title="关于return"></a>关于return</h6><blockquote>
<p>return 语句终止函数的执行,并返回一个指定的值给函数调用者</p>
</blockquote>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">test</span>(<span class="params"></span>) &#123;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; <span class="number">4</span>; i++) &#123;</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">`before: <span class="subst">$&#123;i&#125;</span>`</span>);</span><br><span class="line"> <span class="keyword">if</span> (i === <span class="number">2</span>) <span class="keyword">return</span>;</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">`after: <span class="subst">$&#123;i&#125;</span>`</span>);</span><br><span class="line"> &#125;</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">`result`</span>);</span><br><span class="line">&#125;</span><br><span class="line"><span class="title function_">test</span>();</span><br><span class="line"><span class="comment">// before: 0</span></span><br><span class="line"><span class="comment">// after: 0</span></span><br><span class="line"><span class="comment">// before: 1</span></span><br><span class="line"><span class="comment">// after: 1</span></span><br><span class="line"><span class="comment">// before: 2</span></span><br></pre></td></tr></table></figure>
<p>注意:自动分号补全规则会影响 return 语句。在 return 关键字和被返回的表达式之间不允许使用换行符。</p></summary>
</entry>
<entry>
<title>js类型化数组</title>
<link href="https://sunjinkang.github.io/2023/04/18/49-typed-array/"/>
<id>https://sunjinkang.github.io/2023/04/18/49-typed-array/</id>
<published>2023-04-18T10:17:14.000Z</published>
<updated>2023-08-03T03:05:40.218Z</updated>
<content type="html"><![CDATA[<h6 id="什么是类型化数组(Typed-Array)"><a href="#什么是类型化数组(Typed-Array)" class="headerlink" title="什么是类型化数组(Typed Array)?"></a>什么是类型化数组(Typed Array)?</h6><blockquote><p>JavaScript 类型化数组(typed array)是一种类似数组的对象,并提供了一种用于在内存缓冲区中访问原始二进制数据的机制。</p></blockquote><p><em>JavaScript 类型化数组中的每一个元素都是原始二进制值,而二进制值采用多种支持的格式之一(从 8 位整数到 64 位浮点数)。</em></p><span id="more"></span><p><strong>注意:类型数组和普通数组不一样,使用Array.isArray()判断类型数组返回false,此外,一些在普通数组上使用的方法,在类型数组上无法使用</strong></p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> bufferArray = <span class="keyword">new</span> <span class="title class_">ArrayBuffer</span>(<span class="number">16</span>);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title class_">Array</span>.<span class="title function_">isArray</span>(bufferArray));</span><br><span class="line"><span class="comment">// false</span></span><br><span class="line">bufferArray.<span class="title function_">push</span>(<span class="number">1</span>);</span><br><span class="line"><span class="comment">// TypeError: bufferArray.push is not a function</span></span><br><span class="line">bufferArray.<span class="title function_">pop</span>(<span class="number">1</span>);</span><br><span class="line"><span class="comment">// TypeError: bufferArray.pop is not a function</span></span><br></pre></td></tr></table></figure><h6 id="类型化数组的语法"><a href="#类型化数组的语法" class="headerlink" title="类型化数组的语法"></a>类型化数组的语法</h6><h6 id="类型化数组的特性、方法、使用场景"><a href="#类型化数组的特性、方法、使用场景" class="headerlink" title="类型化数组的特性、方法、使用场景"></a>类型化数组的特性、方法、使用场景</h6><h6 id="类型化数组的局限性、限制"><a href="#类型化数组的局限性、限制" class="headerlink" title="类型化数组的局限性、限制"></a>类型化数组的局限性、限制</h6>]]></content>
<summary type="html"><h6 id="什么是类型化数组(Typed-Array)"><a href="#什么是类型化数组(Typed-Array)" class="headerlink" title="什么是类型化数组(Typed Array)?"></a>什么是类型化数组(Typed Array)?</h6><blockquote>
<p>JavaScript 类型化数组(typed array)是一种类似数组的对象,并提供了一种用于在内存缓冲区中访问原始二进制数据的机制。</p>
</blockquote>
<p><em>JavaScript 类型化数组中的每一个元素都是原始二进制值,而二进制值采用多种支持的格式之一(从 8 位整数到 64 位浮点数)。</em></p></summary>
</entry>
<entry>
<title>import、import()、require的区别</title>
<link href="https://sunjinkang.github.io/2023/04/06/48-difference-about-require-import/"/>
<id>https://sunjinkang.github.io/2023/04/06/48-difference-about-require-import/</id>
<published>2023-04-06T02:42:59.000Z</published>
<updated>2023-07-24T09:24:46.457Z</updated>
</entry>
<entry>
<title>生成器函数和yield关键字</title>
<link href="https://sunjinkang.github.io/2023/03/31/47-about-generate-function/"/>
<id>https://sunjinkang.github.io/2023/03/31/47-about-generate-function/</id>
<published>2023-03-31T06:00:46.000Z</published>
<updated>2023-08-03T03:05:03.177Z</updated>
<content type="html"><![CDATA[<h6 id="什么是生成器函数?"><a href="#什么是生成器函数?" class="headerlink" title="什么是生成器函数?"></a>什么是生成器函数?</h6><blockquote><p>function* 这种声明方式 (function关键字后跟一个星号)会定义一个生成器函数 (generator function),它返回一个 Generator 对象。<br>也可以使用构造函数 GeneratorFunction 或 function* expression 定义**生成器函数 **</p></blockquote><h6 id="语法"><a href="#语法" class="headerlink" title="语法"></a>语法</h6><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span>* <span class="title function_">name</span>(<span class="params">[param[, param[, ... param]]]</span>) { statements }</span><br><span class="line"><span class="comment">// name: 函数名</span></span><br><span class="line"><span class="comment">// param: 参数</span></span><br><span class="line"><span class="comment">// statements: 执行语句</span></span><br><span class="line"><span class="comment">// 声明方式可以为:function* name(){} 或者 function *name(){}</span></span><br></pre></td></tr></table></figure><span id="more"></span><h6 id="简单举例"><a href="#简单举例" class="headerlink" title="简单举例"></a>简单举例</h6><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span>* <span class="title function_">generator</span>(<span class="params">i</span>) {</span><br><span class="line"> <span class="keyword">return</span> i+<span class="number">1</span>;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">const</span> gen = <span class="title function_">generator</span>(<span class="number">3</span>);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(gen.<span class="title function_">next</span>());</span><br><span class="line"><span class="comment">// {value: 4, done: true}</span></span><br></pre></td></tr></table></figure><p><em>生成器函数不能作为构造函数使用</em></p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span>* <span class="title class_">Test</span>() {</span><br><span class="line"> <span class="comment">// some operation</span></span><br><span class="line">}</span><br><span class="line"><span class="keyword">const</span> newTest = <span class="keyword">new</span> <span class="title class_">Test</span>();</span><br></pre></td></tr></table></figure><h6 id="生成器函数的特性"><a href="#生成器函数的特性" class="headerlink" title="生成器函数的特性"></a>生成器函数的特性</h6><p>1、调用一个生成器函数并不会马上执行它里面的语句,而是返回一个这个生成器的 迭代器 ( iterator )对象。通过next()方法获取返回值</p><p>2、next()方法返回一个对象,这个对象包含两个属性:value 和 done, done为true表示函数完成,为false函数未完成,可继续调用next方法</p><h6 id="生成器函数的相关特性"><a href="#生成器函数的相关特性" class="headerlink" title="生成器函数的相关特性"></a>生成器函数的相关特性</h6><p>1、yield<br>yield 关键字用于暂停和恢复生成器函数。</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span>* <span class="title function_">testYield</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">let</span> num = <span class="number">0</span>; num < <span class="number">3</span>; num++) {</span><br><span class="line"> <span class="keyword">yield</span> num;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="keyword">const</span> result = <span class="title function_">testYield</span>();</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(result.<span class="title function_">next</span>());</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(result.<span class="title function_">next</span>());</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(result.<span class="title function_">next</span>());</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(result.<span class="title function_">next</span>());</span><br><span class="line"><span class="comment">// { value: 0, done: false }</span></span><br><span class="line"><span class="comment">// { value: 1, done: false }</span></span><br><span class="line"><span class="comment">// { value: 2, done: false }</span></span><br><span class="line"><span class="comment">// { value: undefined, done: true }</span></span><br></pre></td></tr></table></figure><p>yield 关键字使生成器函数执行暂停,yield 关键字后面的表达式的值返回给生成器的调用者,即表达式的值为返回对象中的value。它可以被认为是一个基于生成器的版本的 return 关键字。</p><p>返回:</p><ul><li>IteratorResult 对象<ul><li>value</li><li>done</li></ul></li></ul><p>一旦遇到 yield 表达式,生成器的代码将被暂停运行,直到生成器的 next() 方法被调用。每次调用生成器的 next() 方法时,生成器都会恢复执行,直到达到以下某个值:</p><ul><li>yield:导致生成器再次暂停并返回生成器的新值。下一次调用 next() 时,在 yield 之后紧接着的语句继续执行。</li><li>throw:用于从生成器中抛出异常。这让生成器完全停止执行,并在调用者中继续执行,正如通常情况下抛出异常一样。</li><li>到达生成器函数的结尾.在这种情况下,生成器的执行结束,并且 IteratorResult 给调用者返回 value 的值是 undefined 并且 done 为 true。</li><li>到达 return 语句。在这种情况下,生成器的执行结束,并将 IteratorResult 返回给调用者,其 value 的值是由 return 语句指定的,并且 done 为 true。<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// throw</span></span><br><span class="line"><span class="keyword">function</span>* <span class="title function_">testYield</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">let</span> num = <span class="number">0</span>; num < <span class="number">3</span>; num++) {</span><br><span class="line"> <span class="keyword">yield</span> num;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="keyword">const</span> result = <span class="title function_">testYield</span>();</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(result.<span class="title function_">next</span>());</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(result.<span class="keyword">throw</span>(<span class="keyword">new</span> <span class="title class_">Error</span>(<span class="string">'1'</span>)));</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(result.<span class="title function_">next</span>());</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(result.<span class="title function_">next</span>());</span><br><span class="line"><span class="comment">// { value: 0, done: false }</span></span><br><span class="line"><span class="comment">// Error: 1</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// return</span></span><br><span class="line"><span class="keyword">function</span>* <span class="title function_">testYield</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">let</span> num = <span class="number">0</span>; num < <span class="number">3</span>; num++) {</span><br><span class="line"> <span class="keyword">yield</span> num;</span><br><span class="line"> <span class="keyword">return</span> <span class="number">45</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="keyword">const</span> result = <span class="title function_">testYield</span>();</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(result.<span class="title function_">next</span>());</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(result.<span class="title function_">next</span>());</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(result.<span class="title function_">next</span>());</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(result.<span class="title function_">next</span>());</span><br><span class="line"><span class="comment">// { value: 0, done: false }</span></span><br><span class="line"><span class="comment">// { value: 45, done: true }</span></span><br><span class="line"><span class="comment">// { value: undefined, done: true }</span></span><br><span class="line"><span class="comment">// { value: undefined, done: true }</span></span><br></pre></td></tr></table></figure>如果将参数传递给生成器的 next() 方法,则该值将成为生成器当前 yield 操作返回的值</li></ul><p><em>注意:第一个next只是为了启动生成器,传递的参数不起作用</em></p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span>* <span class="title function_">testYield</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="keyword">let</span> num = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">while</span> (<span class="literal">true</span>) {</span><br><span class="line"> <span class="keyword">const</span> result = <span class="keyword">yield</span> num;</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(result);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="keyword">const</span> result = <span class="title function_">testYield</span>();</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(result.<span class="title function_">next</span>(<span class="number">2</span>)); <span class="comment">// no result return</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(result.<span class="title function_">next</span>(<span class="number">3</span>)); <span class="comment">// result: 3</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(result.<span class="title function_">next</span>(<span class="number">6</span>)); <span class="comment">// result: 6</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(result.<span class="title function_">next</span>());</span><br></pre></td></tr></table></figure><p>2、yield*<br>用于委托给另一个generator或可迭代对象</p><ul><li>yield* 表达式迭代操作数,并产生它返回的每个值。</li><li>yield* 表达式本身的值是当迭代器关闭时返回的值(即done为true时)。</li><li>yield* 还可以 yield 其他任意的可迭代对象,比如说数组、字符串、arguments 对象等等。<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// eg:one</span></span><br><span class="line"><span class="keyword">function</span>* <span class="title function_">testOne</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="keyword">yield</span> <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">yield</span> <span class="number">4</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span>* <span class="title function_">testTwo</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="keyword">yield</span> <span class="number">2</span>;</span><br><span class="line"> <span class="keyword">yield</span>* <span class="title function_">testOne</span>();</span><br><span class="line"> <span class="keyword">yield</span> <span class="number">3</span>;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">const</span> result = <span class="title function_">testTwo</span>();</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(result.<span class="title function_">next</span>());</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(result.<span class="title function_">next</span>());</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(result.<span class="title function_">next</span>());</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(result.<span class="title function_">next</span>());</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(result.<span class="title function_">next</span>());</span><br><span class="line"><span class="comment">// { value: 1, done: false }</span></span><br><span class="line"><span class="comment">// { value: 2, done: false }</span></span><br><span class="line"><span class="comment">// { value: 3, done: false }</span></span><br><span class="line"><span class="comment">// { value: 4, done: false }</span></span><br><span class="line"><span class="comment">// { value: undefined, done: true }</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// eg:two</span></span><br><span class="line"><span class="keyword">function</span>* test () {</span><br><span class="line"> <span class="keyword">yield</span>* [<span class="number">1</span>,<span class="number">2</span>];</span><br><span class="line"> <span class="keyword">yield</span>* <span class="string">'3,4'</span>;</span><br><span class="line"> <span class="keyword">yield</span>* <span class="variable language_">arguments</span>;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">const</span> result = <span class="title function_">test</span>(<span class="number">5</span>, <span class="number">6</span>);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(result.<span class="title function_">next</span>());</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(result.<span class="title function_">next</span>());</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(result.<span class="title function_">next</span>());</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(result.<span class="title function_">next</span>());</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(result.<span class="title function_">next</span>());</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(result.<span class="title function_">next</span>());</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(result.<span class="title function_">next</span>());</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(result.<span class="title function_">next</span>());</span><br><span class="line"><span class="comment">// { value: 1, done: false }</span></span><br><span class="line"><span class="comment">// { value: 2, done: false }</span></span><br><span class="line"><span class="comment">// { value: '3', done: false }</span></span><br><span class="line"><span class="comment">// { value: ',', done: false }</span></span><br><span class="line"><span class="comment">// { value: '4', done: false }</span></span><br><span class="line"><span class="comment">// { value: 5, done: false }</span></span><br><span class="line"><span class="comment">// { value: 6, done: false }</span></span><br><span class="line"><span class="comment">// { value: undefined, done: true }</span></span><br></pre></td></tr></table></figure></li></ul><p><em>调用 next()方法时,如果传入了参数,那么这个参数会传给上一条执行的 yield 语句左边的变量</em></p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span>* <span class="title function_">test</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="keyword">yield</span> <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">const</span> x = <span class="keyword">yield</span> <span class="string">'one'</span>;</span><br><span class="line"> <span class="keyword">yield</span> x;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> result = <span class="title function_">test</span>();</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(result.<span class="title function_">next</span>());</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(result.<span class="title function_">next</span>());</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(result.<span class="title function_">next</span>(<span class="number">100</span>));</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(result.<span class="title function_">next</span>());</span><br><span class="line"><span class="comment">// { value: 1, done: false }</span></span><br><span class="line"><span class="comment">// { value: 'one', done: false }</span></span><br><span class="line"><span class="comment">// { value: 100, done: false }</span></span><br><span class="line"><span class="comment">// { value: undefined, done: true }</span></span><br></pre></td></tr></table></figure><h6 id="生成器函数的作用"><a href="#生成器函数的作用" class="headerlink" title="生成器函数的作用"></a>生成器函数的作用</h6><p>生成器函数是ES6引入的新特性</p><p>延迟执行:生成器可以在需要时逐个生成值,而不是一次性生成所有值。这种延迟执行可以节省内存和提高性能。<br>无限序列:生成器可以用来创建无限序列,如斐波那契数列或素数序列,这些序列通常很难使用常规方法来实现。<br>异步编程:生成器可以用来实现异步编程,通过使用生成器来实现异步函数,可以更方便地处理异步调用和异步错误。<br>迭代器:生成器可以用来创建迭代器,使得对集合的遍历变得更加方便和可读。<br>生成器协程:生成器可以用作协程,在 JavaScript 中实现类似线程的功能,从而实现更高级的并发和并行编程。</p><p><em>举例</em></p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span>* <span class="title function_">iterArr</span>(<span class="params">arr</span>) {</span><br><span class="line"> <span class="keyword">if</span> (<span class="title class_">Array</span>.<span class="title function_">isArray</span>(arr)) {</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">let</span> i=<span class="number">0</span>; i < arr.<span class="property">length</span>; i++) {</span><br><span class="line"> <span class="keyword">yield</span>* <span class="title function_">iterArr</span>(arr[i]);</span><br><span class="line"> }</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">yield</span> arr;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="keyword">let</span> arr = [ <span class="string">'a'</span>, [<span class="string">'b'</span>,[ <span class="string">'c'</span>, [<span class="string">'d'</span>, <span class="string">'e'</span>]]]];</span><br><span class="line"><span class="keyword">const</span> result = <span class="title function_">iterArr</span>(arr);</span><br><span class="line">arr = [...result];</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(arr);</span><br><span class="line"><span class="comment">// [ 'a', 'b', 'c', 'd', 'e' ]</span></span><br></pre></td></tr></table></figure><h6 id="参考文献"><a href="#参考文献" class="headerlink" title="参考文献"></a>参考文献</h6><p><a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Statements/function*">MDN: 生成器函数</a></p><p>issue:</p><ul><li>co,执行生成器函数的库</li><li>生成器函数的回收机制</li><li>实现异步的操作,生成器函数比较鸡肋,使用async、await</li><li>生成器函数是目前js中唯一可以实现暂停执行的方法</li></ul>]]></content>
<summary type="html"><h6 id="什么是生成器函数?"><a href="#什么是生成器函数?" class="headerlink" title="什么是生成器函数?"></a>什么是生成器函数?</h6><blockquote>
<p>function* 这种声明方式 (function关键字后跟一个星号)会定义一个生成器函数 (generator function),它返回一个 Generator 对象。<br>也可以使用构造函数 GeneratorFunction 或 function* expression 定义**生成器函数 **</p>
</blockquote>
<h6 id="语法"><a href="#语法" class="headerlink" title="语法"></a>语法</h6><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span>* <span class="title function_">name</span>(<span class="params">[param[, param[, ... param]]]</span>) &#123; statements &#125;</span><br><span class="line"><span class="comment">// name: 函数名</span></span><br><span class="line"><span class="comment">// param: 参数</span></span><br><span class="line"><span class="comment">// statements: 执行语句</span></span><br><span class="line"><span class="comment">// 声明方式可以为:function* name()&#123;&#125; 或者 function *name()&#123;&#125;</span></span><br></pre></td></tr></table></figure></summary>
</entry>
<entry>
<title>linux系统进程相关笔记</title>
<link href="https://sunjinkang.github.io/2023/01/17/46-linux-process/"/>
<id>https://sunjinkang.github.io/2023/01/17/46-linux-process/</id>
<published>2023-01-17T02:45:24.000Z</published>
<updated>2023-08-03T03:04:54.515Z</updated>
<content type="html"><![CDATA[<h4 id="查看进程"><a href="#查看进程" class="headerlink" title="查看进程"></a>查看进程</h4><p>ps<br><img src="ps.png" class="lazyload" data-srcset="ps.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="ps"></p><span id="more"></span><p>ps aux<br><img src="ps-aux.png" class="lazyload" data-srcset="ps-aux.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="ps-aux"></p><p>ps -elf<br><img src="ps-elf.png" class="lazyload" data-srcset="ps-elf.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="ps-elf"></p><p>字段说明:</p><ul><li>USER:启动该进程的用户账号名称 </li><li>PID:该进程的ID号,在当前系统中是唯一的 </li><li>%CPU:CPU占用的百分比 </li><li>%MEM:内存占用的百分比</li><li>VSZ:占用虚拟内存(swap空间)的大小 </li><li>RSS:占用常驻内存(物理内存)的大小</li><li>TTY:该进程在哪个终端上运行。“?”表未知或不需要终端 </li><li>STAT:显示了进程当前的状态,<ul><li>S(休眠): 进程在等待事件完成,如socket连接,等待信号量唤醒等等,也叫可中断睡眠。</li><li>R(运行): 进程要么在运行,要么在运行队列中,等待被OS分配时间片(调度)</li><li>Z(僵死): 子程序已停止,父程序无法读取子程序结束信息, <em>对处于僵死状态的进程应予以手动终止。</em></li><li>D(休眠): 不可中断的状态,又叫不可中断睡眠状态,通常等待I/O结束并告知其</li><li>T(停止): 目前进程正在侦测或停止,可以通过发送 SIGSTOP 信号给进程来停止(T)进程。这个被暂停的进程可以通过发送 SIGCONT 信号让进程继续运行。</li><li>X(死亡): 只是一个返回状态,你不会在任务列表里看到这个状态。当父进程读取子进程的返回结果时,子进程立刻释放资源。死亡状态是非常短暂的,几乎不可能通过ps命令捕捉到。</li><li><(高优先级)</li><li>N(低优先级)</li><li>L(进程有页面文件锁定在进程中)</li><li>s(进程为控制进程,如systemd进程)</li><li>+(前台进程,后台运行在命令之后加 &)</li><li>I(多线程)</li></ul></li><li>START:启动该进程的时间 </li><li>TIME:该进程占用CPU时间 </li><li>COMMAND:启动该进程的命令的名称</li><li>PPID为父进程的PID</li></ul><p>top<br><img src="top.png" class="lazyload" data-srcset="top.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="top"></p><ul><li>Tasks(系统任务)信息:<ul><li>total,总进程数;</li><li>running,正在运行的进程数;</li><li>sleeping,休眠的进程数;</li><li>stopped,中止的进程数;</li><li>zombie,僵死无响应的进程数。</li></ul></li><li>CPU信息:<ul><li>us,用户占用;</li><li>sy,内核占用;</li><li>ni,优先级调度占用;</li><li>id,空闲CPU;<em>了解空闲的CPU百分比,主要看%id部分</em></li><li>wa,I/O等待占用;</li><li>hi,硬件中断占用;</li><li>si,软件中断占用;</li><li>st,虚拟化占用。</li></ul></li><li>Mem(内存)信息:<ul><li>total,总内存空间;</li><li>used,已用内存;</li><li>free,空闲内存;</li><li>buffers,缓存区域。</li></ul></li><li>Swap(交换空间)信息:<ul><li>total,总交换空间;</li><li>used,已用交换空间;</li><li>free,空闲交换空间;</li><li>cached,缓存空间。</li></ul></li></ul>]]></content>
<summary type="html"><h4 id="查看进程"><a href="#查看进程" class="headerlink" title="查看进程"></a>查看进程</h4><p>ps<br><img src="ps.png" alt="ps"></p></summary>
</entry>
<entry>
<title>linux系统常见操作命令</title>
<link href="https://sunjinkang.github.io/2023/01/17/45-linux-common-command/"/>
<id>https://sunjinkang.github.io/2023/01/17/45-linux-common-command/</id>
<published>2023-01-17T02:17:43.000Z</published>
<updated>2023-08-03T03:04:45.288Z</updated>
<content type="html"><![CDATA[<p><strong>查看进程</strong><br>ps</p><p>ps aux</p><ul><li>a:显示当前终端下的所有进程信息,包括其他用户的进程。</li><li>u:使用以用户为主的格式输出进程信息。</li><li>x:显示当前用户在所有终端下的进程。</li></ul><p>ps -elf</p><ul><li>-e:显示系统内的所有进程信息。</li><li>-l:使用长(long)格式显示进程信息。</li><li>-f:使用完整的(full)格式显示进程信息。<span id="more"></span>top<br>以全屏交互式的界面显示进程排名,及时跟踪包括CPU、内存等系统资源占用情况,默认情况下每三秒刷新一次</li></ul><p>pstree<br>pstree -aup<br>以树状图的方式展现进程之间的派生关系,显示效果比较直观。 </p><ul><li>-a:显示每个程序的完整指令,包含路径,参数或是常驻服务的标示; </li><li>-c:不使用精简标示法; </li><li>-G:使用VT100终端机的列绘图字符; </li><li>-h:列出树状图时,特别标明现在执行的程序; </li><li>-H<程序识别码>:此参数的效果和指定”-h”参数类似,但特别标明指定的程序; </li><li>-l:采用长列格式显示树状图; </li><li>-n:用程序识别码排序。预设是以程序名称来排序; </li><li>-p:显示程序识别码; </li><li>-u:显示用户名称;</li></ul><p><strong>带筛选条件查看进程</strong><br>ps aux | grep xxxxx</p>]]></content>
<summary type="html"><p><strong>查看进程</strong><br>ps</p>
<p>ps aux</p>
<ul>
<li>a:显示当前终端下的所有进程信息,包括其他用户的进程。</li>
<li>u:使用以用户为主的格式输出进程信息。</li>
<li>x:显示当前用户在所有终端下的进程。</li>
</ul>
<p>ps -elf</p>
<ul>
<li>-e:显示系统内的所有进程信息。</li>
<li>-l:使用长(long)格式显示进程信息。</li>
<li>-f:使用完整的(full)格式显示进程信息。</summary>
</entry>
<entry>
<title>关于grid布局的相关内容</title>
<link href="https://sunjinkang.github.io/2023/01/03/44-about-grid/"/>
<id>https://sunjinkang.github.io/2023/01/03/44-about-grid/</id>
<published>2023-01-03T07:28:21.000Z</published>
<updated>2023-08-03T03:04:36.225Z</updated>
<content type="html"><![CDATA[<h6 id="什么是grid布局?"><a href="#什么是grid布局?" class="headerlink" title="什么是grid布局?"></a>什么是grid布局?</h6><h6 id="怎么实现grid布局?"><a href="#怎么实现grid布局?" class="headerlink" title="怎么实现grid布局?"></a>怎么实现grid布局?</h6><h6 id="grid布局的好处"><a href="#grid布局的好处" class="headerlink" title="grid布局的好处"></a>grid布局的好处</h6><h6 id="grid布局中一些常用设置说明"><a href="#grid布局中一些常用设置说明" class="headerlink" title="grid布局中一些常用设置说明"></a>grid布局中一些常用设置说明</h6><ul><li>grid-row: grid-row-start / grid-row-end;<ul><li>grid-row-start 指定在哪一行开始显示网格元素。</li><li>grid-row-end 指定停止显示网格元素的行,或要跨越多少行。</li></ul></li></ul><span id="more"></span><figure class="highlight css"><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="comment">/* 设置 "item1" 在第 1 行开始,在第 4 行前结束 */</span></span><br><span class="line"><span class="selector-class">.item1</span> {</span><br><span class="line"> <span class="attribute">grid-row</span>: <span class="number">1</span> / <span class="number">4</span>;</span><br><span class="line">}</span><br><span class="line"><span class="comment">/* 可以参考行号来设置网格元素,也可以使用关键字 "span" 来定义元素将跨越的行数。 */</span></span><br><span class="line"><span class="comment">/* 设置 "item1" 跨越两行 */</span></span><br><span class="line"><span class="selector-class">.item1</span> {</span><br><span class="line"> <span class="attribute">grid-row</span>: <span class="number">1</span> / span <span class="number">2</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><ul><li>grid-template-columns<ul><li>规定网格布局中的列数(和宽度)<figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 设置三列,每列10px */</span></span><br><span class="line"><span class="selector-class">.grid-container</span> {</span><br><span class="line"> <span class="attribute">grid-template-columns</span>: <span class="number">10px</span> <span class="number">10px</span> <span class="number">10px</span>;</span><br><span class="line">}</span><br><span class="line"><span class="comment">/* 设置四列,每列宽度自适应 */</span></span><br><span class="line"><span class="selector-class">.grid-container</span> {</span><br><span class="line"> <span class="attribute">grid-template-columns</span>: auto auto auto auto;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li></ul></li><li>repeat()<ul><li>函数表示轨道列表的重复片段,允许以更紧凑的形式写入大量显示重复模式的列或行。</li><li>该函数可以用于 CSS Grid 属性中 grid-template-columns 和 grid-template-rows。<figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* repeat(4, 1fr) */</span></span><br><span class="line"><span class="comment">/* 设置四列,每列均分 */</span></span><br><span class="line"><span class="selector-class">.grid-container</span> {</span><br><span class="line"> <span class="attribute">grid-template-columns</span>: <span class="built_in">repeat</span>(<span class="number">4</span>, <span class="number">1</span>fr);</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li></ul></li><li>fr<ul><li>一种新的长度单位 fr(fraction)。它表示 Grid 布局中中剩余空间(leftover space)的一部分(fraction)。</li><li>一般来说 1fr 的意思是“100%的剩余空间”, .25fr 意味着“25%的剩余空间”。当时当 fr 大于 1 的时候,则会重新计算比例来分配</li><li>一般都建议使用 fr>=1 的情况, 比如说 1fr 2fr 就比 .33fr .67fr 可读性更强。</li></ul></li></ul>]]></content>
<summary type="html"><h6 id="什么是grid布局?"><a href="#什么是grid布局?" class="headerlink" title="什么是grid布局?"></a>什么是grid布局?</h6><h6 id="怎么实现grid布局?"><a href="#怎么实现grid布局?" class="headerlink" title="怎么实现grid布局?"></a>怎么实现grid布局?</h6><h6 id="grid布局的好处"><a href="#grid布局的好处" class="headerlink" title="grid布局的好处"></a>grid布局的好处</h6><h6 id="grid布局中一些常用设置说明"><a href="#grid布局中一些常用设置说明" class="headerlink" title="grid布局中一些常用设置说明"></a>grid布局中一些常用设置说明</h6><ul>
<li>grid-row: grid-row-start / grid-row-end;<ul>
<li>grid-row-start 指定在哪一行开始显示网格元素。</li>
<li>grid-row-end 指定停止显示网格元素的行,或要跨越多少行。</li>
</ul>
</li>
</ul></summary>
</entry>
</feed>