-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathatom.xml
433 lines (351 loc) · 141 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
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>wah's life</title>
<subtitle>西斗门路前端手艺人</subtitle>
<link href="/atom.xml" rel="self"/>
<link href="http://shiwah.me/"/>
<updated>2017-11-29T06:58:38.000Z</updated>
<id>http://shiwah.me/</id>
<author>
<name>石华</name>
</author>
<generator uri="http://hexo.io/">Hexo</generator>
<entry>
<title>使用execCommand将文字样式设置成css样式的办法</title>
<link href="http://shiwah.me/2017/11/29/20171129_contentEditable/"/>
<id>http://shiwah.me/2017/11/29/20171129_contentEditable/</id>
<published>2017-11-29T07:00:00.000Z</published>
<updated>2017-11-29T06:58:38.000Z</updated>
<content type="html"><![CDATA[<p>我们在使用<code>contenteditable</code>属性做富文本编辑器时经常会用到<code>document.execCommand</code>方法来处理文字的样式。但当我们要设置比如<code>font-size</code>,会发现这个命令只支持(1-7)这几种字体大小值,而不是我们想要的类似css样式的值<a href="https://developer.mozilla.org/zh-CN/docs/Web/API/Document/execCommand" target="_blank" rel="external">详细文档</a>。有此类问题的样式还包括行高、颜色等到。但实际上我们的需求可能是将其设置成css样式,那就可以使用下面的方法来实现。</p>
<a id="more"></a>
<p>以设置字体大小为例:</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div></pre></td><td class="code"><pre><div class="line"><span class="comment">// 先将文字的样式改用CSS样式展示</span></div><div class="line"><span class="built_in">document</span>.execCommand(<span class="string">'styleWithCSS'</span>, <span class="literal">null</span>, <span class="literal">true</span>);</div><div class="line"><span class="comment">// 先将文字大小设置成1-7号中的任何一个大小</span></div><div class="line"><span class="built_in">document</span>.execCommand(<span class="string">'fontSize'</span>, <span class="literal">false</span>, <span class="number">1</span>);</div><div class="line"><span class="comment">// 这时候浏览器会默认将文字包裹一层span,然后css设置在span上,然后我们再去寻找这个span,将其css修改成我们实际想要的字体大小</span></div><div class="line"><span class="keyword">let</span> $parent = <span class="built_in">document</span>.querySelector(<span class="string">'正在编辑的元素的父容器'</span>);</div><div class="line"><span class="keyword">let</span> $spans = $parent.querySelectorAll(<span class="string">'span'</span>);</div><div class="line"><span class="keyword">let</span> value = <span class="string">'48px'</span>; <span class="comment">// 假设我们要将字体大小设置成48px</span></div><div class="line">$spans.forEach(<span class="function">(<span class="params">$span</span>) =></span> {</div><div class="line"> <span class="keyword">let</span> fontSize = $span.style.fontSize;</div><div class="line"> <span class="keyword">if</span> (<span class="string">'x-small'</span> == fs) {</div><div class="line"> $span.style.fontSize = value;</div><div class="line"> }</div><div class="line">});</div></pre></td></tr></table></figure>
<p>其它样式调整也可以用该方法找到对应的span后修改<code>style</code>值实现,只是最后要把<code>font-size='x-small'</code>的样式清空。</p>
]]></content>
<summary type="html">
<p>我们在使用<code>contenteditable</code>属性做富文本编辑器时经常会用到<code>document.execCommand</code>方法来处理文字的样式。但当我们要设置比如<code>font-size</code>,会发现这个命令只支持(1-7)这几种字体大小值,而不是我们想要的类似css样式的值<a href="https://developer.mozilla.org/zh-CN/docs/Web/API/Document/execCommand" target="_blank" rel="external">详细文档</a>。有此类问题的样式还包括行高、颜色等到。但实际上我们的需求可能是将其设置成css样式,那就可以使用下面的方法来实现。</p>
</summary>
</entry>
<entry>
<title>获取TouchEvent准确的Target</title>
<link href="http://shiwah.me/2017/08/24/20170824_eventTarget/"/>
<id>http://shiwah.me/2017/08/24/20170824_eventTarget/</id>
<published>2017-08-24T14:00:00.000Z</published>
<updated>2017-08-24T13:57:22.000Z</updated>
<content type="html"><![CDATA[<p>细心朋友可能已经发现了,我们在处理<code>touchmove</code>、<code>touchend</code>事件时,通过<code>event.target</code>属性获取的永远等于<code>touchstart</code>起始触发的元素。<br>也就是说当我们从A元素开始触屏,即使我们现在划到B元素上,<code>event.target</code>返回的还是A。<br>这个表现与<code>mousemove</code>事件的表现不一致。<br>可以通过下列方法获得事件真实的target。</p>
<a id="more"></a>
<h2 id="document-elementFromPoint"><a href="#document-elementFromPoint" class="headerlink" title="document.elementFromPoint"></a>document.elementFromPoint</h2><p>首先可以获取事件触发时的坐标点,通过<code>document.elementFromPoint</code>方法获取当前点对应的元素</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">let</span> params = {<span class="attr">clientX</span>: <span class="number">0</span>, <span class="attr">clientX</span>: <span class="number">0</span>};</div><div class="line"><span class="keyword">let</span> clientX = e.touches[<span class="number">0</span>].clientX;</div><div class="line"><span class="keyword">let</span> clientY = e.touches[<span class="number">0</span>].clientY;</div><div class="line">params = {clientX, clientY};</div><div class="line"><span class="keyword">let</span> $target = <span class="built_in">document</span>.elementFromPoint(params.clientX, params.clientY);</div></pre></td></tr></table></figure>
<h2 id="判断元素的子孙关系(parentNode、childNodes、isEqualNode)"><a href="#判断元素的子孙关系(parentNode、childNodes、isEqualNode)" class="headerlink" title="判断元素的子孙关系(parentNode、childNodes、isEqualNode)"></a>判断元素的子孙关系(parentNode、childNodes、isEqualNode)</h2><p>上述方法获取元素会带来一个问题。<br>比如:页面元素的从属关系是A->B->C,当我们点击B元素的子元素C,我们获得的target是C。<br>那就可以遍历检测A与C的子孙关系,进一步获得我们更关心A元素和B元素的关系。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">let</span> el = <span class="string">'父元素A'</span></div><div class="line"><span class="keyword">let</span> index = <span class="number">-1</span>; <span class="comment">// B元素相对于A元素的索引</span></div><div class="line"><span class="keyword">let</span> aTargetEl = [];</div><div class="line"><span class="comment">// 遍历获取target元素在dom树中的路径</span></div><div class="line"><span class="keyword">while</span> ($target.tagName.toLowerCase() != <span class="string">'body'</span>) {</div><div class="line"> aTargetEl.push($target);</div><div class="line"> $target = $target.parentNode;</div><div class="line">}</div><div class="line"><span class="keyword">for</span> (<span class="keyword">let</span> idx = <span class="number">0</span>, len = el.childNodes.length; idx < len; idx++) {</div><div class="line"> <span class="keyword">let</span> child = el.childNodes[idx];</div><div class="line"> <span class="comment">// 遍历A的子元素判断是否处于target元素的dom树路径中</span></div><div class="line"> <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>, l = aTargetEl.length; i < l; i++) {</div><div class="line"> <span class="keyword">let</span> oEl = aTargetEl[i];</div><div class="line"> <span class="keyword">if</span> (child.isEqualNode(oEl)) {</div><div class="line"> index = idx;</div><div class="line"> <span class="keyword">break</span>;</div><div class="line"> }</div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure>
]]></content>
<summary type="html">
<p>细心朋友可能已经发现了,我们在处理<code>touchmove</code>、<code>touchend</code>事件时,通过<code>event.target</code>属性获取的永远等于<code>touchstart</code>起始触发的元素。<br>也就是说当我们从A元素开始触屏,即使我们现在划到B元素上,<code>event.target</code>返回的还是A。<br>这个表现与<code>mousemove</code>事件的表现不一致。<br>可以通过下列方法获得事件真实的target。</p>
</summary>
</entry>
<entry>
<title>javascript拾遗</title>
<link href="http://shiwah.me/2017/08/09/20170809_oldthings/"/>
<id>http://shiwah.me/2017/08/09/20170809_oldthings/</id>
<published>2017-08-09T14:00:00.000Z</published>
<updated>2017-08-09T14:04:02.000Z</updated>
<content type="html"><![CDATA[<p>将过去零零散散的问题收集记录于此</p>
<a id="more"></a>
<h2 id="复制引用类型数据"><a href="#复制引用类型数据" class="headerlink" title="复制引用类型数据"></a>复制引用类型数据</h2><p>经常会遇到需要复制一个array或者object的需求。<br>如果是简单粗暴的 a = b 这样复制那就可能出问题了,你会发现当b中数据发生变化时, a的数据竟然也改变了,这也许并不是你想见到的结果,因为 a = b 这样对引用类型赋值时,a实际上等于b对象的一个内存地址,也就是说,访问a时实际上访问的是b。<br>正确复制引用类型的方法如下:</p>
<ol>
<li><p>复制array</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line"><span class="comment">// 方法一 简单粗暴循环生成新数组</span></div><div class="line"><span class="keyword">var</span> arr = [];</div><div class="line"><span class="keyword">for</span> (<span class="keyword">var</span> i = <span class="number">0</span>; i < aUser.length; i++) {</div><div class="line"> arr.push(aUser[i]);</div><div class="line">}</div><div class="line"><span class="comment">// 方法二 用concat</span></div><div class="line"><span class="keyword">var</span> arr = aUser.concat()</div></pre></td></tr></table></figure>
</li>
<li><p>复制object<br>当object中存的数据为基本数据类型时,可以使用浅拷贝。反之,如果object中有很多层数据时,若使用浅拷贝会发现其子层还是会遇到之前发生的问题</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line"><span class="comment">// 循环复制</span></div><div class="line"><span class="keyword">var</span> obj = [];</div><div class="line"><span class="keyword">for</span> (<span class="keyword">var</span> key <span class="keyword">in</span> oUserData) {</div><div class="line"> obj[key] = oUserData[key];</div><div class="line">}</div><div class="line"></div><div class="line"><span class="comment">// 深拷贝就是要拓展一个递归的方法,去一层一层遍历,当子层数据类型为object时递归遍历下一次,直至最后一层。网上很多代码的。不贴了……</span></div></pre></td></tr></table></figure>
</li>
</ol>
<h2 id="在iframe子窗口调用父级窗口方法"><a href="#在iframe子窗口调用父级窗口方法" class="headerlink" title="在iframe子窗口调用父级窗口方法"></a>在iframe子窗口调用父级窗口方法</h2><p>iframe子窗口调用父级窗口方法分为两种情况,跨越及同域调用</p>
<!-- more -->
<h2 id="iframe子窗口调用父级窗口"><a href="#iframe子窗口调用父级窗口" class="headerlink" title="iframe子窗口调用父级窗口"></a>iframe子窗口调用父级窗口</h2><p>假设父级窗口index.html中有一个<code>closeModal</code>方法,和一个iframe,我们想在iframe中调用这个方法。</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line"><span class="comment"><!-- index.html --></span></div><div class="line"><span class="tag"><<span class="name">iframe</span> <span class="attr">id</span>=<span class="string">"ifr"</span> <span class="attr">src</span>=<span class="string">""</span>></span><span class="tag"></<span class="name">iframe</span>></span></div><div class="line"><span class="tag"><<span class="name">script</span> <span class="attr">type</span>=<span class="string">"text/javascript"</span>></span><span class="javascript"></span></div><div class="line"> <span class="function"><span class="keyword">function</span> <span class="title">closeModal</span>(<span class="params"></span>) </span>{</div><div class="line"> <span class="comment">// todo</span></div><div class="line"> }</div><div class="line"><span class="tag"></<span class="name">script</span>></span></div></pre></td></tr></table></figure>
<p>当iframe打开的页面与父窗口在同一个域名下时,我们通过window.parent拿到父窗口的window句柄,从而调用到父窗口window句柄下的方法<br><figure class="highlight html"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line"><span class="comment"><!-- iframe content --></span></div><div class="line"><span class="tag"><<span class="name">script</span> <span class="attr">type</span>=<span class="string">"text/javascript"</span>></span><span class="javascript"></span></div><div class="line"> <span class="built_in">window</span>.parent.closeModal();</div><div class="line"><span class="tag"></<span class="name">script</span>></span></div></pre></td></tr></table></figure></p>
<p>由于js对跨域权限做了限制,当iframe打开的是另一个域名下的地址时,我们可以通过下面这种方法“巧妙”的调用到父窗口下的方法——在iframe中再嵌入一层子iframe用于打开一个与父级同域名的页面,由于这个子iframe与父级同域,因此可以通过他调用我们需要的方法<br><figure class="highlight html"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line"><span class="comment"><!-- iframe content --></span></div><div class="line"><span class="tag"><<span class="name">iframe</span> <span class="attr">id</span>=<span class="string">"child"</span> <span class="attr">src</span>=<span class="string">""</span>></span><span class="tag"></<span class="name">iframe</span>></span></div></pre></td></tr></table></figure></p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line"><span class="comment"><!-- child content --></span></div><div class="line"><span class="tag"><<span class="name">script</span> <span class="attr">type</span>=<span class="string">"text/javascript"</span>></span><span class="javascript"></span></div><div class="line"> <span class="built_in">window</span>.parent.parent.closeModal();</div><div class="line"><span class="tag"></<span class="name">script</span>></span></div></pre></td></tr></table></figure>
<p>上述方法非常的“投机”,那么下面这种方法则可以说是名门正派了。</p>
<p>##HTML5中的postMessage<br>HTML5提供了新的通信api——<code>postMessage</code>,可以允许父容器与子容器间进行通信<br>那么实现的过程就如下:</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div></pre></td><td class="code"><pre><div class="line"><span class="comment"><!-- index.html --></span></div><div class="line"><span class="tag"><<span class="name">iframe</span> <span class="attr">id</span>=<span class="string">"ifr"</span> <span class="attr">src</span>=<span class="string">""</span>></span><span class="tag"></<span class="name">iframe</span>></span></div><div class="line"><span class="tag"><<span class="name">script</span> <span class="attr">type</span>=<span class="string">"text/javascript"</span>></span><span class="javascript"></span></div><div class="line"> <span class="function"><span class="keyword">function</span> <span class="title">closeModal</span>(<span class="params"></span>) </span>{</div><div class="line"> <span class="comment">// todo</span></div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="built_in">window</span>.addEventListener(<span class="string">'message'</span>, <span class="function"><span class="keyword">function</span>(<span class="params">e</span>)</span>{</div><div class="line"> <span class="string">'closeModal'</span> == e.data && closeModal();</div><div class="line"> },<span class="literal">false</span>);</div><div class="line"><span class="tag"></<span class="name">script</span>></span></div></pre></td></tr></table></figure>
<p>iframe中通过postMessage向父窗口发消息<br><figure class="highlight html"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div></pre></td><td class="code"><pre><div class="line"><span class="comment"><!-- iframe.html --></span></div><div class="line"><span class="tag"><<span class="name">script</span> <span class="attr">type</span>=<span class="string">"text/javascript"</span>></span><span class="javascript"></span></div><div class="line"> parent.postMessage(<span class="string">'closeModal'</span>, <span class="string">'*'</span>);</div><div class="line"> <span class="comment">/*</span></div><div class="line"> postMessage(data, origin);</div><div class="line"> 参数:data 消息内容</div><div class="line"> origin 发送消息窗口的源(协议+主机+端口号)</div><div class="line"> */</div><div class="line"><span class="tag"></<span class="name">script</span>></span></div></pre></td></tr></table></figure></p>
<h2 id="prototype-function与this-function的区别"><a href="#prototype-function与this-function的区别" class="headerlink" title="prototype.function与this.function的区别"></a>prototype.function与this.function的区别</h2><p>prototype.function与this.function都可以定义对象的方法,那二者有何区别呢?<br><!-- more --></p>
<h2 id="初步分析"><a href="#初步分析" class="headerlink" title="初步分析"></a>初步分析</h2><p>先用一段代码来说明二者的区别:</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">var</span> actor = <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>{</div><div class="line"> <span class="keyword">var</span> param = <span class="number">1</span>;</div><div class="line"> <span class="keyword">this</span>.act = <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>{</div><div class="line"> <span class="keyword">return</span> param;</div><div class="line"> }</div><div class="line">};</div><div class="line">actor.prototype.play = <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>{</div><div class="line"> <span class="keyword">return</span> <span class="keyword">typeof</span> param;</div><div class="line">};</div><div class="line"><span class="keyword">var</span> man1 = <span class="keyword">new</span> actor();</div><div class="line"><span class="keyword">var</span> man2 = <span class="keyword">new</span> actor();</div><div class="line"><span class="built_in">console</span>.log(man1.act === man2.act); <span class="comment">// false</span></div><div class="line"><span class="built_in">console</span>.log(man1.play === man2.play); <span class="comment">// true</span></div><div class="line"></div><div class="line"><span class="built_in">console</span>.log(man1.act()); <span class="comment">// 1</span></div><div class="line"><span class="built_in">console</span>.log(man1.play()); <span class="comment">// undefined</span></div></pre></td></tr></table></figure>
<h2 id="简单工厂模式"><a href="#简单工厂模式" class="headerlink" title="简单工厂模式"></a>简单工厂模式</h2><p><code>简单工厂模式(Simple Factory)又叫静态工厂方法,由一个工厂对象决定创建某种产品对象类的实例。</code><br>以我的理解,这种设计模式的目的是:统一几个对象的创建入口,这样就可以抽取这几个对象创建时的共性(共用代码),同时可以由该工厂方法决定具体创建那个对象。</p>
<p>比如屏幕中有modal和pop两种弹出窗体,他们在打开前都需要获取window的width和height属性,那么我们可以通过一个openWin方法实现对两者的调用。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">var</span> modal = <span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>{}</div><div class="line"><span class="keyword">var</span> pop = <span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>{}</div><div class="line"><span class="keyword">var</span> openWin = <span class="function"><span class="keyword">function</span>(<span class="params">mode</span>) </span>{</div><div class="line"> <span class="keyword">var</span> width = <span class="built_in">window</span>.width;</div><div class="line"> <span class="keyword">var</span> height = <span class="built_in">window</span>.height;</div><div class="line"> <span class="keyword">if</span> (<span class="string">'modal'</span> == mode) {</div><div class="line"> <span class="keyword">new</span> model(width, height);</div><div class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (<span class="string">'pop'</span> == mode) {</div><div class="line"> <span class="keyword">new</span> pop(width, height);</div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure>
<h2 id="工厂方法模式"><a href="#工厂方法模式" class="headerlink" title="工厂方法模式"></a>工厂方法模式</h2><p>在上述的模式中有这样一个小缺陷,比方说当系统中新增了一个类dialog,此时我们不仅需要写dialog相关的构造放,还需要在openWin中的判断多加一条,这样静态的方法似乎显得不是很灵活。</p>
<p>而工厂方法模式比之前的简单工厂模式进一步的抽取了共性,不仅是通过一个方法的调用获得两种对象(统一入口),而且要实现两种对象可以通过同一个类(即工厂类)new出来。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">var</span> Factory = <span class="function"><span class="keyword">function</span>(<span class="params">type, content</span>) </span>{</div><div class="line"> <span class="comment">// 先判断this是否指向Factory</span></div><div class="line"> <span class="keyword">if</span> (<span class="keyword">this</span> <span class="keyword">instanceof</span> Factory) {</div><div class="line"> <span class="keyword">var</span> s = <span class="keyword">new</span> <span class="keyword">this</span>[type](content);</div><div class="line"> <span class="keyword">return</span> s;</div><div class="line"> } <span class="keyword">else</span> {</div><div class="line"> <span class="keyword">return</span> <span class="keyword">new</span> Factory(type, content);</div><div class="line"> }</div><div class="line">}</div><div class="line">Factory.prototype = {</div><div class="line"> <span class="string">'modal'</span>: <span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>{}</div><div class="line">, <span class="string">'pop'</span>: <span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>{}</div><div class="line">, <span class="string">'dialog'</span>: <span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>{}</div><div class="line">}</div></pre></td></tr></table></figure>
<h2 id="抽象工厂模式"><a href="#抽象工厂模式" class="headerlink" title="抽象工厂模式"></a>抽象工厂模式</h2><p><code>抽象工厂模式</code>通过对类的工厂抽象使其业务用于产品类簇的创建,而不负责创建某一类产品的实例。<br>比如在上面的工厂方法中,modal类还分为smallModal和bigModal两种子类,他们都有一个共同的属性type,那我们再把他们的共性抽取出来,作为一个抽象类,不用于实现。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div></pre></td><td class="code"><pre><div class="line"><span class="comment">// 抽象工厂方法</span></div><div class="line"><span class="keyword">var</span> WinFactory = <span class="function"><span class="keyword">function</span>(<span class="params">subType, superType</span>) </span>{</div><div class="line"> <span class="comment">// 判断抽象工厂中是否有该抽象类</span></div><div class="line"> <span class="keyword">if</span> (<span class="keyword">typeof</span> WinFactory[superType] === <span class="string">'function'</span>) {</div><div class="line"> <span class="comment">// 缓存类</span></div><div class="line"> <span class="function"><span class="keyword">function</span> <span class="title">F</span>(<span class="params"></span>)</span>{};</div><div class="line"> <span class="comment">// 继承父类的属性和方法</span></div><div class="line"> F.prototype = <span class="keyword">new</span> WinFactory[superType]();</div><div class="line"> <span class="comment">// 将子类的构造器指向子类</span></div><div class="line"> subType.constructor = subType;</div><div class="line"> <span class="comment">// 子类原型继承『父类』</span></div><div class="line"> subType.prototype = <span class="keyword">new</span> F();</div><div class="line"> } <span class="keyword">else</span> {</div><div class="line"> <span class="comment">// 不存在该抽象类</span></div><div class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> <span class="built_in">Error</span>(<span class="string">'未创建该抽象类'</span>);</div><div class="line"> }</div><div class="line">}</div><div class="line">WinFactory.modal = <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>{</div><div class="line"> <span class="keyword">this</span>.type = <span class="string">'modal'</span>;</div><div class="line">}</div><div class="line">WinFactory.modal.prototype = {</div><div class="line"> <span class="attr">show</span>: <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>{</div><div class="line"> <span class="keyword">return</span> <span class="keyword">new</span> <span class="built_in">Error</span>(<span class="string">'抽象方法不能调用'</span>);</div><div class="line"> }</div><div class="line">}</div><div class="line"></div><div class="line"><span class="comment">// 生成一个smallModal子类</span></div><div class="line"><span class="keyword">var</span> smallModal = <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>{</div><div class="line">} </div><div class="line">WinFactory(smallModal, <span class="string">'modal'</span>);</div><div class="line">smallModal.prototype.show = <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>{</div><div class="line"> <span class="keyword">return</span> <span class="string">'show'</span>;</div><div class="line">}</div><div class="line"><span class="keyword">var</span> modal = <span class="keyword">new</span> smallModal();</div><div class="line"><span class="built_in">console</span>.log(modal.show());</div><div class="line"><span class="built_in">console</span>.log(modal.type);</div></pre></td></tr></table></figure>]]></content>
<summary type="html">
<p>将过去零零散散的问题收集记录于此</p>
</summary>
</entry>
<entry>
<title>MessagePack在浏览器端的应用</title>
<link href="http://shiwah.me/2017/08/09/20170809_msgpack/"/>
<id>http://shiwah.me/2017/08/09/20170809_msgpack/</id>
<published>2017-08-09T14:00:00.000Z</published>
<updated>2017-08-09T14:48:08.000Z</updated>
<content type="html"><![CDATA[<a id="more"></a>
<h2 id="简介"><a href="#简介" class="headerlink" title="简介"></a>简介</h2><p>MessagePack是一种高效的2进制序列化数据格式,你可以在不同的语言环境中使用它来进行数据通信(如PHP -> js, cpp -> js, lua -> js 等),就像使用JSON数据格式一样,但它比同级别的json数据要小,传输和解析速度也更快。因此有很多开发者考虑用它来替代JSON作为数据传输的解决方案。<br>目前市面上绝大多数流行的开发语言都有了支持msgpack的类库。js也不例外,但是能在浏览器环境下跑的不是特别多,主要原因我觉得是:<br>1.只有大多数新的浏览器才支持对2进制数据直接进行访问控制,因此兼容性大打折扣<br>2.json数据对前端太友好了,数据无痛读取,没有兼容性问题,何苦自废武功寻求这种「另类」的解决方案。</p>
<p>如果必须使用的话,目前官方推荐的<code>msgpack-lite</code>这个库还是能用的,其自称性能还不错。<br>git地址:<br><code>https://github.com/kawanet/msgpack-lite</code></p>
<h2 id="用法"><a href="#用法" class="headerlink" title="用法"></a>用法</h2><p>用法就超级简单了,<code>msgpack.encode</code>和<code>msgpack.decode</code>一下就可以得到msgpack数据/json数据了。</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div></pre></td><td class="code"><pre><div class="line"></div><div class="line"><span class="comment">// encode from JS Object to MessagePack (Buffer)</span></div><div class="line"><span class="keyword">var</span> buffer = msgpack.encode({<span class="string">"foo"</span>: <span class="string">"bar"</span>});</div><div class="line"></div><div class="line"><span class="comment">// decode from MessagePack (Buffer) to JS Object</span></div><div class="line"><span class="keyword">var</span> data = msgpack.decode(buffer); <span class="comment">// => {"foo": "bar"}</span></div><div class="line"></div><div class="line"><span class="comment">// if encode/decode receives an invalid argument an error is thrown</span></div></pre></td></tr></table></figure>
<p>因为编程语言的差异,如果遇到解析出来本来应该是字符串的字段值是一个<code>Uint8Array</code>,那么可能就需要用TextDecoder再转解析一下:<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line"></div><div class="line"><span class="keyword">var</span> decoder = <span class="keyword">new</span> TextDecoder(<span class="string">'utf-8'</span>);</div><div class="line"></div><div class="line"><span class="comment">// bytes模拟数据表示msgpack.decode后取到的`Uint8Array`</span></div><div class="line"><span class="keyword">var</span> bytes = <span class="keyword">new</span> <span class="built_in">Uint8Array</span>([<span class="number">207</span>, <span class="number">240</span>, <span class="number">232</span>, <span class="number">226</span>, <span class="number">2</span>]);</div><div class="line"></div><div class="line"><span class="keyword">var</span> data = decoder.decode(bytes);</div></pre></td></tr></table></figure></p>
]]></content>
<summary type="html">
<a id="more"></a>
<h2 id="简介"><a href="#简介" class="headerlink" title="简介"></a>简介</h2><p>MessagePack是一种高效的2进制序列化数据格式,你可以在不同的语言环境中使用它来进行数据通信(如
</summary>
</entry>
<entry>
<title>移动端开发玄学研究分析</title>
<link href="http://shiwah.me/2017/06/03/20170603_mobileWeb/"/>
<id>http://shiwah.me/2017/06/03/20170603_mobileWeb/</id>
<published>2017-06-03T06:00:00.000Z</published>
<updated>2017-08-09T14:13:17.000Z</updated>
<content type="html"><![CDATA[<p>移动端领域玄学集合</p>
<a id="more"></a>
<h2 id="滚动不流畅"><a href="#滚动不流畅" class="headerlink" title="滚动不流畅"></a>滚动不流畅</h2><p>在滚动的容器中添加以下属性,在IOS中实现弹性滚动<br><figure class="highlight css"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line"><span class="selector-tag">-webkit-overflow-scrolling</span> : <span class="selector-tag">touch</span>;</div></pre></td></tr></table></figure></p>
<p>如若在滚动事件上的绑定,可以在检测兼容性之后,使用<code>passive</code>事件绑定优化性能。<br>因为在移动端会默认先去执行listener,判断里面是否会阻止默认事件(<code>e.preventDefaut()</code>)。如果没有,才会触发默认事件(如这里说的滚动),所以如果我们的事件绑定不想阻止默认事件的话,可以将<code>passive = true</code>,这样浏览器就会无阻塞的执行默认事件了。<br><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line">XXX.addEventListener(type, listener, {</div><div class="line"> <span class="attr">capture</span>: <span class="literal">false</span>,</div><div class="line"> <span class="attr">passive</span>: <span class="literal">true</span>,</div><div class="line"> <span class="attr">once</span>: <span class="literal">false</span></div><div class="line">})</div></pre></td></tr></table></figure></p>
<h2 id="安卓设备,输入框弹出时,屏幕尺寸发生改变"><a href="#安卓设备,输入框弹出时,屏幕尺寸发生改变" class="headerlink" title="安卓设备,输入框弹出时,屏幕尺寸发生改变"></a>安卓设备,输入框弹出时,屏幕尺寸发生改变</h2><p>这个神坑会带来几个常见的问题:</p>
<ul>
<li><code>background-size: 100% 100%</code>的全屏背景图变形</li>
<li><code>position: fixed</code>的元素漂移,当键盘收起后不会恢复原位</li>
<li><code>position: absolute</code>的根据<code>bottom</code>定位的元素位置不对<br>解决办法:</li>
<li>媒体查询一下或者JS监测一下,当页面高度低于多少时,设一个足够大或者写死的背景高度</li>
<li>移动端尽量不用<code>fixed</code></li>
<li>想要尽量完美就耀用js或者媒体查询了,做一些特殊处理</li>
</ul>
<h2 id="某些版本的IOS设备,内容为纯数字的标签样式异常"><a href="#某些版本的IOS设备,内容为纯数字的标签样式异常" class="headerlink" title="某些版本的IOS设备,内容为纯数字的标签样式异常"></a>某些版本的IOS设备,内容为纯数字的标签样式异常</h2><p>在某些版本的IOS设备中,内容为纯数字的标签会会被浏览器解析成电话号码,表现类似于在原标签外包了一层<a></a>标签。<br>这就有可能会对页面样式造成影响。<br><figure class="highlight html"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line"><span class="tag"><<span class="name">span</span>></span>12345678<span class="tag"></<span class="name">span</span>></span> <span class="comment"><!-- you want it like this --></span></div><div class="line"><span class="tag"><<span class="name">a</span>></span><span class="tag"><<span class="name">span</span>></span>12345678<span class="tag"></<span class="name">span</span>></span><span class="tag"></<span class="name">a</span>></span> <span class="comment"><!-- in fact --></span></div></pre></td></tr></table></figure></p>
<p>解决办法是头部加标签屏蔽该功能<br><figure class="highlight html"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line"><span class="tag"><<span class="name">meta</span> <span class="attr">content</span>=<span class="string">"telephone=no"</span> <span class="attr">name</span>=<span class="string">"format-detection"</span>/></span></div></pre></td></tr></table></figure></p>
<h2 id="IOS9-3的iphone-5s下,微信内置浏览器屏幕宽度获取异常"><a href="#IOS9-3的iphone-5s下,微信内置浏览器屏幕宽度获取异常" class="headerlink" title="IOS9.3的iphone 5s下,微信内置浏览器屏幕宽度获取异常"></a>IOS9.3的iphone 5s下,微信内置浏览器屏幕宽度获取异常</h2><p>在该版本系统下,DOMContentLoaded时,window.innerWidth获取到的屏幕宽度是980。<br>网上的方法是在meta里加上<code>shrink-to-fit=no</code>,然而似乎不起作用。<br><figure class="highlight html"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line"><span class="tag"><<span class="name">meta</span> <span class="attr">name</span>=<span class="string">"viewport"</span> <span class="attr">content</span>=<span class="string">"width=device-width, initial-scale=1.0, user-scalable=no, maximum-scale=1, shrink-to-fit=no"</span>></span></div></pre></td></tr></table></figure></p>
<p>目前还是保险起见的换了方法,用clientWitdh获取<br><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">var</span> wid = <span class="built_in">document</span>.body.clientWidth;</div></pre></td></tr></table></figure></p>
<h2 id="绝对定位叠加的元素错位或不显示"><a href="#绝对定位叠加的元素错位或不显示" class="headerlink" title="绝对定位叠加的元素错位或不显示"></a>绝对定位叠加的元素错位或不显示</h2><p>虽然元素排在后面,但依然会被前面的同班元素元素挡住,这时候加一个<code>z-index</code>明确层级。<br><figure class="highlight css"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line"><span class="selector-class">.ab</span> {</div><div class="line"> <span class="attribute">z-index</span>: <span class="number">1</span>;</div><div class="line">}</div></pre></td></tr></table></figure></p>
<h2 id="自定背景的input光标太长"><a href="#自定背景的input光标太长" class="headerlink" title="自定背景的input光标太长"></a>自定背景的input光标太长</h2><p>需要加上appearance:none这个属性,它的作用是将input默认的属性样式去掉。</p>
<figure class="highlight css"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div></pre></td><td class="code"><pre><div class="line"><span class="selector-class">.input-wrap</span> <span class="selector-tag">input</span> {</div><div class="line"> <span class="attribute">display</span>: block;</div><div class="line"> <span class="attribute">width</span>: <span class="number">5.06rem</span>;</div><div class="line"> <span class="attribute">height</span>: .<span class="number">96rem</span>;</div><div class="line"> <span class="attribute">margin</span>: <span class="number">0</span> auto;</div><div class="line"> <span class="attribute">border</span>: none;</div><div class="line"> <span class="attribute">background</span>: none;</div><div class="line"> <span class="attribute">color</span>: <span class="number">#602f00</span>;</div><div class="line"> <span class="attribute">vertical-align</span>: middle;</div><div class="line"> <span class="attribute">font-size</span>: .<span class="number">48rem</span>;</div><div class="line"> <span class="attribute">-webkit-appearance</span>:none; <span class="comment">/* Safari 和 Chrome */</span></div><div class="line"> <span class="attribute">appearance</span>:none;</div><div class="line">}</div></pre></td></tr></table></figure>
<h2 id="Flex布局"><a href="#Flex布局" class="headerlink" title="Flex布局"></a>Flex布局</h2><p>要在微信端推广的web,现阶段尽量不要用flex布局,要不然800块的安卓及各种老机器会把你教育到怀疑人生。</p>
<h2 id="iphone复制文字时内容错误"><a href="#iphone复制文字时内容错误" class="headerlink" title="iphone复制文字时内容错误"></a>iphone复制文字时内容错误</h2><p>比如以下情况,<code>12345</code>前后的标签都设置了<code>user-select:none</code>,但是长按后调用系统复制,会发现复制到的内容是<code>12345长按复制</code><br><figure class="highlight html"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line"><span class="tag"><<span class="name">div</span>></span></div><div class="line"> <span class="tag"><<span class="name">p</span> <span class="attr">style</span>=<span class="string">"user-select:none"</span>></span>你的抽奖号为:<span class="tag"></<span class="name">p</span>></span></div><div class="line"> <span class="tag"><<span class="name">p</span> <span class="attr">style</span>=<span class="string">"user-select:auto"</span>></span>12345<span class="tag"></<span class="name">p</span>></span></div><div class="line"> <span class="tag"><<span class="name">p</span> <span class="attr">style</span>=<span class="string">"user-select:none"</span>></span>长按复制<span class="tag"></<span class="name">p</span>></span></div><div class="line"><span class="tag"></<span class="name">div</span>></span></div></pre></td></tr></table></figure></p>
<p>最简单粗暴的解决办法就是在不影响布局的情况下调换一下标签顺序。。。<br><figure class="highlight html"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line"><span class="tag"><<span class="name">div</span>></span></div><div class="line"> <span class="tag"><<span class="name">p</span> <span class="attr">style</span>=<span class="string">"user-select:none"</span>></span>你的抽奖号为:<span class="tag"></<span class="name">p</span>></span></div><div class="line"> <span class="tag"><<span class="name">p</span> <span class="attr">style</span>=<span class="string">"user-select:none"</span>></span>长按复制<span class="tag"></<span class="name">p</span>></span></div><div class="line"> <span class="tag"><<span class="name">p</span> <span class="attr">style</span>=<span class="string">"user-select:auto"</span>></span>12345<span class="tag"></<span class="name">p</span>></span></div><div class="line"><span class="tag"></<span class="name">div</span>></span></div></pre></td></tr></table></figure></p>
<h2 id="自动播放音频"><a href="#自动播放音频" class="headerlink" title="自动播放音频"></a>自动播放音频</h2><p>监听页面上某张图片的加载事件<br><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line">img.onload = <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>{</div><div class="line"> audio.play();</div><div class="line">}</div></pre></td></tr></table></figure></p>
<h2 id="判断是否是在移动端-微信中打开"><a href="#判断是否是在移动端-微信中打开" class="headerlink" title="判断是否是在移动端/微信中打开"></a>判断是否是在移动端/微信中打开</h2><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">if</span>(<span class="regexp">/iphone|ios|android|mobile/i</span>.test(navigator.userAgent.toLowerCase())) {</div><div class="line"> <span class="comment">// 在移动端打开</span></div><div class="line">}</div></pre></td></tr></table></figure>
<p>同理,判断页面是否是在微信中打开</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">if</span>(<span class="regexp">/micromessenger/i</span>.test(navigator.userAgent.toLowerCase())) {</div><div class="line"> <span class="comment">// 微信内置浏览器</span></div><div class="line">}</div></pre></td></tr></table></figure>
<h2 id="判断横竖屏"><a href="#判断横竖屏" class="headerlink" title="判断横竖屏"></a>判断横竖屏</h2><p>监听<code>onorientationchange/resize</code>事件来判断屏幕方向发生了改变。<br>然后<br><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div></pre></td><td class="code"><pre><div class="line"><span class="built_in">window</span>.addEventListener(<span class="string">"onorientationchange"</span> <span class="keyword">in</span> <span class="built_in">window</span> ? <span class="string">"orientationchange"</span> : <span class="string">"resize"</span>, <span class="function"><span class="keyword">function</span>(<span class="params">e</span>)</span>{</div><div class="line"> <span class="keyword">if</span> (<span class="built_in">window</span>.orientation == <span class="number">0</span> || <span class="built_in">window</span>.orientation == <span class="number">180</span>) {</div><div class="line"> <span class="comment">// 竖屏</span></div><div class="line"> } <span class="keyword">else</span> {</div><div class="line"> <span class="comment">// 横屏</span></div><div class="line"> }</div><div class="line"> </div><div class="line"> <span class="comment">// 或者根据屏幕宽度</span></div><div class="line"> <span class="keyword">if</span> (<span class="built_in">document</span>.body.clientWidth < <span class="built_in">document</span>.body.clientHeight) {</div><div class="line"> <span class="comment">// 竖屏</span></div><div class="line"> } <span class="keyword">else</span> {</div><div class="line"> <span class="comment">// 横屏</span></div><div class="line"> }</div><div class="line">}, <span class="literal">false</span>);</div></pre></td></tr></table></figure></p>
<h2 id="websocket-cocos2d-js开发的游戏在微信中必须触摸屏幕才能接收到消息"><a href="#websocket-cocos2d-js开发的游戏在微信中必须触摸屏幕才能接收到消息" class="headerlink" title="websocket+cocos2d-js开发的游戏在微信中必须触摸屏幕才能接收到消息"></a>websocket+cocos2d-js开发的游戏在微信中必须触摸屏幕才能接收到消息</h2><p>讲真我还没找到这个玄学的原因,后来我改用<code>EGRET</code>引擎重写了客户端就没有这个现象了,服务端和通信模块一点没变……</p>
<h2 id="video全屏播放"><a href="#video全屏播放" class="headerlink" title="video全屏播放"></a>video全屏播放</h2><p>思路是用一个宽高均为100%的容器<code>.video-wrap</code>来包住<code>video</code>,再让<code>video</code>的高度等于容器的高度,进而实现全屏。</p>
<p>不过这里遇到了2个问题:</p>
<ul>
<li>在ios上,微信会默认调用原生的播放器来全屏播放视频,会出现白色的菜单和进度条,影响全屏的体验。</li>
<li>在安卓上,微信会调用X5引擎底层播放器组件来播放视频,容器的z-index属性对其无效。此时也会出现菜单,而且最后还会无耻的出现“推荐视频”一栏…… 据说如果播放的是qq.com域名下的视频则不会碰到这个问题。</li>
</ul>
<p>在ios中,我们用<code>webkit-playsinline</code>可以让webview使用H5的video直接播放,而不再出现菜单和进度条。</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line"><span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"video-wrap"</span>></span></div><div class="line"> <span class="tag"><<span class="name">video</span> <span class="attr">id</span>=<span class="string">"video"</span> <span class="attr">height</span>=<span class="string">"100%"</span> <span class="attr">x-webkit-airplay</span>=<span class="string">"true"</span> <span class="attr">webkit-playsinline</span>=<span class="string">"true"</span> <span class="attr">preload</span>=<span class="string">"auto"</span>></span></div><div class="line"> <span class="tag"><<span class="name">source</span> <span class="attr">src</span>=<span class="string">"res/video.mp4"</span>></span></div><div class="line"> <span class="tag"></<span class="name">video</span>></span></div><div class="line"><span class="tag"></<span class="name">div</span>></span></div></pre></td></tr></table></figure>
<figure class="highlight css"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div></pre></td><td class="code"><pre><div class="line"><span class="selector-class">.video-wrap</span> {</div><div class="line"> <span class="attribute">position</span>: absolute;</div><div class="line"> <span class="attribute">z-index</span>: <span class="number">2</span>;</div><div class="line"> <span class="attribute">width</span>: <span class="number">100%</span>;</div><div class="line"> <span class="attribute">height</span>: <span class="number">100%</span>;</div><div class="line"> <span class="attribute">background</span>: <span class="built_in">url</span>(../images/p2/bg.jpg);</div><div class="line"> <span class="attribute">background-size</span>: cover;</div><div class="line"> <span class="comment">/*display: none;*/</span></div><div class="line">}</div><div class="line"><span class="selector-tag">video</span> { <span class="attribute">font-size</span>: <span class="number">100%</span>; <span class="attribute">line-height</span>: <span class="number">0</span>; <span class="attribute">vertical-align</span>: baseline; <span class="attribute">-webkit-user-select</span>: none; <span class="attribute">-moz-user-select</span>: none; <span class="attribute">-ms-user-select</span>: none; <span class="attribute">user-select</span>: none; <span class="attribute">outline</span>: none; }</div></pre></td></tr></table></figure>
<h2 id="自动(定时)播放视频"><a href="#自动(定时)播放视频" class="headerlink" title="自动(定时)播放视频"></a>自动(定时)播放视频</h2><p>在ios下,我们可以直接调用<code>video</code>的play方法实现视频的播放</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line">setTimeout(<span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>{</div><div class="line"> <span class="comment">// 原生</span></div><div class="line"> <span class="built_in">document</span>.querySelector(<span class="string">'#video'</span>).play();</div><div class="line"> <span class="comment">// jQuery</span></div><div class="line"> $(<span class="string">'video'</span>)[<span class="number">0</span>].play();</div><div class="line">}, <span class="number">1000</span>);</div></pre></td></tr></table></figure>
<p>但在安卓下,由于X5内核绑架了<code>video</code>标签,而且要求视频首次播放时,必须是由用户亲自点击事件触发的才能播放,所以setTimeout不能调用play方法,并且也不能用js去触发click事件……<a href="http://x5.tencent.com/guide?id=2009" target="_blank" rel="external">X5内核视频播放官方问题集</a><br>解决的办法:<br>A.改成用户点击某个按钮后开始播放。<br>B.在游戏开始按钮时,先播放视频然后马上暂停,等到正式要播放视频时,就可以实现跟ios一样的调用方法了。</p>
<h2 id="监听视频播放完毕"><a href="#监听视频播放完毕" class="headerlink" title="监听视频播放完毕"></a>监听视频播放完毕</h2><p>当视频播放完毕后我们希望它能自动隐藏掉并跳到其他界面。<br>video提供了一个视频播放完毕后的事件<code>ended</code><br><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line"><span class="built_in">document</span>.querySelector(<span class="string">'#video'</span>).addEventListener(<span class="string">'ended'</span>, <span class="function"><span class="keyword">function</span>(<span class="params">evt</span>) </span>{</div><div class="line"> <span class="built_in">document</span>.querySelector(<span class="string">'.video-wrap'</span>).innerHTML(<span class="string">''</span>);</div><div class="line">});</div></pre></td></tr></table></figure></p>
]]></content>
<summary type="html">
<p>移动端领域玄学集合</p>
</summary>
</entry>
<entry>
<title>DOM元素的尺寸和位置</title>
<link href="http://shiwah.me/2017/03/19/20170319_domSizePos/"/>
<id>http://shiwah.me/2017/03/19/20170319_domSizePos/</id>
<published>2017-03-19T10:00:00.000Z</published>
<updated>2017-06-05T09:45:20.000Z</updated>
<content type="html"><![CDATA[<p><code>box-sizing</code> 、<code>offsetWidth</code>、<code>clientWidth</code>、<code>clientLeft</code><br><a id="more"></a></p>
<h2 id="DOM元素的尺寸"><a href="#DOM元素的尺寸" class="headerlink" title="DOM元素的尺寸"></a>DOM元素的尺寸</h2><h3 id="box-sizing对属性的影响"><a href="#box-sizing对属性的影响" class="headerlink" title="box-sizing对属性的影响"></a>box-sizing对属性的影响</h3><p>box-sizing的属性值会直接影响盒模型的尺寸计算。一般常用的box-sizing值有几个:</p>
<blockquote>
<p><code>content-box</code>: (默认值)标准盒模型。width = 内容的宽度,height = 内容的高度。宽度和高度都不包含内容的边框(border)和内边距(padding)<br><code>border-box</code>:width 和 height 属性包括内容,填充和边框,但不包括边距。<br><code>padding-box</code>: 只有火狐支持了,不展开研究</p>
</blockquote>
<p>以下面的代码为例。</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line"><span class="tag"><<span class="name">div</span> <span class="attr">id</span>=<span class="string">"boderBox"</span> <span class="attr">style</span>=<span class="string">"width: 200px;height: 100px;box-sizing: border-box;border: 5px solid #123456; margin: 20px 10px; padding: 7px;"</span>></span><span class="tag"></<span class="name">div</span>></span></div><div class="line"><span class="tag"><<span class="name">div</span> <span class="attr">id</span>=<span class="string">"contentBox"</span> <span class="attr">style</span>=<span class="string">"width: 200px;height: 100px;box-sizing: content-box;border: 5px solid #654321; margin: 20px 10px; padding: 7px;"</span>></span><span class="tag"></<span class="name">div</span>></span></div></pre></td></tr></table></figure>
<figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line">$boderBox = <span class="built_in">document</span>.querySelector(<span class="string">'#boderBox'</span>);</div><div class="line">$contentBox = <span class="built_in">document</span>.querySelector(<span class="string">'#contentBox'</span>);</div><div class="line"><span class="built_in">console</span>.info(<span class="string">'offsetWidth'</span>, $boderBox.offsetWidth); <span class="comment">// 200</span></div><div class="line"><span class="built_in">console</span>.info(<span class="string">'offsetWidth'</span>, $contentBox.offsetWidth); <span class="comment">// 224</span></div></pre></td></tr></table></figure>
<p>可见<code>border-box</code>和<code>content-box</code>获取到的offsetWidth值是不同的。<code>content-box</code>的<br>计算方法:<br><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">offsetWidth = <span class="number">200</span>(内容宽度) + <span class="number">5</span> * <span class="number">2</span>(左右border宽度) + <span class="number">7</span> * <span class="number">2</span> (左右padding值)</div></pre></td></tr></table></figure></p>
<p>###不同属性值的含义</p>
<p>再来看看不同属性值所指代的含义:</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div></pre></td><td class="code"><pre><div class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">id</span>=<span class="string">"contentBox"</span> <span class="attr">style</span>=<span class="string">"width: 200px;height: 100px;box-sizing: content-box;border: 5px solid #654321; margin: 20px 10px; padding: 7px;"</span>></span></div><div class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">style</span>=<span class="string">"width: 250px;height: 50px;background: green"</span>></span>aaa<span class="tag"></<span class="name">div</span>></span></div><div class="line"> <span class="tag"></<span class="name">div</span>></span></div><div class="line"></div><div class="line">```js</div><div class="line"> $contentBox = document.querySelector('#contentBox');</div><div class="line"></div><div class="line"> console.info('offsetWidth', '200(不含溢出的内容width)+ 7 * 2(内边距) + 5 * 2(边框)', $contentBox.offsetWidth); // 224</div><div class="line"></div><div class="line"> console.info('clientWidth', '200(不含溢出的内容width)+ 7 * 2 (内边距)- 滚动条宽度(if overflow-y == "scroll")', $contentBox.clientWidth); // 214</div><div class="line"> </div><div class="line"> console.info('scrollWidth', '250(内容实际宽度) + 7(内边距)', $contentBox.scrollWidth); // 257</div></pre></td></tr></table></figure>
<p>这里需要注意,当父容器加上<code>overflow-y: scroll</code>属性后,clientwidth会再减去15px的滚动条宽度(因不同系统不同浏览器而异)。同理<code>overflow-x: scroll</code>后高度也会减去15px(因不同系统不同浏览器而异)。</p>
<p>因此这三种属性可以理解为:</p>
<blockquote>
<p><code>offsetWidth</code>: 元素在页面布局中实际所占的宽度<br><code>clientWidth</code>: 元素边框内部可视区域(不含溢出部分)的宽度<br><code>scrollWidth</code>: 元素内容实际宽度(含溢出)</p>
</blockquote>
<h2 id="元素的位置"><a href="#元素的位置" class="headerlink" title="元素的位置"></a>元素的位置</h2><p>一般主要使用三个属性值: </p>
<blockquote>
<p><code>offsetLeft</code>: 元素外框相对于offsetParent的位置(父容器的offsetLeft为起点)<br><code>clientLeft</code>: 元素内框(border内)对于外框的宽度,即边框border的宽度<br><code>scrollLeft</code>: 元素滚动到的位置</p>
</blockquote>
<p>so一般使用<code>offsetLeft</code>和<code>offsetTop</code>获取元素的位置。<br>需要注意,当元素父容器有css定位时(position),offsetParent返回一个指向最近的(closest,指包含层级上的最近)包含该元素的定位元素。如果没有定位的元素,则 offsetParent 为最近的 table 元素对象或根元素(标准模式下为 html;quirks 模式下为 body)。当元素的 style.display 设置为 “none” 时,offsetParent 返回 null。offsetParent 很有用,因为 offsetTop 和 offsetLeft 都是相对于其内边距边界的。</p>
<h3 id="getBoundingClientRect"><a href="#getBoundingClientRect" class="headerlink" title="getBoundingClientRect"></a>getBoundingClientRect</h3><p>可用于返回改元素相对于视口的位置。</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div></pre></td><td class="code"><pre><div class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"demo"</span> <span class="attr">style</span>=<span class="string">"position: absolute;left: 70px;margin-left: 100px;border: 5px solid green;width: 100%"</span>></span></div><div class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">id</span>=<span class="string">"boderBox"</span> <span class="attr">style</span>=<span class="string">"position: absolute; top:100px;left:100px; width: 200px;height: 100px;border: 10px solid #ccc"</span>></span></div><div class="line"> <span class="tag"></<span class="name">div</span>></span></div><div class="line"> <span class="tag"></<span class="name">div</span>></span></div><div class="line"></div><div class="line">```js</div><div class="line"> $boderBox = document.querySelector('#boderBox');</div><div class="line"> var rectObject = $boderBox.getBoundingClientRect();</div><div class="line"></div><div class="line"> console.info('offsetLeft', '相对于父容器的位置', $boderBox.offsetLeft); // 100</div><div class="line"> console.info('rect-left', '相对于浏览器视口左上角的位置', rectObject.left); // 275</div></pre></td></tr></table></figure>
]]></content>
<summary type="html">
<p><code>box-sizing</code> 、<code>offsetWidth</code>、<code>clientWidth</code>、<code>clientLeft</code><br>
</summary>
</entry>
<entry>
<title>Typescript中实现观察者模式的事件管理器</title>
<link href="http://shiwah.me/2016/09/29/20160929_tsSubPub/"/>
<id>http://shiwah.me/2016/09/29/20160929_tsSubPub/</id>
<published>2016-09-29T01:00:00.000Z</published>
<updated>2017-06-05T09:45:20.000Z</updated>
<content type="html"><![CDATA[<p>观察者模式的事件管理器可以让游戏中各模块间的功能调用以事件响应的方式相对独立开来,使得各模块间的功能相对更加独立。TS中的实现方法与JS类似,只是某些语法略有不同。<br><a id="more"></a></p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div></pre></td><td class="code"><pre><div class="line"><span class="comment">/**</span></div><div class="line"> *</div><div class="line"> * @shihua</div><div class="line"> * 2016.08.29</div><div class="line"> */</div><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">EventManager</span> </span>{</div><div class="line"> private <span class="keyword">static</span> _listeners = {};</div><div class="line"> private <span class="keyword">static</span> guid: number = <span class="number">1</span>; <span class="comment">// 识别方法的唯一标识</span></div><div class="line"> <span class="comment">// 订阅事件</span></div><div class="line"> public <span class="keyword">static</span> sub(type: string,fn): <span class="keyword">void</span> {</div><div class="line"> <span class="keyword">if</span> (<span class="keyword">typeof</span> <span class="keyword">this</span>._listeners[type] === <span class="string">'undefined'</span>) {</div><div class="line"> <span class="keyword">this</span>._listeners[type] = [];</div><div class="line"> }</div><div class="line"> <span class="keyword">if</span> (<span class="keyword">typeof</span> fn === <span class="string">'function'</span>) {</div><div class="line"> <span class="keyword">this</span>._listeners[type].push(fn);</div><div class="line"> fn.guid = <span class="keyword">this</span>.guid;</div><div class="line"> <span class="keyword">this</span>.guid++;</div><div class="line"> }</div><div class="line"> }</div><div class="line"> <span class="comment">//取消订阅事件</span></div><div class="line"> public <span class="keyword">static</span> unsub(type: string, fn): <span class="keyword">void</span> {</div><div class="line"> <span class="keyword">var</span> arrayEvent = <span class="keyword">this</span>._listeners[type];</div><div class="line"> <span class="keyword">if</span> (<span class="keyword">typeof</span> type === <span class="string">'string'</span> && arrayEvent <span class="keyword">instanceof</span> <span class="built_in">Array</span>) {</div><div class="line"> <span class="keyword">if</span> (<span class="keyword">typeof</span> fn === <span class="string">'function'</span>) {</div><div class="line"> <span class="keyword">for</span> (<span class="keyword">var</span> i = <span class="number">0</span>,length = arrayEvent.length; i < length; i += <span class="number">1</span>) {</div><div class="line"> <span class="keyword">if</span> (arrayEvent[i].guid === fn.guid) {</div><div class="line"> <span class="comment">// 通过guid识别function</span></div><div class="line"> <span class="keyword">this</span>._listeners[type].splice(i,<span class="number">1</span>);</div><div class="line"> <span class="keyword">break</span>;</div><div class="line"> }</div><div class="line"> }</div><div class="line"> } <span class="keyword">else</span> {</div><div class="line"> <span class="keyword">delete</span> <span class="keyword">this</span>._listeners[type];</div><div class="line"> }</div><div class="line"> }</div><div class="line"> }</div><div class="line"> <span class="comment">//发布事件</span></div><div class="line"> public <span class="keyword">static</span> pub(type: string, ...data: any[]): <span class="keyword">void</span> {</div><div class="line"> <span class="keyword">var</span> arrayEvent = <span class="keyword">this</span>._listeners[type];</div><div class="line"> <span class="keyword">var</span> handlerArgs = <span class="built_in">Array</span>.prototype.slice.call(<span class="built_in">arguments</span>, <span class="number">1</span>);</div><div class="line"> <span class="keyword">if</span> (arrayEvent <span class="keyword">instanceof</span> <span class="built_in">Array</span>) {</div><div class="line"> <span class="keyword">for</span> (<span class="keyword">var</span> i = <span class="number">0</span>,length = arrayEvent.length; i < length; i += <span class="number">1</span>) {</div><div class="line"> <span class="keyword">if</span> (<span class="keyword">typeof</span> arrayEvent[i] === <span class="string">'function'</span>) {</div><div class="line"> arrayEvent[i].apply(<span class="keyword">this</span>, handlerArgs);</div><div class="line"> }</div><div class="line"> }</div><div class="line"> }</div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure>
]]></content>
<summary type="html">
<p>观察者模式的事件管理器可以让游戏中各模块间的功能调用以事件响应的方式相对独立开来,使得各模块间的功能相对更加独立。TS中的实现方法与JS类似,只是某些语法略有不同。<br>
</summary>
</entry>
<entry>
<title>js在浏览器端对二进制流进行AES加密和解密</title>
<link href="http://shiwah.me/2015/12/29/20151229_aes/"/>
<id>http://shiwah.me/2015/12/29/20151229_aes/</id>
<published>2015-12-29T13:00:00.000Z</published>
<updated>2017-06-05T09:45:20.000Z</updated>
<content type="html"><![CDATA[<p>最近有一个项目,需要前端通过websocket与服务端连接,服务端直接向前端发二进制的数据协议包,但是这个协议包的内容是经过AES加密的,需要前端来在直接解密二进制流。</p>
<a id="more"></a>
<h2 id="开始解密"><a href="#开始解密" class="headerlink" title="开始解密"></a>开始解密</h2><p>简单了解一下所用的的AES加密算法,我们用的是AES的CFB加密方式,服务端会提供给我一个key和iv的二进制字节串。密文也是二进制字节串。</p>
<p>我用的加密/解密插件: <a href="http://code.google.com/p/crypto-js" target="_blank" rel="external">crypto-js</a></p>
<p>一般的应用场景下,key和iv以及密文都是字符串,按照网上的教程基本上很快就能搞出来了。<br><strong>这里只简述一下key、iv、密文均为二进制字节串的情况下怎么用crypto-js来解密。</strong></p>
<p>需要引进下面几个js:<br><figure class="highlight html"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line"><span class="tag"><<span class="name">script</span> <span class="attr">src</span>=<span class="string">"aes.js"</span>></span><span class="undefined"></span><span class="tag"></<span class="name">script</span>></span></div><div class="line"><span class="tag"><<span class="name">script</span> <span class="attr">src</span>=<span class="string">"mode-cfb.js"</span>></span><span class="undefined"></span><span class="tag"></<span class="name">script</span>></span></div><div class="line"><span class="tag"><<span class="name">script</span> <span class="attr">src</span>=<span class="string">"pad-nopadding.js"</span>></span><span class="undefined"></span><span class="tag"></<span class="name">script</span>></span></div><div class="line"><span class="tag"><<span class="name">script</span> <span class="attr">src</span>=<span class="string">"lib-typedarrays.js"</span>></span><span class="undefined"></span><span class="tag"></<span class="name">script</span>></span></div><div class="line"><span class="tag"><<span class="name">script</span> <span class="attr">src</span>=<span class="string">"enc-base64.js"</span>></span><span class="undefined"></span><span class="tag"></<span class="name">script</span>></span></div><div class="line"><span class="tag"><<span class="name">script</span> <span class="attr">src</span>=<span class="string">"js/lib/enc-u8array.js"</span>></span><span class="undefined"></span><span class="tag"></<span class="name">script</span>></span> <span class="comment"><!-- 注意一下这个,并不在插件源文件中 --></span></div></pre></td></tr></table></figure></p>
<p>注意一下最后一个文件,是我从网上摘录的,在插件源文件中是没有的。内容如下:</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div></pre></td><td class="code"><pre><div class="line">CryptoJS.enc.u8array = {</div><div class="line"> <span class="comment">/**</span></div><div class="line"> * Converts a word array to a Uint8Array.</div><div class="line"> *</div><div class="line"> * @param {WordArray} wordArray The word array.</div><div class="line"> *</div><div class="line"> * @return {Uint8Array} The Uint8Array.</div><div class="line"> *</div><div class="line"> * @static</div><div class="line"> *</div><div class="line"> * @example</div><div class="line"> *</div><div class="line"> * var u8arr = CryptoJS.enc.u8array.stringify(wordArray);</div><div class="line"> */</div><div class="line"> stringify: <span class="function"><span class="keyword">function</span> (<span class="params">wordArray</span>) </span>{</div><div class="line"> <span class="comment">// Shortcuts</span></div><div class="line"> <span class="keyword">var</span> words = wordArray.words;</div><div class="line"> <span class="keyword">var</span> sigBytes = wordArray.sigBytes;</div><div class="line"> <span class="comment">// Convert</span></div><div class="line"> <span class="keyword">var</span> u8 = <span class="keyword">new</span> <span class="built_in">Uint8Array</span>(sigBytes);</div><div class="line"> <span class="keyword">for</span> (<span class="keyword">var</span> i = <span class="number">0</span>; i < sigBytes; i++) {</div><div class="line"> <span class="keyword">var</span> byte = (words[i >>> <span class="number">2</span>] >>> (<span class="number">24</span> - (i % <span class="number">4</span>) * <span class="number">8</span>)) & <span class="number">0xff</span>;</div><div class="line"> u8[i]=byte;</div><div class="line"> }</div><div class="line"> <span class="keyword">return</span> u8;</div><div class="line"> },</div><div class="line"> <span class="comment">/**</span></div><div class="line"> * Converts a Uint8Array to a word array.</div><div class="line"> *</div><div class="line"> * @param {string} u8Str The Uint8Array.</div><div class="line"> *</div><div class="line"> * @return {WordArray} The word array.</div><div class="line"> *</div><div class="line"> * @static</div><div class="line"> *</div><div class="line"> * @example</div><div class="line"> *</div><div class="line"> * var wordArray = CryptoJS.enc.u8array.parse(u8arr);</div><div class="line"> */</div><div class="line"> parse: <span class="function"><span class="keyword">function</span> (<span class="params">u8arr</span>) </span>{</div><div class="line"> <span class="comment">// Shortcut</span></div><div class="line"> <span class="keyword">var</span> len = u8arr.length;</div><div class="line"> <span class="comment">// Convert</span></div><div class="line"> <span class="keyword">var</span> words = [];</div><div class="line"> <span class="keyword">for</span> (<span class="keyword">var</span> i = <span class="number">0</span>; i < len; i++) {</div><div class="line"> words[i >>> <span class="number">2</span>] |= (u8arr[i] & <span class="number">0xff</span>) << (<span class="number">24</span> - (i % <span class="number">4</span>) * <span class="number">8</span>);</div><div class="line"> }</div><div class="line"> <span class="keyword">return</span> CryptoJS.lib.WordArray.create(words, len);</div><div class="line"> }</div><div class="line">};</div></pre></td></tr></table></figure>
<p>插件本身提供一个key、iv、明文均是WordArray的加密方法,而这个WordArray的数据格式长得非常像uint8数据,而<br>这个组件的组件的功能就是是uint8数组和WordArray之间的互相转换。<br>那么有了它我们就可以进行加解密了。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div></pre></td><td class="code"><pre><div class="line"></div><div class="line"><span class="comment">// 服务端提供的32位key</span></div><div class="line"><span class="keyword">var</span> akey = [<span class="number">0x26</span>,<span class="number">0xAF</span>,<span class="number">0xE2</span>,<span class="number">0x1A</span>,<span class="number">0x0C</span>,<span class="number">0x16</span>,<span class="number">0x73</span>,<span class="number">0x54</span>,<span class="number">0x13</span>,<span class="number">0xFD</span>,<span class="number">0x68</span>,<span class="number">0xDD</span>,<span class="number">0x8F</span>,<span class="number">0xA0</span>,<span class="number">0xB7</span>,<span class="number">0xC1</span>,<span class="number">0x57</span>,<span class="number">0xA6</span>,<span class="number">0x90</span>,<span class="number">0xFF</span>,<span class="number">0xCD</span>,<span class="number">0xB3</span>,<span class="number">0x54</span>,<span class="number">0x61</span>,<span class="number">0x10</span>,<span class="number">0x07</span>,<span class="number">0xD5</span>,<span class="number">0x7E</span>,<span class="number">0xDB</span>,<span class="number">0x1E</span>,<span class="number">0x4C</span>,<span class="number">0xE9</span>];</div><div class="line"><span class="comment">// 服务端提供的16位iv</span></div><div class="line"><span class="keyword">var</span> aiv = [<span class="number">0x15</span>,<span class="number">0x4C</span>,<span class="number">0xD3</span>,<span class="number">0x55</span>,<span class="number">0xFE</span>,<span class="number">0xA1</span>,<span class="number">0xFF</span>,<span class="number">0x01</span>,<span class="number">0x00</span>,<span class="number">0x34</span>,<span class="number">0xAB</span>,<span class="number">0x22</span>,<span class="number">0x08</span>,<span class="number">0x4F</span>,<span class="number">0x13</span>,<span class="number">0x07</span>];</div><div class="line"></div><div class="line"><span class="comment">// 将key和iv转换成uint8数组</span></div><div class="line"><span class="keyword">var</span> keyBv = <span class="keyword">new</span> <span class="built_in">Uint8Array</span>(akey);</div><div class="line"><span class="keyword">var</span> ivBv = <span class="keyword">new</span> <span class="built_in">Uint8Array</span>(aiv);</div><div class="line"></div><div class="line"><span class="comment">// 将key和iv转换成WordArray</span></div><div class="line">keyWA = CryptoJS.enc.u8array.parse(keyBv);</div><div class="line">ivWA = CryptoJS.enc.u8array.parse(ivBv);</div><div class="line"></div><div class="line"><span class="comment">// 解密方法 传入密文的uint8数组</span></div><div class="line"><span class="function"><span class="keyword">function</span> <span class="title">decryptU8arry</span>(<span class="params">array</span>) </span>{</div><div class="line"> <span class="keyword">var</span> acontent = array;</div><div class="line"> <span class="comment">// 将密文转换成WordArray</span></div><div class="line"> contentWA = CryptoJS.enc.u8array.parse(acontent);</div><div class="line"> <span class="comment">// 插件要求密文是base64格式</span></div><div class="line"> <span class="keyword">var</span> dcBase64String = contentWA.toString(CryptoJS.enc.Base64);</div><div class="line"> <span class="comment">// 解密 选定mode是CFB类型,无偏移量</span></div><div class="line"> <span class="keyword">var</span> decrypted = CryptoJS.AES.decrypt(dcBase64String, keyWA, { <span class="attr">iv</span>: ivWA,<span class="attr">mode</span>:CryptoJS.mode.CFB,<span class="attr">padding</span>:CryptoJS.pad.NoPadding});</div><div class="line"> <span class="comment">// 将解密后的明文转回uint8数组</span></div><div class="line"> <span class="keyword">var</span> bv = CryptoJS.enc.u8array.stringify(decrypted);</div><div class="line"> <span class="keyword">return</span> bv;</div><div class="line">}</div><div class="line"></div><div class="line"><span class="comment">// 加密方法 传入明文的uint8数组</span></div><div class="line"><span class="function"><span class="keyword">function</span> <span class="title">encryptU8arry</span>(<span class="params">array</span>) </span>{</div><div class="line"> <span class="keyword">var</span> acontent = array;</div><div class="line"> <span class="comment">// 将明文转换成WordArray</span></div><div class="line"> contentWA = CryptoJS.enc.u8array.parse(acontent);</div><div class="line"> <span class="comment">// 插件要求明文是base64格式</span></div><div class="line"> <span class="keyword">var</span> dcBase64String = contentWA.toString(CryptoJS.enc.Base64);</div><div class="line"> <span class="comment">// 加密 选定mode是CFB类型,无偏移量</span></div><div class="line"> <span class="keyword">var</span> encrypted = CryptoJS.AES.encrypt(contentWA, keyWA, { <span class="attr">iv</span>: ivWA,<span class="attr">mode</span>:CryptoJS.mode.CFB,<span class="attr">padding</span>:CryptoJS.pad.NoPadding});</div><div class="line"> <span class="comment">// 将密文转回uint8数组</span></div><div class="line"> <span class="keyword">var</span> bv = CryptoJS.enc.u8array.stringify(encrypted.ciphertext);</div><div class="line"> <span class="keyword">return</span> bv;</div><div class="line">}</div></pre></td></tr></table></figure>
<p>由此可以对二进制流进行加密解密了:<br><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">var</span> aData = [<span class="number">0</span>,<span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>,<span class="number">4</span>];</div><div class="line"><span class="keyword">var</span> dv = <span class="keyword">new</span> <span class="built_in">Uint8Array</span>(aData);</div><div class="line"><span class="keyword">var</span> enu8 = encryptU8arry(dv); <span class="comment">// 加密后的二进制流</span></div><div class="line"><span class="built_in">console</span>.log(enu8);</div><div class="line"><span class="keyword">var</span> deu8 = decryptU8arry(enu8); <span class="comment">// 解密后的二进制流</span></div><div class="line"><span class="built_in">console</span>.log(deu8);</div></pre></td></tr></table></figure></p>
]]></content>
<summary type="html">
<p>最近有一个项目,需要前端通过websocket与服务端连接,服务端直接向前端发二进制的数据协议包,但是这个协议包的内容是经过AES加密的,需要前端来在直接解密二进制流。</p>
</summary>
</entry>
<entry>
<title>TypeArray、ArrayBuffer、Blob的相互转换</title>
<link href="http://shiwah.me/2015/12/29/20151229_arrayBuffer/"/>
<id>http://shiwah.me/2015/12/29/20151229_arrayBuffer/</id>
<published>2015-12-29T12:00:00.000Z</published>
<updated>2017-06-05T09:45:20.000Z</updated>
<content type="html"><![CDATA[<a id="more"></a>
<ul>
<li><code>Blob</code>是现代浏览器中提供的能够装载二进制流(文件)的容器对象。</li>
<li><code>ArrayBuffer</code>是能够装载<code>Blob</code>(二进制流)数据的原始缓冲区,<code>ArrayBuffer</code>不能直接通过js读写。</li>
<li><code>TypeArray</code>是<code>ArrayBuffer</code>的一种类数组的视图对象,可以将<code>ArrayBuffer</code>按不同字节数读取成类似数组形式的数据类型,从而可以向读写数组元素一样,实现对<code>ArrayBuffer</code>数据的读写。常见的<code>TypeArray</code>包括<code>Uint8Array</code>,<code>Uint16Array</code>,<code>Uint32Array</code>等。<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray" target="_blank" rel="external">点这里查看所有的TypedArray</a></li>
</ul>
<p>所以我对三者的理解是: <code>Blob</code> <-> <code>ArrayBuffer</code> <-> <code>TypeArray</code> <—-> <code>Array</code><br>由于<code>TypeArray</code>和<code>Array</code>有些相似,因此往往我会选择在<code>TypeArray</code>这层做处理。<br>下面是<code>TypeArray</code>、<code>ArrayBuffer</code>和<code>Blob</code>之间相互转换的方法。</p>
<h2 id="websocket接收arrayBuffer"><a href="#websocket接收arrayBuffer" class="headerlink" title="websocket接收arrayBuffer"></a>websocket接收arrayBuffer</h2><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line"><span class="comment">/* websocket的情况下二进制流的获取 */</span></div><div class="line"><span class="keyword">var</span> svip = <span class="string">'ws://127.0.0.1:8080'</span>;</div><div class="line"><span class="keyword">var</span> ws = <span class="keyword">new</span> WebSocket(svip);</div><div class="line">ws.binaryType = <span class="string">'arraybuffer'</span></div><div class="line">ws.onmessage = <span class="function"><span class="keyword">function</span> (<span class="params">e</span>) </span>{</div><div class="line"> <span class="keyword">var</span> message = e.data;</div><div class="line">}</div></pre></td></tr></table></figure>
<h2 id="blob轉arrayBuffer"><a href="#blob轉arrayBuffer" class="headerlink" title="blob轉arrayBuffer"></a>blob轉arrayBuffer</h2><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">var</span> bl = <span class="keyword">new</span> Blob(); <span class="comment">// bl是要转换的blob</span></div><div class="line"><span class="keyword">var</span> fr = <span class="keyword">new</span> FileReader();</div><div class="line">fr.onload = <span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>{</div><div class="line"> <span class="keyword">var</span> ab = <span class="keyword">this</span>.result; <span class="comment">// ab是转换后的结果</span></div><div class="line">}</div><div class="line">fr.readAsArrayBuffer(bl);</div></pre></td></tr></table></figure>
<h2 id="ArrayBuffer-to-Blob-(ArrayBuffer转Blob)"><a href="#ArrayBuffer-to-Blob-(ArrayBuffer转Blob)" class="headerlink" title="ArrayBuffer to Blob (ArrayBuffer转Blob)"></a>ArrayBuffer to Blob (ArrayBuffer转Blob)</h2><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">var</span> ab = <span class="keyword">new</span> <span class="built_in">ArrayBuffer</span>(<span class="number">32</span>);</div><div class="line"><span class="keyword">var</span> blob = <span class="keyword">new</span> Blob([ab]); <span class="comment">// 注意必须包裹[]</span></div></pre></td></tr></table></figure>
<h2 id="ArrayBuffer-to-Uint8-(ArrayBuffer转Uint8数组)"><a href="#ArrayBuffer-to-Uint8-(ArrayBuffer转Uint8数组)" class="headerlink" title="ArrayBuffer to Uint8 (ArrayBuffer转Uint8数组)"></a>ArrayBuffer to Uint8 (ArrayBuffer转Uint8数组)</h2><p>Uint8数组可以直观的看到ArrayBuffer中每个字节(1字节 == 8位)的值。一般我们要将ArrayBuffer转成Uint类型数组后才能对其中的字节进行存取操作。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">var</span> ab = arrayBuffer; <span class="comment">// arrayBuffer为要转换的值</span></div><div class="line"><span class="keyword">var</span> u8 = <span class="keyword">new</span> <span class="built_in">Uint8Array</span>(ab);</div></pre></td></tr></table></figure>
<h2 id="Uint8-to-ArrayBuffer(Uint数组转ArrayBuffer)"><a href="#Uint8-to-ArrayBuffer(Uint数组转ArrayBuffer)" class="headerlink" title="Uint8 to ArrayBuffer(Uint数组转ArrayBuffer)"></a>Uint8 to ArrayBuffer(Uint数组转ArrayBuffer)</h2><p>我们Uint8数组可以直观的看到ArrayBuffer中每个字节(1字节 == 8位)的值。一般我们要将ArrayBuffer转成Uint类型数组后才能对其中的字节进行存取操作。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">var</span> u8 = <span class="keyword">new</span> <span class="built_in">Uint8Array</span>();</div><div class="line"><span class="keyword">var</span> ab = u8.buffer; <span class="comment">// ab即是u8对应的arrayBuffer</span></div></pre></td></tr></table></figure>
<h2 id="Array-to-ArrayBuffer(普通数组转ArrayBuffer)"><a href="#Array-to-ArrayBuffer(普通数组转ArrayBuffer)" class="headerlink" title="Array to ArrayBuffer(普通数组转ArrayBuffer)"></a>Array to ArrayBuffer(普通数组转ArrayBuffer)</h2><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">var</span> arr = [<span class="number">0x15</span>,<span class="number">0xFF</span>,<span class="number">0x01</span>,<span class="number">0x00</span>,<span class="number">0x34</span>,<span class="number">0xAB</span>,<span class="number">0x11</span>];</div><div class="line"><span class="keyword">var</span> u8 = <span class="keyword">new</span> <span class="built_in">Uint8Array</span>(arr);</div><div class="line"><span class="keyword">var</span> ab = u8.buffer;</div><div class="line"><span class="built_in">console</span>.log(ab); <span class="comment">// ab为要解析的ArrayBuffer</span></div></pre></td></tr></table></figure>
<h2 id="获取-设置ArrayBuffer对应的数值"><a href="#获取-设置ArrayBuffer对应的数值" class="headerlink" title="获取/设置ArrayBuffer对应的数值"></a>获取/设置ArrayBuffer对应的数值</h2><p>一串ArrayBuffer是可以被“理解”为很多个值的,以下面这个值为例,</p>
<p>按照服务端的协议,这串数据流的格式如下:<br>1 unsign byte (1字节) + 1 unsign int (4字节) + 1 unsign short (2字节)</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">var</span> arr = [<span class="number">0x01</span>,<span class="number">0x02</span>,<span class="number">0x00</span>,<span class="number">0x00</span>,<span class="number">0x00</span>,<span class="number">0x00</span>,<span class="number">0x03</span>];</div><div class="line"><span class="keyword">var</span> u8 = <span class="keyword">new</span> <span class="built_in">Uint8Array</span>(arr);</div><div class="line"><span class="keyword">var</span> ab = u8.buffer;</div><div class="line"><span class="built_in">console</span>.log(ab); <span class="comment">// ab为要解析的ArrayBuffer</span></div><div class="line"></div><div class="line"><span class="keyword">var</span> u8 = <span class="keyword">new</span> <span class="built_in">Uint8Array</span>(ab, <span class="number">0</span>, <span class="number">1</span>); <span class="comment">// (arraybuffer, 字节解析的起点, 解析的长度)</span></div><div class="line"><span class="keyword">var</span> val_byte = u8[<span class="number">0</span>];</div><div class="line"><span class="built_in">console</span>.log(val_byte);</div><div class="line"></div><div class="line"><span class="comment">// 解析unsign int</span></div><div class="line"><span class="comment">// 由于Uint32Array的解析起点必须是4的整数倍,而在流中该数据的起点是1,所以选择先“裁剪”(slice)出要解析的流片段,再用Uint32去解析该片段</span></div><div class="line"><span class="keyword">var</span> u32buff = ab.slice(<span class="number">1</span>, <span class="number">5</span>);</div><div class="line"><span class="keyword">var</span> u32 = <span class="keyword">new</span> <span class="built_in">Uint32Array</span>(u32buff);</div><div class="line"><span class="keyword">var</span> val_uint = u32[<span class="number">0</span>];</div><div class="line"><span class="built_in">console</span>.log(val_uint);</div><div class="line"></div><div class="line"><span class="comment">// 解析unsign short</span></div><div class="line"><span class="keyword">var</span> u16buff = ab.slice(<span class="number">5</span>, <span class="number">7</span>);</div><div class="line"><span class="keyword">var</span> u16 = <span class="keyword">new</span> <span class="built_in">Uint16Array</span>(u16buff);</div><div class="line"><span class="keyword">var</span> val_short = u16[<span class="number">0</span>];</div><div class="line"><span class="built_in">console</span>.log(val_short);</div></pre></td></tr></table></figure>
<h2 id="TypeArray-to-Array"><a href="#TypeArray-to-Array" class="headerlink" title="TypeArray to Array"></a>TypeArray to Array</h2><p>在上文中可以看到,普通数组可以轻松的转换成TypeArray。<br>但TypeArray并不是Array的子集,所以它没有Array的许多方法,比如<code>push</code><br>TypeArray的方法参见:<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray" target="_blank" rel="external">TypedArray的方法</a></p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">var</span> arr = [<span class="number">0x01</span>,<span class="number">0x02</span>,<span class="number">0x00</span>,<span class="number">0x00</span>,<span class="number">0x00</span>,<span class="number">0x00</span>,<span class="number">0x03</span>];</div><div class="line"><span class="keyword">var</span> u8 = <span class="keyword">new</span> <span class="built_in">Uint8Array</span>(arr);</div><div class="line"><span class="built_in">console</span>.log(<span class="keyword">typeof</span> u8.push);</div></pre></td></tr></table></figure>
<p>所以需要进行转换。<br>TypeArray to Array的方法,在ES6中可以用Array.form实现 (<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from" target="_blank" rel="external">什么是Array.form</a>)</p>
<p>也可以比较简单的封装一下。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div></pre></td><td class="code"><pre><div class="line"></div><div class="line"><span class="function"><span class="keyword">function</span> <span class="title">Uint8Array2Array</span>(<span class="params">u8a</span>) </span>{</div><div class="line"> <span class="keyword">var</span> arr = [];</div><div class="line"> <span class="keyword">for</span> (<span class="keyword">var</span> i = <span class="number">0</span>; i < u8a.length; i++) {</div><div class="line"> arr.push(u8a[i]);</div><div class="line"> }</div><div class="line"> <span class="keyword">return</span> arr;</div><div class="line">}</div></pre></td></tr></table></figure>]]></content>
<summary type="html">
<a id="more"></a>
<ul>
<li><code>Blob</code>是现代浏览器中提供的能够装载二进制流(文件)的容器对象。</li>
<li><code>ArrayBuffer</code>是能够装载<code>Blob</code>(二进制流)数据的原始缓
</summary>
</entry>
<entry>
<title>js代码优化的思考</title>
<link href="http://shiwah.me/2015/11/18/20150918_codeBeter/"/>
<id>http://shiwah.me/2015/11/18/20150918_codeBeter/</id>
<published>2015-11-17T16:00:00.000Z</published>
<updated>2017-08-24T13:11:26.000Z</updated>
<content type="html"><![CDATA[<p>变量抽取 策略模式 相关</p>
<a id="more"></a>
<p>程序员经常喜欢将程序体中要调用的变量直接写死代码中。<br>比如我们要计算一个边长是100的正方形面积:<br><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">var</span> a = <span class="number">100</span> * <span class="number">100</span>;</div></pre></td></tr></table></figure></p>
<p>因为我们会习惯性的认为100是一个确定的值,我们就直接用数字里表明,而不是一个变量。</p>
<p>那么这个时候就会带来两个问题:</p>
<ol>
<li>100这个数值的含义不清楚。当代码交到别人手上,或者过了一段时间后自己再回来看时,可能就不清楚这个100是什么意思了。这就变成了传说中的<code>magic number</code>;</li>
<li>如果有一天,正方形的边长变了,是不是就要把数值改变了呢?假设这个边长在程序中多个地方进行运算,与此同时如果程序中有其它变量的值也是100,那么改起来就头疼了;</li>
</ol>
<p>所以一个良好的编程习惯就是少用写死。这会让你的代码质量(可读性、复用性等)有一个质的飞跃</p>
<p><strong>注意,避免写死是一种编程的思想,而不是简单的把数值变量化</strong></p>
<h2 id="目的"><a href="#目的" class="headerlink" title="目的"></a>目的</h2><p>首先要先清楚去除写死的目的:</p>
<blockquote>
<ol>
<li>让代码更加语义化。让自己/他人在阅读(审查)代码时都能很快的看懂某一个变量、方法等的意思;</li>
<li>提高代码的复用性。在去除写死的过程中,其实我们已经将数值相同的变量的入口提取出来(抽取共性),这样就只需要一处修改、多处受用了。</li>
<li>提高效率。避免在编码过程中认为输错某些字符而出错……</li>
</ol>
</blockquote>
<h2 id="几个经典的应用:"><a href="#几个经典的应用:" class="headerlink" title="几个经典的应用:"></a>几个经典的应用:</h2><h3 id="ajax的url"><a href="#ajax的url" class="headerlink" title="ajax的url"></a>ajax的url</h3><p>很多时候某个请求地址的用途很难从url字面看懂(如a.php),如果我们将其提取出来,放到一个oUrl[‘getUserInfo’]对象中。<br>那么首先它的作用就可以从字面上理解了,getUserInfo嘛。<br>其实还有一个更大好处,在实际项目中,当前后端分工明确时,前端常常需要自己测试ajax模块,而不是直接去调实际PHP给出的接口(又或者说前端往往先于PHP开发),当我们在本地测试时,ajax的请求地址就和线上的不同了。<br>如果我们采取这种写法,将地址的配置参数暴露出来,当我们提交给PHP后,他只需要修改这几个配置项就可以了。而不需要再改我们的js代码了。<br>假如程序中很多个(假设10个)模块都需要访问a.php调数据,那么如果有一天,接口的地址换了(比如上面这种前后端分离后前端交付js给php后的情景),那么我就不需要10个模块都一一的去改。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">var</span> oUrl = {</div><div class="line"> <span class="string">'getUserInfo'</span>: <span class="string">'a.php'</span></div><div class="line">, <span class="string">'setUserInfo'</span>: <span class="string">'b.php'</span></div><div class="line">};</div><div class="line">$ajax({</div><div class="line"> <span class="string">'url'</span>: oUrl[<span class="string">'getUserInfo'</span>]</div><div class="line">, <span class="string">'type'</span>: <span class="string">'GET'</span></div><div class="line">});</div></pre></td></tr></table></figure>
<h3 id="事件绑定"><a href="#事件绑定" class="headerlink" title="事件绑定"></a>事件绑定</h3><p>ajax的例子中已经把优点说的很明显了,下面再分享一种在事件绑定中的应用:<br>我们知道,在pc端我们的点击事件一般都是绑定click,而移动端我们为了更快的响应则往往绑定touchstart事件,于是就会发现在pc端上调试touchstart事件不太方便而在移动端click又不是我们想要的结果。</p>
<p>因此,我们把要绑定的事件抽取成变量,先判断系统环境然后再给变量赋值,这样就可以快捷的在pc和手机上切换啦。(判断方法仅供参考)</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">function</span> <span class="title">fCheckMoblie</span>(<span class="params"></span>) </span></div><div class="line">{ </div><div class="line"> <span class="keyword">var</span> aUserAgentInfo = navigator.userAgent; </div><div class="line"> <span class="keyword">var</span> aMoblieAgent = [<span class="string">'Android'</span>, <span class="string">'iPhone'</span>, <span class="string">'SymbianOS'</span>, <span class="string">'Windows Phone'</span>, <span class="string">'iPad'</span>, <span class="string">'iPod'</span>];</div><div class="line"> <span class="keyword">var</span> bFlag = <span class="literal">false</span>; </div><div class="line"> <span class="keyword">for</span> (<span class="keyword">var</span> i = <span class="number">0</span>; i < aMoblieAgent.length; i++) { </div><div class="line"> <span class="keyword">if</span> (aUserAgentInfo.indexOf(Agents[i]) > <span class="number">0</span>) { </div><div class="line"> bFlag = <span class="literal">true</span>; </div><div class="line"> <span class="keyword">break</span>; </div><div class="line"> } </div><div class="line"> } </div><div class="line"> <span class="keyword">return</span> bFlag; </div><div class="line">} </div><div class="line"><span class="keyword">var</span> bMobile = fCheckMoblie();</div><div class="line"><span class="keyword">var</span> sClickType = bMobile ? <span class="string">'touchstart'</span> : <span class="string">'click'</span>;</div><div class="line">$(<span class="string">'#aaa'</span>).on(sClickType, <span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>{</div><div class="line"> <span class="comment">// todo</span></div><div class="line">})</div></pre></td></tr></table></figure>
<h3 id="思路拓展-——-抽取方法(代码片段)"><a href="#思路拓展-——-抽取方法(代码片段)" class="headerlink" title="思路拓展 —— 抽取方法(代码片段)"></a>思路拓展 —— 抽取方法(代码片段)</h3><p>上面两个案例可以看到将变量提取出来的优点,其实这样的思路不仅对于变量受用,对于方法(或者是一整段的逻辑代码)也同样适用。</p>
<p>我们刚开始接触一些业务复杂的js时可能都会写过下面几种代码:</p>
<ul>
<li><ol>
<li>超级多的if else<figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div></pre></td><td class="code"><pre><div class="line">functon aaa(sCity) {</div><div class="line"> <span class="keyword">if</span> (<span class="string">'shanghai'</span> == sCity) {</div><div class="line"> <span class="comment">// 这里是50行逻辑代码代码</span></div><div class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (<span class="string">'beijing'</span> == sCity) {</div><div class="line"> / 这里是<span class="number">50</span>行逻辑代码代码</div><div class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (<span class="string">'guangzhou'</span> == sCity) {</div><div class="line"> / 这里是<span class="number">50</span>行逻辑代码代码</div><div class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (<span class="string">'hangzhou'</span> == sCity) {</div><div class="line"> / 这里是<span class="number">50</span>行逻辑代码代码</div><div class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (<span class="string">'nanning'</span> == sCity) {</div><div class="line"> / 这里是<span class="number">50</span>行逻辑代码代码</div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure>
</li>
</ol>
</li>
</ul>
<p>上面这种一个分多种情况处理的逻辑代码,假设每个情况50行,当你写完后要进行调试修改代码时发现滚轮内心几乎是崩溃的。这种现象很常见,因为和有可能在开始编码时不能预见逻辑会如此复杂。但客观的说这样的代码可读性略差。</p>
<p><strong>有的人会说这种情况换 <code>switch case</code> 会更好</strong><br>但其实如果每种情况要里有几十行上百行代码时这么写其实是换汤不换药的。</p>
<p>一种更为推荐的写法,假如只有<code>shanghai</code> 、 <code>beijing</code>等这5种情况,那么我们先将这这些情况的逻辑代码抽取出来:</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div></pre></td><td class="code"><pre><div class="line">oFunc = {</div><div class="line"> <span class="string">'shanghai'</span>: <span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>{</div><div class="line"> <span class="comment">// 上海的50行</span></div><div class="line"> }</div><div class="line">, <span class="string">'beijing'</span>: <span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>{</div><div class="line"> <span class="comment">// 50行</span></div><div class="line"> }</div><div class="line">, <span class="string">'guangzhou'</span>: <span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>{</div><div class="line"> <span class="comment">// 50行</span></div><div class="line"> }</div><div class="line">, <span class="string">'hangzhou'</span>: <span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>{</div><div class="line"> <span class="comment">// 50行</span></div><div class="line"> }</div><div class="line">, <span class="string">'nanning'</span>: <span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>{</div><div class="line"> <span class="comment">// 50行</span></div><div class="line"> }</div><div class="line">}</div><div class="line"><span class="function"><span class="keyword">function</span> <span class="title">aaa</span>(<span class="params">sCity</span>) </span>{</div><div class="line"> oFunc[sCity]();</div><div class="line">}</div></pre></td></tr></table></figure>
<p>这时候aaa这个方法就轻便了很多了,而原来数十行的代码段也有了自己的方法,这时候就可以多处去调用相同的代码片段了。如果这时候你下意识的想去看看oFunc中的五个方法是不是再可以抽取共同的模块(代码片段)那么基本上就已经溜的飞起了。</p>
<ul>
<li><ol>
<li>重复写很多相似的代码<br>当页面中要处理很多元素时,就经常会遇到这种情况。</li>
</ol>
</li>
</ul>
<figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">var</span> a = <span class="keyword">new</span> Person();</div><div class="line">a.name = <span class="string">'name1'</span>;</div><div class="line">a.gender = <span class="string">'man'</span>;</div><div class="line">a.age = <span class="string">'18'</span>;</div><div class="line"></div><div class="line"><span class="keyword">var</span> b = <span class="keyword">new</span> Person();</div><div class="line">b.name = <span class="string">'name1'</span>;</div><div class="line">b.gender = <span class="string">'man'</span>;</div><div class="line">b.age = <span class="string">'18'</span>;</div><div class="line"></div><div class="line"><span class="keyword">var</span> c = <span class="keyword">new</span> Person();</div><div class="line">c.name = <span class="string">'name1'</span>;</div><div class="line">c.gender = <span class="string">'man'</span>;</div><div class="line">c.age = <span class="string">'18'</span>;</div></pre></td></tr></table></figure>
<p>其实处理的这三个元素所进行的工序是一毛一样的。一般遇到这种情况,超过三段相同的代码时就可以考虑进行封装了。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div></pre></td><td class="code"><pre><div class="line">funtion fCreatePerson(name, gender, age) {</div><div class="line"> <span class="keyword">var</span> o = <span class="keyword">new</span> Person();</div><div class="line"> o.name = name;</div><div class="line"> o.gender = gender;</div><div class="line"> o.age = age;</div><div class="line"> <span class="keyword">return</span> o;</div><div class="line">}</div><div class="line"></div><div class="line"><span class="keyword">var</span> a = fCreatePerson(<span class="string">'name1'</span>, <span class="string">'man'</span>, <span class="string">'18'</span>);</div><div class="line"><span class="keyword">var</span> b = fCreatePerson(<span class="string">'name1'</span>, <span class="string">'man'</span>, <span class="string">'18'</span>);</div><div class="line"><span class="keyword">var</span> c = fCreatePerson(<span class="string">'name1'</span>, <span class="string">'man'</span>, <span class="string">'18'</span>);</div></pre></td></tr></table></figure>
<p>上面这种情况普遍出现在某些匿名函数中,比如:</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div></pre></td><td class="code"><pre><div class="line">$(<span class="string">'#btn1'</span>).on(<span class="string">'click'</span>, <span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>{</div><div class="line"> a = $(<span class="keyword">this</span>).data(<span class="string">'abc'</span>);</div><div class="line"> alert(a);</div><div class="line">});</div><div class="line"></div><div class="line">$(<span class="string">'#btn2'</span>).on(<span class="string">'click'</span>, <span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>{</div><div class="line"> a = $(<span class="keyword">this</span>).data(<span class="string">'abc'</span>);</div><div class="line"> alert(a);</div><div class="line">});</div></pre></td></tr></table></figure>
<p>刚开始往往会被匿名函数牵着鼻子走,习惯性的把逻辑代码都写在这个匿名function中。<br>而实际上,按照本文的思路,这段匿名函数其实可以抽出来写……</p>
<h3 id="脑洞大开-CSS也行?"><a href="#脑洞大开-CSS也行?" class="headerlink" title="脑洞大开 CSS也行?"></a>脑洞大开 CSS也行?</h3><p>其实这个是胡扯啦,css这种静态的stylesheet基本上不存在变量这种说法啦~<br>基本上就是你在css里定义了多少,那么页面上就显示多少了。<br>不过直至rem的出现。<br>rem在这里就可以看成是一个预设的变量啦,它的默认值是根元素的font-size。<br>当页面加载后,你可以修个font-size的大小,这时候,所有基于rem设置大小的值都会响应啦。<br>是不是很叼???</p>
]]></content>
<summary type="html">
<p>变量抽取 策略模式 相关</p>
</summary>
</entry>
<entry>
<title>HTML5中计时器的三种方案</title>
<link href="http://shiwah.me/2015/10/11/20151111_h5Timer/"/>
<id>http://shiwah.me/2015/10/11/20151111_h5Timer/</id>
<published>2015-10-10T16:00:00.000Z</published>
<updated>2017-06-05T09:45:20.000Z</updated>
<content type="html"><![CDATA[<p>在做HTML5游戏或者单页应用时我们常常需要使用到计时器模块,比如游戏中的倒计时功能。</p>
<a id="more"></a>
<h2 id="常规方案"><a href="#常规方案" class="headerlink" title="常规方案"></a>常规方案</h2><p>最常见的计时器方案一般无非<code>setTimeout</code>和<code>setInterval</code>,基本上已经被玩坏了……<br><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">var</span> nTimeCount = <span class="number">15</span>;</div><div class="line"></div><div class="line"><span class="comment">// setTimeout</span></div><div class="line"><span class="function"><span class="keyword">function</span> <span class="title">fCountTime</span>(<span class="params"></span>) </span>{</div><div class="line"> <span class="keyword">if</span> (nTimeCount > <span class="number">0</span>) {</div><div class="line"> nTimeCount--;</div><div class="line"> setTimeout(<span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>{</div><div class="line"> fCountTime();</div><div class="line"> }, <span class="number">1000</span>);</div><div class="line"> } <span class="keyword">else</span> {</div><div class="line"> <span class="built_in">console</span>.log(<span class="string">'时间到'</span>);</div><div class="line"> }</div><div class="line">}</div><div class="line">fCountTime();</div><div class="line"></div><div class="line"><span class="comment">// setInterval</span></div><div class="line"><span class="function"><span class="keyword">function</span> <span class="title">fCountTime</span>(<span class="params"></span>) </span>{</div><div class="line"> <span class="keyword">if</span> (nTimeCount > <span class="number">0</span>) {</div><div class="line"> nTimeCount--;</div><div class="line"> } <span class="keyword">else</span> {</div><div class="line"> clearInterval(timer);</div><div class="line"> timer = <span class="literal">null</span>;</div><div class="line"> <span class="built_in">console</span>.log(<span class="string">'时间到'</span>);</div><div class="line"> }</div><div class="line">}</div><div class="line"><span class="keyword">var</span> timer = setInterval(<span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>{</div><div class="line"> fCountTime();</div><div class="line">}, <span class="number">1000</span>);</div></pre></td></tr></table></figure></p>
<h2 id="存在问题"><a href="#存在问题" class="headerlink" title="存在问题"></a>存在问题</h2><p>在pc上看,这样的实现方法并没有太大的问题,然而到了移动端似乎就会出现下面两个问题。</p>
<ol>
<li>在移动端上,如IOS,当用户拖曳整张页面时,页面是停止渲染工作的,这时候setTimeout和setInterval也会随之暂停,那么当用户拖曳结束时,时间可能就已经延迟了不少。</li>
<li>在一些性能相对已经比较慢的手机上玩一些相对操作比较多、画面更新幅度大的游戏时,如IOS7下的iphone4s,会出现页面卡顿,以导致setTimeout、setInterval触发时间延迟被拖慢的问题。</li>
</ol>
<h2 id="解决方案"><a href="#解决方案" class="headerlink" title="解决方案"></a>解决方案</h2><p>首先解决第一个问题,这个利用简单nTimeCount计数器的方案在setTimeout和setInterval有不可靠(这里指不能保证每一秒执行一次)的风险时,显然是不靠谱的,靠谱的方案还是得根据准确的时间进行判断。以setTimeout为例:<br><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">var</span> nTimeCount = <span class="number">15</span>;</div><div class="line"><span class="keyword">var</span> nStartTime = <span class="number">0</span>;</div><div class="line"><span class="keyword">var</span> nEndTime = <span class="number">0</span>;</div><div class="line"><span class="comment">// setTimeout</span></div><div class="line"><span class="function"><span class="keyword">function</span> <span class="title">fCountTime</span>(<span class="params"></span>) </span>{</div><div class="line"> <span class="keyword">if</span> (<span class="number">0</span> == nStartTime) {</div><div class="line"> nStartTime = +<span class="keyword">new</span> <span class="built_in">Date</span>(); <span class="comment">// 初始化记下开始计时的时间戳</span></div><div class="line"> }</div><div class="line"> nEndTime = +<span class="keyword">new</span> <span class="built_in">Date</span>(); <span class="comment">// 初始化记下开始计时的时间戳</span></div><div class="line"> nPassSec = <span class="built_in">Math</span>.floor((nEndTime - nStartTime) / <span class="number">1000</span>); <span class="comment">// 时间戳相减获得pass的毫秒数, /1000向下取整获得过去的秒数</span></div><div class="line"> nTimeCount -= nPassSec; <span class="comment">// 时间总数减去pass的秒数获得所剩的时间</span></div><div class="line"> <span class="keyword">if</span> (nTimeCount > <span class="number">0</span>) {</div><div class="line"> setTimeout(<span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>{</div><div class="line"> fCountTime();</div><div class="line"> }, <span class="number">1000</span>);</div><div class="line"> } <span class="keyword">else</span> {</div><div class="line"> <span class="built_in">console</span>.log(<span class="string">'时间到'</span>);</div><div class="line"> }</div><div class="line">}</div><div class="line">fCountTime();</div></pre></td></tr></table></figure></p>
<p>这样似乎可以保证时间至少相对靠谱了,那么来考虑第二个问题——性能问题。<br>当然,这时候可以适当降低setTimout的时间片来减少性能对计时的影响,但似乎<strong>HTML5已经推出了更好的解决方案</strong>。</p>
<h2 id="这才是重点"><a href="#这才是重点" class="headerlink" title="这才是重点"></a>这才是重点</h2><p>这里要推出的方法是HTML5中的新方法:<br>requestAnimationFrame, 它可以在浏览器每渲染一帧后立即执行回调,而不会像setTimeout一样有延迟风险。<br>现代浏览器在正常情况下每秒会渲染60帧画面,也就是会执行60次requestAnimationFrame的回调,你可以把它等价为一个16.7毫秒的setTimeout模式。<br>下面是一个兼容性的解决方案,并定义了一个计时器,<br>可以满足每一秒、每一帧都有对应回调可以调用,同时还有暂停、继续计时的功能:<br><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div><div class="line">62</div><div class="line">63</div><div class="line">64</div><div class="line">65</div><div class="line">66</div><div class="line">67</div><div class="line">68</div><div class="line">69</div><div class="line">70</div><div class="line">71</div></pre></td><td class="code"><pre><div class="line"><span class="comment">// 先将api进行兼容性封装</span></div><div class="line">(<span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>{</div><div class="line"> <span class="keyword">var</span> lastTime = <span class="number">0</span>;</div><div class="line"> <span class="keyword">var</span> vendors = [<span class="string">'webkit'</span>, <span class="string">'moz'</span>];</div><div class="line"> <span class="keyword">for</span>(<span class="keyword">var</span> x = <span class="number">0</span>; x < vendors.length && !<span class="built_in">window</span>.requestAnimationFrame; ++x) {</div><div class="line"> <span class="built_in">window</span>.requestAnimationFrame = <span class="built_in">window</span>[vendors[x] + <span class="string">'RequestAnimationFrame'</span>];</div><div class="line"> <span class="built_in">window</span>.cancelAnimationFrame = <span class="built_in">window</span>[vendors[x] + <span class="string">'CancelAnimationFrame'</span>] || <span class="comment">// Webkit中此取消方法的名字变了</span></div><div class="line"> <span class="built_in">window</span>[vendors[x] + <span class="string">'CancelRequestAnimationFrame'</span>];</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="keyword">if</span> (!<span class="built_in">window</span>.requestAnimationFrame) {</div><div class="line"> <span class="built_in">window</span>.requestAnimationFrame = <span class="function"><span class="keyword">function</span>(<span class="params">callback, element</span>) </span>{</div><div class="line"> <span class="keyword">var</span> currTime = <span class="keyword">new</span> <span class="built_in">Date</span>().getTime();</div><div class="line"> <span class="keyword">var</span> timeToCall = <span class="built_in">Math</span>.max(<span class="number">0</span>, <span class="number">16.7</span> - (currTime - lastTime));</div><div class="line"> <span class="keyword">var</span> id = <span class="built_in">window</span>.setTimeout(<span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>{</div><div class="line"> callback(currTime + timeToCall);</div><div class="line"> }, timeToCall);</div><div class="line"> lastTime = currTime + timeToCall;</div><div class="line"> <span class="keyword">return</span> id;</div><div class="line"> };</div><div class="line"> }</div><div class="line"> <span class="keyword">if</span> (!<span class="built_in">window</span>.cancelAnimationFrame) {</div><div class="line"> <span class="built_in">window</span>.cancelAnimationFrame = <span class="function"><span class="keyword">function</span>(<span class="params">id</span>) </span>{</div><div class="line"> clearTimeout(id);</div><div class="line"> };</div><div class="line"> }</div><div class="line">}());</div><div class="line"></div><div class="line"><span class="comment">// 定义一个计时器对象</span></div><div class="line"><span class="keyword">var</span> _timeCount = {</div><div class="line"> <span class="attr">restTime</span>: <span class="number">0</span></div><div class="line">, <span class="attr">totalTime</span>: <span class="number">0</span></div><div class="line">, <span class="attr">startTime</span>: <span class="number">0</span></div><div class="line">, <span class="attr">dormant</span>: <span class="literal">false</span></div><div class="line">, <span class="attr">count</span>: <span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>{</div><div class="line"> <span class="keyword">var</span> self = _timeCount;</div><div class="line"> <span class="keyword">if</span>(self.dormant) <span class="keyword">return</span>;</div><div class="line"> <span class="keyword">var</span> cur = +<span class="keyword">new</span> <span class="built_in">Date</span>();</div><div class="line"> <span class="keyword">var</span> s = self.totalTime - <span class="built_in">Math</span>.floor((cur - self.startTime)/<span class="number">1000</span>);</div><div class="line"> <span class="keyword">if</span>(s != self.restTime){</div><div class="line"> self.restTime--;</div><div class="line"> self.secPass();</div><div class="line"> }</div><div class="line"> <span class="keyword">if</span>(self.restTime != <span class="number">0</span>){</div><div class="line"> requestAnimationFrame(_timeCount.inter);</div><div class="line"> }<span class="keyword">else</span>{</div><div class="line"> _timeCount.finish();</div><div class="line"> }</div><div class="line"> }</div><div class="line">, <span class="attr">inter</span>: <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>{</div><div class="line"> <span class="comment">// 每帧执行的回调</span></div><div class="line"> _timeCount.count();</div><div class="line"> }</div><div class="line">, <span class="attr">secPass</span>: <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>{</div><div class="line"> <span class="comment">// 每秒执行的回调</span></div><div class="line"> }</div><div class="line">, <span class="attr">pause</span>: <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>{</div><div class="line"> <span class="comment">// 暂停</span></div><div class="line"> <span class="keyword">this</span>.dormant = <span class="literal">true</span>;</div><div class="line"> <span class="keyword">this</span>.totalTime = <span class="keyword">this</span>.restTime;</div><div class="line"> }</div><div class="line">, <span class="attr">keepOn</span>: <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>{</div><div class="line"> <span class="comment">// 继续计时</span></div><div class="line"> <span class="keyword">this</span>.startTime = +<span class="keyword">new</span> <span class="built_in">Date</span>();</div><div class="line"> <span class="keyword">this</span>.dormant = <span class="literal">false</span>;</div><div class="line"> <span class="keyword">this</span>.count();</div><div class="line"> }</div><div class="line">, <span class="attr">finish</span>: <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>{</div><div class="line"> <span class="comment">// 时间到</span></div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure></p>
<p>然而,网上有一些大神也指出,requestAnimationFrame的性能其实并没有比setTimeout高到哪里去,甚至还不如后者,不过,年轻人嘛,不就应该多多尝试新事物吗?</p>
]]></content>
<summary type="html">
<p>在做HTML5游戏或者单页应用时我们常常需要使用到计时器模块,比如游戏中的倒计时功能。</p>
</summary>
</entry>
</feed>