Vue学习笔记01-使用Vue3

Vue学习之路 https://vuejs.org/guide/introduction.html

1. 基础认知

1.1. 认识Vue

https://cn.vuejs.org/index.html

  • Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架

    • 全称是Vue.js或者Vuejs;

    • 什么是渐进式框架呢?

      表示可以在项目中一点点来引入和使用Vue,而不一定需要全部使用Vue来开发整个项目;

1.2. 前端框架

目前前端最流行的三大框架:Vue,React,Angular

  • Angular:入门门槛较高,并且国内市场占率较低,不否认本身非常优秀
  • React:在国内外市场占有率非常高,必须学习的一个框架
  • Vue:国内占有率最高

1.3. Vue3

  • 在2020年的9月19日,万众期待的Vue3终于发布了正式版,命名为“One Piece”
    • 它也带来了很多新的特性:更好的性能、更小的包体积、更好的TypeScript集成、更优秀的API设计
    • 在vue3刚刚发布时,很多人也是跃跃欲试,想要尝试vue3的各种新特性
    • 但是事实上在刚刚发布的时候使用vue3来写demo练习是没有问题的,真正在实际业务项目中使用vue3还需要一个相对的过程
    • 包括vue3的进一步稳定、包括社区更多vue3相关的插件、组件库的支持和完善
  • 那么需要学习vue3吗?
    • 答案是肯定的
    • 首先vue3在经过一系列的更新和维护后,已经是趋于稳定,并且在之前尤雨溪也宣布在2021年第二季度会将vue3作为Vue CLI的默认版本
    • 目前社区也经过一定时间的沉淀,更加的完善了,包括AntDesignVue、Element-Plus都提供了对Vue3的支持,所以很多公司目前新的项目都已经在使用Vue3来进行开发了
    • 并且在面试的时候,几乎都会问到各种各样Vue3、Vite2工具相关的问题

1.4. Vue3带来的变化(源码)

  • 源码通过monorepo的形式来管理源代码:

    • Mono:单个
    • Repo:repository仓库
    • 主要是将许多项目的代码存储在同一个repository中;
    • 这样做的目的是多个包本身相互独立,可以有自己的功能逻辑、单元测试等,同时又在同一个仓库下方便管理;
    • 而且模块划分的更加清晰,可维护性、可扩展性更强;
  • 源码使用TypeScript来进行重写:

    • 在Vue2.x的时候,Vue使用Flow来进行类型检测;
    • 在Vue3.x的时候,Vue的源码全部使用TypeScript来进行重构,并且Vue本身对TypeScript支持也更好了;

1.5. Vue3带来的变化(性能)

  • 使用Proxy进行数据劫持
    • 在Vue2.x的时候,Vue2是使用Object.defineProperty来劫持数据的getter和setter方法的;
    • 这种方式一致存在一个缺陷就是当给对象添加或者删除属性时,是无法劫持和监听的;
    • 所以在Vue2.x的时候,不得不提供一些特殊的API,比如$set$delete,事实上都是一些hack方法,也增加了 开发者学习新的API的成本;
    • 而在Vue3.x开始,Vue使用Proxy来实现数据的劫持;
  • 删除了一些不必要的API
    • 移除了实例上的 $on, $off$once;
    • 移除了一些特性:如filter、内联模板等;
  • 包括编译方面的优化
    • 生成Block Tree、Slot编译优化、diff算法优化;

1.6. Vue3带来的变化(新的API)

  • 由Options API 到 Composition API:

    • 在Vue2.x的时候,会通过Options API来描述组件对象;
    • Options API包括data、props、methods、computed、生命周期等等这些选项;
    • 存在比较大的问题是多个逻辑可能是在不同的地方:
      • 比如created中会使用某一个method来修改data的数据,代码的内聚性非常差;
    • Composition API可以将 相关联的代码 放到同一处 进行处理,而不需要在多个Options之间寻找;
  • Hooks函数增加代码的复用性:

    • 在Vue2.x的时候,通常通过mixins在多个组件之间共享逻辑;
    • 但是有一个很大的缺陷就是 mixins也是由一大堆的Options组成的,并且多个mixins会存在命名冲突的问题;
    • 在Vue3.x中,我们可以通过Hook函数,来将一部分独立的逻辑抽取出去,并且它们还可以做到是响应式的;

