-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathatom.xml
367 lines (212 loc) · 408 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
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>找试卷</title>
<link href="/atom.xml" rel="self"/>
<link href="http://yoursite.com/"/>
<updated>2021-07-13T07:43:41.720Z</updated>
<id>http://yoursite.com/</id>
<author>
<name>zhaoShijuan</name>
</author>
<generator uri="http://hexo.io/">Hexo</generator>
<entry>
<title>css选择器世界</title>
<link href="http://yoursite.com/2021/07/13/css%E9%80%89%E6%8B%A9%E5%99%A8%E4%B8%96%E7%95%8C/"/>
<id>http://yoursite.com/2021/07/13/css选择器世界/</id>
<published>2021-07-13T07:32:33.000Z</published>
<updated>2021-07-13T07:43:41.720Z</updated>
<content type="html"><![CDATA[<p>一听到张鑫旭发了一本书,名为《css选择器世界》。作为他《css世界》的读者,对他的这本新书一直念念不忘,直到今年上半年,才入手了这本新书。《css选择器世界》这本书篇幅少的让我有点意外,但是坚信“浓缩就是精华”的我,还是满怀期待地打开学习了。读完这本书后,内容都知道,但是可能一些巧妙的使用以及小的细节点是我以前所没有注意的。总之,这本书比较推荐给初中级的读者,如果你是一位css能力很棒的开发话,推荐你快速阅读即可。下面我只挑出一些常用的进行阐述。</p><a id="more"></a><h4 id="1-后代选择符-空格"><a href="#1-后代选择符-空格" class="headerlink" title="1. 后代选择符 - 空格"></a>1. 后代选择符 - 空格</h4><p> 选择后代中符合的元素来使用当前的CSS样式规则。</p><ul><li><p>错误认识</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">style</span>></span><span class="undefined"></span></span><br><span class="line"><span class="undefined"> .fd-red p {</span></span><br><span class="line"><span class="undefined"> color: red;</span></span><br><span class="line"><span class="undefined"> }</span></span><br><span class="line"><span class="undefined"> .fd-blue p {</span></span><br><span class="line"><span class="undefined"> color: blue;</span></span><br><span class="line"><span class="undefined"> }</span></span><br><span class="line"><span class="undefined"></span><span class="tag"></<span class="name">style</span>></span></span><br><span class="line"><span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"fd-red"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"fd-blue"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">p</span>></span>1颜色<span class="tag"></<span class="name">p</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">div</span>></span></span><br><span class="line"><span class="tag"></<span class="name">div</span>></span></span><br><span class="line"><span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"fd-blue"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"fd-red"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">p</span>></span>2颜色<span class="tag"></<span class="name">p</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">div</span>></span></span><br><span class="line"><span class="tag"></<span class="name">div</span>></span></span><br></pre></td></tr></table></figure><p>当包含后代选择符的时候,整个选择器的优先级与祖先元素的DOM层级没有任何关系,这时需要看落地元素的优先级。上述案例中,落地元素是最后p元素,两个p元素彼此分离,没有嵌套关系,DOM层级平行,没有先后;再看选择器优先级:<code>.fd-red p</code>与<code>.fd-blue p</code>是一个类选择器(10) + 标签选择器(1),选择器优先级的计算值也是一样的。这时就需要看在CSS文件中的位置,后面的比前面的优先。</p><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-pseudo">:not(.fd-red)</span> <span class="selector-tag">p</span> {<span class="attribute">color</span>: blue;}</span><br><span class="line"><span class="selector-class">.fd-red</span> <span class="selector-tag">p</span> {<span class="attribute">color</span>: red;}</span><br></pre></td></tr></table></figure><p>:not()本身的优先级为0</p><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-class">.fd-blue</span><span class="selector-class">.fd-blue</span> <span class="selector-tag">p</span> {<span class="attribute">color</span>: blue;}</span><br><span class="line"><span class="selector-class">.fd-red</span> <span class="selector-tag">p</span> {<span class="attribute">color</span>: red;}</span><br></pre></td></tr></table></figure></li></ul><ul><li><p>JS中后端选择符错误认识</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"fd-wrap"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"fd-first"</span>></span>第一<span class="tag"></<span class="name">div</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"fd-outer"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"fd-inner"</span>></span>内外开花<span class="tag"></<span class="name">div</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">div</span>></span></span><br><span class="line"><span class="tag"></<span class="name">div</span>></span></span><br><span class="line"><span class="tag"><<span class="name">script</span>></span><span class="undefined"></span></span><br><span class="line"><span class="javascript"> <span class="keyword">var</span> len1 = <span class="built_in">document</span>.querySelectorAll(<span class="string">'.fd-wrap div div'</span>).length;</span></span><br><span class="line"><span class="javascript"> <span class="keyword">var</span> len2 = <span class="built_in">document</span>.querySelector(<span class="string">'.fd-wrap'</span>).querySelectorAll(<span class="string">'div div'</span>).length;</span></span><br><span class="line"><span class="undefined"></span><span class="tag"></<span class="name">script</span>></span></span><br></pre></td></tr></table></figure><p><strong>CSS选择器是独立于整个页面的</strong></p><blockquote><p>想修改querySelectorAll后面的选择器不是全局匹配,可以使用:scope伪类,其作用就是让CSS选择器的作用域局限在某一范围内。</p></blockquote><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">document</span>.querySelector(<span class="string">'.fd-wrap'</span>).querySelectorAll(<span class="string">':scope div div'</span>).length;</span><br></pre></td></tr></table></figure></li></ul><h4 id="2-子选择符-箭头-gt"><a href="#2-子选择符-箭头-gt" class="headerlink" title="2. 子选择符 - 箭头>"></a>2. 子选择符 - 箭头></h4><p> 子选择器只会匹配第一代子元素。后代选择器会匹配所有子元素。</p><figure class="highlight"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><<span class="selector-tag">style</span>></span><br><span class="line"> <span class="selector-tag">ol</span> <span class="selector-tag">li</span> {</span><br><span class="line"> <span class="attribute">color</span>: red;</span><br><span class="line"> <span class="attribute">text-decoration</span>: underline;</span><br><span class="line"> }</span><br><span class="line"> <span class="selector-tag">ol</span> > <span class="selector-tag">li</span> {</span><br><span class="line"> <span class="attribute">color</span>: blue;</span><br><span class="line"> <span class="attribute">text-decoration</span>: underline wavy;</span><br><span class="line"> }</span><br><span class="line"></style></span><br><span class="line"><<span class="selector-tag">ol</span>></span><br><span class="line"> <li>1颜色</li></span><br><span class="line"> <<span class="selector-tag">li</span>>2颜色</span><br><span class="line"> <<span class="selector-tag">ul</span>></span><br><span class="line"> <li>2-1颜色</li></span><br><span class="line"> <li>2-2颜色</li></span><br><span class="line"> </ul></span><br><span class="line"> </li></span><br><span class="line"> <li>3颜色</li></span><br><span class="line"></ol></span><br></pre></td></tr></table></figure><p><img src="子选择符.png" alt="子选择符"></p><p> 子选择器的匹配性能优于后代选择器,但是性能优势的价值有限。(当没有达到一定量级的时候,此优势不能作为选择符技术选型的优先条件)</p><p> <strong>使用子选择符的主要目的是避免冲突。</strong></p><ul><li>适合子选择符的场景<ul><li>状态类名控制</li><li>标签受限</li><li>层级位置与动态判断</li></ul></li></ul><blockquote><p>子选择符通过限制关系使得结构更加稳固,但同时也失去了弹性和变化,需要慎重使用。</p></blockquote><h4 id="3-相邻兄弟选择符-加号"><a href="#3-相邻兄弟选择符-加号" class="headerlink" title="3. 相邻兄弟选择符 - 加号+"></a>3. 相邻兄弟选择符 - 加号+</h4><p> 用于选择相邻的兄弟元素,但只能选择后面一个兄弟。</p> <figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">style</span>></span><span class="undefined"></span></span><br><span class="line"><span class="css"> <span class="selector-class">.fd-li</span> + <span class="selector-tag">li</span> {</span></span><br><span class="line"><span class="undefined"> color: red;</span></span><br><span class="line"><span class="undefined"> }</span></span><br><span class="line"><span class="undefined"></span><span class="tag"></<span class="name">style</span>></span></span><br><span class="line"><span class="tag"><<span class="name">ol</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">li</span>></span>颜色<span class="tag"></<span class="name">li</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">li</span> <span class="attr">class</span>=<span class="string">"fd-li"</span>></span>颜色<span class="tag"></<span class="name">li</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">li</span>></span>颜色<span class="tag"></<span class="name">li</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">li</span>></span>颜色<span class="tag"></<span class="name">li</span>></span></span><br><span class="line"><span class="tag"></<span class="name">ol</span>></span></span><br></pre></td></tr></table></figure><p><code>.fd-li + li</code>选择的是.fd-li元素后面一个相邻且标签是li的元素。</p><ul><li><p>文本节点与相邻兄弟选择符</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">style</span>></span><span class="undefined"></span></span><br><span class="line"><span class="css"> <span class="selector-class">.fd-li</span> + <span class="selector-tag">li</span> {</span></span><br><span class="line"><span class="undefined"> color: red;</span></span><br><span class="line"><span class="undefined"> }</span></span><br><span class="line"><span class="undefined"></span><span class="tag"></<span class="name">style</span>></span></span><br><span class="line"><span class="tag"><<span class="name">ol</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">li</span>></span>颜色<span class="tag"></<span class="name">li</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">li</span> <span class="attr">class</span>=<span class="string">"fd-li"</span>></span>颜色<span class="tag"></<span class="name">li</span>></span></span><br><span class="line"> 这是一段文本节点,间隔开li</span><br><span class="line"> <span class="tag"><<span class="name">li</span>></span>颜色<span class="tag"></<span class="name">li</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">li</span>></span>颜色<span class="tag"></<span class="name">li</span>></span></span><br><span class="line"><span class="tag"></<span class="name">ol</span>></span></span><br></pre></td></tr></table></figure><p><strong>兄弟选择符忽略文本节点</strong></p></li></ul><ul><li><p>注释节点与相邻兄弟选择符</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">style</span>></span><span class="undefined"></span></span><br><span class="line"><span class="css"> <span class="selector-class">.fd-li</span> + <span class="selector-tag">li</span> {</span></span><br><span class="line"><span class="undefined"> color: red;</span></span><br><span class="line"><span class="undefined"> }</span></span><br><span class="line"><span class="undefined"></span><span class="tag"></<span class="name">style</span>></span></span><br><span class="line"><span class="tag"><<span class="name">ol</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">li</span>></span>颜色<span class="tag"></<span class="name">li</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">li</span> <span class="attr">class</span>=<span class="string">"fd-li"</span>></span>颜色<span class="tag"></<span class="name">li</span>></span></span><br><span class="line"> <span class="comment"><!-- 这是一段注释节点,间隔开li --></span></span><br><span class="line"> <span class="tag"><<span class="name">li</span>></span>颜色<span class="tag"></<span class="name">li</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">li</span>></span>颜色<span class="tag"></<span class="name">li</span>></span></span><br><span class="line"><span class="tag"></<span class="name">ol</span>></span></span><br></pre></td></tr></table></figure><p><strong>兄弟选择符忽略注释节点</strong></p></li></ul><ul><li><p>:first-child效果</p><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-class">.fd-li</span><span class="selector-pseudo">:not(</span><span class="selector-pseudo">:first-child)</span> {<span class="attribute">color</span>: blue;}</span><br></pre></td></tr></table></figure><blockquote><p>使用相邻兄弟选择符实现</p></blockquote><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-class">.fd-li</span> + <span class="selector-class">.fd-li</span> {<span class="attribute">color</span>: blue;}</span><br></pre></td></tr></table></figure></li></ul><h4 id="4-随后兄弟选择符-波浪号"><a href="#4-随后兄弟选择符-波浪号" class="headerlink" title="4. 随后兄弟选择符 - 波浪号~"></a>4. 随后兄弟选择符 - 波浪号~</h4><p> 随后兄弟选择符会匹配后面的所有兄弟元素,而相邻兄弟选择符只会匹配后面的第一个兄弟元素。</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">style</span>></span><span class="undefined"></span></span><br><span class="line"><span class="css"> <span class="selector-class">.fd-p</span> ~ <span class="selector-class">.fd-li</span> {</span></span><br><span class="line"><span class="undefined"> color: red;</span></span><br><span class="line"><span class="undefined"> text-decoration: underline;</span></span><br><span class="line"><span class="undefined"> }</span></span><br><span class="line"><span class="css"> <span class="selector-class">.fd-p</span> + <span class="selector-class">.fd-li</span> {</span></span><br><span class="line"><span class="undefined"> text-decoration: underline wavy;</span></span><br><span class="line"><span class="undefined"> }</span></span><br><span class="line"><span class="undefined"></span><span class="tag"></<span class="name">style</span>></span></span><br><span class="line"><span class="tag"><<span class="name">li</span> <span class="attr">class</span>=<span class="string">"fd-li"</span>></span>1列表<span class="tag"></<span class="name">li</span>></span></span><br><span class="line"><span class="tag"><<span class="name">p</span> <span class="attr">class</span>=<span class="string">"fd-p"</span>></span>标题文本<span class="tag"></<span class="name">p</span>></span></span><br><span class="line"><span class="tag"><<span class="name">li</span> <span class="attr">class</span>=<span class="string">"fd-li"</span>></span>2列表<span class="tag"></<span class="name">li</span>></span></span><br><span class="line"><span class="tag"><<span class="name">li</span> <span class="attr">class</span>=<span class="string">"fd-li"</span>></span>3列表<span class="tag"></<span class="name">li</span>></span></span><br></pre></td></tr></table></figure><p><strong>随后兄弟选择符与相邻兄弟选择符一致,会忽略文本节点与注释节点</strong></p><h4 id="5-列选择符-双管道"><a href="#5-列选择符-双管道" class="headerlink" title="5. 列选择符 - 双管道||"></a>5. 列选择符 - 双管道||</h4><p> 列选择器,目前浏览器的兼容性还不能让其在实际项目中得到应用。</p><p> table布局和grid布局中有列的概念。如果想要控制列的样式,有两种方案:</p><pre><code>1. 借助:nth-col()或者:nth-last-col()伪类,目前浏览器还未支持这两个伪类;2. 借助原生table布局中的colgroup和col原生来实现</code></pre><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">// 属于的含义。选择所有属于col.fd-col-demo的td元素,哪怕这个td元素横跨多列。</span><br><span class="line">col.fd-col-demo || td {</span><br><span class="line"> <span class="selector-tag">background-color</span>: <span class="selector-tag">greenyellow</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><blockquote><p>为何没有前面兄弟选择符或者父元素选择符</p></blockquote><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">浏览器解析HTML文档是从前往后,由外及里进行,所以页面总是先出现头部再出现主体内容的。</span><br><span class="line">如果CSS支持前面兄弟选择符或者父元素选择符,那就必须要等要页面所有子元素加载完毕后才能渲染HTML文档。</span><br><span class="line">“前面兄弟选择符”:后面的DOM元素影响前面的DOM元素,如果后面的元素还没被加载并处理,那么又如何印象前面元素的样式呢。</span><br><span class="line">如果浏览器支持这样的选择符,那么网页呈现速度会减慢;或者会出现重排、重绘。</span><br></pre></td></tr></table></figure><blockquote><p>如何实现前面兄弟选择符效果</p></blockquote><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">兄弟选择符只能选择后面元素,其中“后面”仅仅指代码层面的后面,而不是视觉层面的后面。如果实现“前面兄弟选择符”效果,可以把“前面元素”的相关代码依然放在后面,但是视觉上将它呈现在前面。</span><br></pre></td></tr></table></figure><ul><li>flex布局</li><li>float浮动</li><li>absolute绝对定位</li></ul><p><a href="https://demo.cssworld.cn/selector/4/4-2.php" target="_blank" rel="noopener">实现代码参考</a></p><h3 id="元素属性选择器"><a href="#元素属性选择器" class="headerlink" title="元素属性选择器"></a>元素属性选择器</h3><p> 元素选择器包含两类:标签选择器、通配符选择器。</p><p> 属性选择器:id选择器、类选择器、属性值选择器。</p><h4 id="1-元素选择器"><a href="#1-元素选择器" class="headerlink" title="1. 元素选择器"></a>1. 元素选择器</h4><ul><li><p>元素选择器是唯一不能重复自身的选择器</p><p>由于元素选择器不能重复自身来提高优先级,可以通过其他方法来提高优先级:</p><ol><li>借助html、body标签来提高优先级 <code>body foo {}</code></li><li>借助:not()伪类,括号里是任意其他不一样的标签名即可:<code>p:not(a) {}</code></li></ol></li><li><p>级联使用的时候元素选择器必须写在最前面</p></li><li><p>特殊标签选择器:通配符选择器</p></li></ul><h4 id="2-属性选择器"><a href="#2-属性选择器" class="headerlink" title="2. 属性选择器"></a>2. 属性选择器</h4><p> 属性选择器:元素上的属性、以及属性值</p><ul><li><p>[attr] 匹配包含指定的属性元素</p><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-attr">[disabled]</span> {}</span><br></pre></td></tr></table></figure></li></ul><ul><li><p>[attr=’value’] 属性值完全匹配选择器</p><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-attr">[type='radio']</span>{}</span><br></pre></td></tr></table></figure></li></ul><ul><li><p>[attr~=’value’] 属性值单词完全匹配选择器</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">style</span>></span><span class="undefined"></span></span><br><span class="line"><span class="css"> <span class="selector-attr">[rel~='nofllow']</span> {}</span></span><br><span class="line"><span class="undefined"></span><span class="tag"></<span class="name">style</span>></span></span><br><span class="line"><span class="tag"><<span class="name">a</span> <span class="attr">rel</span>=<span class="string">"nofllow noopener"</span>></span>链接<span class="tag"></<span class="name">a</span>></span></span><br></pre></td></tr></table></figure></li></ul><ul><li><p>[attr|=’value’] 属性值其实片段完全匹配选择器,表示具有attr属性的元素,其值要么正好是val,要么以val外加短横线-开头,|=用于连接需要匹配的属性和属性内容</p><figure class="highlight"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><<span class="selector-tag">style</span>></span><br><span class="line"><span class="selector-class">.fd-div</span><span class="selector-attr">[mytype]</span> {</span><br><span class="line"> <span class="attribute">background-color</span>: hotpink;</span><br><span class="line">}</span><br><span class="line"><span class="selector-class">.fd-div</span><span class="selector-attr">[mytype='test']</span> {</span><br><span class="line"> <span class="attribute">background-color</span>: khaki;</span><br><span class="line">}</span><br><span class="line"><span class="selector-class">.fd-div</span><span class="selector-attr">[data-align~='top']</span> {</span><br><span class="line"> <span class="attribute">background-color</span>: lightseagreen;</span><br><span class="line">}</span><br><span class="line"><span class="selector-class">.fd-div</span><span class="selector-attr">[class|='fd-button']</span> {</span><br><span class="line"> <span class="attribute">background-color</span>: lightsteelblue;</span><br><span class="line">}</span><br><span class="line"></style></span><br><span class="line"><<span class="selector-tag">body</span>></span><br><span class="line"> <div class="fd-div" mytype>[attr]</div></span><br><span class="line"> <div class="fd-div" mytype='test'>[attr='val']</div></span><br><span class="line"> <div class="fd-div" data-align="top left">[attr~='val']</div></span><br><span class="line"> <div class="fd-button-sure fd-div">[attr|='val']</div></span><br><span class="line"> <div class="fd-div fd-button-cancel">[attr|='val']</div></span><br><span class="line"></body></span><br></pre></td></tr></table></figure></li></ul><ul><li><p>[attr^=’val’] 匹配attr属性值以字符val开头元素</p></li><li><p>[attr$=’val’] 匹配attr属性值以字符val结尾元素</p></li><li><p>[attr*=’val’] 匹配attr属性值包含字符val的元素</p></li></ul><p> <strong>忽略大小写的正则匹配运算符:[attr~=’val’ i]</strong></p><h4 id="搜索过滤技术"><a href="#搜索过滤技术" class="headerlink" title="搜索过滤技术"></a>搜索过滤技术</h4><blockquote><p>利用[data-city-name*=’cityname’]</p></blockquote><h3 id="树结构伪类"><a href="#树结构伪类" class="headerlink" title="树结构伪类"></a>树结构伪类</h3><h4 id="1-root"><a href="#1-root" class="headerlink" title="1. :root"></a>1. :root</h4><p> 表示的就是html元素</p><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-pseudo">:root.fd-page</span> {<span class="attribute">background-color</span>: red;}</span><br></pre></td></tr></table></figure><blockquote><p>由于:root只兼容IE9+,因此一般会作为IE8、IE9浏览器兼容hack</p></blockquote><h4 id="2-empty"><a href="#2-empty" class="headerlink" title="2. :empty"></a>2. :empty</h4><p> 匹配空标签元素</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">style</span>></span><span class="undefined"></span></span><br><span class="line"><span class="css"><span class="selector-class">.fd-empty</span><span class="selector-pseudo">:empty</span> {</span></span><br><span class="line"><span class="undefined">width: 100px;</span></span><br><span class="line"><span class="undefined">height: 100px;</span></span><br><span class="line"><span class="undefined">border: 10px dashed;</span></span><br><span class="line"><span class="undefined">}</span></span><br><span class="line"><span class="undefined"></span><span class="tag"></<span class="name">style</span>></span></span><br><span class="line"><span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"fd-empty"</span>></span><span class="tag"></<span class="name">div</span>></span></span><br></pre></td></tr></table></figure><p><strong>如果元素中含有空格、换行,则:empty不会对其进行匹配。</strong></p><p><strong>::after、::before伪元素不会影响到:empty伪类的匹配。</strong></p><ul><li><p>应用</p><ul><li><p>隐藏空元素</p></li><li><p>字段缺失</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">style</span>></span><span class="undefined"></span></span><br><span class="line"><span class="css"> <span class="selector-class">.fd-form-item</span> {</span></span><br><span class="line"><span class="undefined"> position: relative;</span></span><br><span class="line"><span class="undefined"> padding-left: 80px;</span></span><br><span class="line"><span class="undefined"> color: lightgreen;</span></span><br><span class="line"><span class="undefined"> font-size: 16px;</span></span><br><span class="line"><span class="undefined"> line-height: 25px;</span></span><br><span class="line"><span class="undefined"> }</span></span><br><span class="line"><span class="css"> <span class="selector-class">.fd-form-label</span> {</span></span><br><span class="line"><span class="undefined"> position: absolute;</span></span><br><span class="line"><span class="undefined"> top: 0;</span></span><br><span class="line"><span class="undefined"> left: 0;</span></span><br><span class="line"><span class="undefined"> width: 80px;</span></span><br><span class="line"><span class="undefined"> text-align: right;</span></span><br><span class="line"><span class="css"> <span class="selector-tag">color</span>: <span class="selector-id">#333</span>;</span></span><br><span class="line"><span class="undefined"> }</span></span><br><span class="line"><span class="css"> <span class="selector-class">.fd-form-val</span> {</span></span><br><span class="line"><span class="undefined"> display: inline-block;</span></span><br><span class="line"><span class="undefined"> min-width: 200px;</span></span><br><span class="line"><span class="undefined"> height: 100%;</span></span><br><span class="line"><span class="undefined"> }</span></span><br><span class="line"><span class="css"> <span class="selector-class">.fd-form-val</span><span class="selector-pseudo">:empty</span><span class="selector-pseudo">::before</span> {</span></span><br><span class="line"><span class="undefined"> content: '暂无';</span></span><br><span class="line"><span class="undefined"> color: red;</span></span><br><span class="line"><span class="undefined"> }</span></span><br><span class="line"><span class="undefined"></span><span class="tag"></<span class="name">style</span>></span></span><br><span class="line"><span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"fd-form"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"fd-form-item"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">label</span> <span class="attr">class</span>=<span class="string">"fd-form-label"</span>></span>姓名:<span class="tag"></<span class="name">label</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">span</span> <span class="attr">class</span>=<span class="string">"fd-form-val"</span>></span>赵士娟<span class="tag"></<span class="name">span</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">div</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"fd-form-item"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">label</span> <span class="attr">class</span>=<span class="string">"fd-form-label"</span>></span>地址:<span class="tag"></<span class="name">label</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">span</span> <span class="attr">class</span>=<span class="string">"fd-form-val"</span>></span><span class="tag"></<span class="name">span</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">div</span>></span></span><br><span class="line"><span class="tag"></<span class="name">div</span>></span></span><br></pre></td></tr></table></figure></li></ul></li></ul><h4 id="3-子索引伪类"><a href="#3-子索引伪类" class="headerlink" title="3. 子索引伪类"></a>3. 子索引伪类</h4><ul><li><p>:first-child、:last-child</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">style</span>></span><span class="undefined"></span></span><br><span class="line"><span class="css"> <span class="selector-class">.fd-child</span><span class="selector-pseudo">:first-child</span> {</span></span><br><span class="line"><span class="undefined"> color: red;</span></span><br><span class="line"><span class="undefined"> }</span></span><br><span class="line"><span class="undefined"></span><span class="tag"></<span class="name">style</span>></span></span><br><span class="line"><span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"fd-parent"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">p</span>></span>1<span class="tag"></<span class="name">p</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">li</span> <span class="attr">class</span>=<span class="string">"fd-child"</span>></span>2<span class="tag"></<span class="name">li</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">li</span> <span class="attr">class</span>=<span class="string">"fd-child"</span>></span>3<span class="tag"></<span class="name">li</span>></span></span><br><span class="line"><span class="tag"></<span class="name">div</span>></span></span><br></pre></td></tr></table></figure><p>匹配满足:是第一个/最后一个元素同时选择器也匹配的</p></li></ul><ul><li><p>:only-child </p><p>匹配没有任何兄弟元素的元素,忽略前后文本内容。</p><p><a href="https://demo.cssworld.cn/selector/10/3-1.php" target="_blank" rel="noopener">应用案例</a></p></li></ul><ul><li><p>:nth-child、:nth-last-child</p><ul><li><p>关键字形式:odd/even表示奇数个/偶数个</p></li><li><p>函数符号形式:An+B【n从0开始】</p><p>odd = 2n + 1,even = 2n</p><p>:nth-child(-n + 3)表示匹配前三个元素</p><p>:nth-child(n + 4):nth-child(-n + 10)表示匹配第4-10个元素</p></li></ul><blockquote><p>应用</p></blockquote><ol><li><p>固定行列样式</p><p><a href="https://demo.cssworld.cn/selector/10/3-2.php" target="_blank" rel="noopener">demo</a></p></li><li><p>动态列表数量匹配</p><p><a href="https://demo.cssworld.cn/selector/10/3-3.php" target="_blank" rel="noopener">demo</a></p></li></ol></li></ul><h4 id="4-匹配类型的子索引伪类"><a href="#4-匹配类型的子索引伪类" class="headerlink" title="4. 匹配类型的子索引伪类"></a>4. 匹配类型的子索引伪类</h4><p> 匹配类型的子索引伪类是在同级列表中相同标签元素之间进行的索引与解析。</p><ul><li><p>:first-of-type、:last-of-type</p><p>匹配同一类型元素的第一个、同一类型元素的最后一个</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">style</span>></span><span class="undefined"></span></span><br><span class="line"><span class="css"> <span class="selector-class">.fd-content</span> > <span class="selector-pseudo">:first-of-type</span> {</span></span><br><span class="line"><span class="undefined"> color: red;</span></span><br><span class="line"><span class="undefined"> }</span></span><br><span class="line"><span class="css"> <span class="selector-class">.fd-content</span> > <span class="selector-pseudo">:last-of-type</span> {</span></span><br><span class="line"><span class="undefined"> color: green;</span></span><br><span class="line"><span class="undefined"> }</span></span><br><span class="line"><span class="undefined"></span><span class="tag"></<span class="name">style</span>></span></span><br><span class="line"><span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"fd-content"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">header</span> <span class="attr">class</span>=<span class="string">"fd-head"</span>></span>标题1<span class="tag"></<span class="name">header</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">p</span> <span class="attr">class</span>=<span class="string">"fd-section"</span>></span>段落1<span class="tag"></<span class="name">p</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">header</span> <span class="attr">class</span>=<span class="string">"fd-head"</span>></span>标题2<span class="tag"></<span class="name">header</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">p</span> <span class="attr">class</span>=<span class="string">"fd-section"</span>></span>段落2<span class="tag"></<span class="name">p</span>></span></span><br><span class="line"><span class="tag"></<span class="name">div</span>></span></span><br></pre></td></tr></table></figure></li></ul><ul><li><p>:only-of-type</p><p>匹配唯一标签类型的元素。匹配:only-child的元素一定匹配:only-of-type,但是匹配:only-of-type的元素不一定匹配:only-child。</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">style</span>></span><span class="undefined"></span></span><br><span class="line"><span class="css"> <span class="selector-class">.fd-content-only</span> > <span class="selector-pseudo">:only-of-type</span> {</span></span><br><span class="line"><span class="undefined"> color: red;</span></span><br><span class="line"><span class="undefined"> }</span></span><br><span class="line"><span class="undefined"></span><span class="tag"></<span class="name">style</span>></span></span><br><span class="line"><span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"fd-content-only"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">header</span> <span class="attr">class</span>=<span class="string">"fd-head"</span>></span>标题1<span class="tag"></<span class="name">header</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">p</span> <span class="attr">class</span>=<span class="string">"fd-section"</span>></span>段落1<span class="tag"></<span class="name">p</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">header</span> <span class="attr">class</span>=<span class="string">"fd-head"</span>></span>标题2<span class="tag"></<span class="name">header</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">p</span> <span class="attr">class</span>=<span class="string">"fd-section"</span>></span>段落2<span class="tag"></<span class="name">p</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">section</span>></span>我是内容主题<span class="tag"></<span class="name">section</span>></span></span><br><span class="line"><span class="tag"></<span class="name">div</span>></span></span><br></pre></td></tr></table></figure></li></ul><ul><li><p>:nth-of-type、:nth-last-of-type</p><p>匹配指定索引的当前标签类型元素。</p><p>与:nth-child一样,也有关键字形式【even/odd】、函数符号形式【An+B】</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">style</span>></span><span class="undefined"></span></span><br><span class="line"><span class="css"> <span class="selector-class">.fd-content-nth</span> > <span class="selector-class">.fd-section</span><span class="selector-pseudo">:nth-of-type(2n)</span> {</span></span><br><span class="line"><span class="undefined"> color: green;</span></span><br><span class="line"><span class="undefined"> }</span></span><br><span class="line"><span class="undefined"></span><span class="tag"></<span class="name">style</span>></span></span><br><span class="line"><span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"fd-content-nth"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">header</span> <span class="attr">class</span>=<span class="string">"fd-head"</span>></span>标题1<span class="tag"></<span class="name">header</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">p</span> <span class="attr">class</span>=<span class="string">"fd-section"</span>></span>段落1<span class="tag"></<span class="name">p</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">header</span> <span class="attr">class</span>=<span class="string">"fd-head"</span>></span>标题2<span class="tag"></<span class="name">header</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">p</span> <span class="attr">class</span>=<span class="string">"fd-section"</span>></span>段落2<span class="tag"></<span class="name">p</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">section</span>></span>我是内容主题<span class="tag"></<span class="name">section</span>></span></span><br><span class="line"><span class="tag"></<span class="name">div</span>></span></span><br></pre></td></tr></table></figure></li></ul><h3 id="逻辑组合伪类"><a href="#逻辑组合伪类" class="headerlink" title="逻辑组合伪类"></a>逻辑组合伪类</h3><h4 id="1-否定伪类-not"><a href="#1-否定伪类-not" class="headerlink" title="1. 否定伪类:not()"></a>1. 否定伪类:not()</h4><p> 如果当前元素与括号中选择器不匹配,则伪类会进行匹配。</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">style</span>></span><span class="undefined"></span></span><br><span class="line"><span class="css"> <span class="selector-class">.fd-content</span> {</span></span><br><span class="line"><span class="undefined"> display: inline-block;</span></span><br><span class="line"><span class="undefined"> padding: 0 10px;</span></span><br><span class="line"><span class="undefined"> height: 30px;</span></span><br><span class="line"><span class="undefined"> background-color: lightgreen;</span></span><br><span class="line"><span class="undefined"> border-radius: 15px;</span></span><br><span class="line"><span class="undefined"> }</span></span><br><span class="line"><span class="css"> <span class="selector-class">.fd-box</span> {</span></span><br><span class="line"><span class="undefined"> display: inline-block;</span></span><br><span class="line"><span class="undefined"> vertical-align: top;</span></span><br><span class="line"><span class="undefined"> padding: 0 10px;</span></span><br><span class="line"><span class="undefined"> height: 100%;</span></span><br><span class="line"><span class="undefined"> line-height: 30px;</span></span><br><span class="line"><span class="undefined"> }</span></span><br><span class="line"><span class="css"> <span class="selector-class">.fd-box</span><span class="selector-pseudo">:not(</span><span class="selector-pseudo">:last-child)</span> {</span></span><br><span class="line"><span class="undefined"> border-right: 1px dashed green;</span></span><br><span class="line"><span class="undefined"> }</span></span><br><span class="line"><span class="undefined"></span><span class="tag"></<span class="name">style</span>></span></span><br><span class="line"><span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"fd-content"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"fd-box"</span>></span>本年<span class="tag"></<span class="name">div</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"fd-box"</span>></span>本季<span class="tag"></<span class="name">div</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"fd-box"</span>></span>本月<span class="tag"></<span class="name">div</span>></span></span><br><span class="line"><span class="tag"></<span class="name">div</span>></span></span><br></pre></td></tr></table></figure><ul><li><p>:not()伪类优先级为0</p><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 优先级就是p选择器优先级 */</span></span><br><span class="line"><span class="selector-pseudo">:not(p)</span>{}</span><br></pre></td></tr></table></figure></li><li><p>:not()伪类可以不断级联</p><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-tag">input</span><span class="selector-pseudo">:not(</span><span class="selector-pseudo">:disabled)</span><span class="selector-pseudo">:not(</span><span class="selector-pseudo">:read-only)</span>{}</span><br></pre></td></tr></table></figure></li><li><p>:not()伪类目前尚未支持多个表达式,也不支持出现选择符</p><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 不支持 */</span></span><br><span class="line"><span class="selector-tag">input</span><span class="selector-pseudo">:not(</span><span class="selector-pseudo">:disabled</span><span class="selector-pseudo">:read-only)</span> {}</span><br><span class="line"><span class="selector-tag">input</span><span class="selector-pseudo">:not(</span><span class="selector-attr">[id]</span><span class="selector-attr">[title]</span>) {}</span><br><span class="line"><span class="selector-tag">input</span><span class="selector-pseudo">:not(p</span><span class="selector-pseudo">:read-only)</span> {}</span><br></pre></td></tr></table></figure></li></ul><h4 id="2-任意匹配伪类-is"><a href="#2-任意匹配伪类-is" class="headerlink" title="2. 任意匹配伪类:is()"></a>2. 任意匹配伪类:is()</h4><p> :is()伪类可以把括号中的选择器依次分配出去,对于复杂的有很多逗号分隔的选择器非常有用。</p><p> :is()伪类本身优先级为0,整个选择器优先级由伪类里面参数优先级最高的那个选择器决定。比如:</p><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 优先级等同于.fd-active p */</span></span><br><span class="line"><span class="selector-pseudo">:is(.fd-active</span>, <span class="selector-tag">section</span>) <span class="selector-tag">p</span> {}</span><br></pre></td></tr></table></figure><p>:is()伪类的作用:<strong>简化选择器</strong></p><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-class">.fd-a</span> > <span class="selector-tag">span</span>,</span><br><span class="line"><span class="selector-class">.fd-b</span> > <span class="selector-tag">span</span>,</span><br><span class="line"><span class="selector-class">.fd-c</span> > <span class="selector-tag">span</span>,</span><br><span class="line"><span class="selector-class">.fd-d</span> > <span class="selector-tag">sapan</span> {</span><br><span class="line"> <span class="attribute">color</span>: red;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>等同于下面:</p><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-pseudo">:is(.fd-a</span>, <span class="selector-class">.fd-b</span>, <span class="selector-class">.fd-c</span>, <span class="selector-class">.fd-d</span>) > <span class="selector-tag">span</span> {<span class="attribute">color</span>: red;}</span><br></pre></td></tr></table></figure><h4 id="3-任意匹配伪类-where"><a href="#3-任意匹配伪类-where" class="headerlink" title="3. 任意匹配伪类:where()"></a>3. 任意匹配伪类:where()</h4><p> :where()伪类和:is()伪类的含义、语法、作用一模一样,唯一区别就是优先级不一样。</p><p> :where()伪类的优先级永远是0,比如:</p><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 优先级等同于 p */</span></span><br><span class="line"><span class="selector-pseudo">:where(.fd-active</span>, <span class="selector-tag">section</span>) <span class="selector-tag">p</span> {}</span><br></pre></td></tr></table></figure><h4 id="4-关联伪类-has"><a href="#4-关联伪类-has" class="headerlink" title="4. 关联伪类:has()"></a>4. 关联伪类:has()</h4><p> <strong>目前没有浏览器支持</strong></p><p> 如果此伪类得到实现,就可以实现类似父选择器、前面兄弟选择器的功能。</p><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 匹配所有包含img标签元素的a元素 */</span></span><br><span class="line"><span class="selector-tag">a</span><span class="selector-pseudo">:has(</span>><span class="selector-tag">img</span>) {}</span><br><span class="line"><span class="comment">/* 匹配后面跟随p标签的header元素 */</span></span><br><span class="line"><span class="selector-tag">header</span><span class="selector-pseudo">:has(+</span> <span class="selector-tag">p</span>) {}</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
<p>一听到张鑫旭发了一本书,名为《css选择器世界》。作为他《css世界》的读者,对他的这本新书一直念念不忘,直到今年上半年,才入手了这本新书。《css选择器世界》这本书篇幅少的让我有点意外,但是坚信“浓缩就是精华”的我,还是满怀期待地打开学习了。读完这本书后,内容都知道,但是可能一些巧妙的使用以及小的细节点是我以前所没有注意的。总之,这本书比较推荐给初中级的读者,如果你是一位css能力很棒的开发话,推荐你快速阅读即可。下面我只挑出一些常用的进行阐述。</p>
</summary>
</entry>
<entry>
<title>VueRouter</title>
<link href="http://yoursite.com/2019/12/14/VueRouter/"/>
<id>http://yoursite.com/2019/12/14/VueRouter/</id>
<published>2019-12-14T06:09:48.000Z</published>
<updated>2019-12-14T06:10:08.004Z</updated>
<content type="html"><![CDATA[<h2 id="VueRouter"><a href="#VueRouter" class="headerlink" title="VueRouter"></a>VueRouter</h2><ol><li><p>在Vue组件中注册VueRouter</p> <figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Vue.use(VueRouter)</span><br></pre></td></tr></table></figure></li><li><p>定义(路由)组件</p><p> 定义创建路由配置信息时所需要用到的组件。</p></li><li><p>创建VueRouter实例,并且配置路由匹配信息以及其他配置信息</p> <figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> router = <span class="keyword">new</span> VueRouter({</span><br><span class="line"> routes: [</span><br><span class="line"> {<span class="attr">path</span>: <span class="string">''</span>, <span class="attr">name</span>: <span class="string">''</span>, <span class="attr">component</span>: componentName}</span><br><span class="line"> ]</span><br><span class="line">})</span><br></pre></td></tr></table></figure></li><li><p>Vue实例中挂载VueRouter实例</p> <figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">new</span> Vue({</span><br><span class="line"> router</span><br><span class="line">})</span><br></pre></td></tr></table></figure></li></ol><h2 id="路由注册"><a href="#路由注册" class="headerlink" title="路由注册"></a>路由注册</h2><h3 id="1-Vue-use-VueRouter"><a href="#1-Vue-use-VueRouter" class="headerlink" title="1. Vue.use(VueRouter)"></a>1. Vue.use(VueRouter)</h3><blockquote><p>只有在new Vue实例时,传入routers配置执行install才是有意义的。</p></blockquote><p>Vue.use方法调用的是VueRouter中的install方法。VueRouter中install方法利用了Vue.mixin混入beforeCreate和destroyed钩子函数。</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line">Vue.mixin({</span><br><span class="line"> beforeCreate () {</span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">this</span>.$options.router !== <span class="literal">undefined</span>) {</span><br><span class="line"> <span class="comment">// 根组件Vue实例</span></span><br><span class="line"> <span class="keyword">this</span>._routerRoot = <span class="keyword">this</span></span><br><span class="line"> <span class="comment">// 注册路由相关信息:$route, $router等</span></span><br><span class="line"> <span class="keyword">this</span>._router = <span class="keyword">this</span>.$options.router</span><br><span class="line"> <span class="comment">// this._router实际是一个VueRouter实例</span></span><br><span class="line"> <span class="keyword">this</span>._router.init(<span class="keyword">this</span>)</span><br><span class="line"> <span class="comment">// 将_route变成一个响应式的</span></span><br><span class="line"> Vue.util.defineReactive(<span class="keyword">this</span>, <span class="string">'_route'</span>, <span class="keyword">this</span>._router.history.current)</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="comment">// 非根组件</span></span><br><span class="line"> <span class="keyword">this</span>._routerRoot = (<span class="keyword">this</span>.$parent || <span class="keyword">this</span>.$parent._routerRoot) || <span class="keyword">this</span></span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// 调用registerInstance方法,此方法会在RouterView组件中使用</span></span><br><span class="line"> registerInstance(<span class="keyword">this</span>, <span class="keyword">this</span>)</span><br><span class="line"> },</span><br><span class="line"> destroyed () {</span><br><span class="line"> <span class="comment">// 销毁路由</span></span><br><span class="line"> registerInstance(<span class="keyword">this</span>)</span><br><span class="line"> }</span><br><span class="line">})</span><br></pre></td></tr></table></figure><p>在Vue原型上挂载了$router, $route属性;注册了全局组件-RouterView和RouterLink;定义路由导航的合并策略-与vue的created钩子函数合并规则一致。</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 挂载$router</span></span><br><span class="line"><span class="built_in">Object</span>.defineProperty(Vue.prototype, <span class="string">'$router'</span>, {</span><br><span class="line"> get () {</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">this</span>._routerRoot._router</span><br><span class="line"> }</span><br><span class="line">})</span><br><span class="line"><span class="comment">// 挂载$route</span></span><br><span class="line"><span class="built_in">Object</span>.defineProperty(Vue.prototype, <span class="string">'$route'</span>, {</span><br><span class="line"> get () {</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">this</span>._routerRoot._route</span><br><span class="line"> }</span><br><span class="line">})</span><br><span class="line"><span class="comment">// 注册全局组件</span></span><br><span class="line">Vue.component(<span class="string">'RouterView'</span>, View)</span><br><span class="line">Vue.component(<span class="string">'RouterLink'</span>, Link)</span><br><span class="line"><span class="comment">// 定义合并策略</span></span><br><span class="line"><span class="keyword">const</span> strats = Vue.config.optionMergeStrategies</span><br><span class="line">strats.beforeRouteEnter = strats.beforeRouteLeave = strats.beforeRouteUpdate = strats.created</span><br></pre></td></tr></table></figure><h4 id="总结:"><a href="#总结:" class="headerlink" title="总结:"></a>总结:</h4><ol><li>Vue编写插件的时候需要提供静态的install方法</li><li>VueRouter的install方法会给每个组件注入beforeCreate和destroyed钩子函数,在beforeCreate进行一些私有属性定义和路由初始化。</li></ol><h3 id="2-VueRouter、路由初始化"><a href="#2-VueRouter、路由初始化" class="headerlink" title="2. VueRouter、路由初始化"></a>2. VueRouter、路由初始化</h3><ol start="3"><li>init方法执行transitionTo方法做路由过渡</li><li>执行router.macth方法,此方法中执行matcher.match</li></ol><h4 id="路由初始化"><a href="#路由初始化" class="headerlink" title="路由初始化"></a>路由初始化</h4><h4 id="1-实例化VueRouter"><a href="#1-实例化VueRouter" class="headerlink" title="1. 实例化VueRouter"></a>1. 实例化VueRouter</h4><p> new VueRouter会进入VueRouter类中的constructor构造器中。构造器接受一个配置项信息options对象,包含了路由配置信息routes,路由模式mode,降级处理fallback等。</p><ul><li>fallback:降级处理,对于路由模式的降级处理,如果不支持history就会降级到hash模式。</li><li>路由模式hash,history,abstract分别对应不同的类HashHistory,Html5History,AbstractHistory。这三个类都继承于history类。</li></ul> <figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">VueRouter</span> </span>{</span><br><span class="line"> <span class="keyword">constructor</span> (options) {</span><br><span class="line"> ...</span><br><span class="line"> <span class="comment">// options.routes就是实例化VueRouter传递参数中的routes路由配置信息</span></span><br><span class="line"> <span class="keyword">this</span>.matcher = createMatcher(options.routes || [], <span class="keyword">this</span>)</span><br><span class="line"> <span class="comment">// ...路由模式配置以及根据路由模式来创建对应的history实例</span></span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p> 创建路由映射表,方便以后根据path或者name查找到想要的record。并且对外提供了addRoutes(routes)方法,方便动态添加routes信息。</p> <figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line">function createMatcher (routes, router) {</span><br><span class="line"> const {pathList, pathMap, nameMap} = createRouteMap(routes)</span><br><span class="line"> </span><br><span class="line"> function addRoutes (routes) {</span><br><span class="line"> createRouteMap(routes, pathList, pathMap, nameMap)</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> // 对外提供一个addRoutes方法,方便自己动态添加routes信息</span><br><span class="line"> return {match, addRoutes}</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">// 创建路由映射表</span><br><span class="line">function createRouteMap (routes, oldPathList, oldPathMap, oladNameMap) {</span><br><span class="line"> const pathList = oldPathList || []</span><br><span class="line"> const pathMap = oldPathMap || Object.create(null)</span><br><span class="line"> const nameMap = oldNameMap || Object.create(null)</span><br><span class="line"> </span><br><span class="line"> // 对路由配置进行一个遍历:添加路由记录信息</span><br><span class="line"> routes.forEach(route => {</span><br><span class="line"> addRouteRecord(pathList, pathMap, nameMap, route)</span><br><span class="line"> })</span><br><span class="line"> </span><br><span class="line"> // 调整通配符优先级,放在结尾【含有通配符的路由应该放在最后】</span><br><span class="line"> for (let i = 0, l = pathList.length; i < l; i++) {</span><br><span class="line"> if (pathList[i] === '*') {</span><br><span class="line"> pathList.push(pathList.splice(i, 1)[0])</span><br><span class="line"> l--</span><br><span class="line"> i--</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> return {pathList, pathMap, nameMap}</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p> 递归实例化VueRouter时传递的路由信息配置routes</p> <figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">addRouteRecord</span> (<span class="params">pathList, pathMap, nameMap, route, parent, matchAs</span>) </span>{</span><br><span class="line"> <span class="comment">// 获取路由配置信息中配置的path和name,path不能为空</span></span><br><span class="line"> <span class="keyword">const</span> {path, name} = route</span><br><span class="line"> <span class="comment">// route.component必须是一个组件</span></span><br><span class="line"> <span class="comment">// routes中配置 编译正则</span></span><br><span class="line"> <span class="keyword">const</span> pathToRegexpoptions = route.pathToRegexpOptions || {}</span><br><span class="line"> </span><br><span class="line"> <span class="comment">// 对路径path的一个处理以及对路径path拼接-parent.path/path</span></span><br><span class="line"> <span class="keyword">const</span> normalizedPath = normalizePath(path, parent, pathToRegexpOptions.strict)</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">const</span> record = {</span><br><span class="line"> path: normalizedPath,</span><br><span class="line"> regex: compileRouteRegex(normalizedPath, pathToRegexpOptions),</span><br><span class="line"> components: route.components || {<span class="attr">default</span>: route.component},</span><br><span class="line"> instance: {},</span><br><span class="line"> name,</span><br><span class="line"> parent,</span><br><span class="line"> matchAs,</span><br><span class="line"> redirect: route.redirect,</span><br><span class="line"> beforeEnter: route.beforeEnter,</span><br><span class="line"> meta: route.meta || {},</span><br><span class="line"> props: route.props == <span class="literal">null</span> ? {} : route.components ? route.props : {<span class="attr">default</span>: route.props}</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// 遍历route中的children,递归添加addRouteRecord</span></span><br><span class="line"> <span class="keyword">if</span> (route.children) {</span><br><span class="line"> route.children.forEach(<span class="function"><span class="params">child</span> =></span> {</span><br><span class="line"> <span class="keyword">const</span> childMatchAs = matchAs ? cleanPath(<span class="string">`<span class="subst">${matchAs}</span>/<span class="subst">${child.path}</span>`</span>) : <span class="literal">undefined</span></span><br><span class="line"> addRouteRecord(pathList, pathMap, nameMap, child, record, childMatchAs)</span><br><span class="line"> })</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="comment">// ... 对alias路由别名的处理</span></span><br><span class="line"> </span><br><span class="line"> <span class="comment">// 递归上面的addRouteRecord后一直到route没有children子节点会执行下面</span></span><br><span class="line"> <span class="comment">// 会先push最底层的children,然后一层一层往上push【因为递归是从外向内,这个方法就会从内向外】</span></span><br><span class="line"> <span class="keyword">if</span> (!pathMap[record.path]) {</span><br><span class="line"> pathList.push(record.path)</span><br><span class="line"> pathMap[record.path] = record</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="comment">// 如果也配置了name,会将record也保存在nameMap中</span></span><br><span class="line"> <span class="keyword">if</span> (name) {</span><br><span class="line"> <span class="keyword">if</span> (!nameMap[name]) {</span><br><span class="line"> nameMap[name] = record</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p> 上面初始化一系列pathList,pathMap以及nameMap后,是为了方面后期的查找match【初始化开始beforeCreate=>init=>transitionTo=>router,match】,详情见下文。</p><h4 id="2-初始化开始:组件初始化阶段的beforeCreate-调用混入的router-init"><a href="#2-初始化开始:组件初始化阶段的beforeCreate-调用混入的router-init" class="headerlink" title="2. 初始化开始:组件初始化阶段的beforeCreate-调用混入的router.init"></a>2. 初始化开始:组件初始化阶段的beforeCreate-调用混入的router.init</h4><p> Vue.use(VueRouter)之后混入了beforeCreate钩子函数执行时,会调用this._route.init(this)也就是调用VueRouter中的init方法。</p> <figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// VueRouter类中,app其实就是一个vue组件实例</span></span><br><span class="line">init (app) {</span><br><span class="line"> <span class="keyword">this</span>.app.push(app)</span><br><span class="line"> <span class="comment">// 确保后面的逻辑只执行一次</span></span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">this</span>.app) <span class="keyword">return</span></span><br><span class="line"> <span class="keyword">this</span>.app = app</span><br><span class="line"> <span class="keyword">const</span> history = <span class="keyword">this</span>.history</span><br><span class="line"> <span class="keyword">if</span> (history <span class="keyword">instanceof</span> HTML5History) {</span><br><span class="line"> <span class="comment">// transitionTo:路由跳转</span></span><br><span class="line"> history.transitionTo(history.getCurrentLocation())</span><br><span class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (history <span class="keyword">instanceof</span> HashHistory) {</span><br><span class="line"> <span class="keyword">const</span> setupHashListener = <span class="function"><span class="params">()</span> =></span> {</span><br><span class="line"> history.setupListeners()</span><br><span class="line"> }</span><br><span class="line"> history.transitionTo(history.getCurrentLocation(), setupHashListener, setupHashListener)</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> history.listen(<span class="function"><span class="params">router</span> =></span> {</span><br><span class="line"> <span class="keyword">this</span>.app.forEach(<span class="function">(<span class="params">app</span>) =></span> {</span><br><span class="line"> app._route = route</span><br><span class="line"> })</span><br><span class="line"> })</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p> transitionTo进行路由跳转</p> <figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">transitionTo (location, onComplete) {</span><br><span class="line"> <span class="comment">// 获取当前路径</span></span><br><span class="line"> <span class="keyword">const</span> route = <span class="keyword">this</span>.router.match(location, <span class="keyword">this</span>.current)</span><br><span class="line"> <span class="keyword">this</span>.confirmTransition(route, () => {...})</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p> 获取当前路径this.router.match指向的是VueRouter中的match函数,match本质指向Matcher中的match函数。此match函数中利用到前面初始化的pathList,pathMap,nameMap数据。</p> <figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// VueRouter类中的match函数</span></span><br><span class="line">match (raawLocation, current, redirectedFrom) {</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">this</span>.matcher.match(raawLocation, current, redirectedFrom)</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p> Matcher中match函数,利用到前面初始化的pathList,pathMap,nameMap数据。此函数的作用:根据传递的location和当前route计算得出当前的路由。</p> <figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Matcher中的match函数</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">match</span> (<span class="params">raw, currentRoute, redirectedFrom</span>) </span>{</span><br><span class="line"> <span class="comment">// 处理当前的路径等信息得到当前的path,query,hash以及_normalized数据信息</span></span><br><span class="line"> <span class="comment">// 或者得到的是name,params,_normalized</span></span><br><span class="line"> <span class="keyword">const</span> location = normalizeLocatin(raw, currentRoute, <span class="literal">false</span>, router)</span><br><span class="line"> <span class="keyword">const</span> {name} = location</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">if</span> (name) {</span><br><span class="line"> <span class="keyword">const</span> record = nameMap[name]</span><br><span class="line"> <span class="keyword">if</span> (!record) <span class="keyword">return</span> _createRoute(<span class="literal">null</span>, location)</span><br><span class="line"> <span class="comment">// 对于params参数进行处理</span></span><br><span class="line"> <span class="keyword">const</span> paramNames = record.regex.keys.filter(<span class="function"><span class="params">key</span> =></span> !key.optional).map(<span class="function"><span class="params">key</span> =></span> key.name)</span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">typeof</span> location.params !== <span class="string">'object'</span>) {</span><br><span class="line"> location.params = {}</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (currentRoute && <span class="keyword">typeof</span> currentRoute.params === <span class="string">'object'</span>) {</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">const</span> key <span class="keyword">in</span> currentRoute.params) {</span><br><span class="line"> <span class="keyword">if</span> (!(key <span class="keyword">in</span> location.params) && paramNames.includes(key)) {</span><br><span class="line"> location.params[key] = currentRoute.params[key]</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> _createRoute(record, location, redirectedFrom)</span><br><span class="line"> <span class="comment">// 对于没有name属性,有path属性而言</span></span><br><span class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (location.path) {</span><br><span class="line"> location.params = {}</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i < pathList.length; i++) {</span><br><span class="line"> <span class="keyword">const</span> path = pathList[i]</span><br><span class="line"> <span class="keyword">const</span> record = pathMap[path]</span><br><span class="line"> <span class="comment">// 判断location.path是否匹配record.regex正则,并且如果有params会对params进行处理。</span></span><br><span class="line"> <span class="keyword">if</span> (matchRoute(record.regex, location.path, location, params)) {</span><br><span class="line"> <span class="keyword">return</span> _createRoute(record, location, redirectedFrom)</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> _createRoute(<span class="literal">null</span>, location)</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p> 会执行 _createRoute 函数,创建一个路由路径route。_createRoute会对record路径进行一系列的处理后,调用真正创建路由route的createRoute方法。</p> <figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">_createRoute</span> (<span class="params">record, location, redirectedFrom</span>) </span>{</span><br><span class="line"> <span class="keyword">if</span> (record && record.redirect) {</span><br><span class="line"> <span class="keyword">return</span> redirect(record, redirectedFrom || location)</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (record && record.matchAs) {</span><br><span class="line"> <span class="keyword">return</span> alias(record, location, record.matchAs)</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> createRoute(record, location, redirectedFrom, router)</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p> createRoute创建路由,location指的是当前路径解析得到的数据对象,record则是指初始化路由routes时所保存初始的route配置相关信息,router是VueRoute实例。</p> <figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">createRoute</span> (<span class="params">record, location, redirectedFrom, router</span>) </span>{</span><br><span class="line"> <span class="keyword">const</span> stringifyQuery = router && router.options.stringifyQuery</span><br><span class="line"> <span class="keyword">let</span> query = location.query || {}</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> query = clone(query)</span><br><span class="line"> } <span class="keyword">catch</span>(e) {}</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">const</span> route = {</span><br><span class="line"> name: location.name || (record && record.name),</span><br><span class="line"> meta: (record && record.meta) || {},</span><br><span class="line"> path: location.path || <span class="string">'/'</span>,</span><br><span class="line"> hash: location.hash || <span class="string">''</span>,</span><br><span class="line"> query,</span><br><span class="line"> params: location.params || {},</span><br><span class="line"> fullPath: getFullPath(location, stringifyQuery),</span><br><span class="line"> matched: record ? formatMatch(record) : []</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">if</span> (redirectedFrom) {</span><br><span class="line"> route.redirectedFrom = getFullPath(redirectedFrom, stringifyQuery)</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// 避免对route进行修改</span></span><br><span class="line"> <span class="keyword">return</span> <span class="built_in">Object</span>.freeze(route)</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="总结:-1"><a href="#总结:-1" class="headerlink" title="总结:"></a>总结:</h4><ol><li>createMatcher的初始化就是根据路由的配置描述routes创建映射表(一个含有pathList,pathMap,nameMap对象),包含路径、名称到路由record的映射关系。</li><li>match方法会根据传入的位置和路径计算出新的位置,并匹配到对应的路由route,然后根据新的位置和record创建新的路径route并返回。</li></ol><h2 id="路由切换"><a href="#路由切换" class="headerlink" title="路由切换"></a>路由切换</h2><p> 路由切换关系到导航守卫管理,URL变化,路由组件渲染等。路由切换主要就是上面有提到过的transitionTo,而transitionTo这个方法除了在初始化的时候有触发,也在VueRoute实例router的push和replace方法触发(HTML5History和HashHistory的push和replace方法)。</p><h3 id="1-开始:路由切换-transitionTo"><a href="#1-开始:路由切换-transitionTo" class="headerlink" title="1. 开始:路由切换-transitionTo"></a>1. 开始:路由切换-transitionTo</h3> <figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">transitionTo</span> (<span class="params">location, onComplete, onAbort</span>) </span>{</span><br><span class="line"> <span class="comment">// 得到匹配的路由信息</span></span><br><span class="line"> <span class="keyword">const</span> route = <span class="keyword">this</span>.router.match(location, <span class="keyword">this</span>.current)</span><br><span class="line"> <span class="comment">// 完成路径的切换</span></span><br><span class="line"> <span class="keyword">this</span>.confirmTransition(route, () => {</span><br><span class="line"> <span class="comment">// 当前updateRoute方法中含有全局router.afterEachr执行</span></span><br><span class="line"><span class="keyword">this</span>.updateRoute(route)</span><br><span class="line"><span class="comment">// 执行push或者replace中传入的onComplete方法</span></span><br><span class="line">onComplete && onComplete(route)</span><br><span class="line"><span class="keyword">this</span>.ensureURL()</span><br><span class="line"></span><br><span class="line"><span class="comment">// 执行注册的onReady方法</span></span><br><span class="line"><span class="keyword">if</span> (!<span class="keyword">this</span>.ready) {</span><br><span class="line"> <span class="keyword">this</span>.ready = <span class="literal">true</span></span><br><span class="line"> <span class="keyword">this</span>.readyCbs.forEach(<span class="function"><span class="params">cb</span> =></span> {</span><br><span class="line"> cb(route)</span><br><span class="line"> })</span><br><span class="line">}</span><br><span class="line"> }, error => {</span><br><span class="line"> </span><br><span class="line"> })</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// updateRoute方法</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">updateRoute</span> (<span class="params">route</span>) </span>{</span><br><span class="line"> <span class="keyword">const</span> prev = <span class="keyword">this</span>.current</span><br><span class="line"> <span class="keyword">this</span>.current = route</span><br><span class="line"> <span class="keyword">this</span>.cb && <span class="keyword">this</span>.cb(route)</span><br><span class="line"> <span class="comment">// 全局router.afterEach</span></span><br><span class="line"> <span class="keyword">this</span>.router.afterHooks.forEach(<span class="function"><span class="params">hook</span> =></span> {</span><br><span class="line"> hook && hook(route, prev)</span><br><span class="line"> })</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p> 真正路由切换confirmTransition</p> <figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">confirmTransirionTo</span> (<span class="params">route, onComplete, onAbort</span>) </span>{</span><br><span class="line"> <span class="comment">// 当前路径,也就是form旧路径</span></span><br><span class="line"> <span class="keyword">const</span> current = <span class="keyword">this</span>.current</span><br><span class="line"> <span class="comment">// 取消或者失败的方法</span></span><br><span class="line"> <span class="keyword">const</span> abort = <span class="function"><span class="params">error</span> =></span> {</span><br><span class="line"> ...</span><br><span class="line"> onAbort && onAbort(error)</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// 对于当前路径form和要跳转的路径to</span></span><br><span class="line"> <span class="keyword">if</span> (isSameRoute(route, current) && route.matched.length === current.matched.length) {</span><br><span class="line"> <span class="keyword">this</span>.ensureURL() <span class="comment">// 与URL变化相关的</span></span><br><span class="line"> <span class="keyword">return</span> abort()</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="2-导航守卫触发"><a href="#2-导航守卫触发" class="headerlink" title="2. 导航守卫触发"></a>2. 导航守卫触发</h3><p> 在confirmTransition方法中,判断from和to不是相同路径后,会开始触发导航守卫</p> <figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">confirmTransition</span> (<span class="params">route, onComplete, onAbort</span>) </span>{</span><br><span class="line"> <span class="comment">// ... 前期处理,current就是form旧路径</span></span><br><span class="line"> <span class="keyword">const</span> current = <span class="keyword">this</span>.current</span><br><span class="line"> <span class="keyword">const</span> abort = <span class="function"><span class="params">error</span> =></span> {}</span><br><span class="line"> </span><br><span class="line"> <span class="comment">// 获取得到的updated是两个共同拥有的,deactived表示form所拥有的,active的表示to所拥有的</span></span><br><span class="line"> <span class="keyword">const</span> {updated, deactivated, activated} = resolveQueue(<span class="keyword">this</span>.current.matched, route.matched)</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">const</span> queue = [].concat(</span><br><span class="line"> <span class="comment">// 组件内的beforeRouteLeave</span></span><br><span class="line"> extractLeaveGuards(deactivated),</span><br><span class="line"> <span class="comment">// 全局配置的router.beforeEach</span></span><br><span class="line"> <span class="keyword">this</span>.router.beforeHooks,</span><br><span class="line"> <span class="comment">// 组件内的beforeRouteUpdate</span></span><br><span class="line"> extractUpdateGuards(updated),</span><br><span class="line"> <span class="comment">// 路由信息配置routes中的beforeEnter</span></span><br><span class="line"> activated.map(<span class="function"><span class="params">m</span> =></span> m.beforeEnter)</span><br><span class="line"> <span class="comment">// async组件,异步组件</span></span><br><span class="line"> resolveAsyncComponents(activated)</span><br><span class="line"> )</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">this</span>.pending = route</span><br><span class="line"> <span class="keyword">const</span> iterator = <span class="function">(<span class="params">hook, next</span>) =></span> {</span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">this</span>.pending !== route) {</span><br><span class="line"> <span class="keyword">return</span> abort()</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> hook(route, current, (to) => {</span><br><span class="line"> <span class="comment">// 前面判断进行容错</span></span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">typeof</span> to === <span class="string">'string'</span> ||</span><br><span class="line"> (<span class="keyword">typeof</span> to === <span class="string">'object'</span> && (<span class="keyword">typeof</span> to.path === <span class="string">'string'</span>) || <span class="keyword">typeof</span> to.name === <span class="string">'string'</span>)) {</span><br><span class="line"> abort()</span><br><span class="line"> <span class="keyword">if</span> (route.replace) {</span><br><span class="line"> <span class="keyword">this</span>.replace(to)</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">this</span>.push(to)</span><br><span class="line"> }</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> next(to)</span><br><span class="line"> }</span><br><span class="line"> })</span><br><span class="line"> } <span class="keyword">catch</span>(error) {</span><br><span class="line"> abort(error)</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="comment">// </span></span><br><span class="line"> runQueue(queue, iterator, () => {</span><br><span class="line"> <span class="keyword">const</span> postEnterCbs = []</span><br><span class="line"> <span class="keyword">const</span> isValid = <span class="function"><span class="params">()</span> =></span> <span class="keyword">this</span>.current === route</span><br><span class="line"> <span class="comment">// 组件beforeRouteEnter</span></span><br><span class="line"> <span class="keyword">const</span> enterGuards = extractEnterGuards(activated, postEnterCbs, isValid)</span><br><span class="line"> <span class="comment">// 全局router.beforeResolve</span></span><br><span class="line"> <span class="keyword">const</span> queue = enterGuards.concat(<span class="keyword">this</span>.router.resolveHooks)</span><br><span class="line"> runQueue(queue, iterator, () => {</span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">this</span>.pending !== route) {</span><br><span class="line"> <span class="keyword">return</span> abort()</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">this</span>.pending = <span class="literal">null</span></span><br><span class="line"> <span class="comment">// onComplete来源于transitionTo方法,此方法里面包含了updateRoute执行,并且updateRoute方法中含有</span></span><br><span class="line"> <span class="comment">// 全局router.afterEach的执行</span></span><br><span class="line"> onComplete(route)</span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">this</span>.router.app) {</span><br><span class="line"> <span class="keyword">this</span>.router.app.$nextTick(<span class="function"><span class="params">()</span> =></span> {</span><br><span class="line"> postEnterCbs.forEach(<span class="function"><span class="params">cb</span> =></span> {</span><br><span class="line"> cb()</span><br><span class="line"> })</span><br><span class="line"> })</span><br><span class="line"> }</span><br><span class="line"> })</span><br><span class="line"> })</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p> 根据上面的代码逻辑,可以得到有关路由的守卫函数等的执行顺序是:组件beforeRouteLeave => 全局router.beforeEach => 组件beforeRouteUpdate => 路由配置routes的beforeEnter => 解析异步组件 => 组件beforeRouteEnter => 全局router.beforeResolve => 全局router.afterEach。</p>]]></content>
<summary type="html">
<h2 id="VueRouter"><a href="#VueRouter" class="headerlink" title="VueRouter"></a>VueRouter</h2><ol>
<li><p>在Vue组件中注册VueRouter</p>
<figure c
</summary>
</entry>
<entry>
<title>Vuex</title>
<link href="http://yoursite.com/2019/12/14/Vuex/"/>
<id>http://yoursite.com/2019/12/14/Vuex/</id>
<published>2019-12-14T06:08:50.000Z</published>
<updated>2019-12-14T06:09:18.432Z</updated>
<content type="html"><![CDATA[<h1 id="vuex"><a href="#vuex" class="headerlink" title="vuex"></a>vuex</h1><h2 id="基本概念"><a href="#基本概念" class="headerlink" title="基本概念"></a>基本概念</h2><h3 id="Vuex状态管理"><a href="#Vuex状态管理" class="headerlink" title="Vuex状态管理"></a>Vuex状态管理</h3><blockquote><p>状态管理模式</p></blockquote><ul><li>state,驱动应用的数据源</li><li>view,以声明方式将state映射到视图</li><li>actions,响应在view上的用户输入导致的状态变化</li></ul><blockquote><p>应用遇到多个组件共享状态时,单向数据流的简洁性很容易被破坏:</p></blockquote><ul><li>多少个视图依赖于同一状态</li><li>来自不同视图的行为需要变更同一状态</li></ul><blockquote><p>Vuex</p></blockquote><ul><li>一个全局的单例模式</li><li>核心就是store,包含着应用中大部分的状态。</li></ul><blockquote><p>Vuex和单纯的全局对象的不同:</p></blockquote><ul><li>Vuex的状态存储是响应式的。Store中的状态发生变化时,相应的组件也会相应地得到高效更新。</li><li>不能直接修改store中的状态。改变store中状态的唯一方式就是显示提交(commit)mutation。</li></ul><p><strong>Vuex是一个不闭合的状态管理模式实例,它将状态管理模式中的数据state和变更state的事物actions、mutations与Vue组件进行结合,形成一个闭合的状态管理。组件通过显示提交修改Vuex中数据,Vuex中数据结合Vue响应式原理来触发组件更新。其中,Devtools工具可以监听Vuex中mutations事务中对state的修改。</strong></p><h3 id="Store"><a href="#Store" class="headerlink" title="Store"></a>Store</h3><ol><li><p>Store构造器选项</p><ul><li><p>state – 存储数据,Store实例的根state对象</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">state: <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>{</span><br><span class="line"> <span class="keyword">return</span> {}</span><br><span class="line">}</span><br></pre></td></tr></table></figure><blockquote><p>传入的是一个函数,是为了防止state被共享,创建单例想法。与vue中data是一个函数想法一致。</p></blockquote></li><li><p>getters – store实例的计算属性,类似于computed</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">getters: {</span><br><span class="line"> getShoppingCartLen(state) {</span><br><span class="line"> <span class="keyword">return</span> state.shoppingCart.length</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li></ul></li></ol><ul><li><p>mutations – 修改store中状态的处理事务,类似事件注册</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 注册事务</span></span><br><span class="line"><span class="keyword">import</span> {SET_USER_NAME} <span class="keyword">from</span> <span class="string">'mutations-types'</span></span><br><span class="line">mutations: {</span><br><span class="line"> SET_USER_NAME: <span class="function"><span class="keyword">function</span> (<span class="params">state, payload</span>) </span>{</span><br><span class="line"> state.user.name = payload</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 提交修改store中状态</span></span><br><span class="line"><span class="keyword">this</span>.$store.commit(<span class="string">'SET_USER_NAME'</span>, <span class="string">'zhaoshijuan'</span>)</span><br></pre></td></tr></table></figure><blockquote><p>vuex的store是响应式的,因此需要mutation操作store中状态时注意以下几点:</p><ol><li>提前在store中初始化好所有所需属性</li><li>需要添加新属性:Vue.set(obj, property, value); 或者 新对象替换老对象。</li></ol></blockquote></li></ul><ul><li><p>actions – 异步操作事务</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">actions: {</span><br><span class="line"> setusername: <span class="function"><span class="keyword">function</span> (<span class="params">context, payload</span>) </span>{</span><br><span class="line"> context.commit(<span class="string">'SET_USER_NAME'</span>, payload)</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><blockquote><p>actions与mutations区别:action提交的是mutation,mutation直接修改状态;action可以包含异步操作。</p></blockquote></li></ul><ul><li><p>modules – 模块</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">modules: {</span><br><span class="line"> user: {</span><br><span class="line"> namespaced: <span class="literal">true</span>,</span><br><span class="line"> state: {<span class="attr">name</span>: <span class="string">''</span>},</span><br><span class="line"> getters: {},</span><br><span class="line"> mutations: {},</span><br><span class="line"> actions: {}</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><blockquote><p>所有有关状态的,拿到的都是局部状态,包含context.state指向的也是局部状态。context.rootState指向根状态,或者作为参数rootState传递。</p></blockquote></li><li><p>plugins – 插件,方法数组,store是方法参数</p></li><li><p>strict – 是否是严格模式。严格模式下,任何mutation处理函数以外修改Vuex state都会报错。</p></li><li><p>devtools – 订阅到devtools插件</p></li></ul><ol start="2"><li><p>Store实例属性</p><ul><li>state – this.$store.state是store中状态</li><li>getters – this.$store.getters是store中getters</li></ul></li></ol><ol start="3"><li><p>Store实例方法</p><ul><li><p>commit – 提交mutation</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">this</span>.$store.commit(<span class="string">'mutationType'</span>, mutationPayload, options);</span><br><span class="line"><span class="keyword">this</span>.$store.commit({</span><br><span class="line"> type: <span class="string">'mutationType'</span>,</span><br><span class="line"> mutationPayload: mutationPayload</span><br><span class="line">}, options)</span><br></pre></td></tr></table></figure></li><li><p>dispatch – 分发action</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">this</span>.$store.dispatch(type, payload, options);</span><br><span class="line"><span class="keyword">this</span>.$store.dispathc({</span><br><span class="line"> type: type,</span><br><span class="line"> payload: payload</span><br><span class="line">}, options)</span><br></pre></td></tr></table></figure></li><li><p>replaceState – 替换store的根状态</p></li><li>watch – 响应式监听fn返回值。watch(fn, callback, options)</li><li>subscribe – 订阅mutation,mutation完成后调用</li><li>subscribeAction – 订阅action,默认是在action调用之前触发。含有before,after指定订阅处理函数在action分发之前,之后调用</li><li>registerModule – 注册指定path的module</li><li>unregisterModule – 卸载指定path的module</li><li>hotUpdate – 热替换新的action和mutation</li></ul></li></ol><h3 id="辅助函数"><a href="#辅助函数" class="headerlink" title="辅助函数"></a>辅助函数</h3><ul><li>mapState – 在计算属性中混入store中状态</li><li>mapGetters – 计算属性中混入store中getters</li><li>mapMutations – 方法methods混入mutation事务</li><li>mapActions – 方法methods混入action事务</li><li>createNamespacedHelpers – 创建基于命名空间的辅助函数,是一个包含指定命名空间的mapState,mapGetters,mapMutations,mapActions对象</li></ul><h2 id="源码实现"><a href="#源码实现" class="headerlink" title="源码实现"></a>源码实现</h2><h3 id="Vuex安装注册"><a href="#Vuex安装注册" class="headerlink" title="Vuex安装注册"></a>Vuex安装注册</h3><ul><li>Vue.use(Vuex) => 会触发Vuex的install方法</li><li>Vuex中applyMixin方法:对于Vue版本进行判断,2.x版本中,Vue.mixin({beforeCreate: vuexInit})</li><li>vuexInit方法:将this.$options.store注入到this.$store上</li></ul><h3 id="Store实例化-Vuex依赖于promise"><a href="#Store实例化-Vuex依赖于promise" class="headerlink" title="Store实例化 [Vuex依赖于promise]"></a>Store实例化 [Vuex依赖于promise]</h3><ul><li><p>new ModuleCollection(options)</p><ul><li>ModuleCollection.register(path, rawModule)</li><li>new Module(rawModule):每个module模块</li><li>对于刚开始,path为空数组,会执行this.root = newModule</li><li><p>rawModule.modules也就是在new Vuex.Store时传递的modules数据,如果有值,就会递归运行如下[将modules建立成一个树状结构]</p> <figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// this指向ModuleCollection,path是一直贯穿的数据</span></span><br><span class="line">forEachValue(rawModule.modules, (rawChildModule, key) => {</span><br><span class="line"> <span class="keyword">this</span>.register(path.concat(key), rawChildModule, runtime);</span><br><span class="line">})</span><br></pre></td></tr></table></figure></li><li><p>path已经不再是空数组,会执行以下代码</p> <figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// this指向ModuleCollection,建立父子关系</span></span><br><span class="line"><span class="keyword">const</span> parent = <span class="keyword">this</span>.get(path.slice(<span class="number">0</span>, <span class="number">-1</span>))</span><br><span class="line">parent.addChild(path[path.length - <span class="number">1</span>], newModule)</span><br><span class="line"></span><br><span class="line"><span class="comment">// parent是module实例,parent.addChild方法如下[this指向module]</span></span><br><span class="line">addChild(key, <span class="built_in">module</span>) {</span><br><span class="line"> <span class="keyword">this</span>._children[key] = <span class="built_in">module</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure></li></ul></li></ul><ul><li><p>installModule(this, state, [], _this.module.root)</p><p> 上面数据state就是_this.module.root.state。installModule(state, rootState, path, module, hot)</p></li></ul><p><span style="color: #4d4d4c; font-weight: bold; background-color: #f7f7f7; text-align: left; display: inline-block; margin-left: 50px;"> 对于mutations,actions,getters,_wrapperGetters等初始化。遍历每个module的actions,mutations,getters,child数据 </span></p><ul><li>根据namespace设置_store._modulesNamespaceMap[namespace] = module。</li><li>设置每个module.context = makeLocalContext,可以避免重名问题,commit提交mutation时,不加namespace也可以成功。</li><li><strong>makeLocalContext</strong>返回的是一个local对象:dispatch,commit,getters。dispatch、commit根据传递的参数namespace + type形成新的type值,再调用store[methodName](type)。</li></ul><p><span style="color: #4d4d4c; font-weight: bold; background-color: #f7f7f7; text-align: left; display: inline-block; margin-left: 50px;"> mutation,action对应的commit(namespace/mutationName),dispathc(namespace/actionName),_mutation和_action一层对象,key值是含有一层层namespace;state对应的state[namespace]对象形式一层一层往下查找。</span></p><ul><li><strong>forEachMutation</strong> 递归registerMutation</li><li><strong>forEachAction</strong> 递归registerAction,每个action(除了返回值是Promise类型的)被执行后返回的是一个Promise.resolve(action函数执行后结果)实例化后的Promise实例</li><li><strong>forEachGetter</strong> 递归registerGetter,每个getter会挂载在store._wrappedGetters上</li><li><strong>forEachChild</strong> 递归执行installModule,传递的path是:全局path一直concat(key)</li></ul><ul><li><p>resetStoreVM(this, state)</p><p><span style="color: #4d4d4c;font-weight: bold;background-color: #f7f7f7;text-align: left;display: inline-block;margin-left: 5px;"> 保证了Vuex的store中state存储数据是响应式,并且getters类似于Vue的computed,拥有缓存。</span></p></li></ul><ul><li><p>store.getters的每个getter做一个get拦截,拦截返回store._vm[key]:store._vm实例上对应的computed-key</p></li><li><p>store._vm是一个Vue实例,data数据$$state: state, computed其实就是传递的所有的getters</p></li></ul><h2 id="实现Vuex关键点"><a href="#实现Vuex关键点" class="headerlink" title="实现Vuex关键点"></a>实现Vuex关键点</h2><h3 id="构造函数参数"><a href="#构造函数参数" class="headerlink" title="构造函数参数"></a>构造函数参数</h3><ul><li>state响应式,利用new Vue({data: {$$state: state}})实例化Vue,使得state拥有和Vue一样的响应式。</li><li>getters缓存计算,利用Vue实例的computed特性。</li><li>mutations注意模块化,执行上下文利用call</li><li>actions注意模块化,同时context传递的不是store本身,而是一个拥有相同dispatch,commit,getters,state,rootGetters,rootState数据的对象</li><li>modules 递归实现<ul><li>首先需要一个LocalContext</li><li>递归给rootState添加state形成一个树形状态管理</li><li>将getters直接挂载在store_wrappedGetters,Object.defineProperty(store.getters)get拦截返回vue实例compute,注册到store实例的getters属性</li><li>将mutations挂载在store._mutation,并且属性名称就是namespace + ‘/‘ + key,属性值是一个数组</li><li>将actions挂载在store._actions,属性名称是namspace + ‘/‘ + key,属性值是一个数组</li><li>modules递归挂载在store._modules.root._children,一层一层形成一个树状结构</li></ul></li></ul><h3 id="实例属性"><a href="#实例属性" class="headerlink" title="实例属性"></a>实例属性</h3><ul><li>state 返回的是store实例上_vm._data.\$\$state,也就是Vue实例中data的$$state数据</li><li>getters registerGetter时,将每个module提取到this._wrappedGetters对象中,在对store实例getters每个属性进行拦截时,Object.defineProperty中get返回this._wrappedGetters对应getter</li></ul><h3 id="实例方法"><a href="#实例方法" class="headerlink" title="实例方法"></a>实例方法</h3><ul><li>dispatch</li><li>commit</li><li>subscribe 返回的是一个函数,运行后可以停止订阅。订阅mutation,在每个mutation完成后调用。</li><li>subscribeAction 返回的是一个函数,运行后停止订阅。订阅action,在每个action分发调用。【before,after指定action分发之前之后】</li><li>replaceState 替换整个store实例上的state数据</li><li>watch 实际是this._watcherVM.$watch。返回函数用于停止监听。</li><li>registerModule 注册模块。需要installModule,resetStoreVM</li><li>unregisterModule 卸载模块。删除模块数据,同时将state也Vue.delete。根据最新数据installModule和resetStoreVM</li></ul>]]></content>
<summary type="html">
<h1 id="vuex"><a href="#vuex" class="headerlink" title="vuex"></a>vuex</h1><h2 id="基本概念"><a href="#基本概念" class="headerlink" title="基本概念"></a
</summary>
</entry>
<entry>
<title>Vue实战开发-生态篇</title>
<link href="http://yoursite.com/2019/12/14/Vue%E5%AE%9E%E6%88%98%E5%BC%80%E5%8F%91-%E7%94%9F%E6%80%81%E7%AF%87/"/>
<id>http://yoursite.com/2019/12/14/Vue实战开发-生态篇/</id>
<published>2019-12-14T05:30:58.000Z</published>
<updated>2019-12-14T06:05:01.067Z</updated>
<content type="html"><![CDATA[<p>Vue生态圈中,常用到的就是Vuex以及VueRouter,那么它们是如何实现的?以及是如何挂载到Vue实例上的?这些问题将是我下面👇内容的重点。当然也涉及到一些在开发中所使用到的组件库以及单元测试jest,这些只是一笔带过…<br><a id="more"></a></p><h2 id="Vue实战开发-生态篇"><a href="#Vue实战开发-生态篇" class="headerlink" title="Vue实战开发-生态篇"></a>Vue实战开发-生态篇</h2><h3 id="目录"><a href="#目录" class="headerlink" title="目录"></a>目录</h3><ul><li><a href="#Vuex-demo">Vuex实战</a></li><li><a href="#Vuex">Vuex原理以及源码分析</a></li><li><a href="#VueRouter">VueRouter原理</a></li><li><a href="#VueRouter-mode">VueRouter路由模式</a></li><li><a href="#SPA">单页面SPA & 解决方案Nuxt</a></li><li><a href="#componentsUI">UI组件库</a></li><li><a href="#jest">单元测试</a></li></ul><h3 id="Vuex实战"><a href="#Vuex实战" class="headerlink" title="Vuex实战"></a><div id="Vuex-demo">Vuex实战</div></h3><blockquote><p>疑问:扩展购物车示例,提供单次添加1-N的数量到购物车功能</p></blockquote><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> Vue <span class="keyword">from</span> <span class="string">'vue'</span>;</span><br><span class="line"><span class="keyword">import</span> Vuex <span class="keyword">from</span> <span class="string">'vuex'</span>;</span><br><span class="line"><span class="keyword">import</span> App <span class="keyword">from</span> <span class="string">'./App.vue'</span>;</span><br><span class="line"></span><br><span class="line">Vue.use(Vuex);</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> store = <span class="keyword">new</span> Vuex.Store({</span><br><span class="line"> state: {},</span><br><span class="line"> mutations: {},</span><br><span class="line"> actions: {},</span><br><span class="line"> modules: {}</span><br><span class="line">});</span><br><span class="line"></span><br><span class="line"><span class="keyword">new</span> Vue({</span><br><span class="line"> store: storeInstance,</span><br><span class="line"> render: <span class="function"><span class="params">h</span> =></span> h(App)</span><br><span class="line">}).$mount(<span class="string">'#app'</span>);</span><br></pre></td></tr></table></figure><p>使用Vuex的步骤:</p><ol><li>注册Vuex:Vue.use(Vuex);</li><li>创建Store实例:new Vuex.Store(options)</li><li>挂载$store:new Vue({store: storeInstance})</li></ol><h3 id="Vuex原理"><a href="#Vuex原理" class="headerlink" title="Vuex原理"></a><div id="Vuex">Vuex原理</div></h3><p><a href="../Vuex">Vuex详解</a></p><blockquote><p>Vuex课后疑问</p></blockquote><ol><li>Vuex是通过什么方式提供响应式数据的?</li></ol><p> 答:利用Vue的data特性实现</p><ol start="2"><li>$store是如何挂载到实例this上的?</li></ol><p> 答:在beforeCreate钩子函数中调用vuexInit</p><ol start="3"><li>扩展min-vuex,实现getters,并实现vuex的方式注入$store</li></ol><p> 答:利用Vue的compute特性 + 拦截实现</p><p><strong>暂且先记住这些疑问,我们先了解一下vuex。</strong></p><p><img src="vuex机制.png" alt="vuex机制"></p><blockquote><p>Vuex提供的属性和方法</p></blockquote><ol><li>属性:state,getters</li><li>方法:commit,dispatch,replaceState,registerModule,unregisterModule,watch,subscribe,subscribeAction,hotUpdate</li><li>辅助函数:mapState,mapGetters,mapMutations,mapActions,createNamespaceHelpers</li></ol><blockquote><p>Vuex思维导图</p></blockquote><p><img src="vuex.png" alt="vuex思维导图"></p><blockquote><p>总结</p></blockquote><ol><li><p>注册Vuex</p> <figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Vue.use会调用执行Vuex对外暴露的install方法</span></span><br><span class="line">Vue.use(Vuex);</span><br><span class="line"><span class="comment">// Vuex-install方法</span></span><br><span class="line"><span class="keyword">let</span> Vue;</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">install</span> (<span class="params">_Vue</span>) </span>{</span><br><span class="line"> <span class="keyword">if</span> (_Vue && Vue === _Vue) {</span><br><span class="line"> <span class="comment">// 说明已经注册过,提示只能注册一次</span></span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> Vue = _Vue;</span><br><span class="line"> <span class="comment">// 全局混入beforeCreate钩子函数,执行VuexInit方法</span></span><br><span class="line"> Vue.mixin({</span><br><span class="line"> beforeCreate: VuexInit</span><br><span class="line"> })</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li><li><p>创建Store实例</p> <figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 创建Store实例</span></span><br><span class="line"><span class="keyword">new</span> Vuex.Store(options)</span><br><span class="line"><span class="comment">// Vuex.Store类</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Store</span> () </span>{</span><br><span class="line"> construct (options) {</span><br><span class="line"> <span class="comment">// ... 初始化数据等等</span></span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li><li><p>挂载$store</p> <figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 每个组件执行到beforeCreate钩子函数时,会执行到注册Vuex时混入的全局beforeCreate中VuexInit函数</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">VuexInit</span>(<span class="params"></span>) </span>{</span><br><span class="line"> <span class="keyword">let</span> options = <span class="keyword">this</span>.$options;</span><br><span class="line"> <span class="keyword">if</span> (options.store) {</span><br><span class="line"> <span class="keyword">this</span>.$store = <span class="built_in">Object</span>.prototype.toString.call(options.store).includes(<span class="string">'Function'</span>)</span><br><span class="line"> ? options.store()</span><br><span class="line"> : options.store;</span><br><span class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (<span class="keyword">this</span>.parent && <span class="keyword">this</span>.parent.$store) {</span><br><span class="line"> <span class="comment">// 保证每个组件中的$store指向的是同一个$store;以及可以直接在每个组件中使用this.$store</span></span><br><span class="line"> <span class="keyword">this</span>.$store = <span class="keyword">this</span>.parent.$store</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li></ol><h3 id="vueRouter原理"><a href="#vueRouter原理" class="headerlink" title="vueRouter原理"></a><div id="VueRouter">vueRouter原理</div></h3><p><a href="../VueRouter">VueRouter详解</a></p><blockquote><p>VueRouter使用</p></blockquote><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 1. VueRouter注册</span></span><br><span class="line">Vue.use(VueRouter);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 2. 创建VueRouter实例</span></span><br><span class="line"><span class="keyword">const</span> router = <span class="keyword">new</span> VueRouter({</span><br><span class="line"> mode: <span class="string">''</span>,</span><br><span class="line"> routes: [</span><br><span class="line"> {</span><br><span class="line"> path: <span class="string">''</span>,</span><br><span class="line"> name: <span class="string">''</span>,</span><br><span class="line"> component: 组件,</span><br><span class="line"> children: []</span><br><span class="line"> }</span><br><span class="line"> ]</span><br><span class="line">});</span><br><span class="line"></span><br><span class="line"><span class="comment">// 3. VueRouter注入组件</span></span><br><span class="line"><span class="keyword">new</span> Vue({</span><br><span class="line"> router</span><br><span class="line">})</span><br></pre></td></tr></table></figure><blockquote><p>VueRouter解析</p></blockquote><ol><li><p>VueRouter注册</p> <figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Vue.use会执行VueRouter的install方法</span></span><br><span class="line">Vue.use(VueRouter);</span><br><span class="line"><span class="comment">// install方法</span></span><br><span class="line"><span class="keyword">let</span> _Vue;</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">install</span> (<span class="params">Vue</span>) </span>{</span><br><span class="line"> <span class="keyword">if</span> (install.installed && _Vue === Vue) <span class="keyword">return</span>;</span><br><span class="line"> install.installed = <span class="literal">true</span>;</span><br><span class="line"> _Vue = Vue;</span><br><span class="line"> <span class="comment">// 混入beforeCreate,destroyed</span></span><br><span class="line"> Vue.mixin({</span><br><span class="line"> beforeCreate(){</span><br><span class="line"> <span class="keyword">if</span> (isDef(<span class="keyword">this</span>.$options.router)) {</span><br><span class="line"> <span class="keyword">this</span>._routerRoot = <span class="keyword">this</span>;</span><br><span class="line"> <span class="keyword">this</span>._router = <span class="keyword">this</span>.$options.router;</span><br><span class="line"> <span class="comment">// VueRouter类中的init方法,会初始化一堆东西,同时执行transitionTo</span></span><br><span class="line"> <span class="keyword">this</span>._router.init(<span class="keyword">this</span>);</span><br><span class="line"> <span class="comment">// 将整个对象变成响应式</span></span><br><span class="line"> Vue.util.defineReactive(<span class="keyword">this</span>, <span class="string">'_route'</span>, <span class="keyword">this</span>._router.history.current);</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">this</span>._routerRoot = (<span class="keyword">this</span>.$parent && <span class="keyword">this</span>.$parent._routerRoot) || <span class="keyword">this</span>;</span><br><span class="line"> }</span><br><span class="line"> },</span><br><span class="line"> destoryed() {}</span><br><span class="line"> });</span><br><span class="line"> <span class="comment">// 挂载属性$ruoter和$route</span></span><br><span class="line"> <span class="built_in">Object</span>.defineProperty(Vue.prototype, <span class="string">'$router'</span>, {</span><br><span class="line"> get () { <span class="keyword">return</span> <span class="keyword">this</span>._routerRoot._router; }</span><br><span class="line"> });</span><br><span class="line"></span><br><span class="line"> <span class="built_in">Object</span>.defineProperty(Vue.prototype, <span class="string">'$route'</span>, {</span><br><span class="line"> get () { <span class="keyword">return</span> <span class="keyword">this</span>._routerRoot._route; }</span><br><span class="line"> });</span><br><span class="line"> <span class="comment">// 注册全局组件</span></span><br><span class="line"> Vue.component(<span class="string">'RouterView'</span>, View);</span><br><span class="line"> Vue.component(<span class="string">'RouterLink'</span>, Link);</span><br><span class="line"> <span class="comment">// 规定组件内路由导航的合并规则</span></span><br><span class="line"> <span class="keyword">const</span> strats = Vue.config.optionMergeStrategies;</span><br><span class="line"> strats.beforeRouteEnter = strats.beforeRouteLeave = strats.beforeRouteUpdate = strats.created;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li><li><p>创建VueRouter实例</p> <figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> router = <span class="keyword">new</span> VueRouter({</span><br><span class="line"> mode: <span class="string">''</span>,</span><br><span class="line"> routes: []</span><br><span class="line"> <span class="comment">// ... 一堆配置项</span></span><br><span class="line">});</span><br><span class="line"></span><br><span class="line"><span class="comment">// VueRouter类</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">VueRouter</span></span>{</span><br><span class="line"> <span class="comment">// 构造函数</span></span><br><span class="line"> <span class="keyword">constructor</span> (options) {</span><br><span class="line"> <span class="comment">// 重要。创建一个包含addRoutes方法 + 映射表对象</span></span><br><span class="line"> <span class="comment">// 映射表是一个包含里面含有pathList, pathMap, nameMap</span></span><br><span class="line"> <span class="keyword">this</span>.matcher = createMatcher(options.routes || [], <span class="keyword">this</span>);</span><br><span class="line"> <span class="comment">// 初始化路由模式</span></span><br><span class="line"> <span class="keyword">let</span> mode = options.mode || <span class="string">'hash'</span>;</span><br><span class="line"> <span class="comment">// supportsPushState是看当前环境是否支持html5的history模式</span></span><br><span class="line"> <span class="keyword">this</span>.fallback = mode === <span class="string">'history'</span> && !supportsPushState && options.fallback !== <span class="literal">false</span>;</span><br><span class="line"> <span class="comment">// 降级处理</span></span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">this</span>.fallback) {</span><br><span class="line"> mode = <span class="string">'hash'</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// 浏览器环境还是服务器环境</span></span><br><span class="line"> <span class="keyword">if</span> (!inBrowser) {</span><br><span class="line"> mode = <span class="string">'abstract'</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">this</span>.mode = mode;</span><br><span class="line"> <span class="comment">// 根据this.mode创建不同的路由模式对象</span></span><br><span class="line"> <span class="comment">// history|hash|abstract模式对应HTML5History|HashHistory|AbstractHistory</span></span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li><li><p>VueRouter注入组件</p><p> 组件在创建执行到beforeCreate钩子函数时,会执行到VueRouter注入的beforeCreate钩子函数。进而,会执行里面的 <code>this._router.init(this);</code></p> <figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 注入组件</span></span><br><span class="line"><span class="keyword">new</span> Vue({</span><br><span class="line"> router</span><br><span class="line">});</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// VueRouter实例的init方法,重点会执行transitionTo方法</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">init</span> (<span class="params"></span>) </span>{</span><br><span class="line"> <span class="keyword">const</span> history = <span class="keyword">this</span>.history;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (history <span class="keyword">instanceof</span> HTML5History) {</span><br><span class="line"> history.transitionTo(history.getCurrentLocation());</span><br><span class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (history <span class="keyword">instanceof</span> HashHistory) {</span><br><span class="line"> <span class="keyword">const</span> setupHashListener = <span class="function"><span class="params">()</span> =></span> {</span><br><span class="line"> history.setupListeners();</span><br><span class="line"> }</span><br><span class="line"> history.transitionTo(</span><br><span class="line"> history.getCurrentLocation(),</span><br><span class="line"> setupHashListener,</span><br><span class="line"> setupHashListener</span><br><span class="line"> );</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li></ol><h4 id="VueRouter路由切换"><a href="#VueRouter路由切换" class="headerlink" title="VueRouter路由切换"></a><span style="color: red; font-weight: bold;">VueRouter路由切换</span></h4><p>核心方法就是confirmTransition,能够触发这个方法的是transitionTo方法,触发transitionTo方法的是:初始化,VueRoute实例router的push和replace方法。</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// transitionTo</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">transitionTo</span> (<span class="params">location, onComplete, onAbort</span>) </span>{</span><br><span class="line"> <span class="comment">// 根据初始化得到的映射表对象进行的match</span></span><br><span class="line"> <span class="keyword">const</span> route = <span class="keyword">this</span>.router.match(location, <span class="keyword">this</span>.current);</span><br><span class="line"> <span class="keyword">this</span>.confirmTransition(</span><br><span class="line"> route,</span><br><span class="line"> () => {</span><br><span class="line"> <span class="comment">// 当前updateRoute方法中含有全局router.afterEach执行</span></span><br><span class="line"> <span class="keyword">this</span>.updateRoute(route)</span><br><span class="line"> <span class="comment">// 执行push或者replace中传入的onComplete方法</span></span><br><span class="line"> onComplete && onComplete(route)</span><br><span class="line"> <span class="keyword">this</span>.ensureURL()</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 执行注册的onReady方法</span></span><br><span class="line"> <span class="keyword">if</span> (!<span class="keyword">this</span>.ready) {</span><br><span class="line"> <span class="keyword">this</span>.ready = <span class="literal">true</span></span><br><span class="line"> <span class="keyword">this</span>.readyCbs.forEach(<span class="function"><span class="params">cb</span> =></span> {</span><br><span class="line"> cb(route)</span><br><span class="line"> })</span><br><span class="line"> }</span><br><span class="line"> },</span><br><span class="line"> err => {</span><br><span class="line"> <span class="keyword">if</span> (onAbort) {</span><br><span class="line"> <span class="comment">// 执行push或者replace中传入的onComplete方法</span></span><br><span class="line"> onAbort(err)</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> )</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// confirmTransition</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">confirmTransition</span> (<span class="params">route, onComplete, onAbort</span>) </span>{</span><br><span class="line"> <span class="comment">// ... 前期处理,current就是form旧路径</span></span><br><span class="line"> <span class="keyword">const</span> current = <span class="keyword">this</span>.current;</span><br><span class="line"> <span class="keyword">const</span> abort = <span class="function"><span class="params">error</span> =></span> {};</span><br><span class="line"> </span><br><span class="line"> <span class="comment">// 获取得到的updated是两个共同拥有的,deactived表示form所拥有的,active的表示to所拥有的</span></span><br><span class="line"> <span class="keyword">const</span> {updated, deactivated, activated} = resolveQueue(<span class="keyword">this</span>.current.matched, route.matched);</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">const</span> queue = [].concat(</span><br><span class="line"> <span class="comment">// 组件内的beforeRouteLeave</span></span><br><span class="line"> extractLeaveGuards(deactivated),</span><br><span class="line"> <span class="comment">// 全局配置的router.beforeEach</span></span><br><span class="line"> <span class="keyword">this</span>.router.beforeHooks,</span><br><span class="line"> <span class="comment">// 组件内的beforeRouteUpdate</span></span><br><span class="line"> extractUpdateGuards(updated),</span><br><span class="line"> <span class="comment">// 路由信息配置routes中的beforeEnter</span></span><br><span class="line"> activated.map(<span class="function"><span class="params">m</span> =></span> m.beforeEnter)</span><br><span class="line"> <span class="comment">// async组件,异步组件</span></span><br><span class="line"> resolveAsyncComponents(activated)</span><br><span class="line"> );</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">this</span>.pending = route;</span><br><span class="line"> <span class="comment">// 遍历器</span></span><br><span class="line"> <span class="keyword">const</span> iterator = <span class="function">(<span class="params">hook, next</span>) =></span> {</span><br><span class="line"> <span class="comment">// 对于函数执行处理</span></span><br><span class="line"> };</span><br><span class="line"> </span><br><span class="line"> <span class="comment">// 执行queue队列函数</span></span><br><span class="line"> runQueue(queue, iterator, () => {</span><br><span class="line"> <span class="keyword">const</span> postEnterCbs = [];</span><br><span class="line"> <span class="keyword">const</span> isValid = <span class="function"><span class="params">()</span> =></span> <span class="keyword">this</span>.current === route;</span><br><span class="line"> <span class="comment">// 组件beforeRouteEnter</span></span><br><span class="line"> <span class="keyword">const</span> enterGuards = extractEnterGuards(activated, postEnterCbs, isValid);</span><br><span class="line"> <span class="comment">// 全局router.beforeResolve</span></span><br><span class="line"> <span class="keyword">const</span> queue = enterGuards.concat(<span class="keyword">this</span>.router.resolveHooks);</span><br><span class="line"> runQueue(queue, iterator, () => {</span><br><span class="line"> <span class="comment">// onComplete来源于transitionTo方法,此方法里面包含了updateRoute执行,并且updateRoute方法中含有</span></span><br><span class="line"> <span class="comment">// 全局router.afterEach的执行</span></span><br><span class="line"> onComplete(route);</span><br><span class="line"> });</span><br><span class="line"> });</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>根据上面的代码可以得到【路由切换时,所有路由导航执行的顺序】:</p><p><img src="导航守卫执行顺序.jpg" alt="导航守卫执行顺序"></p><h3 id="vueRouter路由模式"><a href="#vueRouter路由模式" class="headerlink" title="vueRouter路由模式"></a><div id="VueRouter-mode">vueRouter路由模式</div></h3><ul><li>hash模式:格式如a/#/b</li><li>history模式:格式如a/b,需要浏览器支持</li><li>abstract模式:服务器端</li></ul><blockquote><p>hash和history主要区别就是对于路径处理</p></blockquote><ol><li>push、replace对于路径处理不一致</li><li>window监听的事件不一致</li></ol><ul><li><p>hash路由实现</p> <figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"> <span class="built_in">window</span>.addEventListener(</span><br><span class="line"> supportsPushState ? <span class="string">'popstate'</span> : <span class="string">'hashchange'</span>,</span><br><span class="line"> () => {</span><br><span class="line"> <span class="comment">// 函数处理</span></span><br><span class="line"> }</span><br><span class="line"> );</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">function</span> <span class="title">push</span>(<span class="params">location, onComplete, onAbort</span>) </span>{</span><br><span class="line"> <span class="keyword">const</span> { <span class="attr">current</span>: fromRoute } = <span class="keyword">this</span>;</span><br><span class="line"> <span class="keyword">this</span>.transitionTo(location, route => {</span><br><span class="line"> pushHash(route.fullPath);</span><br><span class="line"> }, onAbort);</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="comment">// pushHash方法</span></span><br><span class="line"> <span class="function"><span class="keyword">function</span> <span class="title">pushHash</span> (<span class="params">path</span>) </span>{</span><br><span class="line"> <span class="keyword">if</span> (supportsPushState) {</span><br><span class="line"> <span class="comment">// 如果当前支持HTML5的history时</span></span><br><span class="line"> <span class="comment">// 则就会执行和history模式一样的pushState方法</span></span><br><span class="line"> pushState(getUrl(path));</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="built_in">window</span>.location.hash = path;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li><li><p>history路由实现</p> <figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="built_in">window</span>.addEventListener(<span class="string">'popstate'</span>, e => {</span><br><span class="line"><span class="comment">// 函数处理</span></span><br><span class="line">});</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">push</span> (<span class="params">location, onComplete, onAbort</span>) </span>{</span><br><span class="line"> <span class="keyword">const</span> { <span class="attr">current</span>: fromRoute } = <span class="keyword">this</span>;</span><br><span class="line"> <span class="keyword">this</span>.transitionTo(location, route => {</span><br><span class="line"> pushState(cleanPath(<span class="keyword">this</span>.base + route.fullPath));</span><br><span class="line"> }, onAbort);</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li><li><p>对于pushState方法,两个是一致的</p> <figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">pushState</span> (<span class="params">url, replace</span>) </span>{</span><br><span class="line"> <span class="keyword">const</span> history = <span class="built_in">window</span>.history;</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="keyword">if</span> (replace) {</span><br><span class="line"> <span class="comment">// 调用的是window.history.replaceState</span></span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="comment">// 调用的是window.history.pushState</span></span><br><span class="line"> }</span><br><span class="line"> } <span class="keyword">catch</span> (e) {</span><br><span class="line"> <span class="comment">// 调用window.location.replace或者是window.location.assign</span></span><br><span class="line"> <span class="built_in">window</span>.location[replace ? <span class="string">'replace'</span> : <span class="string">'assign'</span>](url);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li></ul><blockquote><p>为什么history下刷新页面会404[如果后端不做配置]</p></blockquote><p>答案:history模式形式为a/b/c会被服务器理解成在请求a路径下b路径下c资源,但是在服务器上根本没有这个资源就会出现404错误。因此如果要使用history时,需要后端进行配置。</p><h3 id="单页面SPA-amp-解决方案Nuxt"><a href="#单页面SPA-amp-解决方案Nuxt" class="headerlink" title="单页面SPA & 解决方案Nuxt"></a><div id="SPA">单页面SPA & 解决方案Nuxt</div></h3><blockquote><p>单页面SPA缺点</p></blockquote><ul><li><p>不利于SEO【搜索引擎】</p><p> <strong>解决方案</strong>:服务端处理然后将html返回浏览器端,也就是服务端渲染同构SSR。同构SSR – 适合动态渲染,配置繁琐。<br> <br></p></li><li><p>首屏渲染时间长</p><p> <strong>解决方案</strong>:预渲染Prerendering – Prerendering适合静态站点<br> <br></p></li></ul><blockquote><p>解决方案Nuxt - 解决SEO问题</p></blockquote><p> <a href="https://zh.nuxtjs.org/" target="_blank" rel="noopener">Nuxt官网</a></p><h3 id="UI组件库"><a href="#UI组件库" class="headerlink" title="UI组件库"></a><div id="componentsUI">UI组件库</div></h3><p><img src="组件库对比.jpg" alt="组件库对比"></p><ul><li><a href="https://element.eleme.cn/" target="_blank" rel="noopener">element-ui</a></li><li><a href="https://www.antdv.com/" target="_blank" rel="noopener">Ant Design of Vue</a></li><li><a href="https://www.iviewui.com/" target="_blank" rel="noopener">iview</a></li></ul><blockquote><p>按需加载</p></blockquote><p><a href="https://unpkg.com/browse/[email protected]/" target="_blank" rel="noopener">element-ui包</a></p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 整个引用</span></span><br><span class="line"><span class="keyword">import</span> element <span class="keyword">from</span> <span class="string">'element-ui'</span>;</span><br><span class="line"><span class="comment">// 错误的按需加载</span></span><br><span class="line"><span class="keyword">import</span> {Select, Option, Button, MessageBox, Message} <span class="keyword">from</span> <span class="string">'element-ui'</span>;</span><br></pre></td></tr></table></figure><p>只要是从<code>element-ui</code>引入东西,那么就会执行element-ui/src/index.js文件。而改文件中会将elemeent-ui组件库中所有的组件都import进来,那么就会将所有组件加载过来。只是<code>import {Select} from 'element-ui'</code>这种模式,减少了Vue全局组件的挂载而已,并不是严格意义上的 <code>按需加载</code>。</p><ul><li><p>element-ui官网按需加载推荐<br><img src="element-ui按需加载.jpg" alt="element-ui官网按需加载推荐"></p></li><li><p>Ant Design of Vue官网按需加载推荐<br><img src="antdv按需加载.jpg" alt="Ant Design of Vue官网按需加载推荐"></p></li><li><p>iview官网按需加载推荐<br><img src="iview按需加载.jpg" alt="iview按需加载"></p></li></ul><h3 id="单元测试-jset"><a href="#单元测试-jset" class="headerlink" title="单元测试- jset"></a><div id="jest">单元测试- <a href="https://jestjs.io/" target="_blank" rel="noopener">jset</a></div></h3><blockquote><p>常用方法</p></blockquote><ul><li>describe 创建一个将几个相关测试组合在一起的模块</li><li>test,别名it。运行测试</li><li>expect 断言某个值</li></ul><blockquote><p> 值对比</p></blockquote><ul><li>toBe(value) 原始值或检查对象实例的引用一致性</li><li>toEqual(value) 递归比较对象实例的所有属性</li></ul>]]></content>
<summary type="html">
<p>Vue生态圈中,常用到的就是Vuex以及VueRouter,那么它们是如何实现的?以及是如何挂载到Vue实例上的?这些问题将是我下面👇内容的重点。当然也涉及到一些在开发中所使用到的组件库以及单元测试jest,这些只是一笔带过…<br>
</summary>
</entry>
<entry>
<title>CSS动画性能优化</title>
<link href="http://yoursite.com/2019/06/11/CSS%E5%8A%A8%E7%94%BB%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96/"/>
<id>http://yoursite.com/2019/06/11/CSS动画性能优化/</id>
<published>2019-06-11T02:04:17.000Z</published>
<updated>2019-08-01T08:48:30.561Z</updated>
<content type="html"><![CDATA[<p>每个项目中或多或少地会使用到动画,使得用户体验效果更好。通常简单的动画对性能影响很小,但是涉及到稍微复杂的动画或者在配置比较低的机器上时,一些不当的处理方式会使性能问题变得十分突出……<br><a id="more"></a></p><h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>已经完结的一个项目,最近需要适配其他的机器,出现了一个严重的问题:以前很流畅的动画突然gg了。因为现在适配的机器配置比较低,所以出现了动画卡顿现象:渐进动画变得很鬼畜,没有渐进效果,直接就是一个开始状态,一段时间后直接变成结束状态,让人感受不到中间时间段的渐进效果。以前写动画效果,只考虑到如何才能让这个动画看起来更贴切用户的体验,并没有考虑到动画性能以及优化动画。<br><br></p><h2 id="为什么会出现卡顿"><a href="#为什么会出现卡顿" class="headerlink" title="为什么会出现卡顿"></a>为什么会出现卡顿</h2><h3 id="1-浏览器多进程"><a href="#1-浏览器多进程" class="headerlink" title="1. 浏览器多进程"></a>1. 浏览器多进程</h3><p><strong>前提知识</strong>:浏览器多线程,js单线程。浏览器执行js是单线程执行,意思是在运行时,只有一个线程,并不代表浏览器只有一个线程。 </p><p>现代浏览器中通常会有两个重要的执行线程,这两个线程协同工作来渲染一个页面 —— 主线程,合成线程。</p><ul><li>主线程:运行Javascript,计算HTML元素的CSS样式,页面的布局,将元素绘制到一个或多个位图中,将这些位图交给合成线程;</li><li>合成线程:通过GPU将位图绘制到屏幕上,通知主线程更新页面中可见或即将变成可见的部分位图,计算出页面中哪些部分是可见的,计算当你在滚动页面时哪部分是即将可见的,当你滚动页面时将相应位置的元素移动到可视区域;</li></ul><h3 id="2-卡顿原因-2"><a href="#2-卡顿原因-2" class="headerlink" title="2. 卡顿原因(2)"></a>2. 卡顿原因<sup>(2)</sup></h3><p>如果长时间执行JavaScript或者渲染一个很大的元素会阻塞主线程,在这期间,是无法响应用户的交互。而合成线程则是会尽量去响应用户的交互,当一个页面发生变化时,合成线程会以每秒60帧的间隔去不断重绘这个页面,即使这个页面不完整。而动画的卡顿就是因为主线程和合成线程的调度不合理。</p><p>合成线程会使用GPU将位图绘制到屏幕上,而且GPU相对于CPU而言,更擅长做类似绘图这种重复但是计算量不高的事;CPU的话,更适合做大量的数据计算。【GPU的存储比CPU存储要小的很多】<br>GPU在页面渲染中,快在于:绘制位图到屏幕上,一遍又一遍地绘制相同的位图,将同一位图绘制到不同位置,执行渲染以及缩放处理;慢在于:需要将从CPU接受到的位图加载到它的内存中。</p><p>🍊🌰</p><blockquote><p><em>将一个元素的height从100px改成200px,使用transition: height 0.5s; 来实现过渡效果</em><br>对于使用transition来实现的动画效果,并不会触发硬件加速(也就是GPU),因此,会按照正常的进行。出现的流程就是:主线程-layout元素 => 主线程-paint元素 => 合成线程-更新位图到GPU的存储 => 合成线程-GPU绘制位图到屏幕 => 主线程-开始执行CSS设置的transition =><br>主线程-设置height为101px => 主线程-relayout元素 => 主线程-repaint元素 => 合成线程-更新位图到GPU的存储 => 合成线程-GPU绘制位图到屏幕 =><br>主线程-设置height为102px => 主线程-relayout元素 => 主线程-repaint元素 => 合成线程-更新位图到GPU的存储 => 合成线程-GPU绘制位图到屏幕 =><br>… =><br>… =><br>… =></p></blockquote><p>上面的🌰:意味着浏览器要做大量的工作,意味着这个动画可能会变得卡顿。在动画的每一帧中,浏览器都需要执行布局、绘制、以及将最新的位图传递给GPU。上面提到过,将位图加载到GPU内存中是一个相对比较慢的操作,而且改变了一个元素的高度可能会导致需要同步改变它的子元素、相邻元素、父元素等相关元素的大小,则会触发浏览器重新布局,布局又是一件相对比较慢的操作。那有没有什么办法能够减少位图加载到GPU内存的这一操作或者不触发重新布局呢? </p><!--CPU传输到GPU一个位图,GPU能快速对其进行偏移、缩放、旋转、修改透明度等操作开启硬件加速,让动画元素独立创建一个层。GPU硬件加速优缺点:不要滥用GPU资源,因为GPU会生成不必要的Layer,留意意外生产的Layer。尤其在给A元素使用了硬件加速,会使得A元素之上的元素[z-index比A高,以及A元素的子元素]隐形地生成复合层,在此过程中,会引起重排重绘,将隐形复合层的相关信息传输到GPU,原本所在的层会删除。【措辞待优化】硬件加速意味着Graphics Processing Unit(GPU)会通过代替Central Processing Unit (CPU)做一些负荷比较大的事情,来协助浏览器快速渲染页面,当CSS操作使用硬件加速的时候,通常会使页面渲染速度加快顾名思义,CPU和GPU都是计算机处理单元。CPU在电脑主板,几乎处理电脑的一切操作,有电脑大脑之称;GPU在显卡上,负责处理和渲染图形。此外GPU通过特殊的设计,使其擅长于渲染图形所需的数学和几何运算。因此把操作转嫁到GPU可以获得显著的性能提升,同时也可以减少移动设备CPU的争用。硬件加速(或者说GPU加速)依赖于浏览器渲染页面使用的layering model,当特定的操作(CSS 3D变形)作用于页面上的一个元素,元素移动到它自己的layer,在这个layer中元素合一不受页面其他元素的干扰独立渲染,然后复合到页面中去。在这种隔离内容渲染的工作方式下,如果页面的变化仅仅是该元素的变形,其余部分不必被重新渲染,这会带来显著的速度优势。值得注意的是只有3D变形会有自己的layer,2D变形不会。--><!--js运作在浏览器中,是单线程的,js代码始终在一个线程上执行,此线程被称作js引擎线程。以下是浏览器常见的几种线程: JS引擎线程:也称为JS内核,负责处理Javascript脚本程序。 GUI渲染线程:负责渲染浏览器界面,解析HTML,CSS,构建DOM树和RenderObject树,布局和绘制等。当界面需要重绘或者由于某种操作引发回流(reflow) 时,该线程就会执行。还有事件触发线程,定时触发器线程,异步http请求线程 [^ 传送门 ^](https://www.cnblogs.com/cangqinglang/p/8963557.html) > 注意:GUI渲染线程和JS引擎线程是互斥的,不可以同时运行。 >    假设在使用Javascript操作DOM的同时渲染界面(即JS引擎线程和GUI渲染线程同时运行),那么渲染线程前后获得的元素数据就有可能不一样。为了防止渲染出现不可预期的结果,浏览器就设置JS引擎线程和GUI渲染线程为互斥关系,当JS引擎线程执行时GUI渲染线程就会被挂起,UI页面更新会被保存在一个队列中,等到JS引擎线程空闲时立即执行。进程和线程时不一样的,具体区别大家可以自己去了解,在这就不详细叙述了。 浏览器是多进程的,主要的进程有如下:`Browser进程`:浏览器的主进程(负责协调、主控),只有一个。 `第三方插件进程`:每种类型的插件对应一个进程,绘制到用户界面上。 `GPU进程`:最多一个,用于3D绘制等。 `浏览器渲染进程`(浏览器内核,Renderer进程,内部是多线程的)--><p><br></p><h2 id="网页的分层机制"><a href="#网页的分层机制" class="headerlink" title="网页的分层机制"></a>网页的分层机制</h2><p>如果想要使用GPU硬件加速来解决CSS动画卡顿问题,那么就需要了解一下网页的分层机制。<br>网页中的元素分布在不同的层次中,并且CSS的一些代码会对网页的分层策略产生影响,对于一些需要复杂变换和处理的元素,它们需要新层。 </p><p><strong>为什么会网页要分层?</strong> </p><ul><li>方便网页开发者开发网页并设置网页的层次;</li><li>为了webkit处理上的便利,也就是为了简化渲染的逻辑</li></ul><h3 id="1-Chrome的网页渲染方式"><a href="#1-Chrome的网页渲染方式" class="headerlink" title="1. Chrome的网页渲染方式"></a>1. Chrome的网页渲染方式</h3><p>  在完成构建DOM后,webkit就会构建渲染的内部表示并使用图形库将这些模型绘制出来。网页的渲染方式,目前主要两种方式:软件渲染(绘图操作使用CPU,也就是软件绘图);硬件加速渲染(绘图操作使用GPU,也就是GPU硬件加速绘图)<sup>(1)</sup> ,其实还有一种混合模式:多个层的渲染结果合并到一个图像中,称之为合成渲染。DOM中的每个节点都直接或者间接地对应一个层,一些层有自己的支撑平面,这些层被称为复合层,对于这些复合层而言,compositer是利用GPU将它最终渲染到屏幕上的。 </p><h3 id="2-复合层"><a href="#2-复合层" class="headerlink" title="2. 复合层"></a>2. 复合层</h3><p><strong>复合层形成的条件:</strong> </p><ul><li>含有CSS 3D属性或者CSS透视效果</li><li>使用了硬件加速的视频解码技术的HTML5的video元素</li><li>使用了硬件加速的Canvas 2D元素或者WebGL技术</li><li>CSS透明效果的动画或者CSS变化的动画</li><li>使用了硬件加速的CSS Filters技术</li><li>元素有一个包含复合层的后代节点(也就是,一个元素有一个子元素,子元素是在自己层里的)</li><li>元素有一个z-index较低且包含一个复合层的兄弟元素(换句话说就是该元素在复合层上面渲染)</li></ul><p>最后一条,原文:Element has a sibling with a lower z-index which has a compositing layer (in other words the it’s rendered on top of a composited layer) </p><p>简单点说,主要就是translate3d,translateZ,opacity属性/过渡动画(需要动画执行的过程中才会创建合成层,动画没有开始或者结束后元素还会回到之前的状态),will-change属性。【注意:absolute并不会引起复合层生成】</p><p><strong>absolute和硬件加速的区别</strong><br>absolute:脱落文档流,但是无法脱离默认复合层(也就是和document在一层的)。absolute文档中信息改变时,也不会改变普通文档流中render树。但是浏览器最终绘制时,是整个复合层绘制,所以absolute中信息的改变,仍然会影响整个复合层的绘制,一旦复合层中内容过错,absolute带来的绘制信息变化过大,资源消耗就会变得非常严重。<br>硬件加速:使用硬件加速的会在另外一个复合层中,会自己拥有一个自己的复合层(不是所有的硬件加速在一个复合层中),所以它的信息改变不会影响默认复合层,只会影响属于自己的复合层,只引发最后的合成。</p><h3 id="3-GPU绘图与重排"><a href="#3-GPU绘图与重排" class="headerlink" title="3. GPU绘图与重排"></a>3. GPU绘图与重排</h3><p>  GPU绘图,通常不像软件渲染那样只是计算其中更新的区域,一旦有更新请求,如果没有分层,引擎可能需要重新绘制所有的区域,因为计算更新部分对GPU来说可能耗费更多的时间【毕竟GPU的设计不是为了计算】。当网页分层之后,部分区域的更新可能只在网页的一层或者几层,而不需要将整个网页都重新绘制。通过重新绘制网页的一个或者几个层,并将它们和其他之前绘制完的层[没有重新绘制的层]合成起来,既能使用GPU的能力,又能够减少重绘的开销。因此,在做动画时让GPU参与进来,会提高动画性能。</p><p>  重排,一般需要三个阶段:计算布局(recalculate style)、绘图(update layer tree)和合成(composite layer)。如果想要减少每一帧的时间,提高性能,就着重减少这三个阶段的时间。其中,计算布局和绘图比较费时间,而合成需要的时间相对要少一些。而且,当布局的变化越多,webkit通常需要越多的绘图时间。减少绘制每帧的时间:使用合适的网页分层技术以减少需要重新计算的布局和绘图;使用CSS 3D变形和动画技术。</p><p><br></p><h2 id="硬件加速"><a href="#硬件加速" class="headerlink" title="硬件加速"></a>硬件加速</h2><p>CSS的动画、变形、渐变并不会自动的触发GPU加速,而是使用浏览器稍慢的软件渲染引擎。然而一些浏览器提供了一些可以触发硬件加速的属性来获取更高的渲染性能。 举个例子,opacity属性是几个能够加速的属性之一,因为GPU可以方便的处理。基本上任何层的透明度渐变浏览器都会交给GPU处理来加速。除了opacity能够使用GPU处理的就是CSS 3D变形了。<br>触发GPU硬件加速的属性:opacity,transform,filter,will-change</p><h3 id="1-translateZ-or-translate3d-Hack"><a href="#1-translateZ-or-translate3d-Hack" class="headerlink" title="1. translateZ() (or translate3d()) Hack"></a>1. translateZ() (or translate3d()) Hack</h3><p>很长一段时间内我们都通过translateZ()或者translate3d() hack来骗取浏览器触发硬件加速,具体做法就是为元素添加没有变化的3D变形,比如元素在2维空间可以通过添加以下CSS来硬件加速 </p><blockquote><p>transform: translate3d(0, 0, 0); </p></blockquote><p>所谓硬件加速就是创建了一个被传递到GPU处理的层的操作,然而强制使用hack方式创建layer并不是长久之计,创建layer的技术可以使页面加速,但是也有代价:它们占用RAM和GPU存储空间(考虑到移动设备的存储容量有限),所以必须小心使用,确保这么做真的对页面渲染有所帮助<br>【案例:<a href="http://periodic.famo.us/" target="_blank" rel="noopener">famo.us网站</a>】</p><blockquote><p><a href="https://jsperf.com/translate3d-vs-xy/28" target="_blank" rel="noopener">translate3d、translate、top/left、margin对比</a></p></blockquote><p>为了避免创建layer的hacks,一个允许我们提前通知浏览器我们将对元素做何种变化的CSS属性被引入,这样浏览器可以优化处理元素渲染的方式,为元素提前准备昂贵的动画处理操作,这就是wiil-change属性</p><h3 id="2-will-change"><a href="#2-will-change" class="headerlink" title="2. will-change"></a>2. will-change</h3><p>will-change属性可以提前通知浏览器我们要对元素做什么动画,这样浏览器可以提前准备合适的优化设置。这样可以避免对页面响应速度有重要影响的昂贵成本。元素可以更快的被改变,渲染的也更快,这样页面可以快速更新,表现的更加流畅。</p><p>举个例子,当对于素使用 CSS 3D变形时,元素及其内容可以在合成到页面之前被创建到我们之前说的layer。然而把元素放到layer中是个昂贵的操作,这将会导致变形动画延迟一个课件的瞬间,也就是flicker</p><p>为了避免这种延时,我们可以在发生之前通知浏览器,这样浏览器会有一定的时间去准备这些变化,当发生的时候layer已经准备好了,这样动画就会很流畅,不会闪屏</p><p>使用will-change提示浏览器关于即将发生的变形十分简单,添加个CSS属性就行</p><p>will-change: transform;<br>也可以告诉浏览器要改变元素的滚动条位置,或者多个要变化的属性,写下属性的名字就行,也可以写多个,逗号隔开</p><p>will-change: transform, opacity;<br>声明了元素即将进行的变化会让浏览器在渲染页面时做更好的决定,这明显比之前说的3D hacks要好。<br><br></p><p><strong>提升为合成层简单说来有以下几点好处</strong></p><ul><li>合成层的位图,会交由 GPU 合成,比 CPU 处理要快</li><li>当需要 repaint 时,只需要 repaint 本身,不会影响到其他的层</li><li>对于 transform 和 opacity 效果,不会触发 layout 和 paint</li></ul><h2 id="transform代替盒模型属性变化"><a href="#transform代替盒模型属性变化" class="headerlink" title="transform代替盒模型属性变化"></a>transform代替盒模型属性变化</h2><p>在使用CSS3 transition做动画效果时,transform实现的动画是与合成器线程有关的,不需要等待主线程样式计算或者JS执行,计算速度很快的;而height,width,margin和padding时,导致布局和绘制的调整,主线程需要重新计算样式并且执行JS,计算速度自然就慢了。 </p><blockquote><p>案例:安徽门户首页快捷入口动画,使用margin-left,left,transform的性能差异</p></blockquote><ul><li><p>left<br>  <img src="left.png" alt="left的重绘和重绘时间"><br>  <img src="left-GPU.png" alt="left的GPU使用率"></p></li><li><p>margin-left<br>  <img src="margin.png" alt="margin-left的重绘和重绘时间"><br>  <img src="margin-GPU.png" alt="margin-left的GPU使用率"></p></li><li><p>transfrom - translate<br>  <img src="translate.png" alt="transform-translatet的重绘和重绘时间"><br>  <img src="translate-GPU1.png" alt="transform-translate的GPU使用率"><br>  <img src="translate-GPU2.png" alt="transform-translate的GPU使用率"></p></li></ul><p>耗时对比表,方便计算</p><table><thead><tr><th>耗时</th><th>left</th><th>margin</th><th>transform</th></tr></thead><tbody><tr><td>Summery</td><td>5546ms</td><td>5306ms</td><td>6075ms</td></tr><tr><td>Scripting</td><td>1723.7ms</td><td>1487.6ms</td><td>1488.4ms</td></tr><tr><td>Rendering</td><td>183ms</td><td>191.6ms</td><td>95.3ms</td></tr><tr><td>Painting</td><td>464.6ms</td><td>450.5ms</td><td>78.5ms</td></tr><tr><td>Other</td><td>167.2ms</td><td>165.1ms</td><td>122.2ms</td></tr><tr><td>Idle</td><td>3007.5ms</td><td>3010.6ms</td><td>4291ms</td></tr><tr><td>GPU使用率</td><td>13.7MB</td><td>13.7MB</td><td>平均在22MB,最大可达到23MB+</td></tr></tbody></table><p>通过上面的表格我们可以计算出left,margin,transform-translate实现CSS3动画效果时的性能差异参数。</p><table><thead><tr><th>关键性能参数</th><th>left</th><th>margin</th><th>transform</th></tr></thead><tbody><tr><td>实际动画耗时(总时间 - 空闲时间)</td><td>2538.5ms</td><td>2295.4ms</td><td>1784ms</td></tr></tbody></table><p>计算得出,transform动画耗时约等于其他两个的0.7-0.77倍。<br>对于Other做了什么事情,并不了解,如果实际动画时间还需要减去Other中的时间的话,数据如下:</p><table><thead><tr><th>关键性能参数</th><th>left</th><th>margin</th><th>transform</th></tr></thead><tbody><tr><td>实际动画耗时(总时间 - 空闲时间 - Other时间)</td><td>2371.3ms</td><td>2130.3ms</td><td>1661.8ms</td></tr></tbody></table><p><strong>在使用css3 transtion做动画效果时,优先选择transform,尽量不要使用height,width,margin和padding。</strong></p><h2 id="GPU硬件加速合理使用"><a href="#GPU硬件加速合理使用" class="headerlink" title="GPU硬件加速合理使用"></a>GPU硬件加速合理使用</h2><p>缺点:1. 肆无忌惮的开启GPU硬件加速会导致大量消耗设备电量,降低电池寿命【主要是在移动端】;同时,也会占用浏览器网页用户的大量系统资源; </p><ol start="2"><li>不合理的GPU硬件加速会合成不必要的隐形复合层,这样会让原本在默认复合层的删除,又要布局,绘制位图,传输到GPU,存储到GPU内存这些不必要的操作; </li><li>GPU渲染会影响字体的抗锯齿效果 <a href="https://segmentfault.com/q/1010000000467910" target="_blank" rel="noopener">字体渲染-webkit-font-smoothing</a>; </li></ol><p><a href="https://csstriggers.com/" title="csstriggers-layout、paint、composite" target="_blank" rel="noopener">单个CSS属性给浏览器带来哪些工作量-参考网站</a><br><a href="https://www.smashingmagazine.com/2016/12/gpu-animation-doing-it-right/" target="_blank" rel="noopener">CSS GPU Animation: Doing It Right</a><br><a href="https://www.html5rocks.com/zh/tutorials/speed/layers/" target="_blank" rel="noopener">Accelerated Rendering in Chrome</a><br><a href="https://www.html5rocks.com/zh/tutorials/speed/high-performance-animations/" target="_blank" rel="noopener">High Performance Animations</a><br><a href="https://div.io/topic/1348" target="_blank" rel="noopener">GPU硬件加载的坑</a></p><p><strong>参考文档</strong><br>(1)webkit技术内幕[朱永盛] 第七章 渲染基础<br>(2)<a href="http://blogs.adobe.com/webplatform/2014/03/18/css-animations-and-transitions-performance/" target="_blank" rel="noopener">CSS animations and transitions performance: looking inside the browser</a></p>]]></content>
<summary type="html">
<p>每个项目中或多或少地会使用到动画,使得用户体验效果更好。通常简单的动画对性能影响很小,但是涉及到稍微复杂的动画或者在配置比较低的机器上时,一些不当的处理方式会使性能问题变得十分突出……<br>
</summary>
</entry>
<entry>
<title>CSS预编译器-Less</title>
<link href="http://yoursite.com/2019/05/24/CSS%E9%A2%84%E7%BC%96%E8%AF%91%E5%99%A8-Less/"/>
<id>http://yoursite.com/2019/05/24/CSS预编译器-Less/</id>
<published>2019-05-24T06:25:16.000Z</published>
<updated>2019-06-10T10:53:23.699Z</updated>
<content type="html"><![CDATA[<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>CSS的语法比较简单,但是有时候为了让两个元素(拥有同一个类名)的样式不一样,就需要添加另外一个类或者在书写CSS的时候多加层级。这样很不方便,而且也容易出错。除此还有在CSS中没有变量、函数这种概念,并且有时候为了兼容不同浏览器要写一堆类似的样式。<br><br>在css预编译器中,上面的问题都可以得到解决。css预编译器有很多:Sass、Less 、Stylus这三种是比较常用的,彼此之间都是大同小异。</p><h2 id="变量"><a href="#变量" class="headerlink" title="变量"></a>变量</h2><h3 id="1-值变量"><a href="#1-值变量" class="headerlink" title="1. 值变量"></a>1. 值变量</h3><p>定义<code>@ + 变量名称:值;</code>使用的时候直接就是<code>@ + 变量</code><br><br>在页面样式中,经常会出现好多字体或者背景色什么的设置都是一样的,但是有时候需要把原系统的样式配色换一套,这个时候就需要全局搜索,而且一不小心还会改错。这个时候特别希望能够拥有js的定义变量常量,再赋值的功能,就如下:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> bgColor=<span class="string">"skyblue"</span>;</span><br><span class="line">$(<span class="string">".post-content"</span>).css(<span class="string">"background-color"</span>,bgColor);</span><br><span class="line">$(<span class="string">"#wrap"</span>).css(<span class="string">"background-color"</span>,bgColor);</span><br><span class="line">$(<span class="string">".arctive"</span>).css(<span class="string">"background-color"</span>,bgColor);</span><br></pre></td></tr></table></figure><p>Less变量书写</p><figure class="highlight less"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* Less */</span></span><br><span class="line"><span class="variable">@color:</span> <span class="number">#999</span>;</span><br><span class="line"><span class="variable">@bgColor:</span> skyblue;<span class="comment">//不要添加引号</span></span><br><span class="line"><span class="variable">@width:</span> <span class="number">50%</span>;</span><br><span class="line"><span class="selector-id">#wrap</span> {</span><br><span class="line"> <span class="attribute">color</span>: <span class="variable">@color</span>;</span><br><span class="line"> <span class="attribute">background</span>: <span class="variable">@bgColor</span>;</span><br><span class="line"> <span class="attribute">width</span>: <span class="variable">@width</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 生成后的 CSS */</span></span><br><span class="line"><span class="selector-id">#wrap</span> {</span><br><span class="line"> <span class="attribute">color</span>: <span class="number">#999</span>;</span><br><span class="line"> <span class="attribute">background</span>: skyblue;</span><br><span class="line"> <span class="attribute">width</span>: <span class="number">50%</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="2-选择器变量"><a href="#2-选择器变量" class="headerlink" title="2. 选择器变量"></a>2. 选择器变量</h3><p>定义<code>@ + 变量名称:值;</code>使用的时候直接就是<code>@ + { + 变量 + }</code>,要使用大括号包裹变量名<br><br>选择器变成动态的,后期修改html的css以及ID的时候可以不用重写,直接修改变量值。</p><figure class="highlight less"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* Less */</span></span><br><span class="line"><span class="variable">@mySelector:</span> #wrap;</span><br><span class="line"><span class="variable">@Wrap:</span> wrap;</span><br><span class="line"><span class="variable">@{mySelector}</span>{ <span class="comment">//变量名 必须使用大括号包裹</span></span><br><span class="line"> <span class="attribute">color</span>: <span class="number">#999</span>;</span><br><span class="line"> <span class="attribute">width</span>: <span class="number">50%</span>;</span><br><span class="line">}</span><br><span class="line"><span class="selector-class">.@{Wrap}</span>{</span><br><span class="line"> <span class="attribute">color</span>:<span class="number">#ccc</span>;</span><br><span class="line">}</span><br><span class="line"><span class="selector-id">#@{Wrap}</span>{</span><br><span class="line"> <span class="attribute">color</span>:<span class="number">#666</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 生成的 CSS */</span></span><br><span class="line"><span class="selector-id">#wrap</span>{</span><br><span class="line"> <span class="attribute">color</span>: <span class="number">#999</span>;</span><br><span class="line"> <span class="attribute">width</span>: <span class="number">50%</span>;</span><br><span class="line">}</span><br><span class="line"><span class="selector-class">.wrap</span>{</span><br><span class="line"> <span class="attribute">color</span>:<span class="number">#ccc</span>;</span><br><span class="line">}</span><br><span class="line"><span class="selector-id">#wrap</span>{</span><br><span class="line"> <span class="attribute">color</span>:<span class="number">#666</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="3-属性变量"><a href="#3-属性变量" class="headerlink" title="3. 属性变量"></a>3. 属性变量</h3><p>定义<code>@ + 变量名称:值;</code>使用的时候直接就是<code>@ + { + 变量 + }</code>,要使用大括号包裹变量名<br></p><figure class="highlight less"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* Less */</span></span><br><span class="line"><span class="variable">@borderStyle:</span> border-style;</span><br><span class="line"><span class="variable">@Soild:</span>solid;</span><br><span class="line"><span class="selector-id">#wrap</span>{</span><br><span class="line"> <span class="attribute">@{borderStyle}</span>: <span class="variable">@Soild</span>;<span class="comment">//变量名 必须使用大括号包裹</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 生成的 CSS */</span></span><br><span class="line"><span class="selector-id">#wrap</span>{</span><br><span class="line"> <span class="attribute">border-style</span>:solid;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="4-URL变量"><a href="#4-URL变量" class="headerlink" title="4. URL变量"></a>4. URL变量</h3><p>定义<code>@ + 变量名称:值;</code>使用的时候直接就是<code>@ + { + 变量 + }</code>,要使用大括号包裹变量名<br><br>比较常用的就是,将前面的相同路径定义成一个变量,后期如果image文件夹修改路径了,可以直接修改这个变量,不用每个URL都要修改了。主要就是提取相同的绝对/相对路径。</p><figure class="highlight less"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* Less */</span></span><br><span class="line"><span class="variable">@images:</span> <span class="string">"../img"</span>;<span class="comment">//需要加引号</span></span><br><span class="line"><span class="selector-tag">body</span> {</span><br><span class="line"> <span class="attribute">background</span>: url(<span class="string">"@{images}/dog.png"</span>);<span class="comment">//变量名 必须使用大括号包裹</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 生成的 CSS */</span></span><br><span class="line"><span class="selector-tag">body</span> {</span><br><span class="line"> <span class="attribute">background</span>: url(<span class="string">"../img/dog.png"</span>);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="5-声明变量"><a href="#5-声明变量" class="headerlink" title="5. 声明变量"></a>5. 声明变量</h3><p>定义<code>@name:{属性: 值;};</code>使用的时候直接就是<code>@name()</code>,要使用大括号包裹变量名<br><br>可以将一堆相同的样式提取出来</p><figure class="highlight less"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* Less */</span></span><br><span class="line"><span class="variable">@background:</span> {<span class="attribute">background</span>:red;};</span><br><span class="line"><span class="selector-id">#main</span>{</span><br><span class="line"> <span class="variable">@background</span>();</span><br><span class="line">}</span><br><span class="line"><span class="variable">@Rules:</span>{</span><br><span class="line"> <span class="attribute">width</span>: <span class="number">200px</span>;</span><br><span class="line"> <span class="attribute">height</span>: <span class="number">200px</span>;</span><br><span class="line"> <span class="attribute">border</span>: solid <span class="number">1px</span> red;</span><br><span class="line">};</span><br><span class="line"><span class="selector-id">#con</span>{</span><br><span class="line"> <span class="variable">@Rules</span>();</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 生成的 CSS */</span></span><br><span class="line"><span class="selector-id">#main</span>{</span><br><span class="line"> <span class="attribute">background</span>:red;</span><br><span class="line">}</span><br><span class="line"><span class="selector-id">#con</span>{</span><br><span class="line"> <span class="attribute">width</span>: <span class="number">200px</span>;</span><br><span class="line"> <span class="attribute">height</span>: <span class="number">200px</span>;</span><br><span class="line"> <span class="attribute">border</span>: solid <span class="number">1px</span> red;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="6-变量运算"><a href="#6-变量运算" class="headerlink" title="6. 变量运算"></a>6. 变量运算</h3><ul><li>加减法时,以第一个数据的单位为基准</li><li>乘除法时,注意单位一定要统一</li></ul><p>CSS3中有一个calc()函数,但是局限性比较大</p><figure class="highlight less"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* Less */</span></span><br><span class="line"><span class="variable">@width:</span><span class="number">300px</span>;</span><br><span class="line"><span class="variable">@color:</span><span class="number">#222</span>;</span><br><span class="line"><span class="selector-id">#wrap</span>{</span><br><span class="line"> <span class="attribute">width</span>:<span class="variable">@width-20</span>;</span><br><span class="line"> <span class="attribute">height</span>:<span class="variable">@width-20</span>*<span class="number">5</span>;</span><br><span class="line"> <span class="attribute">margin</span>:(<span class="variable">@width-20</span>)*<span class="number">5</span>;</span><br><span class="line"> <span class="attribute">color</span>:<span class="variable">@color</span>*<span class="number">2</span>;</span><br><span class="line"> <span class="attribute">background-color</span>:<span class="variable">@color</span> + <span class="number">#111</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 生成的 CSS */</span></span><br><span class="line"><span class="selector-id">#wrap</span>{</span><br><span class="line"> <span class="attribute">width</span>:<span class="number">280px</span>;</span><br><span class="line"> <span class="attribute">height</span>:<span class="number">200px</span>;</span><br><span class="line"> <span class="attribute">margin</span>:<span class="number">1400px</span>;</span><br><span class="line"> <span class="attribute">color</span>:<span class="number">#444</span>;</span><br><span class="line"> <span class="attribute">background-color</span>:<span class="number">#333</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="7-变量作用域"><a href="#7-变量作用域" class="headerlink" title="7. 变量作用域"></a>7. 变量作用域</h3><p>一句话理解就是:<strong>就近原则</strong>,不要跟我提闭包。</p><figure class="highlight less"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* Less */</span></span><br><span class="line"><span class="variable">@var:</span> <span class="variable">@a</span>;</span><br><span class="line"><span class="variable">@a:</span> <span class="number">100%</span>;</span><br><span class="line"><span class="selector-id">#wrap</span> {</span><br><span class="line"> <span class="attribute">width</span>: <span class="variable">@var</span>;</span><br><span class="line"> <span class="variable">@a:</span> <span class="number">9%</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 生成的 CSS */</span></span><br><span class="line"><span class="selector-id">#wrap</span> {</span><br><span class="line"> <span class="attribute">width</span>: <span class="number">9%</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="8-用变量去定义变量"><a href="#8-用变量去定义变量" class="headerlink" title="8. 用变量去定义变量"></a>8. 用变量去定义变量</h3><figure class="highlight less"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* Less */</span></span><br><span class="line"><span class="variable">@fnord:</span> <span class="string">"I am fnord."</span>;</span><br><span class="line"><span class="variable">@var:</span> <span class="string">"fnord"</span>;</span><br><span class="line"><span class="selector-id">#wrap</span><span class="selector-pseudo">::after</span>{</span><br><span class="line"> <span class="attribute">content</span>: <span class="variable">@@var</span>; <span class="comment">//将@var替换为其值 content:@fnord;</span></span><br><span class="line">}</span><br><span class="line"><span class="comment">/* 生成的 CSS */</span></span><br><span class="line"><span class="selector-id">#wrap</span><span class="selector-pseudo">::after</span>{</span><br><span class="line"> <span class="attribute">content</span>: <span class="string">"I am fnord."</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><br><br><br></p><h2 id="嵌套"><a href="#嵌套" class="headerlink" title="嵌套"></a>嵌套</h2><p>Less的嵌套是最常用的,并且具有层级关系,能够避免不同层级下的相同类名元素的样式相同。而且便于我们查找样式进行修改。</p><h3 id="1-amp-妙用"><a href="#1-amp-妙用" class="headerlink" title="1. & 妙用"></a>1. & 妙用</h3><p><code>&</code>: 代表的上一层选择器的名字,此例便是header。</p><figure class="highlight less"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* Less */</span></span><br><span class="line"><span class="selector-id">#header</span>{</span><br><span class="line"> <span class="selector-tag">&</span><span class="selector-pseudo">:after</span>{</span><br><span class="line"> <span class="attribute">content</span>:<span class="string">"Less is more!"</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="selector-class">.title</span>{</span><br><span class="line"> <span class="attribute">font-weight</span>:bold;</span><br><span class="line"> }</span><br><span class="line"> <span class="selector-tag">&</span><span class="selector-tag">_content</span>{<span class="comment">//理解方式:直接把 & 替换成 #header</span></span><br><span class="line"> <span class="attribute">margin</span>:<span class="number">20px</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="comment">/* 生成的 CSS */</span></span><br><span class="line"><span class="selector-id">#header</span><span class="selector-pseudo">::after</span>{</span><br><span class="line"> <span class="attribute">content</span>:<span class="string">"Less is more!"</span>;</span><br><span class="line">}</span><br><span class="line"><span class="selector-id">#header</span> <span class="selector-class">.title</span>{ <span class="comment">//嵌套了</span></span><br><span class="line"> <span class="attribute">font-weight</span>:bold;</span><br><span class="line">}</span><br><span class="line"><span class="selector-id">#header_content</span>{<span class="comment">//没有嵌套!</span></span><br><span class="line"> <span class="attribute">margin</span>:<span class="number">20px</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="2-媒体查询"><a href="#2-媒体查询" class="headerlink" title="2. 媒体查询"></a>2. 媒体查询</h3><p>在以往的工作中,我们使用 媒体查询,都要把一个元素 分开写</p><figure class="highlight less"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-id">#wrap</span>{</span><br><span class="line"> <span class="attribute">width</span>:<span class="number">500px</span>;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">@media</span> screen and (<span class="attribute">max-width</span>:<span class="number">768px</span>){</span><br><span class="line"> <span class="selector-id">#wrap</span>{</span><br><span class="line"> <span class="attribute">width</span>:<span class="number">100px</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>Less 提供了一个十分便捷的方式</p><figure class="highlight less"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* Less */</span></span><br><span class="line"><span class="selector-id">#main</span>{</span><br><span class="line"> <span class="comment">//something...</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">@media</span> screen{</span><br><span class="line"> <span class="keyword">@media</span> (<span class="attribute">max-width</span>:<span class="number">768px</span>){</span><br><span class="line"> <span class="attribute">width</span>:<span class="number">100px</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">@media</span> tv {</span><br><span class="line"> <span class="attribute">width</span>:<span class="number">2000px</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="comment">/* 生成的 CSS */</span></span><br><span class="line"><span class="keyword">@media</span> screen and (<span class="attribute">maxwidth</span>:<span class="number">768px</span>){</span><br><span class="line"> <span class="selector-id">#main</span>{</span><br><span class="line"> <span class="attribute">width</span>:<span class="number">100px</span>; </span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="keyword">@media</span> tv{</span><br><span class="line"> <span class="selector-id">#main</span>{</span><br><span class="line"> <span class="attribute">width</span>:<span class="number">2000px</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>唯一的缺点就是 每一个元素都会编译出自己 <code>@media</code> 声明,并不会合并。</p><blockquote><p>可以借助 Less 在元素中,去定义自己的私有样式。</p></blockquote><figure class="highlight less"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* Less */</span></span><br><span class="line"><span class="selector-id">#main</span>{</span><br><span class="line"> <span class="comment">// something..</span></span><br><span class="line"> <span class="selector-tag">&</span><span class="selector-class">.show</span>{</span><br><span class="line"> <span class="attribute">display</span>:block;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="selector-class">.show</span>{</span><br><span class="line"> <span class="attribute">display</span>:none;</span><br><span class="line">}</span><br><span class="line"><span class="comment">/* 生成的 CSS */</span></span><br><span class="line"><span class="selector-id">#main</span><span class="selector-class">.show</span>{</span><br><span class="line"> <span class="attribute">display</span>:block;</span><br><span class="line">}</span><br><span class="line"><span class="selector-class">.show</span>{</span><br><span class="line"> <span class="attribute">display</span>:none; <span class="comment">//会被覆盖。</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="混合方法-mixin"><a href="#混合方法-mixin" class="headerlink" title="混合方法-mixin"></a>混合方法-mixin</h2><h3 id="1-无参数方法"><a href="#1-无参数方法" class="headerlink" title="1. 无参数方法"></a>1. 无参数方法</h3><p>方法犹如 声明的集合,使用时 直接键入名称即可。</p><figure class="highlight less"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* Less */</span></span><br><span class="line"><span class="selector-class">.card</span> { <span class="comment">// 等价于 .card()</span></span><br><span class="line"> <span class="attribute">background</span>: <span class="number">#f6f6f6</span>;</span><br><span class="line"> <span class="attribute">box-shadow</span>: <span class="number">0</span> <span class="number">1px</span> <span class="number">2px</span> rgba(<span class="number">151</span>, <span class="number">151</span>, <span class="number">151</span>, .<span class="number">58</span>);</span><br><span class="line">}</span><br><span class="line"><span class="selector-id">#wrap</span>{</span><br><span class="line"> <span class="selector-class">.card</span>;<span class="comment">//等价于.card();</span></span><br><span class="line">}</span><br><span class="line"><span class="comment">/* 生成的 CSS */</span></span><br><span class="line"><span class="selector-id">#wrap</span>{</span><br><span class="line"> <span class="attribute">background</span>: <span class="number">#f6f6f6</span>;</span><br><span class="line"> <span class="attribute">box-shadow</span>: <span class="number">0</span> <span class="number">1px</span> <span class="number">2px</span> rgba(<span class="number">151</span>, <span class="number">151</span>, <span class="number">151</span>, .<span class="number">58</span>);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>其中 <code>.card</code> 与 <code>.card()</code> 是等价的</p><ul><li>. 与 # 皆可作为 方法前缀。</li><li>方法后写不写 () 看个人习惯。</li></ul><h3 id="2-默认参数方法"><a href="#2-默认参数方法" class="headerlink" title="2. 默认参数方法"></a>2. 默认参数方法</h3><ul><li>Less 可以使用默认参数,如果 没有传参数,那么将使用默认参数。</li><li>@arguments 犹如 JS 中的 arguments 指代的是 全部参数。</li><li>传的参数中 必须带着单位。</li></ul><figure class="highlight less"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* Less */</span></span><br><span class="line"><span class="selector-class">.border</span>(<span class="variable">@a</span>:<span class="number">10px</span>,<span class="variable">@b</span>:<span class="number">50px</span>,<span class="variable">@c</span>:<span class="number">30px</span>,<span class="variable">@color</span>:<span class="number">#000</span>){</span><br><span class="line"> <span class="attribute">border</span>:solid <span class="number">1px</span> <span class="variable">@color</span>;</span><br><span class="line"> <span class="attribute">box-shadow</span>: <span class="variable">@arguments</span>;<span class="comment">//指代的是 全部参数</span></span><br><span class="line">}</span><br><span class="line"><span class="selector-id">#main</span>{</span><br><span class="line"> <span class="selector-class">.border</span>(<span class="number">0px</span>,<span class="number">5px</span>,<span class="number">30px</span>,red);<span class="comment">//必须带着单位</span></span><br><span class="line">}</span><br><span class="line"><span class="selector-id">#wrap</span>{</span><br><span class="line"> <span class="selector-class">.border</span>(<span class="number">0px</span>);</span><br><span class="line">}</span><br><span class="line"><span class="selector-id">#content</span>{</span><br><span class="line"> <span class="selector-class">.border</span>;<span class="comment">//等价于 .border()</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 生成的 CSS */</span></span><br><span class="line"><span class="selector-id">#main</span>{</span><br><span class="line"> <span class="attribute">border</span>:solid <span class="number">1px</span> red;</span><br><span class="line"> <span class="attribute">box-shadow</span>:<span class="number">0px</span>,<span class="number">5px</span>,<span class="number">30px</span>,red;</span><br><span class="line">}</span><br><span class="line"><span class="selector-id">#wrap</span>{</span><br><span class="line"> <span class="attribute">border</span>:solid <span class="number">1px</span> <span class="number">#000</span>;</span><br><span class="line"> <span class="attribute">box-shadow</span>: <span class="number">0px</span> <span class="number">50px</span> <span class="number">30px</span> <span class="number">#000</span>;</span><br><span class="line">}</span><br><span class="line"><span class="selector-id">#content</span>{</span><br><span class="line"> <span class="attribute">border</span>:solid <span class="number">1px</span> <span class="number">#000</span>;</span><br><span class="line"> <span class="attribute">box-shadow</span>: <span class="number">10px</span> <span class="number">50px</span> <span class="number">30px</span> <span class="number">#000</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="3-方法的匹配模式"><a href="#3-方法的匹配模式" class="headerlink" title="3. 方法的匹配模式"></a>3. 方法的匹配模式</h3><p>与 面向对象中的多态 很相似</p><figure class="highlight less"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* Less */</span></span><br><span class="line"><span class="selector-class">.triangle</span>(top,<span class="variable">@width</span>:<span class="number">20px</span>,<span class="variable">@color</span>:<span class="number">#000</span>){</span><br><span class="line"> <span class="attribute">border-color</span>:transparent transparent <span class="variable">@color</span> transparent ;</span><br><span class="line">}</span><br><span class="line"><span class="selector-class">.triangle</span>(right,<span class="variable">@width</span>:<span class="number">20px</span>,<span class="variable">@color</span>:<span class="number">#000</span>){</span><br><span class="line"> <span class="attribute">border-color</span>:transparent <span class="variable">@color</span> transparent transparent ;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="selector-class">.triangle</span>(bottom,<span class="variable">@width</span>:<span class="number">20px</span>,<span class="variable">@color</span>:<span class="number">#000</span>){</span><br><span class="line"> <span class="attribute">border-color</span>:<span class="variable">@color</span> transparent transparent transparent ;</span><br><span class="line">}</span><br><span class="line"><span class="selector-class">.triangle</span>(left,<span class="variable">@width</span>:<span class="number">20px</span>,<span class="variable">@color</span>:<span class="number">#000</span>){</span><br><span class="line"> <span class="attribute">border-color</span>:transparent transparent transparent <span class="variable">@color</span>;</span><br><span class="line">}</span><br><span class="line"><span class="selector-class">.triangle</span>(<span class="variable">@_</span>,<span class="variable">@width</span>:<span class="number">20px</span>,<span class="variable">@color</span>:<span class="number">#000</span>){</span><br><span class="line"> <span class="attribute">border-style</span>: solid;</span><br><span class="line"> <span class="attribute">border-width</span>: <span class="variable">@width</span>;</span><br><span class="line">}</span><br><span class="line"><span class="selector-id">#main</span>{</span><br><span class="line"> <span class="selector-class">.triangle</span>(left, <span class="number">50px</span>, <span class="number">#999</span>)</span><br><span class="line">}</span><br><span class="line"><span class="comment">/* 生成的 CSS */</span></span><br><span class="line"><span class="selector-id">#main</span>{</span><br><span class="line"> <span class="attribute">border-color</span>:transparent transparent transparent <span class="number">#999</span>;</span><br><span class="line"> <span class="attribute">border-style</span>: solid;</span><br><span class="line"> <span class="attribute">border-width</span>: <span class="number">50px</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><ul><li>第一个参数 left 要会找到方法中匹配程度最高的,如果匹配程度相同,将全部选择,并存在着样式覆盖替换。</li><li>如果匹配的参数 是变量,则将会匹配,如 @_ 。</li></ul><h3 id="4-方法的命名空间"><a href="#4-方法的命名空间" class="headerlink" title="4. 方法的命名空间"></a>4. 方法的命名空间</h3><p>让方法更加规范</p><figure class="highlight less"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* Less */</span></span><br><span class="line"><span class="selector-id">#card</span>(){</span><br><span class="line"> <span class="attribute">background</span>: <span class="number">#723232</span>;</span><br><span class="line"> <span class="selector-class">.d</span>(<span class="variable">@w</span>:<span class="number">300px</span>){</span><br><span class="line"> <span class="attribute">width</span>: <span class="variable">@w</span>;</span><br><span class="line"> </span><br><span class="line"> <span class="selector-id">#a</span>(<span class="variable">@h</span>:<span class="number">300px</span>){</span><br><span class="line"> <span class="attribute">height</span>: <span class="variable">@h</span>;<span class="comment">//可以使用上一层传进来的方法</span></span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="selector-id">#wrap</span>{</span><br><span class="line"> <span class="selector-id">#card</span> > <span class="selector-class">.d</span> > <span class="selector-id">#a</span>(<span class="number">100px</span>); <span class="comment">// 父元素不能加 括号</span></span><br><span class="line">}</span><br><span class="line"><span class="selector-id">#main</span>{</span><br><span class="line"> <span class="selector-id">#card</span> <span class="selector-class">.d</span>();</span><br><span class="line">}</span><br><span class="line"><span class="selector-id">#con</span>{</span><br><span class="line"> <span class="comment">//不得单独使用命名空间的方法</span></span><br><span class="line"> <span class="comment">//.d() 如果前面没有引入命名空间 #card ,将会报错</span></span><br><span class="line"> </span><br><span class="line"> <span class="selector-id">#card</span>; <span class="comment">// 等价于 #card();</span></span><br><span class="line"> <span class="selector-class">.d</span>(<span class="number">20px</span>); <span class="comment">//必须先引入 #card</span></span><br><span class="line">}</span><br><span class="line"><span class="comment">/* 生成的 CSS */</span></span><br><span class="line"><span class="selector-id">#wrap</span>{</span><br><span class="line"> <span class="attribute">height</span>:<span class="number">100px</span>;</span><br><span class="line">}</span><br><span class="line"><span class="selector-id">#main</span>{</span><br><span class="line"> <span class="attribute">width</span>:<span class="number">300px</span>;</span><br><span class="line">}</span><br><span class="line"><span class="selector-id">#con</span>{</span><br><span class="line"> <span class="attribute">width</span>:<span class="number">20px</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><ul><li>在 CSS 中> 选择器,选择的是 儿子元素,就是 必须与父元素 有直接血源的元素。</li><li>在引入命令空间时,如使用 > 选择器,父元素不能加 括号。</li><li>不得单独使用命名空间的方法 必须先引入命名空间,才能使用 其中方法。</li><li>子方法 可以使用上一层传进来的方法</li></ul><h3 id="5-方法的条件筛选"><a href="#5-方法的条件筛选" class="headerlink" title="5. 方法的条件筛选"></a>5. 方法的条件筛选</h3><p>Less 没有 if else,可是它有 when</p><figure class="highlight less"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* Less */</span></span><br><span class="line"><span class="selector-id">#card</span>{</span><br><span class="line"> </span><br><span class="line"> <span class="comment">// and 运算符 ,相当于 与运算 &&,必须条件全部符合才会执行</span></span><br><span class="line"> <span class="selector-class">.border</span>(<span class="variable">@width</span>,<span class="variable">@color</span>,<span class="variable">@style</span>) <span class="keyword">when</span> (<span class="variable">@width</span>><span class="number">100px</span>) <span class="keyword">and</span>(<span class="variable">@color</span>=<span class="number">#999</span>){</span><br><span class="line"> <span class="attribute">border</span>:<span class="variable">@style</span> <span class="variable">@color</span> <span class="variable">@width</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// not 运算符,相当于 非运算 !,条件为 不符合才会执行</span></span><br><span class="line"> <span class="selector-class">.background</span>(<span class="variable">@color</span>) <span class="keyword">when</span> <span class="keyword">not</span> (<span class="variable">@color</span>>=<span class="number">#222</span>){</span><br><span class="line"> <span class="attribute">background</span>:<span class="variable">@color</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// , 逗号分隔符:相当于 或运算 ||,只要有一个符合条件就会执行</span></span><br><span class="line"> <span class="selector-class">.font</span>(<span class="variable">@size</span>:<span class="number">20px</span>) <span class="keyword">when</span> (<span class="variable">@size</span>><span class="number">50px</span>) , (<span class="variable">@size</span><<span class="number">100px</span>){</span><br><span class="line"> <span class="attribute">font-size</span>: <span class="variable">@size</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="selector-id">#main</span>{</span><br><span class="line"> <span class="selector-id">#card</span>><span class="selector-class">.border</span>(<span class="number">200px</span>,<span class="number">#999</span>,solid);</span><br><span class="line"> <span class="selector-id">#card</span> <span class="selector-class">.background</span>(<span class="number">#111</span>);</span><br><span class="line"> <span class="selector-id">#card</span> > <span class="selector-class">.font</span>(<span class="number">40px</span>);</span><br><span class="line">}</span><br><span class="line"><span class="comment">/* 生成后的 CSS */</span></span><br><span class="line"><span class="selector-id">#main</span>{</span><br><span class="line"> <span class="attribute">border</span>:solid <span class="number">#999</span> <span class="number">200px</span>;</span><br><span class="line"> <span class="attribute">background</span>:<span class="number">#111</span>;</span><br><span class="line"> <span class="attribute">font-size</span>:<span class="number">40px</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><ul><li>比较运算有: > >= = =<<。< li></li><li>= 代表的是等于</li><li>除去关键字 true 以外的值都被视为 false</li></ul><h3 id="6-数量不定的参数"><a href="#6-数量不定的参数" class="headerlink" title="6. 数量不定的参数"></a>6. 数量不定的参数</h3><p>如果你希望你的方法接受数量不定的参数,你可以使用… ,犹如 ES6 的扩展运算符。</p><figure class="highlight less"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* Less */</span></span><br><span class="line"><span class="selector-class">.boxShadow</span>(...){</span><br><span class="line"> <span class="attribute">box-shadow</span>: <span class="variable">@arguments</span>;</span><br><span class="line">}</span><br><span class="line"><span class="selector-class">.textShadow</span>(<span class="variable">@a</span>,...){</span><br><span class="line"> <span class="attribute">text-shadow</span>: <span class="variable">@arguments</span>;</span><br><span class="line">}</span><br><span class="line"><span class="selector-id">#main</span>{</span><br><span class="line"> <span class="selector-class">.boxShadow</span>(<span class="number">1px</span>,<span class="number">4px</span>,<span class="number">30px</span>,red);</span><br><span class="line"> <span class="selector-class">.textShadow</span>(<span class="number">1px</span>,<span class="number">4px</span>,<span class="number">30px</span>,red);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 生成后的 CSS */</span></span><br><span class="line"><span class="selector-id">#main</span>{</span><br><span class="line"> <span class="attribute">box-shadow</span>: <span class="number">1px</span> <span class="number">4px</span> <span class="number">30px</span> red;</span><br><span class="line"> <span class="attribute">text-shadow</span>: <span class="number">1px</span> <span class="number">4px</span> <span class="number">30px</span> red;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="7-方法使用important!"><a href="#7-方法使用important!" class="headerlink" title="7. 方法使用important!"></a>7. 方法使用important!</h3><p>使用方法 非常简单,在方法名后 加上关键字即可。</p><figure class="highlight less"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* Less */</span></span><br><span class="line"><span class="selector-class">.border</span>{</span><br><span class="line"> <span class="attribute">border</span>: solid <span class="number">1px</span> red;</span><br><span class="line"> <span class="attribute">margin</span>: <span class="number">50px</span>;</span><br><span class="line">}</span><br><span class="line"><span class="selector-id">#main</span>{</span><br><span class="line"> <span class="selector-class">.border</span>() !important;</span><br><span class="line">}</span><br><span class="line"><span class="comment">/* 生成后的 CSS */</span></span><br><span class="line"><span class="selector-id">#main</span> {</span><br><span class="line"> <span class="attribute">border</span>: solid <span class="number">1px</span> red <span class="meta">!important</span>;</span><br><span class="line"> <span class="attribute">margin</span>: <span class="number">50px</span> <span class="meta">!important</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="8-循环方法"><a href="#8-循环方法" class="headerlink" title="8. 循环方法"></a>8. 循环方法</h3><p>Less 并没有提供 for 循环功能,但这也难不倒 聪明的程序员,使用递归去实现。 下面是官网中的一个 Demo,模拟了生成栅格系统。</p><figure class="highlight less"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* Less */</span></span><br><span class="line"><span class="selector-class">.generate-columns</span>(<span class="number">4</span>);</span><br><span class="line"></span><br><span class="line"><span class="selector-class">.generate-columns</span>(<span class="variable">@n</span>, <span class="variable">@i</span>: <span class="number">1</span>) <span class="keyword">when</span> (<span class="variable">@i</span> =<<span class="variable">@n</span>) {</span><br><span class="line"> <span class="selector-class">.column-</span><span class="variable">@{i}</span> {</span><br><span class="line"> <span class="attribute">width</span>: (<span class="variable">@i</span> * <span class="number">100%</span> / <span class="variable">@n</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="selector-class">.generate-columns</span>(<span class="variable">@n</span>, (<span class="variable">@i</span> + <span class="number">1</span>));</span><br><span class="line">}</span><br><span class="line"><span class="comment">/* 生成后的 CSS */</span></span><br><span class="line"><span class="selector-class">.column-1</span> {</span><br><span class="line"> <span class="attribute">width</span>: <span class="number">25%</span>;</span><br><span class="line">}</span><br><span class="line"><span class="selector-class">.column-2</span> {</span><br><span class="line"> <span class="attribute">width</span>: <span class="number">50%</span>;</span><br><span class="line">}</span><br><span class="line"><span class="selector-class">.column-3</span> {</span><br><span class="line"> <span class="attribute">width</span>: <span class="number">75%</span>;</span><br><span class="line">}</span><br><span class="line"><span class="selector-class">.column-4</span> {</span><br><span class="line"> <span class="attribute">width</span>: <span class="number">100%</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="9-属性拼接方法"><a href="#9-属性拼接方法" class="headerlink" title="9. 属性拼接方法"></a>9. 属性拼接方法</h3><p><code>+_</code> 代表的是 空格;<code>+</code> 代表的是 逗号。</p><ul><li>逗号</li></ul><figure class="highlight less"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* Less */</span></span><br><span class="line"><span class="selector-class">.boxShadow</span>() {</span><br><span class="line"> <span class="selector-tag">box-shadow</span>+: <span class="selector-tag">inset</span> <span class="selector-tag">0</span> <span class="selector-tag">0</span> <span class="selector-tag">10px</span> <span class="selector-id">#555</span>;</span><br><span class="line">}</span><br><span class="line"><span class="selector-class">.main</span> {</span><br><span class="line"> <span class="selector-class">.boxShadow</span>();</span><br><span class="line"> <span class="selector-tag">box-shadow</span>+: <span class="selector-tag">0</span> <span class="selector-tag">0</span> <span class="selector-tag">20px</span> <span class="selector-tag">black</span>;</span><br><span class="line">}</span><br><span class="line"><span class="comment">/* 生成后的 CSS */</span></span><br><span class="line"><span class="selector-class">.main</span> {</span><br><span class="line"> <span class="attribute">box-shadow</span>: inset <span class="number">0</span> <span class="number">0</span> <span class="number">10px</span> <span class="number">#555</span>, <span class="number">0</span> <span class="number">0</span> <span class="number">20px</span> black;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><ul><li>空格</li></ul><figure class="highlight less"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* Less */</span></span><br><span class="line"><span class="selector-class">.Animation</span>() {</span><br><span class="line"> <span class="selector-tag">transform</span>+<span class="selector-tag">_</span>: <span class="selector-tag">scale</span>(<span class="number">2</span>);</span><br><span class="line">}</span><br><span class="line"><span class="selector-class">.main</span> {</span><br><span class="line"> <span class="selector-class">.Animation</span>();</span><br><span class="line"> <span class="selector-tag">transform</span>+<span class="selector-tag">_</span>: <span class="selector-tag">rotate</span>(<span class="number">15deg</span>);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 生成的 CSS */</span></span><br><span class="line"><span class="selector-class">.main</span> {</span><br><span class="line"> <span class="attribute">transform</span>: scale(<span class="number">2</span>) rotate(<span class="number">15deg</span>);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><br><br><br></p><h2 id="导入"><a href="#导入" class="headerlink" title="导入"></a>导入</h2><h3 id="1-导入-less-文件-可省略后缀"><a href="#1-导入-less-文件-可省略后缀" class="headerlink" title="1. 导入 less 文件 可省略后缀"></a>1. 导入 less 文件 可省略后缀</h3><figure class="highlight"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">import "main"; </span><br><span class="line"><span class="comment">//等价于</span></span><br><span class="line">import "main.less";</span><br></pre></td></tr></table></figure><h3 id="2-import-的位置可随意放置"><a href="#2-import-的位置可随意放置" class="headerlink" title="2.@import 的位置可随意放置"></a>2.<code>@import</code> 的位置可随意放置</h3><figure class="highlight less"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-id">#main</span>{</span><br><span class="line"> <span class="attribute">font-size</span>:<span class="number">15px</span>;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">@import</span> <span class="string">"style"</span>;</span><br></pre></td></tr></table></figure><h3 id="3-reference"><a href="#3-reference" class="headerlink" title="3. reference"></a>3. reference</h3><p>Less 中 最强大的特性 使用 引入的 Less 文件,但不会 编译它。</p><figure class="highlight less"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* Less */</span></span><br><span class="line"><span class="keyword">@import</span> (reference) <span class="string">"bootstrap.less"</span>; </span><br><span class="line"></span><br><span class="line"><span class="selector-id">#wrap</span><span class="selector-pseudo">:extend(.navbar</span> <span class="keyword">all</span>){}</span><br></pre></td></tr></table></figure><blockquote><p>使用@import (reference)导入外部文件,但不会添加 把导入的文件 编译到最终输出中,只引用。</p></blockquote><h3 id="4-once"><a href="#4-once" class="headerlink" title="4. once"></a>4. once</h3><blockquote><p>@import语句的默认行为。这表明相同的文件只会被导入一次,而随后的导入文件的重复代码都不会解析。</p></blockquote><figure class="highlight less"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">@import</span> (once) <span class="string">"foo.less"</span>;</span><br><span class="line"><span class="keyword">@import</span> (once) <span class="string">"foo.less"</span>; <span class="comment">// this statement will be ignored</span></span><br></pre></td></tr></table></figure><h3 id="5-multiple"><a href="#5-multiple" class="headerlink" title="5. multiple"></a>5. multiple</h3><blockquote><p>使用@import (multiple)允许导入多个同名文件。</p></blockquote><figure class="highlight less"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* Less */</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// file: foo.less</span></span><br><span class="line"><span class="selector-class">.a</span> {</span><br><span class="line"> <span class="attribute">color</span>: green;</span><br><span class="line">}</span><br><span class="line"><span class="comment">// file: main.less</span></span><br><span class="line"><span class="keyword">@import</span> (multiple) <span class="string">"foo.less"</span>;</span><br><span class="line"><span class="keyword">@import</span> (multiple) <span class="string">"foo.less"</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 生成后的 CSS */</span></span><br><span class="line"><span class="selector-class">.a</span> {</span><br><span class="line"> <span class="attribute">color</span>: green;</span><br><span class="line">}</span><br><span class="line"><span class="selector-class">.a</span> {</span><br><span class="line"> <span class="attribute">color</span>: green;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><br><br><br></p><h2 id="函数"><a href="#函数" class="headerlink" title="函数"></a>函数</h2><h3 id="1-判断类型"><a href="#1-判断类型" class="headerlink" title="1. 判断类型"></a>1. 判断类型</h3><ul><li>isnumber<blockquote><p>判断给定的值 是否 是一个数字。</p></blockquote></li></ul><figure class="highlight less"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-tag">isnumber</span>(<span class="number">#ff0</span>); <span class="comment">// false</span></span><br><span class="line"><span class="selector-tag">isnumber</span>(blue); <span class="comment">// false</span></span><br><span class="line"><span class="selector-tag">isnumber</span>(<span class="string">"string"</span>); <span class="comment">// false</span></span><br><span class="line"><span class="selector-tag">isnumber</span>(<span class="number">1234</span>); <span class="comment">// true</span></span><br><span class="line"><span class="selector-tag">isnumber</span>(<span class="number">56px</span>); <span class="comment">// true</span></span><br><span class="line"><span class="selector-tag">isnumber</span>(<span class="number">7.8%</span>); <span class="comment">// true</span></span><br><span class="line"><span class="selector-tag">isnumber</span>(keyword); <span class="comment">// false</span></span><br><span class="line"><span class="selector-tag">isnumber</span>(url(<span class="string">...</span>)); <span class="comment">// false</span></span><br></pre></td></tr></table></figure><ul><li><p>iscolor</p><blockquote><p>判断给定的值 是否 是一个颜色。</p></blockquote></li><li><p>isurl</p><blockquote><p>判断给定的值 是否 是一个 url 。</p></blockquote></li></ul><h3 id="2-颜色操作"><a href="#2-颜色操作" class="headerlink" title="2. 颜色操作"></a>2. 颜色操作</h3><ul><li><p>saturate</p><blockquote><p>增加一定数值的颜色饱和度。</p></blockquote></li><li><p>lighten</p><blockquote><p>增加一定数值的颜色亮度。</p></blockquote></li><li><p>darken</p><blockquote><p>降低一定数值的颜色亮度。</p></blockquote></li><li><p>fade</p><blockquote><p>给颜色设定一定数值的透明度。</p></blockquote></li><li><p>mix</p><blockquote><p>根据比例混合两种颜色。</p></blockquote></li></ul><h3 id="3-数学函数"><a href="#3-数学函数" class="headerlink" title="3. 数学函数"></a>3. 数学函数</h3><ul><li><p>ceil</p><blockquote><p>增向上取整。</p></blockquote></li><li><p>floor</p><blockquote><p>向下取整。</p></blockquote></li><li><p>percentage</p><blockquote><p>将浮点数转换为百分比字符串。</p></blockquote></li><li><p>round</p><blockquote><p>四舍五入。</p></blockquote></li><li><p>sqrt</p><blockquote><p>计算一个数的平方根。</p></blockquote></li></ul><ul><li><p>abs</p><blockquote><p>计算数字的绝对值,原样保持单位。</p></blockquote></li><li><p>pow</p><blockquote><p>计算一个数的乘方。</p></blockquote></li></ul><p><br><br><br></p><h2 id="注释"><a href="#注释" class="headerlink" title="注释"></a>注释</h2><ul><li><code>/* */</code> CSS原生注释,会被编译在 CSS 文件中。</li><li><code>/ /</code> Less提供的一种注释,不会被编译在 CSS 文件中。 </li></ul><p><br><br><br></p><blockquote><p>除此之外,还有继承等一系列的,需要大家参考官网去学习了解<br></p></blockquote><blockquote><p>参考资料:Less中文网 [<a href="http://lesscss.cn/]" target="_blank" rel="noopener">http://lesscss.cn/]</a></p></blockquote>]]></content>
<summary type="html">
<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>CSS的语法比较简单,但是有时候为了让两个元素(拥有同一个类名)的样式不一样,就需要添加另外一个类或者在书写CSS的时候多加层级。这样很不方
</summary>
</entry>
<entry>
<title>ES6基础知识</title>
<link href="http://yoursite.com/2019/05/20/ES6%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/"/>
<id>http://yoursite.com/2019/05/20/ES6基础知识/</id>
<published>2019-05-20T07:09:15.000Z</published>
<updated>2019-05-24T07:45:21.479Z</updated>
<content type="html"><![CDATA[<p>#ES6基础知识点<br>JavaScript的组成:ECMAScript(核心)、DOM(文档对象模型)、BOM (浏览器对象模型)<br>ECMAScript,规定了语言的组成部分:语法、类型、语句、关键字、保留字、操作符、对象。我们现在使用的是ES5,也就是ECMAScript的第5版本。顾名思义,ES6就是ECMAScript的第6版本,在ES5的基础上,在保证向下兼容的前提下,提供大量新特性。</p><h2 id="let-const命令"><a href="#let-const命令" class="headerlink" title="let const命令"></a>let const命令</h2><h3 id="1-let"><a href="#1-let" class="headerlink" title="1. let"></a>1. let</h3><p>let用于声明变量,用法类似于var<br><span class="text-important">let与const的区别如下:</span></p><h5 id="1-1-let声明的变量只在let命令所在的代码块中有效"><a href="#1-1-let声明的变量只在let命令所在的代码块中有效" class="headerlink" title="1.1 let声明的变量只在let命令所在的代码块中有效"></a>1.1 let声明的变量只在let命令所在的代码块中有效</h5><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">{<span class="keyword">var</span> a = <span class="number">10</span>;<span class="keyword">let</span> b = <span class="number">1</span>;}</span><br><span class="line"><span class="built_in">console</span>.log(a)<span class="comment">//==>10</span></span><br><span class="line"><span class="built_in">console</span>.log(b)<span class="comment">//==>报错:b is not defined</span></span><br><span class="line"></span><br><span class="line">典型案例:</span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">let</span> i = <span class="number">0</span>;i < <span class="number">10</span>;i++){}</span><br><span class="line"><span class="built_in">console</span>.log(i);<span class="comment">//==>i is not defined</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> a = <span class="keyword">new</span> <span class="built_in">Array</span>(<span class="number">10</span>);</span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">var</span> i = <span class="number">0</span>;i < <span class="number">10</span>;i++){</span><br><span class="line">a[i] =<span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>{</span><br><span class="line"><span class="built_in">console</span>.log(i);</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line">a[<span class="number">6</span>]();<span class="comment">//==>10 变量i是var声明的,在全局范围内都有效,每次循环,新的i会覆盖掉旧的i</span></span><br></pre></td></tr></table></figure><h5 id="1-2-不存在变量提升-使用let时,一定要在变量声明后使用,否则会报错"><a href="#1-2-不存在变量提升-使用let时,一定要在变量声明后使用,否则会报错" class="headerlink" title="1.2 不存在变量提升,使用let时,一定要在变量声明后使用,否则会报错"></a>1.2 不存在变量提升,使用let时,一定要在变量声明后使用,否则会报错</h5><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">console</span>.log(foo);<span class="comment">//===>ReferenceError:foo is not defined</span></span><br><span class="line"><span class="keyword">let</span> foo = <span class="number">2</span>;</span><br><span class="line"><notice>:此时使用<span class="keyword">typeof</span>不再是一个百分之百安全操作</span><br></pre></td></tr></table></figure><h5 id="1-3-暂时性死区(TDZ)"><a href="#1-3-暂时性死区(TDZ)" class="headerlink" title="1.3 暂时性死区(TDZ)"></a>1.3 暂时性死区(TDZ)</h5><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//只要块级作用域内存在let命令,它所声明的变量就绑定在这个区域,不再受外部的影响</span></span><br><span class="line"><span class="keyword">var</span> tmp = <span class="number">123</span>;</span><br><span class="line"><span class="keyword">if</span>(<span class="literal">true</span>){</span><br><span class="line">tmp = <span class="string">'abc'</span>;</span><br><span class="line"><span class="keyword">let</span> tmp;</span><br><span class="line">}</span><br><span class="line"><span class="comment">//如果区块中存在let和const命令,则这个区块对这些命令声明的变量从一开始就形成封闭作用域</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">bar</span>(<span class="params">x = y,y = <span class="number">2</span></span>)</span>{</span><br><span class="line"><span class="keyword">return</span> [x,y];</span><br><span class="line">}</span><br><span class="line">bar();</span><br></pre></td></tr></table></figure><h5 id="1-4-不允许重复声明"><a href="#1-4-不允许重复声明" class="headerlink" title="1.4 不允许重复声明"></a>1.4 不允许重复声明</h5><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span>不允许在相同作用域内重复声明同一个变量</span><br><span class="line"><span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>{</span><br><span class="line"><span class="keyword">let</span> a = <span class="number">10</span>;</span><br><span class="line"><span class="keyword">let</span> a = <span class="number">8</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span>(<span class="params">arg</span>)</span>{</span><br><span class="line"><span class="keyword">let</span> arg;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span>(<span class="params">arg</span>)</span>{</span><br><span class="line">{<span class="keyword">let</span> arg;}</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="2-const"><a href="#2-const" class="headerlink" title="2. const"></a>2. const</h3><p>const 用来声明常量,一旦声明,其值就不能改变</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> PI = <span class="number">3.14</span>;<span class="xml"><span class="tag"><<span class="name">br</span>/></span></span></span><br><span class="line">PI = <span class="number">3</span>;<span class="comment">//==>TypeError:'PI' is read-only</span></span><br></pre></td></tr></table></figure><blockquote><p>2.1 const 一旦声明常量,就必须立即初始化,不能留到以后赋值;<br><br>2.2 const 只声明不赋值就会报错;SyntaxError:missing = in const declaration<br><br>2.3 const 作用域与let命令相同:只在声明所在的块级作用域内有效<br><br>2.4 const 也存在暂时性死区,只能在声明后使用<br><br>2.5 const 不可重复声明常量<br><br>2.6 对于复合类型的变量,变量名指向地址,不指向数据<br></p></blockquote><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> foo = {};</span><br><span class="line">foo.prop = <span class="number">123</span>;</span><br><span class="line"><span class="built_in">console</span>.log(foo.prop);<span class="comment">//==>123</span></span><br><span class="line"></span><br><span class="line">想对对象冻结,使用 <span class="built_in">Object</span>.freeze,冻结对象本身,冻结对象的属性</span><br><span class="line"><span class="keyword">const</span> foo = <span class="built_in">Object</span>.freeze({});</span><br><span class="line">foo.prop = <span class="number">123</span>;<span class="comment">//==>不起作用,冻结的对象,添加新属性不起作用</span></span><br></pre></td></tr></table></figure><p><br><br><br></p><h2 id="模板字符串"><a href="#模板字符串" class="headerlink" title="模板字符串"></a>模板字符串</h2><p><code><html></html></code> 传统的写法就是用+进行拼接,并且还要考虑到单引号与双引号的交替以及转义,并且不能换行<br>模板字符串直接使用反引号 `` 可以定义多行代码,并且嵌入变量<br><br><span class="text-important">使用模板字符串的注意如下:</span></p><h5 id="2-1-转义"><a href="#2-1-转义" class="headerlink" title="2.1 ``转义 +``"></a>2.1 ``转义 +``</h5><h5 id="2-2-多行字符串,所有的空格以及缩进都会被保留在输出中"><a href="#2-2-多行字符串,所有的空格以及缩进都会被保留在输出中" class="headerlink" title="2.2 多行字符串,所有的空格以及缩进都会被保留在输出中"></a>2.2 多行字符串,所有的空格以及缩进都会被保留在输出中</h5><h5 id="2-3-嵌入变量,需要将变量名写在"><a href="#2-3-嵌入变量,需要将变量名写在" class="headerlink" title="2.3 嵌入变量,需要将变量名写在${}"></a>2.3 嵌入变量,需要将变量名写在${}</h5><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span>(<span class="params">name,value</span>)</span>{</span><br><span class="line"><span class="keyword">throw</span> <span class="keyword">new</span> <span class="built_in">Error</span>(<span class="string">'name:'</span>+name+<span class="string">';value:'</span>+value);<span class="comment">//以前写法</span></span><br><span class="line"><span class="keyword">throw</span> <span class="keyword">new</span> <span class="built_in">Error</span>(<span class="string">`name:<span class="subst">${name}</span>;value:<span class="subst">${value}</span>`</span>);<span class="comment">//模板字符串写法</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><h5 id="2-4-调用函数"><a href="#2-4-调用函数" class="headerlink" title="2.4 调用函数"></a>2.4 调用函数</h5><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">fn</span>(<span class="params"></span>)</span>{</span><br><span class="line"><span class="keyword">return</span> <span class="string">'nihao'</span>;</span><br><span class="line">}</span><br><span class="line"><span class="string">`everyone,<span class="subst">${fn()}</span> yiyi`</span><span class="comment">//==>everyone,nihao yiyi</span></span><br></pre></td></tr></table></figure><h5 id="2-5-大括号中的值不是字符串,按照一般的规则转为字符串"><a href="#2-5-大括号中的值不是字符串,按照一般的规则转为字符串" class="headerlink" title="2.5 ${}大括号中的值不是字符串,按照一般的规则转为字符串"></a>2.5 ${}大括号中的值不是字符串,按照一般的规则转为字符串</h5><p>对象 – toString()<br><br>方法 – 执行方法后得到的值</p><p><br><br><br></p><h2 id="变量的解构赋值"><a href="#变量的解构赋值" class="headerlink" title="变量的解构赋值"></a>变量的解构赋值</h2><p><span class="text-important">按照一定模式,从数组和对象中提取值,对变量进行赋值。</span>类似于“模式匹配”</p><h3 id="1-数组解构赋值"><a href="#1-数组解构赋值" class="headerlink" title="1. 数组解构赋值"></a>1. 数组解构赋值</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> [a, b] = [<span class="number">1</span>, <span class="number">2</span>] <span class="comment">// let a = 1; let b = 2;</span></span><br><span class="line"><span class="keyword">let</span> [a, b, [c, d]] = [<span class="number">1</span>, <span class="number">2</span>, [<span class="number">3</span>, <span class="number">4</span>]] <span class="comment">// let a = 1; b = 2; let c = 3; let d = 4;</span></span><br><span class="line"><span class="keyword">let</span> [ , , third] = [<span class="string">"foo"</span>, <span class="string">"bar"</span>, <span class="string">"baz"</span>]; <span class="comment">// let third = "baz";</span></span><br><span class="line"><span class="keyword">let</span> [x, , y] = [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>]; <span class="comment">// let x = 1; y = 3;</span></span><br><span class="line"><span class="keyword">let</span> [head, ...tail] = [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>]; <span class="comment">// let head = 1; let tail = [2, 3, 4];</span></span><br></pre></td></tr></table></figure><h5 id="1-1-解构不成功,值就会变成undefined"><a href="#1-1-解构不成功,值就会变成undefined" class="headerlink" title="1.1 解构不成功,值就会变成undefined"></a>1.1 解构不成功,值就会变成undefined</h5><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> [x, y, ...z] = [<span class="string">'1'</span>] <span class="comment">// let x = '1'; let y = undefined; let z = [];</span></span><br></pre></td></tr></table></figure><h5 id="1-2-如果等号的右边不是数组,将会报错。"><a href="#1-2-如果等号的右边不是数组,将会报错。" class="headerlink" title="1.2 如果等号的右边不是数组,将会报错。"></a>1.2 如果等号的右边不是数组,将会报错。</h5><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 报错</span></span><br><span class="line"><span class="keyword">let</span> [foo] = <span class="number">1</span>;</span><br><span class="line"><span class="keyword">let</span> [foo] = <span class="literal">false</span>;</span><br><span class="line"><span class="keyword">let</span> [foo] = <span class="literal">NaN</span>;</span><br><span class="line"><span class="keyword">let</span> [foo] = <span class="literal">undefined</span>;</span><br><span class="line"><span class="keyword">let</span> [foo] = <span class="literal">null</span>;</span><br><span class="line"><span class="keyword">let</span> [foo] = {};</span><br></pre></td></tr></table></figure><p><span class="text-important">只要某种数据结构具有 Iterator 接口,都可以采用数组形式的解构赋值。</span></p><h5 id="1-3-解构赋值允许指定默认值"><a href="#1-3-解构赋值允许指定默认值" class="headerlink" title="1.3 解构赋值允许指定默认值"></a>1.3 解构赋值允许指定默认值</h5><blockquote><p>只有当一个数组成员严格等于(===)undefined,默认值才会生效</p></blockquote><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> [x = <span class="number">1</span>] = []; <span class="comment">// x = 1</span></span><br><span class="line"><span class="keyword">let</span> [x, y = <span class="string">'aaa'</span>] = [<span class="number">1</span>, <span class="literal">undefined</span>]; <span class="comment">// x = 1; y = 'aaa'</span></span><br><span class="line"><span class="keyword">let</span> [x = <span class="number">1</span>] = [<span class="literal">null</span>]; <span class="comment">// x = 1</span></span><br></pre></td></tr></table></figure><blockquote><p>如果默认值是一个表达式,那么这个表达式是惰性求值的,即只有在用到的时候,才会求值</p></blockquote><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">f</span>(<span class="params"></span>) </span>{</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">'aaa'</span>);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> [x = f()] = [<span class="number">1</span>];</span><br></pre></td></tr></table></figure><blockquote><p>默认值可以引用解构赋值的其他变量,但该变量必须已经声明</p></blockquote><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> [x = <span class="number">1</span>, y = x] = []; <span class="comment">// x=1; y=1</span></span><br><span class="line"><span class="keyword">let</span> [x = <span class="number">1</span>, y = x] = [<span class="number">2</span>]; <span class="comment">// x=2; y=2</span></span><br><span class="line"><span class="keyword">let</span> [x = <span class="number">1</span>, y = x] = [<span class="number">1</span>, <span class="number">2</span>]; <span class="comment">// x=1; y=2</span></span><br><span class="line"><span class="keyword">let</span> [x = y, y = <span class="number">1</span>] = []; <span class="comment">// ReferenceError: y is not defined</span></span><br></pre></td></tr></table></figure><h3 id="2-对象解构赋值"><a href="#2-对象解构赋值" class="headerlink" title="2. 对象解构赋值"></a>2. 对象解构赋值</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> {a, b} = {<span class="attr">a</span>: <span class="number">1</span>, <span class="attr">b</span>: <span class="number">2</span>} <span class="comment">// a = 1; b = 2;</span></span><br></pre></td></tr></table></figure><blockquote><p>数组的解构与对象解构的不同:数组的元素是<span class="text-important">按次序排列</span>的,变量的取值由它的位置决定;而对象的属性没有次序,变量必须与<span class="text-important">属性同名</span>,才能取到正确的值<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> {sin, cos} = <span class="built_in">Math</span></span><br></pre></td></tr></table></figure></p></blockquote><h5 id="2-1-变量名和属性名不一致"><a href="#2-1-变量名和属性名不一致" class="headerlink" title="2.1 变量名和属性名不一致"></a>2.1 变量名和属性名不一致</h5><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> {<span class="attr">a</span>: m, <span class="attr">b</span>: n} = {<span class="attr">a</span>: <span class="number">1</span>, <span class="attr">b</span>: <span class="number">2</span>} <span class="comment">// m = 1; n = 2;</span></span><br></pre></td></tr></table></figure><p>a,b其实是匹配的模式,而真正的变量是m,n<br>以前所写的<code>let {a, b} = {1, 2}</code>其实是<code>let {a: a, b: b} = {a: 1, b: 2}</code>的缩写</p><h5 id="2-2-嵌套解构"><a href="#2-2-嵌套解构" class="headerlink" title="2.2 嵌套解构"></a>2.2 嵌套解构</h5><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> node = {</span><br><span class="line"> loc: {</span><br><span class="line"> start: {</span><br><span class="line"> line: <span class="number">1</span>,</span><br><span class="line"> column: <span class="number">5</span></span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> { loc, <span class="attr">loc</span>: { start }, <span class="attr">loc</span>: { <span class="attr">start</span>: { line }} } = node;</span><br></pre></td></tr></table></figure><p>上面代码有三次解构赋值,分别是对loc、start、line三个属性的解构赋值。注意,最后一次对line属性的解构赋值之中,只有line是变量,loc和start都是模式,不是变量</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> obj = {};</span><br><span class="line"><span class="keyword">let</span> arr = [];</span><br><span class="line"></span><br><span class="line">({ <span class="attr">foo</span>: obj.prop, <span class="attr">bar</span>: arr[<span class="number">0</span>] } = { <span class="attr">foo</span>: <span class="number">123</span>, <span class="attr">bar</span>: <span class="literal">true</span> });</span><br></pre></td></tr></table></figure><h5 id="2-3-对象解构也有默认值,默认值起作用的条件也是严格等于(-)undefined时"><a href="#2-3-对象解构也有默认值,默认值起作用的条件也是严格等于(-)undefined时" class="headerlink" title="2.3 对象解构也有默认值,默认值起作用的条件也是严格等于(===)undefined时"></a>2.3 对象解构也有默认值,默认值起作用的条件也是严格等于(===)undefined时</h5><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> {<span class="attr">x</span>: y = <span class="number">5</span>, <span class="attr">z</span>: m = <span class="number">1</span>, w = <span class="number">3</span>} = {<span class="literal">null</span>}</span><br></pre></td></tr></table></figure><h3 id="3-解构注意的点⚠️"><a href="#3-解构注意的点⚠️" class="headerlink" title="3. 解构注意的点⚠️"></a>3. 解构注意的点⚠️</h3><h5 id="3-1-将一个已经声明的变量用于解构赋值"><a href="#3-1-将一个已经声明的变量用于解构赋值" class="headerlink" title="3.1 将一个已经声明的变量用于解构赋值"></a>3.1 将一个已经声明的变量用于解构赋值</h5><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> x;</span><br><span class="line">{x} = {<span class="attr">x</span>: <span class="number">1</span>}; <span class="comment">// 会报错,因为{x}会被认为是一个代码块</span></span><br><span class="line">({x} = {<span class="attr">x</span>: <span class="number">1</span>});</span><br></pre></td></tr></table></figure><h5 id="3-2-解构赋值允许等号左边的模式之中,不放置任何变量名"><a href="#3-2-解构赋值允许等号左边的模式之中,不放置任何变量名" class="headerlink" title="3.2 解构赋值允许等号左边的模式之中,不放置任何变量名"></a>3.2 解构赋值允许等号左边的模式之中,不放置任何变量名</h5><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">({} = [<span class="literal">true</span>, <span class="literal">false</span>]);</span><br><span class="line">({} = <span class="string">'abc'</span>);</span><br><span class="line">({} = []);</span><br></pre></td></tr></table></figure><p>不会报错,可以执行,但是没有任何意义</p><h5 id="3-3-由于数组本质是特殊的对象,因此可以对数组进行对象属性的解构"><a href="#3-3-由于数组本质是特殊的对象,因此可以对数组进行对象属性的解构" class="headerlink" title="3.3 由于数组本质是特殊的对象,因此可以对数组进行对象属性的解构"></a>3.3 由于数组本质是特殊的对象,因此可以对数组进行对象属性的解构</h5><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> obj ={};</span><br><span class="line"><span class="keyword">let</span> arr = [];</span><br><span class="line"><span class="keyword">let</span> {<span class="attr">name</span>: obj.name, <span class="attr">index</span>: arr[<span class="number">0</span>]} = {<span class="attr">name</span>: <span class="string">'zhaoshijuan'</span>, <span class="attr">index</span>: <span class="number">1</span>}</span><br></pre></td></tr></table></figure><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> arr = [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>];</span><br><span class="line"><span class="keyword">let</span> {<span class="number">0</span> : first, [arr.length - <span class="number">1</span>] : last} = arr;</span><br><span class="line"><span class="comment">// first = 1; last = 3;</span></span><br></pre></td></tr></table></figure><blockquote><p>除了数组,对象可以解构赋值,还有字符串,布尔值,数值,函数参数等的解构赋值,需要大家自己去学习。</p></blockquote><p><br><br><br></p><h2 id="箭头函数"><a href="#箭头函数" class="headerlink" title="箭头函数"></a>箭头函数</h2><p><span class="text-important">定义函数: var f = v => v;</span>相当于: var f = function(v){return v;}</p><h5 id="1-无参数或者需要多个参数,使用圆括号代表参数部分"><a href="#1-无参数或者需要多个参数,使用圆括号代表参数部分" class="headerlink" title="1. 无参数或者需要多个参数,使用圆括号代表参数部分"></a>1. 无参数或者需要多个参数,使用圆括号代表参数部分</h5><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> f = <span class="function"><span class="params">()</span> =></span><span class="number">5</span>;</span><br><span class="line">相当于:<span class="keyword">var</span> f = <span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>{<span class="keyword">return</span> <span class="number">5</span>;}</span><br><span class="line"><span class="keyword">var</span> f = <span class="function">(<span class="params">num1,num2</span>) =></span> num1+num2;</span><br><span class="line">相当于:<span class="keyword">var</span> f = <span class="function"><span class="keyword">function</span>(<span class="params">num1,num2</span>)</span>{<span class="keyword">return</span> num1+num2;}</span><br></pre></td></tr></table></figure><h5 id="2-代码块部分多于一行代码,使用大括号包裹起来"><a href="#2-代码块部分多于一行代码,使用大括号包裹起来" class="headerlink" title="2. 代码块部分多于一行代码,使用大括号包裹起来"></a>2. 代码块部分多于一行代码,使用大括号包裹起来</h5><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> f = <span class="function">(<span class="params">num1,num2</span>) =></span> {<span class="keyword">return</span> num1+num2;}</span><br></pre></td></tr></table></figure><h5 id="3-大括号是被解释为代码块,所以如果箭头函数直接返回一个对象,必须在对象外面加上括号"><a href="#3-大括号是被解释为代码块,所以如果箭头函数直接返回一个对象,必须在对象外面加上括号" class="headerlink" title="3. 大括号是被解释为代码块,所以如果箭头函数直接返回一个对象,必须在对象外面加上括号"></a>3. 大括号是被解释为代码块,所以如果箭头函数直接返回一个对象,必须在对象外面加上括号</h5><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> getTempItem = <span class="function"><span class="params">id</span> =></span> ({<span class="attr">id</span>:id,<span class="attr">name</span>:<span class="string">'Temp'</span>});</span><br></pre></td></tr></table></figure><h5 id="4-作用:简化回调函数"><a href="#4-作用:简化回调函数" class="headerlink" title="4. 作用:简化回调函数"></a>4. 作用:简化回调函数</h5><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> result = values.sort(<span class="function"><span class="keyword">function</span>(<span class="params">a,b</span>)</span>{<span class="keyword">return</span> a-b;});</span><br><span class="line"><span class="keyword">var</span> result = values.sort(<span class="function">(<span class="params">a,b</span>) =></span> a-b);</span><br></pre></td></tr></table></figure><h5 id="5-rest参数与箭头函数的结合"><a href="#5-rest参数与箭头函数的结合" class="headerlink" title="5. rest参数与箭头函数的结合"></a>5. rest参数与箭头函数的结合</h5><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> numbers = <span class="function">(<span class="params">...nums</span>) =></span> nums;</span><br><span class="line">numbers(<span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>,<span class="number">4</span>,<span class="number">5</span>,<span class="number">6</span>);<span class="comment">//==>[1,2,3,4,5,6]</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> headAndTail = <span class="function">(<span class="params">head,...tail</span>) =></span> [head,tail]</span><br><span class="line">headAndTail(<span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>,<span class="number">4</span>,<span class="number">5</span>);<span class="comment">//==>[1,[2,3,4,5]]</span></span><br></pre></td></tr></table></figure><h3 id="⚠️注意:"><a href="#⚠️注意:" class="headerlink" title="⚠️注意:"></a>⚠️注意:</h3><p>1⃣️函数体内的this对象就是定义时所在的对象,而不是使用时所在的对象<br><br>2⃣️不可以当做构造函数<br></p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">foo</span>(<span class="params"></span>)</span>{</span><br><span class="line"><span class="keyword">return</span> <span class="function"><span class="params">()</span> =></span> {</span><br><span class="line"><span class="keyword">return</span> <span class="function"><span class="params">()</span> =></span>{</span><br><span class="line"><span class="keyword">return</span> <span class="function"><span class="params">()</span> =></span>{</span><br><span class="line"><span class="built_in">console</span>.log(<span class="string">'id'</span>,<span class="keyword">this</span>.id);</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"><span class="comment">//这串代码只有一个this,也就是foo的this,箭头函数是没有this的,所以就不能当做构造函数<br/></span></span><br></pre></td></tr></table></figure><p>3⃣️不可以使用arguments对象,该对象在函数体内不存在,如果要使用,可以使用rest参数代替<br><br>//除了this,arguments、super、new.target在箭头函数中也是不存在的</p><p><br><br><br></p><h2 id="Symbol"><a href="#Symbol" class="headerlink" title="Symbol"></a>Symbol</h2><p>Symbol 独一无二的值,是js语言的第7种数据类型 (Undefined,Null,Boolean,String,Number,Object)</p><h3 id="1-使用注意"><a href="#1-使用注意" class="headerlink" title="1. 使用注意"></a>1. 使用注意</h3><h5 id="1-1-symbol值通过symbol函数生成-symbol值不是对象"><a href="#1-1-symbol值通过symbol函数生成-symbol值不是对象" class="headerlink" title="1.1 symbol值通过symbol函数生成,symbol值不是对象"></a>1.1 symbol值通过symbol函数生成,symbol值不是对象</h5><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> s = <span class="built_in">Symbol</span>();</span><br><span class="line"><span class="built_in">console</span>.log(<span class="keyword">typeof</span> s);<span class="comment">//==>symbol</span></span><br></pre></td></tr></table></figure><h5 id="1-2-可以接受一个字符串作为参数,用于对symbol实例的描述"><a href="#1-2-可以接受一个字符串作为参数,用于对symbol实例的描述" class="headerlink" title="1.2 可以接受一个字符串作为参数,用于对symbol实例的描述"></a>1.2 可以接受一个字符串作为参数,用于对symbol实例的描述</h5><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> s1 = <span class="built_in">Symbol</span>(<span class="string">'foo'</span>);</span><br><span class="line"><span class="built_in">console</span>.log(s1);<span class="comment">//==>Symbol(foo)</span></span><br><span class="line"><span class="built_in">console</span>.log(s1.toString);<span class="comment">//==>'Symbol(foo)'</span></span><br></pre></td></tr></table></figure><h5 id="1-3-Symbol值不能与其他类型的值进行运算"><a href="#1-3-Symbol值不能与其他类型的值进行运算" class="headerlink" title="1.3 Symbol值不能与其他类型的值进行运算"></a>1.3 Symbol值不能与其他类型的值进行运算</h5><h5 id="1-4-Symbol值可以显式转为字符串"><a href="#1-4-Symbol值可以显式转为字符串" class="headerlink" title="1.4 Symbol值可以显式转为字符串"></a>1.4 Symbol值可以显式转为字符串</h5><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> sym = <span class="built_in">Symbol</span>(<span class="string">'my symbol'</span>);</span><br><span class="line"><span class="built_in">console</span>.log(<span class="built_in">String</span>(sym));<span class="comment">//==>'Symbol('my symbol')'</span></span><br><span class="line"><span class="built_in">console</span>.log(sym.toString());<span class="comment">//==>'Symbol('my symbol')'</span></span><br></pre></td></tr></table></figure><h5 id="1-5-Symbol值可以转为Boolean值"><a href="#1-5-Symbol值可以转为Boolean值" class="headerlink" title="1.5 Symbol值可以转为Boolean值"></a>1.5 Symbol值可以转为Boolean值</h5><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> sym1 = <span class="built_in">Symbol</span>();</span><br><span class="line"><span class="built_in">console</span>.log(<span class="built_in">Boolean</span>(sym1));<span class="comment">//==>true</span></span><br><span class="line"><span class="built_in">console</span>.log(<span class="built_in">Boolean</span>(!sym1));<span class="comment">//==>false</span></span><br></pre></td></tr></table></figure><h3 id="2-作为属性名的Symbol"><a href="#2-作为属性名的Symbol" class="headerlink" title="2. 作为属性名的Symbol"></a>2. 作为属性名的Symbol</h3><p>每一个symbol值都是不相等的,因此不会出现同名的属性</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> mySymbol = <span class="built_in">Symbol</span>();</span><br><span class="line"><span class="keyword">var</span> a = {};</span><br><span class="line">a[mySymbol] = <span class="string">'helloWorld'</span>; </span><br><span class="line"><span class="keyword">var</span> a = {[mySymbol]:<span class="string">'helloWorld'</span>};</span><br></pre></td></tr></table></figure><h5 id="2-1-Symbol值作为对象属性名时不能使用点运算符,要放在方括号中"><a href="#2-1-Symbol值作为对象属性名时不能使用点运算符,要放在方括号中" class="headerlink" title="2.1 Symbol值作为对象属性名时不能使用点运算符,要放在方括号中"></a>2.1 Symbol值作为对象属性名时不能使用点运算符,要放在方括号中</h5><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> mySymbol = <span class="built_in">Symbol</span>();</span><br><span class="line"><span class="keyword">var</span> a = {};</span><br><span class="line">a.mySymbol = <span class="string">'helloWorld'</span>;</span><br><span class="line"><span class="built_in">console</span>.log(a[mySymbol]);<span class="comment">//==>undefined</span></span><br><span class="line"><span class="built_in">console</span>.log(a[<span class="string">'mySymbol'</span>]);<span class="comment">//==>'helloWorld'</span></span><br><span class="line"><span class="comment">//此时,a的属性名相当于是一个字符串,而不是一个Symbol值</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> s = <span class="built_in">Symbol</span>();</span><br><span class="line"><span class="keyword">let</span> obj = {[s]:<span class="function"><span class="keyword">function</span>(<span class="params">arg</span>)</span>{...}}</span><br><span class="line"><span class="built_in">console</span>.log(obj[s]);<span class="comment">//==>function(arg){...}</span></span><br></pre></td></tr></table></figure><h5 id="2-2-Symbol类型还可用于定义一组常量,保证这组常量的值都是不相等的。"><a href="#2-2-Symbol类型还可用于定义一组常量,保证这组常量的值都是不相等的。" class="headerlink" title="2.2 Symbol类型还可用于定义一组常量,保证这组常量的值都是不相等的。"></a>2.2 Symbol类型还可用于定义一组常量,保证这组常量的值都是不相等的。</h5><h5 id="2-3-消除魔术字符串"><a href="#2-3-消除魔术字符串" class="headerlink" title="2.3 消除魔术字符串"></a>2.3 消除魔术字符串</h5><p>魔术字符串:在代码之中多次出现、与代码形成强耦合的某一个具体的字符串或数值<br>使用同一个Symbol</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">Symbol</span>.for()</span><br><span class="line"><span class="keyword">var</span> a = <span class="built_in">Symbol</span>.for(<span class="string">'foo'</span>);</span><br><span class="line"><span class="keyword">var</span> b = <span class="built_in">Symbol</span>.for(<span class="string">'foo'</span>);</span><br><span class="line"><span class="built_in">console</span>.log(a === b);<span class="comment">//==>true</span></span><br></pre></td></tr></table></figure><p><br><br><br></p><h2 id="Promise"><a href="#Promise" class="headerlink" title="Promise"></a>Promise</h2><p><span class="text-important">所谓Promise</span>,简单说就是一个<code>容器</code>,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。</p><h3 id="1-Promise特点"><a href="#1-Promise特点" class="headerlink" title="1. Promise特点"></a>1. Promise特点</h3><blockquote><p>1.对象的状态不受外界的影响,三种状态:pending(进行中),fufilled(已成功),rejected(已失败)<br><br>2.一旦状态改变,就不会再变。状态的两种改变:pending—>fulfilled,pending—>rejected</p></blockquote><h3 id="2-promise对象是一个构造函数,用来生成promise实例"><a href="#2-promise对象是一个构造函数,用来生成promise实例" class="headerlink" title="2. promise对象是一个构造函数,用来生成promise实例"></a>2. promise对象是一个构造函数,用来生成promise实例</h3><p>Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolve和reject。它们是两个函数,由 JavaScript 引擎提供,不用自己部署</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> promise = <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function"><span class="keyword">function</span>(<span class="params">resolve, reject</span>) </span>{</span><br><span class="line"> <span class="comment">// ... some code</span></span><br><span class="line"> <span class="keyword">if</span> (<span class="comment">/* 异步操作成功 */</span>){</span><br><span class="line"> resolve(value);</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> reject(error);</span><br><span class="line"> }</span><br><span class="line">});</span><br><span class="line"><span class="comment">//resolve 将Promise对象的状态pending--->fulfilled,</span></span><br><span class="line"><span class="comment">//reject 将Promise对象的状态pending--->rejected</span></span><br></pre></td></tr></table></figure><h3 id="3-then方法指定resolved和rejected回调-then方法返回的是一个新的Promise实例-因此可以使用链式写法"><a href="#3-then方法指定resolved和rejected回调-then方法返回的是一个新的Promise实例-因此可以使用链式写法" class="headerlink" title="3. then方法指定resolved和rejected回调,then方法返回的是一个新的Promise实例,因此可以使用链式写法"></a>3. then方法指定resolved和rejected回调,then方法返回的是一个新的Promise实例,因此可以使用链式写法</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line">promise.then(<span class="function"><span class="keyword">function</span>(<span class="params">value</span>)</span>{</span><br><span class="line"><span class="built_in">console</span>.log(<span class="string">'sucess resolved'</span>)</span><br><span class="line">},<span class="function"><span class="keyword">function</span>(<span class="params">error</span>)</span>{</span><br><span class="line"><span class="built_in">console</span>.log(<span class="string">'failure rejected(可选)'</span>)</span><br><span class="line">});</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">timeout</span>(<span class="params">ms</span>) </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function">(<span class="params">resolve, reject</span>) =></span> {</span><br><span class="line"> setTimeout(resolve, ms, <span class="string">'done'</span>);</span><br><span class="line"> });</span><br><span class="line">}</span><br><span class="line">timeout(<span class="number">100</span>).then(<span class="function">(<span class="params">value</span>) =></span> {</span><br><span class="line"> <span class="built_in">console</span>.log(value);</span><br><span class="line">});</span><br><span class="line"><span class="comment">//链式写法</span></span><br><span class="line">promise.then(<span class="function"><span class="keyword">function</span>(<span class="params">value</span>)</span>{</span><br><span class="line"><span class="built_in">console</span>.log(<span class="string">'sucess resolved'</span>)</span><br><span class="line">},<span class="function"><span class="keyword">function</span>(<span class="params">error</span>)</span>{</span><br><span class="line"><span class="built_in">console</span>.log(<span class="string">'failure rejected(可选)'</span>)</span><br><span class="line">}).then(<span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>{</span><br><span class="line"><span class="built_in">console</span>.log(<span class="string">'then==>sucess'</span>);</span><br><span class="line">},<span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>{</span><br><span class="line"><span class="built_in">console</span>.log(<span class="string">'then==>failure'</span>);</span><br><span class="line">});</span><br></pre></td></tr></table></figure><h3 id="4-Promise-新建后立即执行,所以首先输出的是Promise。然后,then方法指定的回调函数,将在当前脚本所有同步任务执行完才会执行,所以resolved最后输出。"><a href="#4-Promise-新建后立即执行,所以首先输出的是Promise。然后,then方法指定的回调函数,将在当前脚本所有同步任务执行完才会执行,所以resolved最后输出。" class="headerlink" title="4. Promise 新建后立即执行,所以首先输出的是Promise。然后,then方法指定的回调函数,将在当前脚本所有同步任务执行完才会执行,所以resolved最后输出。"></a>4. Promise 新建后立即执行,所以首先输出的是Promise。然后,then方法指定的回调函数,将在当前脚本所有同步任务执行完才会执行,所以resolved最后输出。</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> promise = <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function"><span class="keyword">function</span>(<span class="params">resolve, reject</span>) </span>{</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">'Promise'</span>);</span><br><span class="line"> resolve();</span><br><span class="line">});</span><br><span class="line">promise.then(<span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>{</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">'resolved'</span>);</span><br><span class="line">});</span><br><span class="line"><span class="built_in">console</span>.log(<span class="string">'Hi!'</span>);</span><br><span class="line"><span class="comment">// Promise</span></span><br><span class="line"><span class="comment">// Hi!</span></span><br><span class="line"><span class="comment">// resolved</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> p1 = <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function"><span class="keyword">function</span> (<span class="params">resolve, reject</span>) </span>{</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">'Promise===>p1'</span>);</span><br><span class="line">});</span><br><span class="line"><span class="keyword">var</span> p2 = <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function"><span class="keyword">function</span> (<span class="params">resolve, reject</span>) </span>{</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">'Promise===>p2'</span>);</span><br><span class="line"> resolve(p1);</span><br><span class="line">})</span><br><span class="line"><span class="built_in">console</span>.log(<span class="string">'outside'</span>);</span><br></pre></td></tr></table></figure><p>p1的状态就会传递给p2,也就是说,p1的状态决定了p2的状态。如果p1的状态是pending,那么p2的回调函数就会等待p1的状态改变;如果p1的状态已经是resolved或者rejected,那么p2的回调函数将会立刻执行</p><h3 id="5-catch方法是用于指定发生错误时的回调函数"><a href="#5-catch方法是用于指定发生错误时的回调函数" class="headerlink" title="5. catch方法是用于指定发生错误时的回调函数"></a>5. catch方法是用于指定发生错误时的回调函数</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">getJSON(<span class="string">'/posts.json'</span>).then(<span class="function"><span class="keyword">function</span>(<span class="params">posts</span>) </span>{</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line">}).catch(<span class="function"><span class="keyword">function</span>(<span class="params">error</span>) </span>{</span><br><span class="line"> <span class="comment">// 处理 getJSON 和 前一个回调函数运行时发生的错误</span></span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">'发生错误!'</span>, error);</span><br><span class="line">});</span><br></pre></td></tr></table></figure><p>getJSON方法返回一个 Promise 对象,如果该对象状态变为resolved,则会调用then方法指定的回调函数;如果异步操作抛出错误,状态就会变为rejected,就会调用catch方法指定的回调函数,处理这个错误。另外,then方法指定的回调函数,如果运行中抛出错误,也会被catch方法捕获。</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> promise = <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function"><span class="keyword">function</span>(<span class="params">resolve, reject</span>) </span>{</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> <span class="built_in">Error</span>(<span class="string">'test'</span>);</span><br><span class="line">});</span><br><span class="line">promise.catch(<span class="function"><span class="keyword">function</span>(<span class="params">error</span>) </span>{</span><br><span class="line"> <span class="built_in">console</span>.log(error);</span><br><span class="line">});</span><br><span class="line"><span class="comment">// Error: test</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//如果Promise状态已经变成resolved,再抛出错误是无效的。</span></span><br><span class="line"><span class="keyword">var</span> promise = <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function"><span class="keyword">function</span>(<span class="params">resolve, reject</span>) </span>{</span><br><span class="line">resolve(<span class="string">'ok'</span>);</span><br><span class="line"><span class="keyword">throw</span> <span class="keyword">new</span> <span class="built_in">Error</span>(<span class="string">'test'</span>);</span><br><span class="line">});</span><br><span class="line">promise.then(<span class="function"><span class="keyword">function</span>(<span class="params">value</span>) </span>{ <span class="built_in">console</span>.log(value) })</span><br><span class="line">.catch(<span class="function"><span class="keyword">function</span>(<span class="params">error</span>) </span>{ <span class="built_in">console</span>.log(error) });</span><br><span class="line"><span class="comment">// ok</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// Promise 对象的错误具有“冒泡”性质,会一直向后传递,直到被捕获为止。也就是说,错误总是会被下一个catch语句捕获。</span></span><br><span class="line"><span class="keyword">var</span> promise = <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>{</span><br><span class="line"><span class="built_in">console</span>.log(<span class="string">'p1==>sucess'</span>)</span><br><span class="line">},<span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>{</span><br><span class="line"><span class="keyword">throw</span> <span class="keyword">new</span> <span class="built_in">Error</span>(<span class="string">'test'</span>);</span><br><span class="line">});</span><br><span class="line">promise.then(<span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>{</span><br><span class="line"><span class="built_in">console</span>.log(<span class="string">'p2==>sucess'</span>);</span><br><span class="line"><span class="keyword">throw</span> <span class="keyword">new</span> <span class="built_in">Error</span>(<span class="string">'test'</span>);</span><br><span class="line">}).then(<span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>{</span><br><span class="line"><span class="built_in">console</span>.log(<span class="string">'p3==>sucess'</span>);</span><br><span class="line">}).catch(<span class="function"><span class="keyword">function</span>(<span class="params">error</span>)</span>{</span><br><span class="line"><span class="built_in">console</span>.log(error);<span class="comment">//捕获前三个Promise实例的错误</span></span><br><span class="line">});</span><br></pre></td></tr></table></figure><h3 id="6-Promise-all-用于将多个Promise实例包装成一个新的Promise实例"><a href="#6-Promise-all-用于将多个Promise实例包装成一个新的Promise实例" class="headerlink" title="6. Promise.all() 用于将多个Promise实例包装成一个新的Promise实例"></a>6. Promise.all() 用于将多个Promise实例包装成一个新的Promise实例</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> p1 = <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function"><span class="keyword">function</span>(<span class="params">resolve,reject</span>)</span>{</span><br><span class="line"><span class="built_in">console</span>.log(<span class="string">'p1'</span>);</span><br><span class="line">resolve(<span class="string">'promise1'</span>);</span><br><span class="line">}),p2 = <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function"><span class="keyword">function</span>(<span class="params">resolve,reject</span>)</span>{</span><br><span class="line"><span class="built_in">console</span>.log(<span class="string">'p2'</span>);</span><br><span class="line">resolve(<span class="string">'promise2'</span>);</span><br><span class="line">}),p3 = <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function"><span class="keyword">function</span>(<span class="params">resolve,reject</span>)</span>{</span><br><span class="line"><span class="built_in">console</span>.log(<span class="string">'p3'</span>);</span><br><span class="line">resolve(<span class="string">'promise3'</span>);</span><br><span class="line">});</span><br><span class="line"><span class="keyword">var</span> p = <span class="built_in">Promise</span>.all([p1,p2,p3]);</span><br><span class="line"><span class="built_in">console</span>.log(p);</span><br></pre></td></tr></table></figure><p>p1、p2、p3只要有一个rejected,p就会变成rejected;只有全部是fulfilled,p才会变成fulfilled</p><h3 id="7-Promise-race-将多个Promise实例包装成一个新的Promise实例"><a href="#7-Promise-race-将多个Promise实例包装成一个新的Promise实例" class="headerlink" title="7. Promise.race() 将多个Promise实例包装成一个新的Promise实例"></a>7. Promise.race() 将多个Promise实例包装成一个新的Promise实例</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> p = <span class="built_in">Promise</span>.race([p1,p2,p3]);</span><br><span class="line"><span class="comment">//只要p1,p2,p3有一个率先改变状态,p就会跟着改变。率先改变的Promise实例的返回值,就传递给p的回调函数</span></span><br><span class="line"><span class="keyword">const</span> p = <span class="built_in">Promise</span>.race([</span><br><span class="line"> fetch(<span class="string">'/resource-that-may-take-a-while'</span>),</span><br><span class="line"> <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function"><span class="keyword">function</span> (<span class="params">resolve, reject</span>) </span>{</span><br><span class="line"> setTimeout(<span class="function"><span class="params">()</span> =></span> reject(<span class="keyword">new</span> <span class="built_in">Error</span>(<span class="string">'request timeout'</span>)), <span class="number">5000</span>)</span><br><span class="line"> })</span><br><span class="line">]);</span><br><span class="line">p.then(<span class="function"><span class="params">response</span> =></span> <span class="built_in">console</span>.log(response));</span><br><span class="line">p.catch(<span class="function"><span class="params">error</span> =></span> <span class="built_in">console</span>.log(error));</span><br></pre></td></tr></table></figure><h3 id="8-Promise-reject-将对象转为Promise对象,并且状态为rejected"><a href="#8-Promise-reject-将对象转为Promise对象,并且状态为rejected" class="headerlink" title="8. Promise.reject() 将对象转为Promise对象,并且状态为rejected"></a>8. Promise.reject() 将对象转为Promise对象,并且状态为rejected</h3><h3 id="9-Promise-resolve-将对象转为Promise对象,并且状态为resolved"><a href="#9-Promise-resolve-将对象转为Promise对象,并且状态为resolved" class="headerlink" title="9. Promise.resolve() 将对象转为Promise对象,并且状态为resolved"></a>9. Promise.resolve() 将对象转为Promise对象,并且状态为resolved</h3><p><br><br><br></p><h2 id="Module语法"><a href="#Module语法" class="headerlink" title="Module语法"></a>Module语法</h2><blockquote><p>前言:只介绍module的语法以及使用过程中的注意事项,不会介绍原理,感兴趣的可以自己去研究。</p></blockquote><p>由于原生JavaScript没有模块这一个概念,对于过长的JavaScript文件而言,只能拆分,但是彼此之间又不能建立联系(除了使用window顶层对象,但是这种方法是不提倡的),后期社区执行了一些模块加载方案,主要就是CommonJs与AMD。CommonJs主要应用于服务器端(NodeJs);AMD主要用于客户端(Javascript),其中最常用的就是RequireJs。<br><br>ES6的module可以在服务器端,也可以在客户端,而且语法一致。<br><br>ES6 的模块自动采用严格模式,不管你有没有在模块头部加上”use strict”「ES5的东西,大家可以自己去看看」。ES6模块中的this指向undefined。</p><blockquote><p>模块功能主要由两个命令构成:export和import。export命令用于规定模块的对外接口,import命令用于输入其他模块提供的功能</p></blockquote><h3 id="1-export"><a href="#1-export" class="headerlink" title="1. export"></a>1. export</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">export</span> <span class="keyword">var</span> a = <span class="number">1</span>;</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">var</span> b = <span class="string">'zhaoshijuan'</span>;</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">var</span> c = <span class="literal">true</span>;</span><br></pre></td></tr></table></figure><p>等价于</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> a = <span class="number">1</span>;</span><br><span class="line"><span class="keyword">var</span> b = <span class="string">'zhaoshijuan'</span>;</span><br><span class="line"><span class="keyword">var</span> c = <span class="literal">true</span>;</span><br><span class="line"><span class="keyword">export</span> {a, b, c}</span><br></pre></td></tr></table></figure><h5 id="1-1-别名"><a href="#1-1-别名" class="headerlink" title="1.1 别名"></a>1.1 别名</h5><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">v1</span>(<span class="params"></span>) </span>{ ... }</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">v2</span>(<span class="params"></span>) </span>{ ... }</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> {</span><br><span class="line"> v1 <span class="keyword">as</span> streamV1,</span><br><span class="line"> v2 <span class="keyword">as</span> streamV2,</span><br><span class="line"> v2 <span class="keyword">as</span> streamLatestVersion</span><br><span class="line">};</span><br></pre></td></tr></table></figure><p>使用<code>as</code>关键字,重新命名了函数v1和v2的对外接口。</p><h5 id="1-2-export命令规定的是对外的接口,必须与模块内部的变量建立一一对应关系"><a href="#1-2-export命令规定的是对外的接口,必须与模块内部的变量建立一一对应关系" class="headerlink" title="1.2 export命令规定的是对外的接口,必须与模块内部的变量建立一一对应关系"></a>1.2 export命令规定的是对外的接口,必须与模块内部的变量建立一一对应关系</h5><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 报错,直接输出1,1只是一个值,不是接口</span></span><br><span class="line"><span class="keyword">export</span> <span class="number">1</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 报错,通过变量m,还是输出1</span></span><br><span class="line"><span class="keyword">var</span> m = <span class="number">1</span>;</span><br><span class="line"><span class="keyword">export</span> m;</span><br></pre></td></tr></table></figure><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 写法一</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">var</span> m = <span class="number">1</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 写法二</span></span><br><span class="line"><span class="keyword">var</span> m = <span class="number">1</span>;</span><br><span class="line"><span class="keyword">export</span> {m};</span><br><span class="line"></span><br><span class="line"><span class="comment">// 写法三</span></span><br><span class="line"><span class="keyword">var</span> n = <span class="number">1</span>;</span><br><span class="line"><span class="keyword">export</span> {n <span class="keyword">as</span> m};</span><br></pre></td></tr></table></figure><h5 id="1-3-export命令可以出现在模块的任何位置,只要处于模块顶层就可以。"><a href="#1-3-export命令可以出现在模块的任何位置,只要处于模块顶层就可以。" class="headerlink" title="1.3 export命令可以出现在模块的任何位置,只要处于模块顶层就可以。"></a>1.3 export命令可以出现在模块的任何位置,只要处于模块顶层就可以。</h5><p>如果处于块级作用域内,就会报错,import命令也是如此。这是因为处于条件代码块之中,就没法做静态优化了,违背了 ES6 模块的设计初衷。</p><h3 id="2-import"><a href="#2-import" class="headerlink" title="2. import"></a>2. import</h3><p>使用export命令定义了模块的对外接口以后,其他 JS 文件就可以通过import命令加载这个模块。</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// main.js</span></span><br><span class="line"><span class="keyword">import</span> {firstName, lastName, year} <span class="keyword">from</span> <span class="string">'./profile.js'</span>;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">setName</span>(<span class="params">element</span>) </span>{</span><br><span class="line"> element.textContent = firstName + <span class="string">' '</span> + lastName;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><code>form</code>后面的是模块的位置,可以是绝对路径,也可以是相对路径。.js的后缀可以省略。</p><h5 id="2-1-大括号里面的变量名,必须与被导入模块对外接口的名称相同"><a href="#2-1-大括号里面的变量名,必须与被导入模块对外接口的名称相同" class="headerlink" title="2.1 大括号里面的变量名,必须与被导入模块对外接口的名称相同"></a>2.1 大括号里面的变量名,必须与被导入模块对外接口的名称相同</h5><h5 id="2-2-别名使用as"><a href="#2-2-别名使用as" class="headerlink" title="2.2 别名使用as"></a>2.2 别名使用as</h5><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> { lastName <span class="keyword">as</span> surname } <span class="keyword">from</span> <span class="string">'./profile.js'</span>;</span><br></pre></td></tr></table></figure><h5 id="2-3-import命名输入的变量是只读"><a href="#2-3-import命名输入的变量是只读" class="headerlink" title="2.3 import命名输入的变量是只读"></a>2.3 import命名输入的变量是只读</h5><p>如果是一个对象,则对象里面的属性是可写的,但是不利于后期的排错什么。</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> {a} <span class="keyword">from</span> <span class="string">'./xxx.js'</span></span><br><span class="line">a.foo = <span class="string">'hello'</span>; <span class="comment">// 合法操作</span></span><br></pre></td></tr></table></figure><h5 id="2-4-如果多次重复执行同一句import语句,那么只会执行一次,而不会执行多次"><a href="#2-4-如果多次重复执行同一句import语句,那么只会执行一次,而不会执行多次" class="headerlink" title="2.4 如果多次重复执行同一句import语句,那么只会执行一次,而不会执行多次"></a>2.4 如果多次重复执行同一句import语句,那么只会执行一次,而不会执行多次</h5><h5 id="2-5-import命令具有提升效果,会提升到整个模块的头部,首先执行"><a href="#2-5-import命令具有提升效果,会提升到整个模块的头部,首先执行" class="headerlink" title="2.5 import命令具有提升效果,会提升到整个模块的头部,首先执行"></a>2.5 import命令具有提升效果,会提升到整个模块的头部,首先执行</h5><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">foo();</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> { foo } <span class="keyword">from</span> <span class="string">'my_module'</span>;</span><br></pre></td></tr></table></figure><p>⚠️<span class="text-important">ES6模块是编译时加载,因此在import是静态执行,不可以使用变量,表达式。动态加载使用import()</span></p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 报错</span></span><br><span class="line"><span class="keyword">import</span> { <span class="string">'f'</span> + <span class="string">'oo'</span> } <span class="keyword">from</span> <span class="string">'my_module'</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 报错</span></span><br><span class="line"><span class="keyword">let</span> <span class="built_in">module</span> = <span class="string">'my_module'</span>;</span><br><span class="line"><span class="keyword">import</span> { foo } <span class="keyword">from</span> <span class="built_in">module</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 报错</span></span><br><span class="line"><span class="keyword">if</span> (x === <span class="number">1</span>) {</span><br><span class="line"> <span class="keyword">import</span> { foo } <span class="keyword">from</span> <span class="string">'module1'</span>;</span><br><span class="line">} <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">import</span> { foo } <span class="keyword">from</span> <span class="string">'module2'</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><blockquote><p>参考资料:《ECMAScript 6 入门》阮一峰译(<a href="http://es6.ruanyifeng.com)" target="_blank" rel="noopener">http://es6.ruanyifeng.com)</a></p></blockquote>]]></content>
<summary type="html">
<p>#ES6基础知识点<br>JavaScript的组成:ECMAScript(核心)、DOM(文档对象模型)、BOM (浏览器对象模型)<br>ECMAScript,规定了语言的组成部分:语法、类型、语句、关键字、保留字、操作符、对象。我们现在使用的是ES5,也就是ECMAS
</summary>
</entry>
<entry>
<title>vue源码分析-组件化-异步组件</title>
<link href="http://yoursite.com/2019/02/02/vue%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90-%E7%BB%84%E4%BB%B6%E5%8C%96-%E5%BC%82%E6%AD%A5%E7%BB%84%E4%BB%B6/"/>
<id>http://yoursite.com/2019/02/02/vue源码分析-组件化-异步组件/</id>
<published>2019-02-02T04:55:27.000Z</published>
<updated>2019-02-02T10:03:19.009Z</updated>
<content type="html"><![CDATA[<p>异步组件,一般用于按需加载。对于一些需要优化首屏加载的,会减少首屏的包体积,一般会将一些首屏组件变成异步组件。异步组件的实现方式有三种:工厂函数,promise异步组件,高级异步组件。<br><a id="more"></a></p><h3 id="工厂函数"><a href="#工厂函数" class="headerlink" title="工厂函数"></a>工厂函数</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">Vue.component('AysnComponent', function (resolve, reject) {</span><br><span class="line">// 这个特殊的require语法会告诉webpack,自动将编译后的代码分割成不同的块,这些块会通过Ajax请求加载</span><br><span class="line">require(['./components/AysnComponent'], (res) => {</span><br><span class="line">resolve(res)</span><br><span class="line">})</span><br><span class="line">})</span><br></pre></td></tr></table></figure><p>在定义组件时,使用Vue.component时,第二个参数传递的是一个对象。在这里,定义异步组件的时候,第二个参数传递的是一个函数。<br>在vue的源码中,会判断传递的第二个参数是否是一个普通的对象,如果是,则会使用<strong>extend</strong>来创建一个Ctor构造函数。如果不是,则直接将传递的参数挂载在Vue.options.components.AysnComponent(其中的AynsComponent就是定义的名称),通过resolveAsset来创建一个Ctor,这里的Ctor其实就是一个工厂函数(也就是我们传递进去的函数),通过函数resolveAyscComponent(Ctor, baseCtor, context)「其实,Ctor就是我们传递的函数,baseCtor就是Vue,context当前组件的实例vm」</p><p>———————————————————————— 华丽的分割线 —————————————————————<br><br>「扩展 1 」:once,方法只执行一次的实现方式?</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">function once (fn: Function): Function {</span><br><span class="line">let called = true</span><br><span class="line">return function () {</span><br><span class="line">if (!called) {</span><br><span class="line">called = false</span><br><span class="line">fn.apply(this, arguments)</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line">}</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
<p>异步组件,一般用于按需加载。对于一些需要优化首屏加载的,会减少首屏的包体积,一般会将一些首屏组件变成异步组件。异步组件的实现方式有三种:工厂函数,promise异步组件,高级异步组件。<br>
</summary>
<category term="vue源码分析" scheme="http://yoursite.com/categories/vue%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90/"/>
</entry>
<entry>
<title>electron学习</title>
<link href="http://yoursite.com/2018/11/26/electron%E5%AD%A6%E4%B9%A0/"/>
<id>http://yoursite.com/2018/11/26/electron学习/</id>
<published>2018-11-26T05:53:43.000Z</published>
<updated>2018-11-26T05:57:16.175Z</updated>
<content type="html"><![CDATA[<ol><li>使用vue-electron脚手架时,electron-builder与electron-packager的区别(参考文档:<a href="https://github.com/ielectron-userland/electron-builder与https://github.com/ielectron-userland/electron-packager)" target="_blank" rel="noopener">https://github.com/ielectron-userland/electron-builder与https://github.com/ielectron-userland/electron-packager)</a></li><li></li></ol>]]></content>
<summary type="html">
<ol>
<li>使用vue-electron脚手架时,electron-builder与electron-packager的区别(参考文档:<a href="https://github.com/ielectron-userland/electron-builder与https
</summary>
<category term="Electron" scheme="http://yoursite.com/categories/Electron/"/>
</entry>
<entry>
<title>XHR对象</title>
<link href="http://yoursite.com/2018/11/06/XHR%E5%AF%B9%E8%B1%A1/"/>
<id>http://yoursite.com/2018/11/06/XHR对象/</id>
<published>2018-11-06T09:55:10.000Z</published>
<updated>2018-11-26T05:54:32.258Z</updated>
<content type="html"><![CDATA[<p>XHR其实就是XMLHttpRequest对象,也就是Ajax的核心技术。XHR为向服务器发送请求以及解析服务器响应提供了接口,能够以异步的方式从服务器获取信息。</p>]]></content>
<summary type="html">
<p>XHR其实就是XMLHttpRequest对象,也就是Ajax的核心技术。XHR为向服务器发送请求以及解析服务器响应提供了接口,能够以异步的方式从服务器获取信息。</p>
</summary>
<category term="JavaScript" scheme="http://yoursite.com/categories/JavaScript/"/>
</entry>
<entry>
<title>客户端数据存储</title>
<link href="http://yoursite.com/2018/10/29/%E5%AE%A2%E6%88%B7%E7%AB%AF%E6%95%B0%E6%8D%AE%E5%AD%98%E5%82%A8/"/>
<id>http://yoursite.com/2018/10/29/客户端数据存储/</id>
<published>2018-10-29T11:35:32.000Z</published>
<updated>2018-10-31T09:38:36.134Z</updated>
<content type="html"><![CDATA[<p>常见的客户端数据存储:Cookie,Web Storage。其中Web Storage主要包含localStorage,sessionStorage,globalStorage这三种,Web Storage规范出现主要是为了提供一种除了cookie之外的会话存储的途径,以及一种可以存储大量可以跨会话存在的数据的机制。Cookie也叫做HTTP Cookie,最初在客户端是用于存储会话信息的。👓👌咳咳,接下来,我们深入的了解一下Cookie以及Web Storage吧~~~<br><a id="more"></a></p><h4 id="1-Cookie"><a href="#1-Cookie" class="headerlink" title="1. Cookie"></a>1. Cookie</h4><p>Cookie也就是HTTP Cookie,最初在客户端用于存储会话信息,设置完cookie后,在指定的域地址中,请求中带有cookie的信息(Request Headers中就会包含cookie),cookie的名和值在传送时是需要通过URL编码,否则会乱码。<br>该标准要求服务器对 任意 HTTP 请求发送 Set-Cookie HTTP 头作为响应的一部分,其中包含会话信息。浏览器会存储这样的会话信息,并在这之后,通过为每个请求添加 Cookie HTTP 头将信息发送回服务器。</p><h5 id="1-1-限制"><a href="#1-1-限制" class="headerlink" title="1.1 限制"></a>1.1 限制</h5><p>访问限制:在某个环境下设置了cookie,那么此cookie是绑定在此特定的域名下,以后再给创建它的域名发送请求时,都会包含这个cookie。这个让cookie只能在创建它的域名下被访问,其它环境不可以进行访问。<br>个数限制:不同浏览器下,每个域中所能包含的cookie个数也是有限的。当单个域名下的cookie数量超出限制后,浏览器会删除以前设置的cookie,但是IE与Opera会删除最少使用的cookie,FireFox是随机删除。<br>长度限制:cookie长度,在大多数浏览器下,大约是4096B的长度限制。这个长度限制是对每个域下的所有的cookie的总限制,而不是单个cookie的长度限制。超出长度限制,则浏览器会默默地将cookie丢掉。</p><h5 id="1-2-cookie构成"><a href="#1-2-cookie构成" class="headerlink" title="1.2 cookie构成"></a>1.2 cookie构成</h5><ol><li>名称name: cookie名称不区分大小写,相同字母,大小写不一样的,会被当成一个cookie。在实际中,最好定义以及后面使用的时候,要相同大小写相同字母,因为有些浏览器中cookie键值对需要进行URL编码。</li><li>值value: 对应cookie名称的值,是字符串,需要通过URL编码。</li><li>域domain: cookie的域限制,指定cookie在哪个域下被访问。</li><li>地址path: 指定域中的哪个路径,应该向服务器端发送cookie</li><li>失效时间expires: cookie被删除的时间戳。到达结束时间的时候,cookie会被删除。这个值要是GMT格式的日期(Wdy, DD-Mon-YYYY HH:MM:SS GMT),如果设置的时间是在当前日期之前,则cookie会立马被删除。</li><li>安全标志secure: 指定之后,cookie只有在SSL连接的时候才能发送到服务器(也就是https中只能在https的域中,不能发送给同域名的http中)。是一个非键值对,就一个单独的secure单词标志。</li></ol><h5 id="1-3-cookie的操作"><a href="#1-3-cookie的操作" class="headerlink" title="1.3 cookie的操作"></a>1.3 cookie的操作</h5><p>在浏览器中,cookie是挂载在document上的。<br><strong>获取</strong>: 通过document.cookie来获取当前页面可用的cookie字符串(一个使用分号连接起来的键值对字符串),并且得到的所有的键值对都是经过URL编码的,所以需要通过decodeURIComponent来解码<br><strong>设置</strong>: document.cookie可以设置一个新的cookie字符串,这个cookie字符串会被解析并添加到现有的cookie集合中。设置document.cookie并不会覆盖掉原来的cookie,而是在原先的基础上添加(只有在设置的cookie名相同,则会覆盖掉原先设置的同名cookie的值)。在设置时,最好每次对键值对都进行一次encodeURIComponent编码,防止中文乱码情况<br><strong>删除</strong>:没有直接删除的方法,但是可以通过将有效时间设置成现在之前的时间,从而使得cookie删除</p><pre><code>const COOKIE_UTIL = { get: (name) => { var cookieName = encodeURIComponent(name) + '=', cookieStart = document.cookie.indexOf(cookieName), cookieValue = ''; if (cookieStart > -1) { var cookieEnd = document.cookie.indexOf(';', cookieStart); cookieEnd = cookieEnd === -1 ? document.cookie.length : cookieEnd; cookieValue = decodeURIComponent(document.cookie.substring(cookieStart + cookieName.length, cookieEnd)); } return cookieValue; }, set: (name, value, expires, path, domain, secure) => { var cookieText = encodeURIComponent(name) + "=" + encodeURIComponent(value); if (expires instanceof Date) { cookieText += '; expires=' + expires.toGMTString(); } if (path) { cookieText += '; path=' + path; } if (domain) { cookieText += '; domain=' + domain; } if (secure) { cookieText += ';secure'; } document.cookie = cookieText; }, unset: (name, path, domain, secure) => { this.set(name, "", new Date(0), path, domain, secure); }};</code></pre><h4 id="2-Web-Storage"><a href="#2-Web-Storage" class="headerlink" title="2. Web Storage"></a>2. Web Storage</h4><p>Web Storage是一个标准,包含了sessionStorage,localStorage,globalStorage对象,都是直接挂载于window对象上的。</p><h5 id="2-1-Storage类型"><a href="#2-1-Storage类型" class="headerlink" title="2.1 Storage类型"></a>2.1 Storage类型</h5><p>Storage实例有如下几个方法:<br><strong>1. 增</strong> getItem(name) 指定名称name获取对应的值;key(index) 获取index处的名称<br><strong>2. 删</strong> clear() 删除所有的值; 直接使用对象的删除 delete<br><strong>3. 改</strong> setItem(name, value) 为指定name设置一个对应的值<br><strong>4. 查</strong> getItem(name) 获取指定name的值<br>属性:length ==> Storage实例中含有几对键值对</p><h5 id="2-2-sessionStorage对象"><a href="#2-2-sessionStorage对象" class="headerlink" title="2.2 sessionStorage对象"></a>2.2 sessionStorage对象</h5><p>sessionStorage是用于特定会话中存储数据,并且数据只保留到<span class="font-color-red">浏览器关闭</span>。存储在 sessionStorage 中的数据只能由最初给对象存储数据的页面访问到,所以对多页面应用有限制。Storage实例含有的方法和属性,sessionStorage也拥有。<br><strong>范围限制</strong>:要访问同一个localStorage,需要在同一协议,同一域名,同一端口号的页面。<br><strong>存储时间</strong>:一直保留到浏览器关闭。</p><h5 id="2-3-localStorage对象"><a href="#2-3-localStorage对象" class="headerlink" title="2.3 localStorage对象"></a>2.3 localStorage对象</h5><p>localStorage是在修订后的HTML5规范中取代了globalStorage。localStorage是Storage实例,因此拥有Storage类型的所有方法以及属性。<br><strong>范围限制</strong>:要访问同一个localStorage,需要在同一协议,同一域名,同一端口号的页面。<br><strong>存储时间</strong>:一直保留到主动使用方法删除或者用户清除浏览器缓存。</p><h5 id="2-4-globalStorage对象"><a href="#2-4-globalStorage对象" class="headerlink" title="2.4 globalStorage对象"></a>2.4 globalStorage对象</h5><p>globalStorage主要目的是为了跨域会话,但是也有特定的限制。在使用globalStorage,首先要指定哪些区域可以访问该数据,可以通过方括号标记使用属性来实现。<br>eg: globalStorage[‘my.com’].name = ‘zhaoshijuan’<br>这里访问的globalStorage[‘my.com’]是针对域名‘my.com’的存储空间<br>⚠️ globalStorage不是Storage实例,而上面的globalStorage[‘my.com’]才是Storage对象,因此拥有Storage上的方法以及属性的是globalStorage[‘my.com’]这个对象。<br>globalStorage[‘’].name = ‘zhaoshijuan’,这个设置是对任何人都看见,没有域限制。<br>globalStorage[‘net’].name = ‘zhaoshijuan’,这个设置会让所有以.net结束的域名访问。<br>在不确定域名时,可以通过这样设置:globalStorage[‘location.host’].name = ‘zhaoshijuan’<br><strong>范围限制</strong>:根据globalStorage后[]括号而定。<br><strong>存储时间</strong>:如果没有使用removeItem或者delete删除,会一直保留到用户删除浏览器缓存为止。</p><blockquote><p>Stroge对象中存储的都是字符串</p></blockquote><h5 id="2-5-Storage事件"><a href="#2-5-Storage事件" class="headerlink" title="2.5 Storage事件"></a>2.5 Storage事件</h5><p>对Storage对象进行的修改,都会触发storage事件,storage事件是绑定在document上的。storage事件event对象含有如下几个属性:<br>domain:发生变化的存储空间的域名<br>key:变化的键名<br>newValue:修改值,则是新值;删除值,则是undefined<br>oldValue:键对应值被修改之前的值</p><p>addEventListener(document, ‘storage’, function(event) {})</p><h4 id="3-Cookie与Web-Storage对比"><a href="#3-Cookie与Web-Storage对比" class="headerlink" title="3. Cookie与Web Storage对比"></a>3. Cookie与Web Storage对比</h4><h5 id="3-1-区别"><a href="#3-1-区别" class="headerlink" title="3.1 区别"></a>3.1 区别</h5><ol><li>存储内容是否发送到服务器端:当设置了Cookie后,数据会发送到服务器端,造成一定的宽带浪费; web storage,会将数据保存到本地,不会造成宽带浪费;</li><li>数据存储大小不同:Cookie数据不能超过4K,适用于会话标识;web storage数据存储可以达到5M;</li><li>数据存储的有效期限不同:cookie只在设置了Cookid过期时间之前一直有效,即使关闭窗口或者浏览器;sessionStorage,仅在关闭浏览器之前有效;localStorage,数据存储永久有效;</li><li>作用域不同:cookie和localStorage是在同源同窗口中都是共享的;sessionStorage不在不同的浏览器窗口中共享,即使是同一个页面;</li></ol><h5 id="3-2-Web-Storage相比Cookie的优势"><a href="#3-2-Web-Storage相比Cookie的优势" class="headerlink" title="3.2 Web Storage相比Cookie的优势"></a>3.2 Web Storage相比Cookie的优势</h5><ol><li>存储空间更大:IE8下每个独立的存储空间为10M,其他浏览器实现略有不同,但都比Cookie要大很多。</li><li>存储内容不会发送到服务器:当设置了Cookie后,Cookie的内容会随着请求一并发送的服务器,这对于本地存储的数据是一种带宽浪费。而Web Storage中的数据则仅仅是存在本地,不会与服务器发生任何交互。</li><li>更多丰富易用的接口:Web Storage提供了一套更为丰富的接口,如setItem,getItem,removeItem,clear等,使得数据操作更为简便。cookie需要自己封装。</li><li>独立的存储空间:每个域(包括子域)有独立的存储空间,各个存储空间是完全独立的,因此不会造成数据混乱。</li></ol>]]></content>
<summary type="html">
<p>常见的客户端数据存储:Cookie,Web Storage。其中Web Storage主要包含localStorage,sessionStorage,globalStorage这三种,Web Storage规范出现主要是为了提供一种除了cookie之外的会话存储的途径,以及一种可以存储大量可以跨会话存在的数据的机制。Cookie也叫做HTTP Cookie,最初在客户端是用于存储会话信息的。👓👌咳咳,接下来,我们深入的了解一下Cookie以及Web Storage吧~~~<br>
</summary>
<category term="JavaScript" scheme="http://yoursite.com/categories/JavaScript/"/>
</entry>
<entry>
<title>Function对象</title>
<link href="http://yoursite.com/2018/10/26/Function%E5%AF%B9%E8%B1%A1/"/>
<id>http://yoursite.com/2018/10/26/Function对象/</id>
<published>2018-10-26T06:18:11.000Z</published>
<updated>2018-10-29T09:44:33.098Z</updated>
<content type="html"><![CDATA[<p>每次看源码或者找一些求最大值最小值简便方法时,就会遇见call(),apply()这两个方法,当时的理解就是:设置函数上下文,this指向。但是……理解得太片面了,正好有时间,就打算了解一下👏👏👏<br><a id="more"></a></p><h4 id="1-Function类型"><a href="#1-Function类型" class="headerlink" title="1. Function类型"></a>1. Function类型</h4><p>我们先了解一波Function这种引用类型吧~~~</p><h5 id="1-1-函数定义"><a href="#1-1-函数定义" class="headerlink" title="1.1 函数定义"></a>1.1 函数定义</h5><p>「1」函数声明语法 function fun () {}<br>「2」函数表达式定义 var fun = function () {}<br>「3」Function构造函数 var fun = new Function (‘params1’, ‘params2’, ‘return params1 + prams2’)</p><blockquote><p>不推荐使用Function构造函数定义,因为会导致两次解析:第一次是解析常规的js代码,第二次是解析传入构造函数中的字符串</p></blockquote><h6 id="1-2-函数内部的一些属性"><a href="#1-2-函数内部的一些属性" class="headerlink" title="1.2 函数内部的一些属性"></a>1.2 函数内部的一些属性</h6><p>每个函数内部都可以使用arguments来访问传入的所有的参数(是一个伪数组);<br>arguments.callee是一个指针,指向拥有这个arguments对象的函数;<br>caller是函数对象的属性,保存着调用此函数的函数引用。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">var inner = function() { </span><br><span class="line">console.log(inner.caller); // outer</span><br><span class="line">// 等价于下面</span><br><span class="line">console.log(arguments.callee.caller)</span><br><span class="line">};</span><br><span class="line">var outer = function() {</span><br><span class="line">inner();</span><br><span class="line">};</span><br></pre></td></tr></table></figure><p>如果某函数在全局作用域下调用的话,则某函数的caller为null</p><h5 id="1-3-函数属性"><a href="#1-3-函数属性" class="headerlink" title="1.3 函数属性"></a>1.3 函数属性</h5><p>「1」长度length:表示的函数接受的命名参数的个数<br>「2」原型prototype:不可枚举,保存了所有实例方法</p><h4 id="2-函数内部非继承方法:apply,call,bind"><a href="#2-函数内部非继承方法:apply,call,bind" class="headerlink" title="2. 函数内部非继承方法:apply,call,bind"></a>2. 函数内部非继承方法:apply,call,bind</h4><p>apply,call,bind三个方法都是指定在特定作用域内调用此函数,实际上相当于设置了此函数内的this对象的值</p><h5 id="2-1-apply"><a href="#2-1-apply" class="headerlink" title="2.1 apply"></a>2.1 apply</h5><p>apply(作用域,数组类型参数)<br>两个参数:一个在其中运行的函数的作用域,一个是参数数组(arguments或者Array实例)</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">function sum (num1, num2) {</span><br><span class="line">return num1 + num2;</span><br><span class="line">}</span><br><span class="line">function applySum (num1, num2) {</span><br><span class="line">return sum.apply(this, arguments);</span><br><span class="line">}</span><br><span class="line">function applySum1 (num1, num2) {</span><br><span class="line">return sum.apply(this, [num1, num2]);</span><br><span class="line">}</span><br><span class="line">applySum(10, 10); // 20</span><br><span class="line">applySum1(10, 10); // 20</span><br></pre></td></tr></table></figure><h5 id="2-2-call"><a href="#2-2-call" class="headerlink" title="2.2 call"></a>2.2 call</h5><p>call(作用域,参数1,参数2,……,参数N)<br>两类参数:一类也就是第一个参数在其中运行的函数的作用域;另一类也就是参数,是直接传递给函数的参数,传递给函数的参数必须逐一列举出来</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">function sum (num1, num2) {</span><br><span class="line">return num1 + num2;</span><br><span class="line">}</span><br><span class="line">function callSum (num1, num2) {</span><br><span class="line">return sum.call(this, num1, num2)</span><br><span class="line">}</span><br><span class="line">callSum(10 ,10)// 20</span><br></pre></td></tr></table></figure><h5 id="2-3-bind-IE9"><a href="#2-3-bind-IE9" class="headerlink" title="2.3 bind IE9+"></a>2.3 bind <span class="font-color-red">IE9+</span></h5><p>bind()这个方法会创建一个函数的实例,其this的值会被绑定到传给bind()函数的值。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">window.color = 'red';</span><br><span class="line">var object = { color: 'blue' };</span><br><span class="line">function getColor () {</span><br><span class="line">return this.color;</span><br><span class="line">}</span><br><span class="line">var getColor1 = getColor.bind(object);</span><br><span class="line">getColor1(); // blue</span><br></pre></td></tr></table></figure><h5 id="2-4-apply、call、bind区别"><a href="#2-4-apply、call、bind区别" class="headerlink" title="2.4 apply、call、bind区别"></a>2.4 apply、call、bind区别</h5><p>call,apply,bind作用:扩大了函数赖以运行的作用域。<br>对于call,apply的第一个参数如果指定成null或者undefined的时候,则此时的this就会指向全局环境。</p><p>「1」call,apply区别主要在于传参,除了指定作用域的参数外,call的其他参数主要是直接传递给函数的参数,需要一一列举;而apply的其他参数是一个参数数组(arguments或者Array实例)。其实就是参数格式不一样。<br>「2」bind与call,apply的区别主要是call,apply不会生成一个函数,而是直接传递作用域;而bind则是使用传入的作用域绑定this创建一个函数的实例。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">var numbers = [1, 2, 3, 4, 5, 6, 7];</span><br><span class="line">var max1 = Math.max.apply(null, numbers);</span><br><span class="line">// 等价于下面</span><br><span class="line">var max2 = Math.max.call(null, ...numbers);</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
<p>每次看源码或者找一些求最大值最小值简便方法时,就会遇见call(),apply()这两个方法,当时的理解就是:设置函数上下文,this指向。但是……理解得太片面了,正好有时间,就打算了解一下👏👏👏<br>
</summary>
<category term="JavaScript" scheme="http://yoursite.com/categories/JavaScript/"/>
</entry>
<entry>
<title>Array数组之旅</title>
<link href="http://yoursite.com/2018/10/23/Array%E6%95%B0%E7%BB%84%E4%B9%8B%E6%97%85/"/>
<id>http://yoursite.com/2018/10/23/Array数组之旅/</id>
<published>2018-10-23T07:01:41.000Z</published>
<updated>2018-10-31T09:55:10.166Z</updated>
<content type="html"><![CDATA[<p>要学习ES6中的数组扩展篇章,所以就先去预习了一波原本接触到的Array。所谓温故而知新嘛~~<br>首先我们先了解一下js中的对象:1.内部对象,内部对象包含下面三种:错误对象(标识错误),内置对象(不需要使用new操作符来进行初始化,Math与JSON两种),常用对象(8种,String、Number、Date、Function、Boolean、Array、Object、RegExp);2.宿主对象,宿主对象主要有两个window与document。3.自定义对象,除了内部对象以及宿主对象之外,其它都为自定义对象,也就是开发者自己定义的对象。<br>说起Array,能想到的就是属性length,方法push,pop,reverse,shift,unshift,jion,slice,splice……等方法<br>推荐喜马拉雅上的「陪你读书(JavaScript WEB 编程)」的课程~~~<br><a id="more"></a></p><p>基础数据类型:Number、undefined、null、Boolean、String、symbol<br>复杂类型:Object<br>typeOf(null) === ‘Object’<br>js解释器,会将其进行解释,转化成二进制,默认前三位是0的就是Object类型。而null转化成二进制的时候,会变成所有位置上全是0。</p><h3 id="Array数组"><a href="#Array数组" class="headerlink" title="Array数组"></a>Array数组</h3><p>是一个有序的合集。对象是无序的合集,对于有序的对象称作为数组。数组里面可以包含任何数据类型,数组大小可以调整。</p><h4 id="1-创建数组"><a href="#1-创建数组" class="headerlink" title="1. 创建数组"></a>1. 创建数组</h4><p>new关键字 new Array(参数),其中参数只是一个数字的话,则创建出来的是一个指定长度的数组,里面的每项都是undefined。不要使用多个逗号进行创建数组<br>字面量 [array1, array2]</p><h4 id="2-方法"><a href="#2-方法" class="headerlink" title="2. 方法"></a>2. 方法</h4><h5 id="2-1-读写"><a href="#2-1-读写" class="headerlink" title="2.1 读写"></a>2.1 读写</h5><p>读取arr[index];写arr[index] = 1;<br>删除delete arr[index],数组长度不会变化,但是在index位置上的数据就是undefined</p><h5 id="2-2-判断是否是数组类型"><a href="#2-2-判断是否是数组类型" class="headerlink" title="2.2 判断是否是数组类型"></a>2.2 判断是否是数组类型</h5><ol><li>instanceof arr instanceof Array</li><li>原型构造函数 arr.<strong> proto </strong>.constructor === Array</li><li>Object.prototype.toString.call(arr) == ‘[object Array]’</li><li>ES6中的isArray方法 Array.isArray(arr)</li></ol><h5 id="2-3-变异方法"><a href="#2-3-变异方法" class="headerlink" title="2.3 变异方法"></a>2.3 变异方法</h5><p>变异方法,在Vue中包含,它们会触发视图更新<br>栈方法:push,pop在数组的末端进行添加或者删除,返回值push是数组的长度pop是弹出的那一项,对数组造成影响<br>队列方法:unshift,shift在数组的首端进行添加或者删除,返回值unshift是数组的长度shift是弹出的那一项,对数组造成影响<br>排序:sort 按照字符串的ASII码进行排序。(fn(a,b){})按照fn方法排序,a-b从小到大,b-a从大到小<br>反转:reverse<br>删除,截取,替换:splice(index,num,item) index是添加/删除的位置,负数就是从后往前;num是删除的数量;item是在index位置上添加的新内容</p><h5 id="2-4-非变异方法"><a href="#2-4-非变异方法" class="headerlink" title="2.4 非变异方法"></a>2.4 非变异方法</h5><p>对于非变异的,则不会触发视图更新,需要使用vm.$set或者Vue.set方法<br>截取:slice(start,end)返回的是从start开始,end结束的截取的子数组。start,end可以为负数,表示从数组末端到开始。start,end都没有,则截取整个数组;只有start,从start开始到结束截取;有start,end,截取start至end。<br>转为字符串:join(separator) 将数组转化为字符串,中间使用separator分隔开。<br>连接数组:concat(arr1,……,arrn) 连接两个或者多个数组,返回的是一个数组。</p><blockquote><p>扩展:push与concat的区别,同样:都是连接作用。不同:push会影响数组,concat不影响;如果参数是一个数组,push只会增加一项,直接将数组作为它最新的一项,会变成一个二维数组,concat的话,直接将数组一个一个的添加到原来的数组上,还是一个一维数组。</p></blockquote><h5 id="2-5-ES5的indexOf与lastIndexOf"><a href="#2-5-ES5的indexOf与lastIndexOf" class="headerlink" title="2.5 ES5的indexOf与lastIndexOf"></a>2.5 ES5的indexOf与lastIndexOf</h5><p>arr.indexOf(item) 返回item在arr数组中从左到右的index,有返回index,没有返回-1<br>arr.lastIndexOf(item) 返回item在arr数组中从右到左的index,有返回index,没有返回-1</p><h5 id="2-6-其它一些不常用常见的方法"><a href="#2-6-其它一些不常用常见的方法" class="headerlink" title="2.6 其它一些不常用常见的方法"></a>2.6 其它一些不常用常见的方法</h5><ol><li>every</li><li>fill</li><li>filter</li><li>forEach</li><li>Map</li><li>reduce</li><li>reduceRight</li></ol><h4 id="3-ES6-数组扩展"><a href="#3-ES6-数组扩展" class="headerlink" title="3. ES6 数组扩展"></a>3. ES6 数组扩展</h4><h5 id="3-1"><a href="#3-1" class="headerlink" title="3.1"></a>3.1</h5><h4 id="4-数组应用"><a href="#4-数组应用" class="headerlink" title="4. 数组应用"></a>4. 数组应用</h4><h5 id="4-1-数组去重"><a href="#4-1-数组去重" class="headerlink" title="4.1 数组去重"></a>4.1 数组去重</h5><p>方法一:循环去重</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"></span><br></pre></td></tr></table></figure><p>方法二:ES6中的set数据类型<br>Set它类似于数组,但是成员的值都是唯一的,没有重复的值。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">const set = new Set([1, 2, 3, 4, 4]);</span><br><span class="line">[...set]或者new Array(...set) // [1,2,3,4]</span><br></pre></td></tr></table></figure><p>方法三:数组存放,indexOf判断<br>遍历新数组,不存在就push进新数组中,存在就跳过</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">Array.prototype.unique = function() {</span><br><span class="line"> var n = []; // 存放已遍历的满足条件的元素</span><br><span class="line"> for (var i = 0; i < this.length; i++) {</span><br><span class="line"> // indexOf()判断当前元素是否已存在</span><br><span class="line"> if (n.indexOf(this[i]) == -1) {</span><br><span class="line"> n.push(this[i]);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> return n;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>方法四:对象存放,哈希算法(映射)判断<br>遍历新数组,不存在就push进新数组中,存在就跳过</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">Array.prototype.unique = function() {</span><br><span class="line"> // n为hash表,r为临时数组</span><br><span class="line"> var n = {}, r = [];</span><br><span class="line"> for (var i = 0; i < this.length; i++) {</span><br><span class="line"> // 如果hash表中没有当前项</span><br><span class="line"> if (!n[this[i]]) {</span><br><span class="line"> // 存入hash表</span><br><span class="line"> n[this[i]] = true;</span><br><span class="line"> // 把当前数组的当前项push到临时数组里面</span><br><span class="line"> r.push(this[i]); </span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> return r;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>方法五:现排序,后比较</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">Array.prototype.unique = function() {</span><br><span class="line"> this.sort();</span><br><span class="line"> var re = [this[0]];</span><br><span class="line"> for (var i = 1; i < this.length; i++) {</span><br><span class="line"> if (this[i] !== re[re.length - 1]) {</span><br><span class="line"> re.push(this[i]);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> return re;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h5 id="4-2-数组拍平"><a href="#4-2-数组拍平" class="headerlink" title="4.2 数组拍平"></a>4.2 数组拍平</h5><p>方法一:只适合二维数组</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Array.prototype.concat.apply([],arr)</span><br></pre></td></tr></table></figure><p>方法二:ES6的Generator函数</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">var arr = [1, [[2, 3], 4], [5, 6]];</span><br><span class="line">var arrCopy = [];</span><br><span class="line"></span><br><span class="line">var flat = function* (a) {</span><br><span class="line"> var length = a.length;</span><br><span class="line"> for (var i = 0; i < length; i++) {</span><br><span class="line"> var item = a[i];</span><br><span class="line"> if (Object.prototype.toString.call(item) == '[object Array]') {</span><br><span class="line"> yield* flat(item);</span><br><span class="line"> } else {</span><br><span class="line"> yield item;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line">for (var f of flat(arr)) {</span><br><span class="line"> arrCopy.push(f);</span><br><span class="line">}</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
<p>要学习ES6中的数组扩展篇章,所以就先去预习了一波原本接触到的Array。所谓温故而知新嘛~~<br>首先我们先了解一下js中的对象:1.内部对象,内部对象包含下面三种:错误对象(标识错误),内置对象(不需要使用new操作符来进行初始化,Math与JSON两种),常用对象(8种,String、Number、Date、Function、Boolean、Array、Object、RegExp);2.宿主对象,宿主对象主要有两个window与document。3.自定义对象,除了内部对象以及宿主对象之外,其它都为自定义对象,也就是开发者自己定义的对象。<br>说起Array,能想到的就是属性length,方法push,pop,reverse,shift,unshift,jion,slice,splice……等方法<br>推荐喜马拉雅上的「陪你读书(JavaScript WEB 编程)」的课程~~~<br>
</summary>
<category term="JavaScript" scheme="http://yoursite.com/categories/JavaScript/"/>
</entry>
<entry>
<title>vue源码分析-组件化</title>
<link href="http://yoursite.com/2018/10/15/vue%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90-%E7%BB%84%E4%BB%B6%E5%8C%96/"/>
<id>http://yoursite.com/2018/10/15/vue源码分析-组件化/</id>
<published>2018-10-15T13:39:06.000Z</published>
<updated>2019-02-02T04:50:17.227Z</updated>
<content type="html"><![CDATA[<p>终于弄懂了定义一个vue实例到渲染成页面DOM的整个过程,心情炒鸡棒,今天打算开始了解一下vue的另外一个核心思想 — <strong>组件化</strong>。<br>所谓组件化,也就是将页面根据一些规则(业务/逻辑等)划分成一个个组件(Component),每个组件的css,js,模版,图片等资源都相互独立,每个组件的资源都放在一起开发维护。这样便于维护以及实现可复用~~~<br><a id="more"></a></p><h3 id="组件化"><a href="#组件化" class="headerlink" title="组件化"></a>组件化</h3><p><span class="text-important">组件的 vnode 是没有 children 的</span></p><h4 id="1-createComponent"><a href="#1-createComponent" class="headerlink" title="1. createComponent"></a>1. createComponent</h4><p>组件的创建最开始走的和<a href="../../../../2018/10/09/vue源码分析-数据驱动/#more">vue源码分析-数据驱动</a>章节的流程是一样的。也是,new Vue() ==> this._init() ==> initMixin() ==> $mount() ==> mountComponent() ==> _render() ==> $createElement ==> createElement() ==> _createElement()<br>但是,在_createElement()方法中,有一个判断,与之前的不一样<span class="font-color-red">if (typeof tag === ‘string’)</span><br><img src="createElement.png" alt="判断">在<a href="../../../../2018/10/09/vue源码分析-数据驱动/#more">vue源码分析-数据驱动</a>章节中,tag是一个‘div’满足,则直接进入判断中。此处是一个组件,tag则是一个对象<br><img src="tag_detail.png" alt="tag的详情">所以,直接进入createComponent方法中,并且传入了一系列的参数(tag,data,context,children),其中只有tag以及context有值,并且context其实就是Vue。<br><img src="createComponent.png" alt="createComponent">其中context.$options._base其实就是Vue构造函数,Ctor就是tag,Ctor如果是对象的话,则会调用Vue.extend方法<br><img src="extend.png" alt="extend">extend方法主要是根据Vue构造函数创建一个Sub构造函数,并且在把传入的options和Vue上面原本挂载的options进行一个mergeOptions,将options内容进行合并,并且赋值给Sub.options,则当前组件就会含有自己的options,以及挂载在Vue上的全局component,directive,filter<br>其中,validateComponentName是用来检验组件名称是否合法合理。<br>sub构造函数中含有this. _ init()其实也就是上一章节中 _ init方法。<br>因此后期就会再次进入 _ init方法创建组件,直接进入initInternalComponent方法中,在initInternalComponent方法中,就是一系统的赋值等。</p><h4 id="2-patch"><a href="#2-patch" class="headerlink" title="2. patch"></a>2. patch</h4><p>在上面createComponent之后,进入createComponent方法中<br><img src="createComponent2.png" alt="createComponent2"><br>其中有一个installComponentHooks的方法,hooksToMerge其实就是一个对象,含有init,prepatch,insert,destory这四个字符串,通过便利,给data上添加上钩子函数(hook)<br><img src="installComponentHooks.png" alt="installComponentHooks"><br>将componentVNodeHooks对象中的相应的钩子函数赋值给data。<br>接着执行createComponent里面的方法new VNode,返回一个vnode<br>执行另外一个createComponent方法,调用原本赋值再vnode上的hook函数,将i的init方法赋值给i,再调用i方法<br><img src="createComponent3.png" alt="createComponent3"><br>进入原本hooksToMerge对象赋值给data上的init方法,通过createComponentInstanceForVnode函数创建组件对象<br><img src="componentVNodeHooks-init&prepatch.png" alt="componentVNodeHooks-init&prepatch"><br>在createComponentInstanceForVnode函数中,最终返回<span class="text-important">new vnode.componentOptions.Ctor(options)</span>,而vnode.componentOptions.Cto也就是我们在1. createComponent中利用Vue构造函数创建的一个Sub构造函数<br><img src="createComponentInstanceForVnode.png" alt="createComponentInstanceForVnode"><br>再次回到sub构造函数中,调用了this. _ init方法,其实也就是我们在<a href="../../../../2018/10/09/vue源码分析-数据驱动/#more">vue源码分析-数据驱动</a>章节中new Vue()后立马执行的初始化<br><img src="sub.png" alt="sub"><br>再次进入vue.prototype. _ init方法中,此时由于是组件,会调用initInternalComponent(vm, options);方法,而此时的没有el这个属性值没有值,则就不会去执行vm.$mount(vm.$options.el);<br>在initInternalComponent方法中,进行了一系列的赋值。其中注意:opts._parentVnode = parentVnode,则组件对象上的_parentVnode是一个占位node<br><img src="initInternalComponent.png" alt="initInternalComponent"><br>继续回到componentVNodeHooks中,调用child.$mount方法进行挂载,调用mountComponent,在mountComponent函数中定义 updateComponent = function () { vm._update(vm._render(), hydrating); }; 走起<a href="../../../../2018/10/09/vue源码分析-数据驱动/#more">vue源码分析-数据驱动</a>章节的流程(_render() ==> $createElement ==> createElement ==> _createElement ==> )里层的元素组件进行上面的流程</p>]]></content>
<summary type="html">
<p>终于弄懂了定义一个vue实例到渲染成页面DOM的整个过程,心情炒鸡棒,今天打算开始了解一下vue的另外一个核心思想 — <strong>组件化</strong>。<br>所谓组件化,也就是将页面根据一些规则(业务/逻辑等)划分成一个个组件(Component),每个组件的css,js,模版,图片等资源都相互独立,每个组件的资源都放在一起开发维护。这样便于维护以及实现可复用~~~<br>
</summary>
<category term="vue源码分析" scheme="http://yoursite.com/categories/vue%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90/"/>
</entry>
<entry>
<title>JavaScript - 数据存储</title>
<link href="http://yoursite.com/2018/10/10/JavaScript-%E6%95%B0%E6%8D%AE%E5%AD%98%E5%82%A8/"/>
<id>http://yoursite.com/2018/10/10/JavaScript-数据存储/</id>
<published>2018-10-10T03:09:21.000Z</published>
<updated>2018-10-29T09:44:03.165Z</updated>
<content type="html"><![CDATA[<p>一直以来都知道cookie、sessionStorage、localStorage这些用于缓存数据的,但并没有正式地去了解研究过它们,此次项目中用到这些知识,正好学习一波~<br>cookie:也就是HTTP cookie,客户端用于存储会话信息,是一个标准,并且要求服务器对任意HTTP请求发送Set-Cookie HTTP头作为响应的一部分。<br>Web Storage:一种为了存储大量可以跨会话存在的数据,新途径的标准。包含两种对象定义:sessionStorage、globalStorage……<br><a id="more"></a></p><h3 id="1-cookie"><a href="#1-cookie" class="headerlink" title="1. cookie"></a>1. cookie</h3><h3 id="2-Web-Storage"><a href="#2-Web-Storage" class="headerlink" title="2. Web Storage"></a>2. Web Storage</h3><h4 id="2-1-sessionStorage"><a href="#2-1-sessionStorage" class="headerlink" title="2.1 sessionStorage"></a>2.1 sessionStorage</h4><h4 id="2-2-globalStorage"><a href="#2-2-globalStorage" class="headerlink" title="2.2 globalStorage"></a>2.2 globalStorage</h4>]]></content>
<summary type="html">
<p>一直以来都知道cookie、sessionStorage、localStorage这些用于缓存数据的,但并没有正式地去了解研究过它们,此次项目中用到这些知识,正好学习一波~<br>cookie:也就是HTTP cookie,客户端用于存储会话信息,是一个标准,并且要求服务器对任意HTTP请求发送Set-Cookie HTTP头作为响应的一部分。<br>Web Storage:一种为了存储大量可以跨会话存在的数据,新途径的标准。包含两种对象定义:sessionStorage、globalStorage……<br>
</summary>
<category term="JavaScript" scheme="http://yoursite.com/categories/JavaScript/"/>
</entry>
<entry>
<title>vue源码分析 - 数据驱动</title>
<link href="http://yoursite.com/2018/10/09/vue%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90-%E6%95%B0%E6%8D%AE%E9%A9%B1%E5%8A%A8/"/>
<id>http://yoursite.com/2018/10/09/vue源码分析-数据驱动/</id>
<published>2018-10-09T02:49:58.000Z</published>
<updated>2019-02-02T04:50:51.888Z</updated>
<content type="html"><![CDATA[<p>数据驱动是vue.js的一个重要的思想。数据驱动:视图根据数据驱动生成,我们不会通过直接修改dom来修改视图,会通过修改数据来完成对视图的修改。<br><a id="more"></a></p><blockquote><p>Runtime-only: 需要借助类似于webpack的vue-loader来将.vue文件编译成JavaScript。因为是在编译阶段做的,所以只包含运行时的Vue.js代码,代码体积更轻便。<br><br>Runtime + compiler: 没有对代码做预编译。因为在Vue.js2.0中,最后渲染都是通过render函数,如果编写了template,则需要编译成render函数,而这个编译过程发生在运行时,所以需要带有编译器的版本,并且这个编译过程对性能会有一定的损耗。</p></blockquote><h3 id="1-new"><a href="#1-new" class="headerlink" title="1. new"></a>1. new</h3><blockquote><p>new Vue()一个实例干了什么?</p></blockquote><p><img src="https://i.imgur.com/lny4o5V.png" alt="new vue时的代码"><br>new Vue()后只会判断使用的语法对不对,然后就调用已经挂载到Vue原型上的_init方法(通过initMixin(Vue)),在initMixin()之前,Vue上只有一个构造函数外加一个<strong>proto</strong>(也就是Object所含有的)。<br><img src="https://i.imgur.com/PNzomC5.png" alt="vue.prototype"></p><h3 id="2-init"><a href="#2-init" class="headerlink" title="2. init"></a>2. init</h3><p>initMixin方法在Vue.prototype上挂载了一个_init方法<br><img src="https://i.imgur.com/Yt9N7Rl.png" alt=""><br>在initMixin方法中:先将options进行整合(具体先不管);<br>后又进行了一系统的初始化:生命周期初始化(initLifecycle)、事件初始化(initEvents)、渲染(initRender)、callHook()、初始化数据(initState)以及一些其它的初始化(initInjections、initProvide)</p><p>其中initState方法中含有initData方法(其中含有一个proxy(vm, “_data”, key),为data中数据项进行一个代理设置)</p><p><img src="https://i.imgur.com/UHwd04N.png" alt=""><br>也就是利用了Object.defineProperty()方法来设置访问器属性,从而实现了直接修改类似this.message = 12也就是修改了this._data.message = 12</p><p>除了_data会使用proxy方法来进行一层设置代理,还会有_props,因此_data与_props里面定义的属性名称不能相同,不然就会出现覆盖的情况(写组件中经常就会遇见props中有一个a,data中也有一个a,则后期父组件修改a的值后,组件并不会跟着进行变化)</p><h3 id="3-mount"><a href="#3-mount" class="headerlink" title="3. $mount"></a>3. $mount</h3><p>在initMixin方法的最后根据vm.$options.el是否存在来决定是否挂载</p><p><code>if (vm.$options.el) { vm.$mount(vm.$options.el);}</code></p><p>$mount方法是挂载在vue构造函数prototype上的,里面直接调用的是mountComponent方法,后期又定义了updateComponent函数(里面调用了vue上的 _update 方法, _update 方法中传递了vue的 _render 函数渲染出来的vnode以及hydrating),又新建了一个 <span style="color:red;">渲染watcher</span>(后期发生变化,进行更新的时候,会执行渲染watcher中的updateComponent方法,从而重新渲染了一次)</p><p><img src="$mount.png" alt="$mount"></p><p>该过程主要做了:对options.render进行一个判断,看看是否书写了render函数,如果没有写,则对template进行解析,(其中没有template的时候,会根据getOuterHTML来得到模版字符串),然后会根据template进行编译(使用compileToFunction),编译得到render函数以及staticRenderFns静态render函数。因为vue只认render函数。<br><br>有了render函数之后,就会调用mount.call(this,el,hydrating),这个mount函数其实就是vue.prototype.$mount。然后就会执行上面的过程($mount)</p><h3 id="4-compile"><a href="#4-compile" class="headerlink" title="4. compile"></a>4. compile</h3><p>函数compileToFunction来进行编译,拿到render渲染函数以及staticRenderFns静态render函数</p><h3 id="5-render"><a href="#5-render" class="headerlink" title="5. render"></a>5. render</h3><p>_render方法是实例的一个私有方法,它用来把实例渲染成vnode(虚拟Node)。<br><img src="render.png" alt="_render"><br>vnode = render.call(vm. _renderProxy, vm.$createElement);<br>其中vm. _renderProxy是上下文,在生产环境下,就是vm实例,在开发环境下是一个Proxy实例。(会在init过程中有下面的代码)</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">if (process.env.NODE_ENV !== 'production') {</span><br><span class="line"> initProxy(vm);</span><br><span class="line">} else {</span><br><span class="line"> vm._renderProxy = vm;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>$createElemt在initRender中定义,initRender函数在init中执行。在$createElement函数中调用了createElement方法,createElement方法会返回一个VNode</p><h3 id="6-vnode"><a href="#6-vnode" class="headerlink" title="6. vnode"></a>6. vnode</h3><p>产生的前提:浏览器中的DOM比较庞大,并且设计的比较复杂,频繁地去更新DOM,也会产生性能问题。Virtual DOM 使用js对象来描述DOM。<br>Virtual DOM除了数据结构的定义,映射到真实的DOM上,还需要经历VNode的create、diff、patch等过程。而Vue中的createElement就是VNode的create。</p><p><img src="createElement.png" alt="createElement"></p><p>createElement方法调用的是 _createElement方法,在 _createElement方法中,对children做了normalize处理(也就是将children变成一维数组,涉及到的方法有:normalizeChildren,normalizeArrayChildren,simpleNormalizeChildren)</p><h3 id="7-patch"><a href="#7-patch" class="headerlink" title="7. patch"></a>7. patch</h3><blockquote><p>通过 _render函数以及createElement函数拿到了VNode,如何渲染到真实DOM上呢?</p></blockquote><p>通过vue中 _update方法,将VNode渲染成真实的DOM,此方法会在两种情况下被调用:首次渲染,数据更新。</p><p><img src="update.png" alt="update"></p><p>其中,会走到vm.<strong> patch </strong> 方法<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Vue.prototype.__ patch __ = inBrowser ? patch : noop;</span><br></pre></td></tr></table></figure></p><p><br>在服务器端是没有DOM这个概念的,所以不在客户端中,则是不需要渲染成真实DOM的。<br>调用<strong>patch</strong>方法的时候,第一个参数是真实的DOM,第二个参数是我们得到的VNode。通过<strong>patch</strong>方法中的createElm将VNode挂载到真实的DOM上,(如果有子节点,则递归调用createElm,没有子节点,则直接创建一个DOM),最后通过insert方法插入真实DOM中(里面分情况调用了insertBefore与appendChild)。</p>]]></content>
<summary type="html">
<p>数据驱动是vue.js的一个重要的思想。数据驱动:视图根据数据驱动生成,我们不会通过直接修改dom来修改视图,会通过修改数据来完成对视图的修改。<br>
</summary>
<category term="vue源码分析" scheme="http://yoursite.com/categories/vue%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90/"/>
</entry>
<entry>
<title>Flow初识</title>
<link href="http://yoursite.com/2018/10/06/Flow%E5%88%9D%E8%AF%86/"/>
<id>http://yoursite.com/2018/10/06/Flow初识/</id>
<published>2018-10-06T02:35:16.000Z</published>
<updated>2018-10-29T09:43:14.759Z</updated>
<content type="html"><![CDATA[<p>借助学习vue.js源码,在其过程中,认识到了Flow,该篇主要介绍一下最基本的Flow<br><a id="more"></a></p><h3 id="初识Flow"><a href="#初识Flow" class="headerlink" title="初识Flow"></a>初识Flow</h3><h4 id="1-是什么?"><a href="#1-是什么?" class="headerlink" title="1. 是什么?"></a>1. 是什么?</h4><p>Flow是一种静态类型检查工具,是一种工具。</p><blockquote><p>静态类型检查: 在编辑期间尽早发现(由类型引起的)bug,又不影响代码运行(不需要运行时动态检查类型)</p></blockquote><h4 id="2-Flow的工作方式"><a href="#2-Flow的工作方式" class="headerlink" title="2. Flow的工作方式"></a>2. Flow的工作方式</h4><h5 id="2-1-类型推断"><a href="#2-1-类型推断" class="headerlink" title="2.1 类型推断"></a>2.1 类型推断</h5><blockquote><p>通过变量使用上下文来推断出变量类型,然后根据这些推断来检查类型</p></blockquote><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">/*@flow*/``</span><br><span class="line">function split(str) {</span><br><span class="line"> return str.split(' ')</span><br><span class="line">}</span><br><span class="line">split(11)</span><br></pre></td></tr></table></figure><p><span style="color:red;">会报错</span>:原因是我们期待的是字符串类型,但是传入的是数字类型</p><h5 id="2-2-类型注释"><a href="#2-2-类型注释" class="headerlink" title="2.2 类型注释"></a>2.2 类型注释</h5><blockquote><p>事先注释好我们期待的类型,Flow会基于这些注释来判断</p></blockquote><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">/*@flow*/</span><br><span class="line"></span><br><span class="line">function add(x, y){</span><br><span class="line"> return x + y</span><br><span class="line">}</span><br><span class="line">add('Hello', 11)</span><br></pre></td></tr></table></figure><p>上面的代码<span style="color:red;">不会报错</span>,Flow的检查不出来,因为‘+’可以用于字符串也可以用于数字<br>则,此时就需要使用类型注释(:)</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">/*@flow*/</span><br><span class="line"></span><br><span class="line">function add(x: number, y: number): number {</span><br><span class="line"> return x + y</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">add('Hello', 11)</span><br></pre></td></tr></table></figure><ul><li>数组类型注释格式:Array< T >,T 表示数组中每项的数据类型</li><li>一个变量可能多个类型时,可以使用<span style="color:red;"> ‘|’ </span>来连接两种类型,表示或</li><li>若想任意类型<span style="color:red;"> T </span>可以为 null 或者 undefined,只需类似如下写成可以使用<span style="color:red;"> ?T </span>的格式即可</li></ul><hr><p>参考:<a href="https://flow.org/en/docs/getting-started/" target="_blank" rel="noopener">Flow官网</a></p>]]></content>
<summary type="html">
<p>借助学习vue.js源码,在其过程中,认识到了Flow,该篇主要介绍一下最基本的Flow<br>
</summary>
<category term="JavaScript" scheme="http://yoursite.com/categories/JavaScript/"/>
</entry>
</feed>