-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.html
728 lines (491 loc) · 61.6 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" name="viewport">
<meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1">
<meta name="keywords" content=""/>
<meta name="description" content="Kumiko77"/>
<meta name="Robots" content="all">
<title>Kumiko77</title>
<link rel="icon" href="/images/favicon.ico">
<link rel="stylesheet" href="/css/font-awesome.min.css">
<link rel="stylesheet" href="/css/atom-one-dark.css">
<link rel="stylesheet" href="/css/style.css">
<script src="/js/highlight.min.js"></script>
<meta name="generator" content="Hexo 4.2.1"></head>
<body>
<div class="main-container">
<header class="header">
<div class="global-width">
<nav class="nav-box">
<a class="nav-item" href="/"
>Home</a>
<a class="nav-item" href="/resume"
>Resume</a>
<a class="nav-item" href="/mood"
target="_blank"
>Mood</a>
<a class="nav-item" href="/amusement/tetris"
target="_blank"
>Amusement</a>
<a class="nav-item" href="/about"
>About</a>
</nav>
</div>
</header>
<section class="content global-width">
<div class="main">
<article class="box post post-item">
<div class="post-title"><a href="/2020/11/10/%E5%85%B3%E4%BA%8E%E8%B7%A8%E5%9F%9F/">关于跨域</a></div>
<div class="post-meta">
<i class="fa fa-calendar"></i> <time>2020-11-10</time>
<span class="dotted">|</span>
<i class="fa fa-user"></i>
</div>
<div class="post-excerpt">
<a href="/2020/11/10/%E5%85%B3%E4%BA%8E%E8%B7%A8%E5%9F%9F/">
<p>
1.什么是跨域?简单的说,跨域就是一个域下的文档或者是执行脚本要访问另一个域下的资源或与另一个域进行通信时,就会发生跨域。比如说A域名读取B域名下的图片时、js利用AJAX调用后台域名接口时或者父级页面与不同域名下的iframe通信时等等
要了解跨域,首先要知道域是什么
2.什么是域?跨域的域并不是域名的域,而是由浏览器同源政策限定出的一种概念。
SOP即同源政策,英文全拼为Same origin policy,这个约定在1995年由NetScape公司引入浏览器,它是浏览器最核心合适最基础的安全功能,如果浏览器缺少了同源政策,就很容易收到XSS、XSFR等攻击
同源指的是资源或者目标的协议、域名、端口者相同,即使是不同的域名指向同一个IP地址也会出现跨域
2.1非同源限制
无法读取非同源网页的Cooike、LocalStorage等
无法接触非同源网页的DOM
无法向非同源地址发送AJAX请求3. 如果解决跨域3.1 JSONP跨域<script>标签的src属性并不会被同源政策所约束,所以可以获取任何服务器上的脚本并执行
JSONP的核心思想就是通过添加添加一个<script>标签,向服务器请求JSON数据,服务器接受请求后,将数据放在一个制定名字的回调函数的参数中传递回来
1234567<script src="http://test.com/api/getData?callback=backData"></script>// 处理服务器返回回调函数的数据<script type="text/javascript"> function backData(res){ console.log(res.data) }</script>
同时JQuery也支持JSONP
123456789$.ajax({ url: 'http://www.api.com:8080/login', type: 'get', dataType: 'jsonp', jsonp: "callback", success: () => { //... }});
3.2 优缺点3.2.1 优点
兼容低版本浏览器3.2.2 缺点
只支持get请求
错误处理机制不完善4.1 CORS跨域CORS是跨域资源分享(Cross-Origin Resource Sharing)的缩写。它是W3C标准,属于跨域AJAX请求的根本解决方案。它允许浏览器向跨域源发起XMLHttpRequest请求,从而解决了AJAX只能同源使用的限制
整个CORS的通信过程,都是浏览器自动完成,不需要用户参与。浏览器一旦发现AJAX请求跨域就会自动添加一些附加的头信息,有时还会多出一次附加的请求
普通跨域请求:只需要服务端设置Access-Control-Allow-Origin
带cookie跨域请求:前后端都需要进行配置
并且浏览器会将CORS请求分成两类,简单请求和非简单请求,浏览器对这两种请求的处理是不一样的
4.2.1 简单请求满足以下两个条件的请求就是简单请求
请求方法是HEAD、GET、POST三种方法之一
HTTP的头请求信息不能超出下列字段
Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type(只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain)4.2.2 非简单请求处理上边的简单请求外,剩下的都是非简单请求
对于非简单请求,浏览器在正式通信之前,都会做一次查询请求,整个查询请求叫做预检请求,也叫OPTIONS请求,所以它使用的请求方式是OPTIONS
在OPTIONS请求里,头信息除了有表明来源的Origin字段外,还有一个Access-Control-Request-Method自字段和Access-Control-Request-Headers字段,它们分别表明了本次CORS请求用的HTTP方法和请求会额外发送的头信息字段
预检请求的回应服务器收到预检请求以后,检查了Origin、Access-Control-Request-Method和Access-Contorl-Request-Headers字段以后,确认允许跨域请求,就可以作出回应
只有得到肯定的答复,浏览器才会正式发出XMLHttpRequest请求,否则就会报跨域错误
Access-Control-Allow-Origin :该字段是必须的。它的值要么是请求时Origin字段的值,要么是一个*,表示接受任意域名的请求
Access-Control-Allow-Credentials: 该字段可选。它的值是一个布尔值,表示是否允许发送Cookie。默认情况下,Cookie不包括在CORS请求之中。设为true,即表示服务器明确许可,Cookie可以包含在请求中,一起发给服务器。这个值也只能设为true,如果服务器不要浏览器发送Cookie,删除该字段即可。
Access-Control-Expose-Headers:该字段可选。CORS请求时,XMLHttpRequest对象的getResponseHeader()方法只能拿到6个基本字段:Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma。如果想拿到其他字段,就必须在Access-Control-Expose-Headers里面指定
Access-Control-Max-Age: 该字段可选,用来指定本次预检请求的有效期,单位为秒。在此期间,不用发出另一条预检请求。4.3 优缺点4.3.1 优点
支持多种请求方式
处理机制完善
对于复杂请求,多一次验证,安全性更好4.3.2 缺点
不支持IE10以下浏览器
</p>
</a>
</div>
</article>
<article class="box post post-item">
<div class="post-title"><a href="/2020/11/09/%E6%97%A5%E5%B8%B8%E9%97%AE%E9%A2%98%E8%AE%B0%E5%BD%95/">日常问题记录</a></div>
<div class="post-meta">
<i class="fa fa-calendar"></i> <time>2020-11-09</time>
<span class="dotted">|</span>
<i class="fa fa-user"></i>
</div>
<div class="post-excerpt">
<a href="/2020/11/09/%E6%97%A5%E5%B8%B8%E9%97%AE%E9%A2%98%E8%AE%B0%E5%BD%95/">
<p>
1.脚本<script>放在<head>和放到<body>底部的区别放在上面是先加载script脚本,加载时body并没有渲染完成,如果脚本中内容有涉及到dom操作之类的可能会报错,如果放在body后面就是先完成body渲染在进行加载script脚本,能够有效的访问到body中的元素,就不会出现上述情况
</p>
</a>
</div>
</article>
<article class="box post post-item">
<div class="post-title"><a href="/2020/11/09/reduce%E5%8E%BB%E9%87%8D/">reduce去重</a></div>
<div class="post-meta">
<i class="fa fa-calendar"></i> <time>2020-11-09</time>
<span class="dotted">|</span>
<i class="fa fa-user"></i>
</div>
<div class="post-excerpt">
<a href="/2020/11/09/reduce%E5%8E%BB%E9%87%8D/">
<p>
1.reduce去重解析
先使用Array.sort()对数组进行从小到大排序
每次进入reduce循环先判断新数组长度,若长度为0,则是第一项就直接往里push
之后每次都用当前项与新数组末尾项做对比如果相同则说明数组里存在这一项所以不需要做操作,若不相等则不存在,就往新数组里push该项12345678const arr = [1,3,6,4,3,1,2,3,5,3,2,4,5]let result = arr.sort().reduce((newArr, item) => { if(newArr.length === 0 || newArr[newArr.length - 1] !== item) { newArr.push(item) } return newArr}, [])console.log(result) //[1,2,3,4,5,6]
</p>
</a>
</div>
</article>
<article class="box post post-item">
<div class="post-title"><a href="/2020/11/07/%E5%85%B3%E4%BA%8EVue%E4%B8%AD%E7%9A%84%E8%99%9A%E6%8B%9FDOM/">关于Vue中的虚拟DOM</a></div>
<div class="post-meta">
<i class="fa fa-calendar"></i> <time>2020-11-07</time>
<span class="dotted">|</span>
<i class="fa fa-user"></i>
</div>
<div class="post-excerpt">
<a href="/2020/11/07/%E5%85%B3%E4%BA%8EVue%E4%B8%AD%E7%9A%84%E8%99%9A%E6%8B%9FDOM/">
<p>
1.真实DOM与渲染过程在开始了解虚拟DOM之前,先了解一下真实DOM的渲染与浏览器的解析过程。
1.1 浏览器引擎的工作过程1.1.1 创建DOM树解析HTML生成DOM树 - 渲染引擎首先解析HTML文档,生成DOM树。 用CSS分析器,分析CSS文件和元素上的inline样式,生成页面的样式表
1.1.2 生成render将DOM树和样式表,关联起来,构建一颗Render(渲染)树
1.1.3 布局render树有了Render树,浏览器开始对渲染树的每个节点进行布局处理,确定其在屏幕上的显示位置
1.1.4 绘制render树遍历渲染树并用UI后端层将每一个节点绘制出来
2.虚拟DOM2.1 虚拟DOM是什么?当用原生js或者jq去操作真实DOM的时候,浏览器会从构建DOM树开始从头到尾执行一遍流程。当操作次数过多时,之前计算DOM节点坐标值等都是白白浪费的性能,虚拟DOM由此诞生。
2.2 虚拟DOM有什么好处?假设一次操作中有10次更新DOM的动作,虚拟DOM不会立即操作DOM,而是将这10次更新的diff内容保存到本地一个JS对象中,最终将这个JS对象一次性attch到DOM树上,再进行后续操作,避免大量无谓的计算量。所以,用JS对象模拟DOM节点的好处是,页面的更新可以先全部反映在虚拟DOM上,操作内存中的JS对象的速度显然要更快,等更新完成后,再将最终的JS对象映射成真实的DOM,交由浏览器去绘制。
3. Vue中的虚拟DOM
渲染函数:渲染函数是用来生成虚拟DOM的。Vue推荐使用模板来构建应用界面,在底层实现中Vue将模板编译成渲染函数
Vnode虚拟节点:它可以代表一个真实的dom节点。通过createElement方法将vnode节点渲染成dom节点
patch:虚拟DOM最核心的部分,它可以将vnode渲染成真实的DOM,这个过程是对比新旧虚拟节点之间有哪些不同,然后根据对比结果找出需要更新的的节点进行更新3.模拟实现3.1先我们创建虚拟DOM树1234567891011121314151617// element/index.js// 虚拟DOM元素类,用来描述DOMfunction Element(type, props, children){ this.type = type; //节点类型 this.props = props; //属性 this.children = children; //子节点}// 创建虚拟DOMfunction createElement(type, props, children){ return new Element(type, props, children);}//向外输出export { Element, createElement}
在app.vue中调用createElement方法来创建虚拟DOM树12345678910//App.vueimport {createElement} from './js/element.js'let V_DOM = createElement('ul',{class:'list'},[ createElement('li', {class:'item'},['item1']), createElement('li', {class:'item'},['item2']), createElement('li', {class:'item'},['item3'])])//打印虚拟DOMconsole.log(V_DOM);
打开f12控制台就能看到创建出的虚拟DOM树3.2 模拟渲染函数渲染虚拟DOM123456789101112131415161718192021222324252627282930// element.jsfunction render(dom) { // 根据type类型来创建对应的元素 let el = document.createElement(dom.type); // 再去遍历props属性对象,然后给创建的元素el设置属性 for (let key in dom.props) { // 设置属性的方法 el.setAttribute(key, dom.props[key]); } // 遍历子节点 // // 如果子节点也是虚拟DOM,递归构建DOM节点 // 不是就代表是文本节点,直接创建 dom.children.forEach(child => { child = (child instanceof Element) ? render(child) : document.createTextNode(child); // 添加到对应元素内 el.appendChild(child); }); return el;}//向外输出export { Element, createElement, render,}
回到app.vue中调用render方法123456789101112import {createElement, render, renderDom} from './js/element.js'let V_DOM = createElement('ul',{class:'list'},[ createElement('li', {class:'item'},['item1']), createElement('li', {class:'item'},['item2']), createElement('li', {class:'item'},['item3'])])//打印虚拟DOMconsole.log(V_DOM);var el = render(V_DOM);console.log(el);document.body.appendChild(el);
这样就虚拟DOM对象渲染成来真实DOM对象
</p>
</a>
</div>
</article>
<article class="box post post-item">
<div class="post-title"><a href="/2020/11/07/%E5%85%B3%E4%BA%8EVue%E7%9A%84%E6%95%B0%E6%8D%AE%E5%93%8D%E5%BA%94%E5%BC%8F/">关于Vue的数据响应式</a></div>
<div class="post-meta">
<i class="fa fa-calendar"></i> <time>2020-11-07</time>
<span class="dotted">|</span>
<i class="fa fa-user"></i>
</div>
<div class="post-excerpt">
<a href="/2020/11/07/%E5%85%B3%E4%BA%8EVue%E7%9A%84%E6%95%B0%E6%8D%AE%E5%93%8D%E5%BA%94%E5%BC%8F/">
<p>
什么是数据响应式我对数据响应式的理解是,当data中的数据发生改变时,Vue会通知有使用到该数据的代码将视图更新。这挺神奇,Vue的数据响应式主要是依赖Object.defineProperty(),整个过程是怎么实现的呢,下面我来捋一捋
1.数据的改造为什么第一步是数据的改造呢,因为这是最基础也是最为重要的一步,后面的环节都是依赖这一步执行的
1234567891011121314151617function defineReactive (obj,key,val) { Object.defineProperty(obj,key,{ enumerable: true, configurable: true, get: function () { return val; }, set: function (newVal) { //判断新值与旧值是否相等 //判断的后半段是为了验证新值与旧值都为NaN的情况 NaN不等于自身 if(newVal === val || (newVal !== newVal && value !== value)){ return ; } val = newVal; } });}
例如const obj = {},然后再调用defineReactive(obj,’num’,2)方法,此时在函数内,val=2,然后每次获取obj.num的值的时候都是获取val的值,设置obj.num的时候也是设置val的值。(每次调用defineReactive都会产生一个闭包保存了val的值)
1.1流程
输入数据
改造数据(调用defineReactive())
如果数据改变 => 触发方法
看看第三步,如果数据改变如何触发事件呢?思考了一下,如果要改变数据,就必须要先set数据触发definePerperty的set()方法,所以我们直接在set()中添加事件不就完事了嘛
2.依赖收集我们怎么知道在数据改变之后需要触发什么方法呢?
Vue中,使用数据来渲染视图,在获取数据的时候是收集依赖的最佳时期,Vue在改造数据的时候生成来一个Dep实例,用于收集依赖
1234567891011121314151617181920212223242526272829class Dep { constructor(){ //订阅的信息 this.subs = []; } addSub(sub){ this.subs.push(sub); } removeSub (sub) { remove(this.subs, sub); } //此方法的作用等同于 this.subs.push(Watcher); depend(){ if (Dep.target) { Dep.target.addDep(this); } } //这个方法就是发布通知了 告诉你 有改变啦 notify(){ const subs = this.subs.slice() for (let i = 0, l = subs.length; i < l; i++) { subs[i].update(); } }}Dep.target = null;
着重了解两个方法
depend()可以理解为收集依赖的事件,不考虑其他方面的话,功能等同于addSub()。
notify()这个方法更为直观了,执行所有依赖的update()方法,就是之后的改变视图。
2.1 继续改造代码有了实例Dep之后,defineReactive就变成这样了
12345678910111213141516171819202122function defineReactive (obj,key,val) { const dep = new Dep(); Object.defineProperty(obj,key,{ enumerable: true, configurable: true, get: function () { if(Dep.target){ //获取数据的时候收集依赖 等同于 dep.addSub(Dep.target) dep.depend() } return val; }, set: function (newVal) { if(newVal === val || (newVal !== newVal && val !== val)){ return ; } val = newVal; //发布改变 dep.notify(); } });
2.2 Dep.target是什么?为什么要有Dep.target才会收集依赖呢?
Dep是一个类,Dep.target是类的属性,并不是dep实例的属性。
Dep类在全局可用,所以Dep.target在全局能访问到,可以任意改变它的值。
get这个方法使用很平常,不可能每次使用获取数据值的时候都去调用dep.depend()。
dep.depend()实际上就是dep.addSub(Dep.target)。
那么最好方法就是,在使用之前把Dep.target设置成某个对象,在订阅完成之后设置Dep.target = null。3. 测试一波1234567891011121314151617181920const obj = {} 相当于初始化Vue中的dataconst watcher = { addDep:function (dep) { dep.addSub(this); }, update:function(){ html(); }}//假装这个是渲染页面的function html () { document.querySelector('body').innerHTML = obj.html;}defineReactive(obj,'html','how are you');//定义响应式的数据//把Dep.targer的值设为watcher是为了把watcher添加到订阅信息的subs数组中Dep.target = watcher;html();//第一次渲染界面Dep.target = null;
一开始浏览器页面上显示的是how are you
接着打开f12,输入obj.html = ‘hello’
效果便实现了,页面上的内容变成了hello
</p>
</a>
</div>
</article>
<article class="box post post-item">
<div class="post-title"><a href="/2020/10/28/%E5%85%B3%E4%BA%8Ejs%E5%8E%9F%E5%9E%8B%E5%92%8C%E5%8E%9F%E5%9E%8B%E9%93%BE/">关于js原型和原型链</a></div>
<div class="post-meta">
<i class="fa fa-calendar"></i> <time>2020-10-28</time>
<span class="dotted">|</span>
<i class="fa fa-user"></i>
</div>
<div class="post-excerpt">
<a href="/2020/10/28/%E5%85%B3%E4%BA%8Ejs%E5%8E%9F%E5%9E%8B%E5%92%8C%E5%8E%9F%E5%9E%8B%E9%93%BE/">
<p>
123456function Person() { //...}var person = new Person();person.name = 'Tom';console.log(person.name) // Tom
这里的Person就是一个构造函数,我们用new创建了一个实例对象person
1. prototype
每一个函数都有一个prototype属性
每一个JavaScript对象(null除外)在创建的时候都会关联另外一个对象,这个对象就是我们所说的原型,每一个对象都会从其原型上“继承”属性12345678function Person() { //...}Person.prototype.name = 'Tom';var person1 = new Person();var person2 = new Person();console.log(person1.name) // Tomconsole.log(person2.name) // Tom
2. proto每一个JavaScript对象(null除外)都具有的一个属性,叫proto,这个属性会指向该对象的原型
12345function Person() {//...}var person = new Person();console.log(person.__proto__ === Person.prototype); // true
3. constructor每个原型都有一个constructor属性,指向关联的构造函数
12345678910function Person() {//...}var person = new Person();console.log(person.__proto__ == Person.prototype) // trueconsole.log(Person.prototype.constructor == Person) // true// ES6console.log(Object.getPrototypeOf(person) === Person.prototype) // true
3. 实例与原型12345678910111213function Person() {//...}Person.prototype.name = 'Kevin';var person = new Person();person.name = 'Daisy';console.log(person.name) // Daisydelete person.name;console.log(person.name) // Kevin
在这个例子中,我们给实例对象 person 添加了 name 属性,当我们打印 person.name 的时候,结果自然为 Daisy。
但是当我们删除了 person 的 name 属性时,读取 person.name,从 person对象中找不到name属性就会从person的原型也就是person.proto,也就是 Person.prototype中查找
4. 原型链1console.log(Object.prototype.__proto__ === null) // true
</p>
</a>
</div>
</article>
<article class="box post post-item">
<div class="post-title"><a href="/2020/10/26/Vuex%E6%A8%A1%E5%9D%97%E5%8C%96/">Vuex模块化</a></div>
<div class="post-meta">
<i class="fa fa-calendar"></i> <time>2020-10-26</time>
<span class="dotted">|</span>
<i class="fa fa-user"></i>
</div>
<div class="post-excerpt">
<a href="/2020/10/26/Vuex%E6%A8%A1%E5%9D%97%E5%8C%96/">
<p>
1. Vuex模块化(module)模块这部分正如其名,当所有状态集中在一个对象中时,会变的相当臃肿,这个时候就需要对其进行模块化管理。比如我在store里面定义了两个模块
12345678910111213141516171819const moduleA = { state: { name: 'lee', age: 23, }, mutations: {}, getters: {}, actions: {}};const moduleB = { state: { name: 'wang', age: 22 }, mutations: {}, getters: {}, actions: {}}
然后接着在store里声明模块
123456789export default new Vuex.Store({ modules: { ma: moduleA, mb: moduleB }, state: { ........... // 其他状态 }});
这样一来,如果我们想要在组件里面访问其他模块的状态,可以这样,比如这里我想调用B模块里的状态
12345computed: { msg() { return this.$store.mb; // 这里返回的是:{name: 'wang', age: 22} }}
复制代码关于模块内部的局部状态,这里跟普通的store用法没有多大的区别,主要区别以下外部传进来的状态,比如对于模块内部的 action,局部状态通过 context.state 暴露出来,根节点状态则为 context.rootState,这里截取官方代码
12345678910const moduleA = { // ... actions: { incrementIfOddOnRootSum ({ state, commit, rootState }) { if ((state.count + rootState.count) % 2 === 1) { commit('increment') } } }}
对于模块内部的 getter,根节点状态会作为第三个参数暴露出来:
12345678const moduleA = { // ... getters: { sumWithRootCount (state, getters, rootState) { return state.count + rootState.count } }}
复制代码那么对于getters、mutations、actions里面的方法我们像基本的store那样调用就可以了,不存在作用域限制,还是贴代码栗子吧,下面是我在store.js里面定义的模块B:
123456789101112131415161718const moduleB = { state: { name: 'wang', age: 22, desc: 'nope' }, mutations: { modifyDesc(state, payload) { state.desc = payload.newMsg; } }, getters: { }, actions: { }}
复制代码在组件里面,我定义了以下内容:
1234567891011121314151617181920212223242526272829303132<template> <div> <h2>7、module使用示例</h2> <div> <p>名字:{{ name }}</p> <p>描述:{{ desc }}</p> <button @click="handleClick">修改描述</button> </div> </div></template><script>export default { data() { return { name: this.$store.state.mb.name, // desc: this.$store.state.mb.desc 注意这个如果涉及到要在store里面会被改变的状态,一定要写在 // computed属性里面,不然不能及时反馈到视图上 } }, computed: { desc() { return this.$store.state.mb.desc; } }, methods: { handleClick() { this.$store.commit('modifyDesc', {newMsg: 'lao wang is beautiful!'}); } },}</script>
这样,就可以调用mutation里面的方法了,getters和actions同理
2.命名空间模块默认情况下,mutations、actions、getters这些都是注册在全局上面的,你可以直接调用,如果希望你的模块具有更高的封装度和复用性,你可以通过添加 namespaced: true 的方式使其成为带命名空间的模块。当模块被注册后,它的所有 getter、action 及 mutation 都会自动根据模块注册的路径调整命名。首先我新建一个js文件用来声明模块C:
1234567891011121314151617181920212223export const moduleC = { namespaced: true, state: { name: 'moduleC', desc: '这是模块C,用来测试命名空间的!', list: [1, 2, 3, 4] }, getters: { filterList(state) { return state.list.filter((item, index, arrSelf) => { return item % 2 !== 0; }); } }, mutations: { modifyName(state, payload) { state.name = payload.newName; } }, actions: { }}
复制代码然后在store.js里面引入
1234567import { moduleC } from './module_c.js';export default new Vuex.Store({ modules: { mc: moduleC },});
要想这个模块成为带有命名空间的模块,在上面声明属性namespaced: true就可以了,那么里面的mutations、getters和actions里面的方法的调用就要多走一层路径,比如我在组件里面去调用mutations里面的方法(getters和actions同理)
1234567891011methods: { modify() { // this.$store.commit('mc/modifyName', { // newName: '命名空间模块C' // }) this.$store.commit({ type: 'mc/modifyName', newName: '命名空间模块C' }) }}
复制代码当然模块里面再嵌套模块也可以,路径要不要多走一层主要看你的namespaced: true有没有声明,这里贴一下官方的代码:
12345678910111213141516171819202122232425262728293031323334353637383940const store = new Vuex.Store({ modules: { account: { namespaced: true, // 模块内容(module assets) state: { ... }, // 模块内的状态已经是嵌套的了,使用 `namespaced` 属性不会对其产生影响 getters: { isAdmin () { ... } // -> getters['account/isAdmin'] }, actions: { login () { ... } // -> dispatch('account/login') }, mutations: { login () { ... } // -> commit('account/login') }, // 嵌套模块 modules: { // 继承父模块的命名空间 myPage: { state: { ... }, getters: { profile () { ... } // -> getters['account/profile'] } }, // 进一步嵌套命名空间 posts: { namespaced: true, state: { ... }, getters: { popular () { ... } // -> getters['account/posts/popular'] } } } } }})
在带命名空间的模块内访问全局内容如果想要在模块内部的getters、mutations和actions里面访问到全局的内容,这儿Vuex已经封装好了,你只需要多传几个参数即可
12345678910111213141516171819202122232425262728293031modules: { foo: { namespaced: true, getters: { // 在这个模块的 getter 中,`getters` 被局部化了 // 你可以使用 getter 的第四个参数来调用 `rootGetters` someGetter (state, getters, rootState, rootGetters) { getters.someOtherGetter // -> 'foo/someOtherGetter' rootGetters.someOtherGetter // -> 'someOtherGetter' }, someOtherGetter: state => { ... } }, actions: { // 在这个模块中, dispatch 和 commit 也被局部化了 // 他们可以接受 `root` 属性以访问根 dispatch 或 commit someAction ({ dispatch, commit, getters, rootGetters }) { getters.someGetter // -> 'foo/someGetter' rootGetters.someGetter // -> 'someGetter' dispatch('someOtherAction') // -> 'foo/someOtherAction' dispatch('someOtherAction', null, { root: true }) // -> 'someOtherAction' commit('someMutation') // -> 'foo/someMutation' commit('someMutation', null, { root: true }) // -> 'someMutation' }, someOtherAction (ctx, payload) { ... } } }}
复制代码在模块里面使用辅助函数mapState、mapGetters、mapMutations和mapActions由于存在命名空间,在组件里面采用上面的写法会出现问题,这里要想使用辅助函数来映射模块里面的东西需要指定空间名称来告诉辅助函数应该去哪儿找这些。这儿我以上面我的C模块为例,首先对于mapSatate函数可以这样玩,我在全局的modules里面声明了mc,那我的空间名称就是mc
123computed: { ...mapState('mc', ['name', 'desc']) // 这里模块里面要使用辅助函数的话要多传一个参数才行}
复制代码然后在模版里面写name,desc即可,或者可以这样
12345678910computed: { ...mapState('mc', { name(state) { return state.name; }, desc(state) { return state.desc; } })},
复制代码对于actions、mutations和getters方式类似,主要是要指定空间名称
</p>
</a>
</div>
</article>
<article class="box post post-item">
<div class="post-title"><a href="/2020/10/26/Vuex%E5%9F%BA%E7%A1%80/">Vuex基础</a></div>
<div class="post-meta">
<i class="fa fa-calendar"></i> <time>2020-10-26</time>
<span class="dotted">|</span>
<i class="fa fa-user"></i>
</div>
<div class="post-excerpt">
<a href="/2020/10/26/Vuex%E5%9F%BA%E7%A1%80/">
<p>
1. 关于Vuex1.1 为什么要使用Vuex我们在Vue开发过程中,难免会有一些状态要在多个组件中使用的情况,比如用户昵称、头像等其他用户信息。这些信息在多个组件中会使用到,所以我们就希望其状态一旦发现改变,其他组件也跟着变化,比如用户充值了一百元或是改变了头像,所以这个时候就需要状态管理模式来集中来管理
1.2 基本结构1234567891011121314151617181920212223import Vue from 'vue'import Vuex from 'vuex'Vue.use(Vuex)export default new Vuex.Store({ state: { count: 0 }, mutations: { SET_COUNT:(state) => { state.count ++ } }, actions: { count({ commit }) { commit('SET_COUNT') }, }, getters: { getCountValue: state => state.count, }})
2. StateVuex的核心就是store仓库,这个store实例会被注入到所有子组件中,里边的state保存着我们的状态,比如我们定义一个状态count
12345export default new Vuex.Store({ state: { count: 10 }})
这样我们就有一个集中管理的状态count,那其他组件如何取到这个count呢,可以计算属性来获得
12345678910export default { data() { }, computed: { count() { return this.$store.state.count; } }}
2.1 mapState有的时候一个组件内要获取多个状态,使用计算属性需要调用多次,那就很烦,这里可以使用辅助函数mapState。使用mapState需要在页面中引入此方法
1import { mapState } from 'vuex';
但是使用mapState的话computed的写法会和之前有一些差别
12345678910111213141516171819202122//不使用mapStatedata(){ return{ }}computed: { msg() { return this.$store.state.count; }}//使用mapStatecomputed: { msg() { return this.$store.state.msg; }, // 这里返回一个状态count ...mapState(['count']) // 返回多个你可以这样写...mapState(['count', 'firstName', 'lastName']) }
3. Gettergetter就是对状态进行处理之后在提取出来的公共部分,当状态需要进行筛选这些操作时,我们就可以使用getter将数据处理之后在返回给组件使用,假设在state里定义一个数组
12345export default new Vuex.Store({ state: { list: [1, 2, 3, 4, 5, 6, 7, 8] },});
我们想要将list数组里的数字筛选出偶数在组件中使用,那就可以把这个操作放在getter里进行
1234567891011export default new Vuex.Store({ state: { list: [1, 2, 3, 4, 5, 6, 7, 8] }, getters: { modifyArr(state) { return state.list.filter((item, index, arr) => { return item % 2 == 0; }) }});
之后再在其他组件的computed里面去调用getter来获取想要的状态
12345computed: { list() { return this.$store.getters.modifyArr; },}
3.1 mapGettersmapGetters 辅助函数仅仅是将 store 中的 getter 映射到局部计算属性,当我们想在组件里面引入多个getter时,可以使用mapGetter
1234import {mapGetters} from 'vuex';computed: { ...mapGetter(['modifyArr', 'getLength'])}
也可以为其自定义名字不一定要用getter里设置的名字
123456computed: { ...mapGetter({ arr: 'modifyArr', // 把 `this.arr` 映射为 `this.$store.getters.modifyArr`,下面同理 length: 'getLength' })}
4.Mutation当我们需要改变state里的属性时,我们是不能直接在组件里对其进行修改的,我们需要借助mutation里的里的方法来对其进行修改。比如state里有一个状态count我们要对其进行计数操作
12345678state: { count: 0},mutations: { add(state) { state.count++; }},
在其他组件里我们通过method来触发mutation,这里需要使用commit
12345methods: { add() { this.$store.commit('add'); }}
4.1 参数传递比如我需要在计数时传递自己想要的数字
12345mutations: { add(state, num) { state.count += num; }}
在组件中使用
12345methods: { loadAdd() { this.$store.commit('loadAdd', 100); // 传递额外参数 }}
官方文档建议额外传参最好写成对象的方式,这样可以传递多个字段,代码看起来也会更清晰
123this.$store.commit('add', { num: 100}); // 传递额外参数
4.2 Mutation需要遵循Vue的响应规则在开发中向state增加额外数据时,需要遵循Vue的响应规则
最好提前在你的 store 中初始化好所有所需属性
当需要在对象上添加新属性时,你应该使用 Vue.set(obj, ‘newProp’, 123), 或者以新对象替换老对象。例如,利用 ES6的对象展开运算符
12345addNewState(state, payload) { // 我打算再这儿添加新的属性到state // Vue.set(state, 'newProp', '添加一个新值!'); // 这是一种写法 // 这种写法用新对象替换老对象 this.replaceState({...state, newProp: '添加一个新值!'})}
4.3 Mutation里必须是同步操作下面这种操作必须避免
1234567mutations: { someMutation (state) { api.callAsyncMethod(() => { //..... }) }}
4.4 mapMutations同前
1234567891011121314import {mapMutations} from 'vuex';export default { methods: { ...mapMutations([ 'increment', // 将 `this.increment()` 映射为 `this.$store.commit('increment')` // `mapMutations` 也支持载荷: 'incrementBy' // 将 `this.incrementBy(amount)` 映射为 `this.$store.commit('incrementBy', amount)` ]), ...mapMutations({ add: 'increment' // 将 `this.add()` 映射为 `this.$store.commit('increment')` }) }}
5. Actionaction与mutation类似,不同点在于
action用于提交mutation
action支持任意的异步操作,之前提到mutation只支持同步操作,所以将异步操作放在action里执行,然后再调用mutation中的方法来改变state中的状态首先在state中定义一个状态
123state: { product: 'car'}
接着在mutation中定义一个方法
123changeProduct(state, payload) { state.product = payload.change;}
然后在action中定义一个方法
123456789101112131415actions: { changeProduct({commit}, payload) { // 这个context是一个与 store 实例具有相同方法和属性的对象 // 调用mutation里的changeProduct方法 // commit('changeProduct', {change: 'ship'}); // 改成异步方式 // setTimeout(() => { // commit('changeProduct', {change: 'ship'}); // }, 1500) // 使用载荷 let temp = 'ship+' + payload.extraInfo; setTimeout(() => { commit('changeProduct', {change: temp}); }, 1500) }}
最后在methods中定义事件触发
1234567891011121314methods: { selectProduct() { // this.$store.dispatch('changeProduct') // 载荷方式分发 // this.$store.dispatch('changeProduct', { // extraInfo: 'sportcar' // }) // 或者这种 this.$store.dispatch({ type: 'changeProduct', extraInfo: '->sportcar' }) }}
5.1 mapActions具体用法同前,不做具体说明
123456789101112131415import {mapActions} from 'vuex';export default { // ... methods: { ...mapActions([ 'increment', // 将 `this.increment()` 映射为 `this.$store.dispatch('increment')` // `mapActions` 也支持载荷: 'incrementBy' // 将 `this.incrementBy(amount)` 映射为 `this.$store.dispatch('incrementBy', amount)` ]), ...mapActions({ add: 'increment' // 将 `this.add()` 映射为 `this.$store.dispatch('increment')` }) }}
有时候我们想获取action里面异步执行后的状态然后再去修改其他信息,这个可以借助Promise来实现。这里在state里面声明一个状态
123456state: { userInfo: { // 这个变量用来测试组合变量 name: 'lee', age: 23 }}
复制代码接着声明mutation
123456mutations: { // 以下用来测试组合action changeInfo(state, payload) { state.userInfo.name = 'lee haha'; }}
复制代码声明action
12345678910actions: { changeInfo(context, payload) { return new Promise((resolve, reject) => { setTimeout(() => { context.commit('changeInfo'); resolve(); }, 2000) }) }}
复制代码这时我们在组件里面定义方法去派发这个action
123456789101112data() { return { status: '信息还没修改!' }}methods: { modifyInfo() { this.$store.dispatch('changeInfo').then(() => { this.status = '信息修改成功'; }); }}
</p>
</a>
</div>
</article>
<article class="box post post-item">
<div class="post-title"><a href="/2020/10/22/Vue-Router%E5%9F%BA%E7%A1%80/">Vue-Router基础</a></div>
<div class="post-meta">
<i class="fa fa-calendar"></i> <time>2020-10-22</time>
<span class="dotted">|</span>
<i class="fa fa-user"></i>
</div>
<div class="post-excerpt">
<a href="/2020/10/22/Vue-Router%E5%9F%BA%E7%A1%80/">
<p>
什么是路由?
路由(routing)就是通过互联的网络把信息从源地址传输到目的地址的过程
路由是根据不同的ulr地址展示不同的内容或页面后端路由在早起开发时整个HTML页面是由服务端来渲染的,后端直接将渲染好的HTML页面响应给客户端
浏览器在地址栏中输入不同的URL时,每次都向后端发起请求,后端再响应请求
在后台拼接出不同的HTML页面返回给前端显示
意味着浏览器会刷新页面,如果网速不好的话,页面会全空白再显示出内容,后端路由有一个极大的问题就是前后端不分离前端路由
随着AJAX的出现,有了前后端分离
后端通过API来返回数据,前端通过AJAX来请求数据,然后用JS将数据渲染到页面上
这样的模式使得,前后端任务分工明确,后端注重数据处理,前端注重交互和数据可视化
并且移动端(Android、IOS)出现后,可使用同一套API,无需做任何处理SPA
SPA(single page web application),译为单页Web应用
简单说 SPA 就是一个 web 项目只有一个 html 页面, 一旦页面加载完成, SPA 不会因为用户的操作进行页面的重新加载或跳转
取而代之的是利用 JS 动态的变换 html 的内容, 从而模拟多个视图间跳转前端路由的核心改变URL,但是页面不进行整体的刷新q前端路由的规则url的hash模式也就是锚点(#),本质上是改变window.location的href属性
2.我们可以直接赋值location.hash改变href但是页面不发生刷新
1234location.href// "http://localhost:8080"location.hash = "/home"// "/home"
HTML5的history模式history模式是HTML5新增的, 它有五种模式改变URL而不刷新页面
1.history.pushState()可回退
123456history.pushState({}, '', 'foo')// undefinedhistory.pushState({}, '', 'test')// undefinedhistory.pushState({}, '', 'a')// undefined
2.history.replaceState()替换URL,不可回退
1234history.replaceState({}, '', '/foo')// undefinedhistory.replaceState({}, '', '/test')// undefined
3.history.back()回退到上一次的URL
4.history.forward()前进到上一次的URL
5.history.go(Number)前往指定URL
12history.go(2)// undefined
Vue-Router基础vue-router是Vue.js官方的路由插件, 它和vue.js是深度继承的, 用于构建单页面应用vue-router是基于路由和组件的
路由用于设定访问路径, 将路径和组件映射起来在vue-router的单页面应用中, 页面的路径的改变就是组件的切换
步骤一:npm安装1npm install vue-router --save
步骤二:在项目中引用它
导入路由对象, 并且调用Vue.use(VueRouter)安装路由功能
创建路由实例, 并传入路由映射配置
在主入口文件: 引入创建的路由实例, Vue实例中挂载路由实例
1234567891011121314151617181920212223242526272829303132333435router/index.jsimport VueRouter from 'vue-router'import Vue from 'vue'import Home from '../components/Home.vue'import About from '../components/About.vue'Vue.use(VueRouter)const routes = [ { path: './home', components: Home }, { path: './about', components: About }]const router = new VueRouter({ routes})export default router./math.jsimport Vue from 'vue'import App from './App.vue'import router from './router'new Vue({ render: h => h(App), router}).$('#app')
步骤三:使用vue-router
12345678//使用路由<router-link to="/path">和 <router-view><template> <div> <router-link to="/home">首页</router-link> <router-link to="/about">关闭</router-link> <router-view></router-view> </div></template>
路由组件详解
router-link 该标签是已经内置全局的组件, 它会被渲染成一个a标签
to=”path”: 该属性会被渲染为href属性to=”path”: 属性的值会渲染为 # 开头的 hash 地址
path: 在路由中配置的 path 路径
router-view 该标签会根据当前的路径, 动态渲染出相对应的组件在路由切换时, 切换的是router-view挂载的组件, 其他内容不会发生改变
路由配置其他补充1.路由默认路径进入网站首页, 希望router-view渲染首页的内容
在路由规则中添加默认路径的重定向
12345678const routes = [ { // 配置默认路径 path: '/', // 重定向到/home路径 redirect: '/home' }]
2.路径的History模式页面显示的URL, 不希望是哈希值带 #/home, 希望显示正常的URL: /home
12345// 创建VueRouter对象const router = new VueRouter({ routes,// 路由规则 mode: 'history'// URL显示的模式})
3.router-link和配置路由的属性补充route-link其他的属性
tag=””: tab可以指定router-link组件渲染成什么元素
replace: 没有回退history记录, 前进没有效果
active class=””: 当router-link对应的路径匹配成功时, 会自动给当前元素添加一个router-link-active的class, 设置active-class可以更改默认的名称
4.编程式导航没有使用router-link全局组件, 来跳转URL
this.$router.push(‘path’): 来实现跳转URL, 有回退history记录
this.$router.replace(‘path’): 来实现跳转URL, 没有回退history记录12345678910methods: { home() { // 没有使用<router-link>全局组件,来跳转URL,如何实现 // this.$router.push('/home') // 有回退记录 this.$router.replace('/home') // 没有回退记录 }, about() { // this.$router.push('/about') this.$router.replace('/about') }}
路由传参一般路由有两种传参方式,分为 params 和 queryparams这个 params 是和 name 配合使用的。跳转过去之后路径不会带上参数。12router.push({ name: 'user', params: { userId: '123' }}) //参数传递this.$route.params.id //参数接收
query这个 query 是和 path 配合使用的,跳转过去之后路径会带上参数变成 /search?id=1 般使用在查询方面。12router.push({ path: 'search', query: { id: '1' }}) //参数传递this.$route.query.id //参数接收
路由守卫当路由进行需要进行导航的时候,我们可以通过路由守卫的方式,来进行路由的跳转和和取消跳转。
路由守卫有三种,一种是全局的守卫,一种是路由的守卫,一种是组件的守卫。
全局守卫全局守卫一般用来验证是否已经登陆。如果登陆,就进行,没有登录就跳转到登录页面。
1234567891011router.beforeEach((to, from, next) => { next()})router.beforeResolve((to, from, next) => { next()})router.afterEach((to, from) => { /* 这是全局后置钩子,不会接受 next 函数,也不改变导航*/})
路由独享守卫跟全局路由一样,只不过是针对单个路由,来进行设置。
123456789routes: [ { path: '/foo', component: Foo, beforeEnter: (to, from, next) => { // ... } } ]
组件守卫组件的守卫,一共有三个
123456789101112131415beforeRouteEnter (to, from, next) { // 在渲染该组件的对应路由被 confirm 前调用 // 不!能!获取组件实例 `this` // 因为当守卫执行前,组件实例还没被创建},beforeRouteUpdate (to, from, next) { // 在当前路由改变,但是该组件被复用时调用 // 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候, // 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。 // 可以访问组件实例 `this`},beforeRouteLeave (to, from, next) { // 导航离开该组件的对应路由时调用 // 可以访问组件实例 `this`}
</p>
</a>
</div>
</article>
<article class="box post post-item">
<div class="post-title"><a href="/2020/10/19/js%E5%A4%A7%E9%87%8F%E6%95%B0%E6%8D%AE%E8%AE%A1%E7%AE%97%E5%AF%BC%E8%87%B4%E9%A1%B5%E9%9D%A2%E5%81%87%E6%AD%BB%EF%BC%88Web%20Worker%EF%BC%89/">js大量数据计算导致页面假死(Web Worker)</a></div>
<div class="post-meta">
<i class="fa fa-calendar"></i> <time>2020-10-19</time>
<span class="dotted">|</span>
<i class="fa fa-user"></i>
</div>
<div class="post-excerpt">
<a href="/2020/10/19/js%E5%A4%A7%E9%87%8F%E6%95%B0%E6%8D%AE%E8%AE%A1%E7%AE%97%E5%AF%BC%E8%87%B4%E9%A1%B5%E9%9D%A2%E5%81%87%E6%AD%BB%EF%BC%88Web%20Worker%EF%BC%89/">
<p>
js为什么页面会卡顿呢,以60Hz为例,即一秒钟的动画就是由60张静态图片连在一起。60fps是动画播放比较理想、比较基础的要求,windows系统有个刷新频率也是这个意思。60fps就要求一帧的时间为1s/60=16.67ms。浏览器显示页面的时候,要处理js逻辑,还要做渲染,每个执行片段的时间不能超过16.67ms。实际上,浏览器内核自身支撑体系运行也需要消耗一些时间,所以留给我们的时间差不多只有10ms。并且在处理js计算时,浏览器不会响应用户的操作,所以就造成了页面“假死”。
Web Worker什么是Web WorkerWeb Work,就是为JavaScript创造多线程环境,允许主线程创建Web Worker线程,将一些任务分配给后台运行。在主线程运行的同事,Work线程在后台运行,两者互不干扰。等到Work线程完成计算任务再把结果返回给主线程。这样的好处是,一些密集或者高延迟的计算任务,被Work线程给分担了,这样主线程就会很流程。Worker线程一旦创建成功,就会始终运行,不会被主线程上的活动打断取消。这样有利于随时响应主线程的通信。但是,这也造成了Worker比较耗费资源,不应该过度使用,所以一旦使用完毕,就应该关闭。
注意点:1.同源限制:分配给Worker线程运行的脚本文件,必须与主线程的脚本文件同源。2.DOM限制:Work线程所在的全局对象和主线程不一样,所以无法读取主线程所在网页的DOM对象,也无法使用document,window,parent这些对象。但是可以使用navigator和location。3.通信联系:Worker线程和主线程不在同一个上下文环境,他们不能直接通信,必须通过消息完成。4.脚本限制:Worker线程不能执行alert和confirm方法,但是可以使用XMLHttpRequest对象发出的AJAX请求。5.文件限制:Work线程不能读取本地文件,它所加载的脚本必须来自网络。
用法
创建1var worker = new Worker(“work.js”)
主线程通过postMessage向Work线程发送消息123//postMessage()参数就是传送的数据,支持各种数据类型worker.postMessage('Hello World'); worker.postMessage({method: 'echo', args: ['Work']});
主线程通过onmessage()指定监听函数,接收子线程发回来的消息123worker.onmessage = function (event) { console.log('Received message ' + event.data);}
主线程关闭Work线程
1worker.terminate();
Worker 线程内部需要有一个监听函数,监听message事件。
12345678910111213self.addEventListener('message', function (e) { self.postMessage('You said: ' + e.data);}, false);//上面代码中,self代表子线程自身,即子线程的全局对象。因此,等同于下面两种写法// 写法一this.addEventListener('message', function (e) { this.postMessage('You said: ' + e.data);}, false);// 写法二addEventListener('message', function (e) { postMessage('You said: ' + e.data);}, false);
Work线程内部关闭1self.close();
</p>
</a>
</div>
</article>
<nav class="page-nav">
<span class="page-number current">1</span><a class="page-number" href="/page/2/">2</a><a class="extend next" rel="next" href="/page/2/">Next</a>
</nav>
</div>
<div class="aside">
<div class="box widget">
<div class="introduction">
<p><img src="/images/avatar.jpg" alt="head-sculpture" /></p>
<p class="name">
博落回
</p>
<p class="slogan">流连矣 忘景幻云催 峦栈醺醺说旧梦 重山迟迟映霞辉 向晚共邀归 —— 忆江南</p>
</div>
</div>
<div class="box widget">
<div class="title">Recent</div>
<ul class="item-box">
<li><a href="/2020/11/10/%E5%85%B3%E4%BA%8E%E8%B7%A8%E5%9F%9F/">关于跨域</a></li>
<li><a href="/2020/11/09/%E6%97%A5%E5%B8%B8%E9%97%AE%E9%A2%98%E8%AE%B0%E5%BD%95/">日常问题记录</a></li>
<li><a href="/2020/11/09/reduce%E5%8E%BB%E9%87%8D/">reduce去重</a></li>
<li><a href="/2020/11/07/%E5%85%B3%E4%BA%8EVue%E4%B8%AD%E7%9A%84%E8%99%9A%E6%8B%9FDOM/">关于Vue中的虚拟DOM</a></li>
<li><a href="/2020/11/07/%E5%85%B3%E4%BA%8EVue%E7%9A%84%E6%95%B0%E6%8D%AE%E5%93%8D%E5%BA%94%E5%BC%8F/">关于Vue的数据响应式</a></li>
<li><a href="/2020/10/28/%E5%85%B3%E4%BA%8Ejs%E5%8E%9F%E5%9E%8B%E5%92%8C%E5%8E%9F%E5%9E%8B%E9%93%BE/">关于js原型和原型链</a></li>
<li><a href="/2020/10/26/Vuex%E6%A8%A1%E5%9D%97%E5%8C%96/">Vuex模块化</a></li>
<li><a href="/2020/10/26/Vuex%E5%9F%BA%E7%A1%80/">Vuex基础</a></li>
</ul>
</div>
<div class="box widget">
<div class="title">Archives</div>
<ul class="archive-list"><li class="archive-list-item"><a class="archive-list-link" href="/archives/2020/11/">2020-11</a><span class="archive-list-count">5</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2020/10/">2020-10</a><span class="archive-list-count">10</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2020/06/">2020-06</a><span class="archive-list-count">2</span></li></ul>
</div>
</div>
</section>
<footer class="footer">
<div class="global-width footer-box">
<div class="copyright">
<span>Copyright © 2019</span>
<span class="dotted">|</span>
<span>Powered by <a href="https://hexo.io/" target="_blank" rel="noopener">Hexo</a></span>
<span class="dotted">|</span>
<span>Theme by <a href="javascript:">Loren</a></span>
<span class="dotted">|</span>
<span><a href="http://www.beian.miit.gov.cn" target="_blank" rel="noopener">浙ICP备18016660号-1</a></span>
</div>
</div>
</footer>
</div>
<script>
hljs.initHighlightingOnLoad();
</script>
</body>
</html>