2. 使用Vue

  • Vue的本质,就是一个JavaScript的库:

    • 就把它理解成一个已经封装好的库;
    • 在项目中可以引入并且使用它即可
  • 那么安装和使用Vue这个JavaScript库有哪些方式呢?

    1. 方式一:在页面中通过CDN的方式来引入;
    2. 方式二:下载Vue的JavaScript文件,并且自己手动引入;
    3. 方式三:通过npm包管理工具安装使用它(webpack再讲);
    4. 方式四:直接通过Vue CLI创建项目,并且使用它;

2.1. 方式一:CDN引入

  • 什么是CDN呢?

    • CDN称之为内容分发网络(Content Delivery Network或Content Distribution Network,缩写:CDN)

    • 它是指通过相互连接的网络系统,利用最靠近每个用户的服务器;

      • 最近的边缘节点(服务器)中查找资源,如果没有,查找父节点,如果没有,查找源站。

      • 源站将资源传输给父节点,父节点传输给最近边缘节点

    • 更快、更可靠地将音乐、图片、视频、应用程序及其他文件发送给用户;

    • 来提供高性能、可扩展性及低成本的网络内容传递给用户;

  • 常用的CDN服务器可以大致分为两种:

    • 自己的CDN服务器:需要购买自己的CDN服务器,目前阿里、腾讯、亚马逊、Google等都可以购买CDN服务器;
    • 开源的CDN服务器:国际上使用比较多的是unpkg、 JSDelivr、cdnjs;
  • Vue的CDN引入:

    1
    <script src="https://unpkg.com/vue@next"></script>
  • Hello Vue案例的实现:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    </head>
    <body>
    <div id="app"></div>
    <script src="https://unpkg.com/vue@next"></script>
    <script>
    const why = {
    template: '<h1>Hello Vue</h1>'
    }
    const app = Vue.createApp(why);
    app.mount("#app");
    </script>
    </body>
    </html>

2.2. 方式二:下载和引入

  • 下载Vue的源码,可以直接打开CDN的链接:

    • 打开链接,复制其中所有的代码;
    • 创建一个新的文件,比如vue.js,将代码复制到其中;
  • 通过script标签,引入刚才的文件

  • 案例实现

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    </head>
    <body>
    <div id="app"></div>
    <script src="./vue.js"></script>
    <script>
    Vue.createApp({
    template: '<h1>Hello Vue.js</h1>'
    }).mount('#app');
    </script>
    </body>
    </html>

2.3. 计数器案例

  • 实现一个计数器的案例:

    • 点击+1,那么内容会显示数字+1;
    • 点击-1,那么内容会显示数字-1;
  • 选择很多种方式来实现:

    • 对比原生和Vue的实现方式的不同

2.3.1. 原生js

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div>
<h2 id="title"></h2>
<button id="increment">+1</button>
<button id="decrement">-1</button>
</div>
<script>
// 1. 获取元素
const title = document.querySelector("#title");
const btnIncre = document.querySelector("#increment");
const btnDecre = document.querySelector("#decrement");

// 2. 初始化计数
let counter = 100;
title.innerHTML = counter;

// 3. 监听按钮点击事件
btnIncre.addEventListener("click",function(){
counter++;
title.innerHTML = counter;
});

btnDecre.addEventListener("click",function(){
counter--;
title.innerHTML = counter;
})

</script>
</body>
</html>

2.3.2. Vue.js

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app"></div>
<script src="https://unpkg.com/vue@next"></script>
<script>
Vue.createApp({
template: `
<div>
<h2>{{counter}}</h2>
<button @click = 'increment'>+1</button>
<button @click = 'decrement'>-1</button>
</div>
`,
data: function(){
return {
counter: 100
}
},
methods: {
increment(){
this.counter++;
},
decrement(){
this.counter--;
}
}
}).mount('#app');
</script>
</body>
</html>

