|
@@ -0,0 +1,410 @@
|
|
1
|
+![在这里插入图片描述](https://img-blog.csdnimg.cn/20201008225507487.png#pic_center)
|
|
2
|
+
|
|
3
|
+# 初识
|
|
4
|
+
|
|
5
|
+## 什么是Vue?
|
|
6
|
+
|
|
7
|
+渐进式JavaScript 框架。渐进式就是指可以由浅入深的,由简单到困难的一种方式。
|
|
8
|
+## 它的优点都有什么?
|
|
9
|
+
|
|
10
|
+vue.js拥有更小的体积,压缩后的vue.js就只有33k;vue.js拥有更高的运行效率,vue.js是基于`虚拟dom`的,虚拟dom是一种可以预先通过JavaScript进行各种计算,把最终的dom操作计算出来并进行优化的技术。
|
|
11
|
+
|
|
12
|
+因为这个Dom的操作属于预处理操作,并没有真实的操作Dom,所以叫做虚拟Dom。
|
|
13
|
+
|
|
14
|
+vue.js基于虚拟Dom操作,大幅度提高了Dom的操作以及渲染效率。不仅如此,vue.js还实现了双向数据绑定。vue.js的双向数据绑定,让开发者不用再去操作Dom对象,可以把更多的精力投入到业务逻辑上。
|
|
15
|
+
|
|
16
|
+## vue3.0学习路线
|
|
17
|
+1. 先学习vue2.x,很多2.x内容依然保留;
|
|
18
|
+2. 先学习TypeScript,vue3.0是用TS重写的,想知其然知其所以然必须学习TS。
|
|
19
|
+
|
|
20
|
+## 为什么学习vue3.0?
|
|
21
|
+- 性能比vue2.x快1.2~2倍
|
|
22
|
+- 按需编译,体积比vue2.x更小
|
|
23
|
+- 组合API
|
|
24
|
+- 更好的TS支持
|
|
25
|
+- 暴露了自定义渲染API
|
|
26
|
+- 更先进的组件
|
|
27
|
+
|
|
28
|
+## vue3.0是如何变快的?
|
|
29
|
+### 1、diff方法优化
|
|
30
|
+
|
|
31
|
+vue2.x中的虚拟dom是进行全量的对比。而vue3.0新增了静态标记。在与上次虚拟节点进行对比的时候,只对比带有patch flag的节点,并且可以通过flag的信息得知当前节点要对比的具体内容。
|
|
32
|
+
|
|
33
|
+下面我们来举个例子,以下是代码片段。
|
|
34
|
+```html
|
|
35
|
+<div>
|
|
36
|
+ <p>标签</p>
|
|
37
|
+ <p>{{msg}}</p>
|
|
38
|
+</div>
|
|
39
|
+```
|
|
40
|
+vue2.x的diff算法是对虚拟dom树全量的对比。
|
|
41
|
+
|
|
42
|
+![在这里插入图片描述](https://img-blog.csdnimg.cn/20201011230003622.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM5MDQ1NjQ1,size_16,color_FFFFFF,t_70#pic_center)
|
|
43
|
+
|
|
44
|
+vue3.0的diff算法在创建虚拟dom的时候,会根据dom中的内容是否发生变化,添加静态标记。只对比带有patch flag的节点。
|
|
45
|
+
|
|
46
|
+![在这里插入图片描述](https://img-blog.csdnimg.cn/20201011232453479.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM5MDQ1NjQ1,size_16,color_FFFFFF,t_70#pic_center)
|
|
47
|
+
|
|
48
|
+我们可能看上面这个图不是很明白,那我们就用另一种方式直观看下。你们可以看到下图中存在数据绑定的元素中存在静态标记`1`,测试网址:
|
|
49
|
+
|
|
50
|
+https://vue-next-template-explorer.netlify.app/
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+![在这里插入图片描述](https://img-blog.csdnimg.cn/20201012103554965.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM5MDQ1NjQ1,size_16,color_FFFFFF,t_70#pic_center)
|
|
54
|
+
|
|
55
|
+### 2、hoistStatic(静态提升)
|
|
56
|
+
|
|
57
|
+vue2.x中无论元素是否参与更新,每次都会重新创建,然后再渲染。vue3.0中对于不参与更新的元素,会做静态提升,只会被创建一次,在渲染时直接复用即可。
|
|
58
|
+
|
|
59
|
+我们再来去那个测试网站,在静态标记的选项前面打上对号,这时我们会发现不同,右边之前数据固定不变的标签,也就是这里的`<p>标签</p>`,被放在了`render`函数的外面。所以这样只会在全局创建一次,这样性能就明显提升了。
|
|
60
|
+
|
|
61
|
+![在这里插入图片描述](https://img-blog.csdnimg.cn/2020101210410916.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM5MDQ1NjQ1,size_16,color_FFFFFF,t_70#pic_center)
|
|
62
|
+### 3、cacheHandlers(事件侦听器缓存)
|
|
63
|
+
|
|
64
|
+默认情况下,如`onClick`事件会被视为动态绑定,所以每次都会追踪它的变化,但是因为是同一个函数,所以不用追踪变化,直接缓存起来复用即可。
|
|
65
|
+好,我们来对比一下开启事件侦听器缓存前后。
|
|
66
|
+
|
|
67
|
+- 未开启事件侦听器缓存
|
|
68
|
+
|
|
69
|
+我们会看到有一个静态标记,所以每次都会追踪。
|
|
70
|
+
|
|
71
|
+![在这里插入图片描述](https://img-blog.csdnimg.cn/20201012105810780.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM5MDQ1NjQ1,size_16,color_FFFFFF,t_70#pic_center)
|
|
72
|
+- 开启事件侦听器缓存
|
|
73
|
+
|
|
74
|
+在事件侦听器缓存前打上对号,开启。我们看到没有了静态标记,就没有对比追踪了,性能就提升了。
|
|
75
|
+
|
|
76
|
+![在这里插入图片描述](https://img-blog.csdnimg.cn/20201012110020549.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM5MDQ1NjQ1,size_16,color_FFFFFF,t_70#pic_center)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+# 实战
|
|
80
|
+
|
|
81
|
+## 一、项目搭建
|
|
82
|
+vite是尤大大开发的一款意图取代webpack的工具。其实现原理是利用ES6的import发送请求加载文件的特性。拦截这些请求,做一些编译,省去webpack冗长的打包时间。并将其与Rollup捆绑在一起用于生产。
|
|
83
|
+在开发过程中没有捆绑。源代码中的ES Import语法直接提供给浏览器,浏览器通过本机`<script module>`支持对其进行解析,从而为每次导入发出HTTP请求。开发服务器拦截请求,并在必要时执行代码转换。例如,对`*.vue`文件的导入会在发送回浏览器之前即时进行编译。
|
|
84
|
+
|
|
85
|
+1、全局安装vite脚手架
|
|
86
|
+```bash
|
|
87
|
+npm install -g create-vite-app
|
|
88
|
+```
|
|
89
|
+2、使用脚手架创建项目
|
|
90
|
+```bash
|
|
91
|
+create-vite-app projectName
|
|
92
|
+```
|
|
93
|
+3、进入项目文件夹
|
|
94
|
+```bash
|
|
95
|
+cd projectName
|
|
96
|
+```
|
|
97
|
+4、安装依赖
|
|
98
|
+```bash
|
|
99
|
+npm install
|
|
100
|
+```
|
|
101
|
+5、启动vue3.0项目
|
|
102
|
+```bash
|
|
103
|
+npm run dev
|
|
104
|
+```
|
|
105
|
+## 二、vue2.x存在的问题
|
|
106
|
+2.x中的一点问题是当业务不断增多时,数据跟逻辑分散,会很难维护。
|
|
107
|
+
|
|
108
|
+```html
|
|
109
|
+<template>
|
|
110
|
+ <div>
|
|
111
|
+ <div>
|
|
112
|
+ <input type="text" v-model="obj.id">
|
|
113
|
+ <input type="text" v-model="obj.con">
|
|
114
|
+ <button @click="submit">提 交</button>
|
|
115
|
+ </div>
|
|
116
|
+ <ul>
|
|
117
|
+ <li v-for="(item,index) in list" :key="item.id" @click="cli(index)">
|
|
118
|
+ {{item.id}}-{{item.con}}
|
|
119
|
+ </li>
|
|
120
|
+ </ul>
|
|
121
|
+ </div>
|
|
122
|
+</template>
|
|
123
|
+
|
|
124
|
+<script>
|
|
125
|
+export default {
|
|
126
|
+ name:"filterBox",
|
|
127
|
+ data(){
|
|
128
|
+ return {
|
|
129
|
+ list:[
|
|
130
|
+ {
|
|
131
|
+ id:1,
|
|
132
|
+ con:"a"
|
|
133
|
+ },
|
|
134
|
+ {
|
|
135
|
+ id:2,
|
|
136
|
+ con:"b"
|
|
137
|
+ }
|
|
138
|
+ ],
|
|
139
|
+ obj:{
|
|
140
|
+ id:"",
|
|
141
|
+ con:""
|
|
142
|
+ }
|
|
143
|
+ // 代码数据1
|
|
144
|
+ // 代码数据2
|
|
145
|
+ // ...
|
|
146
|
+ }
|
|
147
|
+ },
|
|
148
|
+ methods:{
|
|
149
|
+ cli(index){
|
|
150
|
+ this.list = this.list.filter((item,idx)=>idx!==index);
|
|
151
|
+ console.log(this.list);
|
|
152
|
+ },
|
|
153
|
+ submit(){
|
|
154
|
+ // const obj = Object.assign({},this.obj);
|
|
155
|
+ this.list.push(this.obj);
|
|
156
|
+ this.obj.id = "";
|
|
157
|
+ this.obj.con = "";
|
|
158
|
+ },
|
|
159
|
+ // 执行代码代码逻辑3
|
|
160
|
+ // ...
|
|
161
|
+ },
|
|
162
|
+ computed:{
|
|
163
|
+ // 执行代码代码逻辑1
|
|
164
|
+ },
|
|
165
|
+ watch:{
|
|
166
|
+ // 执行代码逻辑2
|
|
167
|
+ }
|
|
168
|
+}
|
|
169
|
+</script>
|
|
170
|
+
|
|
171
|
+<style>
|
|
172
|
+
|
|
173
|
+</style>
|
|
174
|
+```
|
|
175
|
+## 三、组合API
|
|
176
|
+### **ref**
|
|
177
|
+
|
|
178
|
+```html
|
|
179
|
+<template>
|
|
180
|
+ <div>
|
|
181
|
+ <p>{{count}}</p>
|
|
182
|
+ <button @click="add">add</button>
|
|
183
|
+ </div>
|
|
184
|
+</template>
|
|
185
|
+
|
|
186
|
+<script>
|
|
187
|
+import {ref} from "vue"
|
|
188
|
+export default {
|
|
189
|
+ name: 'App',
|
|
190
|
+ setup(){
|
|
191
|
+ // 定义一个名称叫做count变量,这个变量的初始值是0
|
|
192
|
+ // 这个变量发生该改变之后,vue会自动更新页面。
|
|
193
|
+ const count = ref(0);
|
|
194
|
+ // 在组合API中,如果想定义方法,不用定义到methods中,直接在setup函数中定义即可。
|
|
195
|
+ const add = () => {
|
|
196
|
+ count.value+=1;
|
|
197
|
+ }
|
|
198
|
+ // 在组合API中定义的变量/方法,要想在外界使用,必须return出去。
|
|
199
|
+ return {
|
|
200
|
+ count,
|
|
201
|
+ add
|
|
202
|
+ }
|
|
203
|
+ }
|
|
204
|
+}
|
|
205
|
+</script>
|
|
206
|
+
|
|
207
|
+```
|
|
208
|
+`ref`只能监听简单类型的变化,不能监听复杂类型的变化(对象/数组)。
|
|
209
|
+
|
|
210
|
+另外,需要注意的是,如果是通过`ref`创建出来的数据,那么在`template`中使用的时候不用通过`.value`来获取。因为Vue会自动给我们添加`.value` 。
|
|
211
|
+
|
|
212
|
+### **reactive**
|
|
213
|
+`reactive` 可以监听复杂类型的变化,如对象或者数组。
|
|
214
|
+
|
|
215
|
+```js
|
|
216
|
+let state = reactive({
|
|
217
|
+ name:"maomin"
|
|
218
|
+});
|
|
219
|
+// 或
|
|
220
|
+let arr = reactive([1,2,3]);
|
|
221
|
+```
|
|
222
|
+我们来做一个小demo。
|
|
223
|
+```html
|
|
224
|
+<template>
|
|
225
|
+ <div>
|
|
226
|
+ <ul>
|
|
227
|
+ <li v-for="(item,index) in state.list" :key="item.id" @click="removeItem(index)">{{item.id}}--{{item.con}}</li>
|
|
228
|
+ </ul>
|
|
229
|
+ </div>
|
|
230
|
+</template>
|
|
231
|
+
|
|
232
|
+<script>
|
|
233
|
+import {reactive} from "vue"
|
|
234
|
+export default {
|
|
235
|
+ name: 'App',
|
|
236
|
+ setup(){
|
|
237
|
+ const state = reactive({
|
|
238
|
+ list:[
|
|
239
|
+ {
|
|
240
|
+ id:1,
|
|
241
|
+ con:"A"
|
|
242
|
+ },
|
|
243
|
+ {
|
|
244
|
+ id:2,
|
|
245
|
+ con:"B"
|
|
246
|
+ },
|
|
247
|
+ {
|
|
248
|
+ id:3,
|
|
249
|
+ con:"C"
|
|
250
|
+ }
|
|
251
|
+ ]
|
|
252
|
+ });
|
|
253
|
+
|
|
254
|
+ const removeItem = (index) => {
|
|
255
|
+ state.list = state.list.filter((item,i)=>i!==index)
|
|
256
|
+ }
|
|
257
|
+
|
|
258
|
+ return {
|
|
259
|
+ state,
|
|
260
|
+ removeItem
|
|
261
|
+ }
|
|
262
|
+ }
|
|
263
|
+}
|
|
264
|
+</script>
|
|
265
|
+
|
|
266
|
+```
|
|
267
|
+我们可以改变下,把数据跟逻辑放在一块,这样就解决了vue2.x的数据跟逻辑分散的问题。
|
|
268
|
+```html
|
|
269
|
+<template>
|
|
270
|
+ <div>
|
|
271
|
+ <ul>
|
|
272
|
+ <li
|
|
273
|
+ v-for="(item, index) in state.list"
|
|
274
|
+ :key="item.id"
|
|
275
|
+ @click="removeItem(index)"
|
|
276
|
+ >
|
|
277
|
+ {{ item.id }}--{{ item.con }}
|
|
278
|
+ </li>
|
|
279
|
+ </ul>
|
|
280
|
+ </div>
|
|
281
|
+</template>
|
|
282
|
+
|
|
283
|
+<script>
|
|
284
|
+import { reactive } from "vue";
|
|
285
|
+export default {
|
|
286
|
+ name: "App",
|
|
287
|
+ setup() {
|
|
288
|
+ let {state,removeItem} = userReturn();
|
|
289
|
+ return {
|
|
290
|
+ state,
|
|
291
|
+ removeItem,
|
|
292
|
+ };
|
|
293
|
+ },
|
|
294
|
+};
|
|
295
|
+
|
|
296
|
+function userReturn(params) {
|
|
297
|
+ const state = reactive({
|
|
298
|
+ list: [
|
|
299
|
+ {
|
|
300
|
+ id: 1,
|
|
301
|
+ con: "A",
|
|
302
|
+ },
|
|
303
|
+ {
|
|
304
|
+ id: 2,
|
|
305
|
+ con: "B",
|
|
306
|
+ },
|
|
307
|
+ {
|
|
308
|
+ id: 3,
|
|
309
|
+ con: "C",
|
|
310
|
+ },
|
|
311
|
+ ],
|
|
312
|
+ });
|
|
313
|
+
|
|
314
|
+ const removeItem = (index) => {
|
|
315
|
+ state.list = state.list.filter((item, i) => i !== index);
|
|
316
|
+ };
|
|
317
|
+
|
|
318
|
+ return {state,removeItem}
|
|
319
|
+}
|
|
320
|
+</script>
|
|
321
|
+
|
|
322
|
+```
|
|
323
|
+
|
|
324
|
+## 四、组合API本质
|
|
325
|
+`compositionAPI`与`optionAPI`可以混合使用。其本质是注入。
|
|
326
|
+
|
|
327
|
+```html
|
|
328
|
+<template>
|
|
329
|
+ <div>
|
|
330
|
+ <p>Vue2.x</p>
|
|
331
|
+ <button @click="cli1">点击</button>
|
|
332
|
+ <p>Vue3.0</p>
|
|
333
|
+ <button @click="cli2">点击</button>
|
|
334
|
+ </div>
|
|
335
|
+</template>
|
|
336
|
+
|
|
337
|
+<script>
|
|
338
|
+import {ref} from "vue"
|
|
339
|
+export default {
|
|
340
|
+ name:"Demo2",
|
|
341
|
+ data(){
|
|
342
|
+ return {
|
|
343
|
+ msg:"Vue2.x"
|
|
344
|
+ }
|
|
345
|
+ },
|
|
346
|
+ methods:{
|
|
347
|
+ cli1(){
|
|
348
|
+ alert(this.msg);
|
|
349
|
+ }
|
|
350
|
+ },
|
|
351
|
+ setup(){
|
|
352
|
+ let txt = ref("Vue3.0"); // 注入到data函数内
|
|
353
|
+ function cli2() { // 注入到methods属性内
|
|
354
|
+ alert(txt.value);
|
|
355
|
+ }
|
|
356
|
+ return {
|
|
357
|
+ txt,
|
|
358
|
+ cli2
|
|
359
|
+ }
|
|
360
|
+ }
|
|
361
|
+}
|
|
362
|
+</script>
|
|
363
|
+
|
|
364
|
+<style>
|
|
365
|
+
|
|
366
|
+</style>
|
|
367
|
+```
|
|
368
|
+## 五、setup执行时机与注意事项
|
|
369
|
+setup函数,是在`beforecreate`钩子之前完成的。所以无法使用`data`跟`methods`。
|
|
370
|
+另外要注意的是setup是同步的,不是异步的。
|
|
371
|
+
|
|
372
|
+```html
|
|
373
|
+<template>
|
|
374
|
+ <div>
|
|
375
|
+ <button @click="name">打开</button>
|
|
376
|
+ </div>
|
|
377
|
+</template>
|
|
378
|
+
|
|
379
|
+<script>
|
|
380
|
+export default {
|
|
381
|
+ name:"Demo3",
|
|
382
|
+ data(){
|
|
383
|
+ return {
|
|
384
|
+ msg:"hello"
|
|
385
|
+ }
|
|
386
|
+ },
|
|
387
|
+ setup(){
|
|
388
|
+ function name() {
|
|
389
|
+ console.log(this.msg); // undefined
|
|
390
|
+ }
|
|
391
|
+ return {
|
|
392
|
+ name
|
|
393
|
+ }
|
|
394
|
+ }
|
|
395
|
+}
|
|
396
|
+</script>
|
|
397
|
+
|
|
398
|
+<style>
|
|
399
|
+
|
|
400
|
+</style>
|
|
401
|
+```
|
|
402
|
+# 适合Vue3.0开发的UI框架
|
|
403
|
+
|
|
404
|
+**Ant Design of Vue**
|
|
405
|
+
|
|
406
|
+https://2x.antdv.com/docs/vue/introduce-cn/
|
|
407
|
+
|
|
408
|
+**Vant**
|
|
409
|
+
|
|
410
|
+https://vant-contrib.gitee.io/vant/next/#/zh-CN/
|