2.3.3. 声明式和命令式

  • 原生开发和Vue开发的模式和特点,是完全不同的,这里其实涉及到两种不同的编程范式:

    • 命令式编程和声明式编程;
    • 命令式编程关注的是 “how to do”,声明式编程关注的是 “what to do”,由框架(机器)完成 “how”的过程;
  • 在原生的实现过程中,如何操作的呢?

    • 每完成一个操作,都需要通过JavaScript编写一条代码,来给浏览器一个指令;
    • 这样的编写代码的过程,称之为命令式编程;
    • 在早期的原生JavaScript和jQuery开发的过程中,我们都是通过这种命令式的方式在编写代码的;
  • 在Vue的实现过程中,如何操作的呢?

    • 在createApp传入的对象中声明需要的内容,模板template、数据data、方法methods;
    • 这样的编写代码的过程,称之为是声明式编程;
    • 目前Vue、React、Angular的编程模式,都称之为声明式编程;

2.4. MVVM模型

  • MVC和MVVM都是一种软件的体系结构

    • MVC是Model – View –Controller的简称,是在前期被使用非常框架的架构模式,比如iOS、前端;

    • MVVM是Model-View-ViewModel的简称,是目前非常流行的架构模式;

  • 通常情况下,也经常称Vue是一个MVVM的框架

    • Vue官方其实有说明,Vue虽然并没有完全遵守MVVM的模型,但是整个设计是受到它的启发的

3. templeate属性

  • 在使用createApp的时候,传入了一个对象

  • template属性:表示的是Vue需要帮忙渲染的模板信息:

    • 目前看到它里面有很多的HTML标签,这些标签会替换掉挂载到的元素(比如id为app的div)innerHTML;
    • 模板中有一些奇怪的语法,比如 @click,这些都是模板特有的语法;
  • 但是这个模板的写法有点过于别扭了,并且IDE很有可能没有任何提示,阻碍编程的效率

  • Vue提供了两种方式:
    1. 方式一:使用script标签,并且标记它的类型为 x-template;
    2. 方式二:使用任意标签(通常使用template标签,因为不会被浏览器渲染),设置id;

3.1. template写法

在createApp的对象中,传入的template以 # 开头:

如果字符串是以 # 开始,那么它将被用作 querySelector,并且使用匹配元素的 innerHTML 作为模板字符串;

3.1.1. 使用script标签

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app"></div>
<script src="https://unpkg.com/vue@next"></script>

<script type="x-template" id = "vue">
<h1>hello world</h1>
</script>

<script>
Vue.createApp({
template: '#vue'
}).mount("#app");
</script>
</body>
</html>

3.1.2. 使用template标签

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app"></div>

<template id = "vue">
<h1>hello template</h1>
</template>

<script src="https://unpkg.com/vue@next"></script>
<script>
Vue.createApp({
template: '#vue'
}).mount("#app");
</script>
</body>
</html>

4. data属性

  • data属性是传入一个函数,并且该函数需要返回一个对象:

  • 在Vue2.x的时候,也可以传入一个对象(虽然官方推荐是一个函数);

  • 在Vue3.x的时候,必须传入一个函数,否则就会直接在浏览器中报错;

  • data中返回的对象会被Vue的响应式系统劫持,之后对该对象的修改或者访问都会在劫持中被处理:

    • 所以在template中通过 访问counter,可以从对象中获取到数据;
    • 所以修改counter的值时,template中的 也会发生改变;

5. methods属性

  • methods属性是一个对象,通常会在这个对象中定义很多的方法:
    • 这些方法可以被绑定到 template 模板中;
    • 在该方法中,可以使用this关键字来直接访问到data中返回的对象的属性;

5.1. 为什么不能使用箭头函数?

  • 官方文档有这么一段描述:
    • 注意,不应该使用箭头函数来定义 method 函数 (例如 plus: () => this.a++)。理由是箭头函数绑定了父级作用域的上下文,所以 this 将不会按照期望指向 Vue 实例,this.a 将是 undefined
  • 在methods中要使用data返回对象中的数据:
    • 那么这个this是必须有值的,并且应该可以通过this获取到data返回对象中的数据。
  • 这个this能不能是window呢?
    • 不可以是window,因为window中无法获取到data返回对象中的数据;
    • 但是如果使用箭头函数,那么这个this就会是window了;
  • 为什么是window呢?
    • 箭头函数中不绑定this,这个this就是window;
    • 这里涉及到箭头函数使用this的查找规则,它会在自己的上层作用于中来查找this;
    • 最终刚好找到的是script作用于中的this,所以就是window;
  • this到底是如何查找和绑定的呢?

5.2. this到底指向的是什么?

事实上Vue的源码当中就是对methods中的所有函数进行了遍历,并且通过bind绑定了this:

/packages/runtime-core/src/componentOptions.ts

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
instance: ComponentInternalInstance

const publicThis = instance.proxy! as any
const ctx = instance.ctx

if (methods) {
// 拿到methods中所有 key
for (const key in methods) {
// 得到 key 对应的方法
const methodHandler = (methods as MethodOptions)[key]
if (isFunction(methodHandler)) {
if (__DEV__) {
Object.defineProperty(ctx, key, {
// 方法绑定 publicThis 代理对象
value: methodHandler.bind(publicThis),
configurable: true,
enumerable: true,
writable: true
})
}
else {
ctx[key] = methodHandler.bind(publicThis)
}
}
}
}

6. 其他属性

  • 比如props、computed、watch、emits、setup等等;
  • 也包括很多的生命周期函数;

7. 查看Vue的源码

  • 如果想要学习Vue的源码,比如看createApp的实现过程,应该怎么办呢?

  • 第一步:在GitHub上搜索 vue-next,下载源代码;

    • 这里推荐通过 git clone 的方式下载;
    • git clone https://github.com/vuejs/core
  • 第二步:安装Vue源码项目相关的依赖;

    • 执行 npm install pnpm -g

    • 执行 pnpm install

  • 第三步:对项目执行打包操作

    • 执行 pnpm dev(执行前修改脚本)
  • 第四步:通过 packages/vue/dist/vue.global.js 调试代码

    • ./package.json 中修改代码

      1
      2
      3
      "scripts": {
      "dev": "node scripts/dev.js --sourcemap"
      }
    • packages/vue/dist/ 中新建 index.html

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      <!DOCTYPE html>
      <html lang="en">
      <head>
      <meta charset="UTF-8">
      <meta http-equiv="X-UA-Compatible" content="IE=edge">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Document</title>
      </head>
      <body>
      <div id="app"></div>
      <template id = "vue">
      <h1>hello template</h1>
      </template>
      <script src="./vue.global.js"></script>
      <script>
      debugger;
      Vue.createApp({
      template: '#vue'
      }).mount("#app");
      </script>
      </body>
      </html>
    • 在chrome中打开 index.html,调试代码,得到源码所在位置

      /packages/runtime-dom/src/index.ts

8. VSCode代码片段

  • 在VSCode中生成一个代码片段,方便快速生成

  • 具体的步骤如下:

    1. 第一步,复制自己需要生成代码片段的代码;

    2. 第二步,https://snippet-generator.app/ 在该网站中生成代码片段;

    3. 第三步,在VSCode中配置代码片段;

      【code】—> 【首选项】—> 【配置用户代码片段】—> 【html.json】添加

      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
      {
      "create vue app": {
      "prefix": "vueapp",
      "body": [
      "<!DOCTYPE html>",
      "<html lang=\"en\">",
      "<head>",
      " <meta charset=\"UTF-8\">",
      " <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">",
      " <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">",
      " <title>Document</title>",
      "</head>",
      "<body>",
      " <div id=\"app\"></div>",
      " <template id = \"vue\">",
      " ",
      " </template>",
      " <script src=\"https://unpkg.com/vue@next\"></script>",
      " <script>",
      " Vue.createApp({",
      " template: '#vue',",
      " data: function(){",
      " return {",
      " ",
      " }",
      " },",
      " watch: {",
      " ",
      " },",
      " methods: {",
      "",
      " }",
      " }).mount(\"#app\");",
      " </script>",
      "</body>",
      "</html>"
      ],
      "description": "create vue app"
      }
      }
本文结束  感谢您的阅读