一、简介

1、认识Vue

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

  • 全程是Vue.js或者Vuejs;

  • 什么是渐进式框架呢?表示我们可以在项目中一点点来引入和使用Vue,而不一定需要全部使用Vue来开发整个项目;

在这里插入图片描述

渐进式: (自底向上逐层的应用)

(1) 简单应用: 只需要一个轻量小巧的核心库

(2) 复杂应用: 可以引用各种vue插件

这里说的渐进式框架其实是与Spring类似的分层架构,Vue由5个模块组成:声明式渲染/组件系统(vue.js)、客户端路由(vue-router)、大规模状态管理(vuex/pinia)、构建工具(vue-loader/webpack/vue-cli/vite)、数据持久化(涉及到后端,没有具体方案)

在这里插入图片描述

目前Vue在前端处于什么地位?

目前前端最流行的是三大框架:Vue、React、Angular。

在这里插入图片描述

2、前端框架数据对比

框架数据对比(Google指数)

在这里插入图片描述

框架数据对比(百度指数)

在这里插入图片描述

框架数据对比(npm下载量)

在这里插入图片描述

框架数据对比(GitHub)

在这里插入图片描述

谁是最好的前端框架?

当然,我不会去给出我的结论:

  • 首先,这是一个敏感的话题,在很多地方都争论不休,就像很多人喜欢争论谁才是世界上最好的语言一样;

  • 其次,争论这个话题是没有意义的,争论不休的话题;

但是,我们从现实的角度,分析一下,学习哪一门语言更容易找到工作?

  • 找后端的工作:优先推荐Java、其次推荐Go、再次推荐Node(JavaScript),可能不推荐PHP、C#;

  • 找前端的工作:优先推荐JavaScript(TypeScript)、其次Flutter、再次Android(Java、Kotlin)、iOS(OC、Swift);

  • 也有很多的其他方向:游戏开发、人工智能、算法工程师等等;

那么,就前端来说,学习了HTML、CSS、JavaScript,哪一个框架更容易找到工作?

  • 如果去国外找工作,优先推荐React、其次是Vue和Angular,不推荐jQuery了;

  • 如果在国内找工作,优先推荐、必须学习Vue,其次是React,其次是Angular,不推荐jQuery了;

3、Vue3带来的变化

Vue对前端工程师的重要性

在这里插入图片描述

学习vue2还是vue3?

在这里插入图片描述

目前需要学习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工具相关的问题。

Vue3带来的变化(源码)

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

  • Mono:单个

  • Repo:repository仓库

  • 主要是将许多项目的代码存储在同一个repository中;

  • 这样做的目的是多个包本身相互独立,可以有自己的功能逻辑、单元测试等,同时又在同一个仓库下方便管理;

  • 而且模块划分的更加清晰,可维护性、可扩展性更强;

源码使用TypeScript来进行重写:

  • 在Vue2.x的时候,Vue使用Flow来进行类型检测;

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

Vue3带来的变化(性能)

使用Proxy进行数据劫持

  • 在Vue2.x的时候,Vue2是使用Object.defineProperty来劫持数据的getter和setter方法的;

  • 这种方式一致存在一个缺陷就是当给对象添加或者删除属性时,是无法劫持和监听的;

  • 所以在Vue2.x的时候,不得不提供一些特殊的API,比如 s e t 或 set或 setdelete,事实上都是一些hack方法,也增加了开发者学习新的API的成本;

  • 而在Vue3.x开始,Vue使用Proxy来实现数据的劫持,这个API的用法和相关的原理我也会在后续讲到;

删除了一些不必要的API:

  • 移除了实例上的$on, $off 和 $once;

  • 移除了一些特性:如filter、内联模板等;

包括编译方面的优化:

  • 生成Block Tree、Slot编译优化、diff算法优化;

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函数,来将一部分独立的逻辑抽取出去,并且它们还可以做到是响应式的;

  • 具体的好处,会在后续的课程中演练和讲解(包括原理);

4、系统学习Vue3+TypeScript

在这里插入图片描述

在这里插入图片描述

5、如何使用Vue呢?

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

  • 刚开始我们不需要把它想象的非常复杂;

  • 我们就把它理解成一个已经帮助我们封装好的库;

  • 在项目中可以引入并且使用它即可。

那么安装和使用Vue这个JavaScript库有哪些方式呢?

  • 方式一:在页面中通过CDN的方式来引入;

  • 方式二:下载Vue的JavaScript文件,并且自己手动引入;

  • 方式三:通过npm包管理工具安装使用它(webpack再讲);

  • 方式四:直接通过Vue CLI创建项目,并且使用它;

6、引入方式一:CDN引入

什么是CDN呢?CDN称之为内容分发网络(Content Delivery Network或Content Distribution Network,缩 写:CDN

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

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

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

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

  • 自己的CDN服务器:需要购买自己的CDN服务器,目前阿里、腾讯、亚马逊、Google等都可以购买CDN服务器;

  • 开源的CDN服务器:国际上使用比较多的是unpkg、 JSDelivr、cdnjs;

在这里插入图片描述

Vue的CDN引入:

<script src="https://unpkg.com/vue@next"></script>

Hello Vue案例的实现:

<div id="app">
  <h2>Hello World</h2>
</div>

<script src="https://unpkg.com/vue@next"></script>
<script>
  const why = {
    template: '<h2>Hello World</h2>'
  }

  const app = Vue.createApp(why);
  app.mount("#app")
</script>
7、引入方式二:下载和引入

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

  • 打开链接,复制其中所有的代码;

  • 创建一个新的文件,比如vue.js,将代码复制到其中;

通过script标签,引入刚才的文件:

<script src="../js/vue.js"></script>

你好啊,Vue3,案例的实现:

<div id="app"></div>

<script src="../js/vue.js"></script>
<script>
  Vue.createApp({
    template: `<h2>你好啊, 李银河</h2>`
  }).mount("#app");
</script>
8、声明式和命令式

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

  • 命令式编程和声明式编程;

  • 命令式编程关注的是 “how to do”,声明式编程关注的是 “what to do”,由框架(机器)完成 “how”的过程;

在原生的实现过程中,我们是如何操作的呢?

  • 我们每完成一个操作,都需要通过JavaScript编写一条代码,来给浏览器一个指令;

  • 这样的编写代码的过程,我们称之为命令式编程;

  • 在早期的原生JavaScript和jQuery开发的过程中,我们都是通过这种命令式的方式在编写代码的;

在Vue的实现过程中,我们是如何操作的呢?

  • 我们会在createApp传入的对象中声明需要的内容,模板template、数据data、方法methods;

  • 这样的编写代码的过程,我们称之为是声明式编程;

  • 目前Vue、React、Angular的编程模式,我们称之为声明式编程;

9、MVVM模型

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

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

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

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

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

在这里插入图片描述

① MVVM介绍

MVVM 是Model-View-ViewModel 的缩写,它是一种基于前端开发的架构模式,是一种事件驱动编程方式

  • Model :vue对象的data属性里面的数据,这里的数据要显示到页面中
  • View :vue中数据要显示的HTML页面,在vue中,也称之为“视图模板” (HTML+CSS)
  • ViewModel:vue中编写代码时的vm对象,它是vue.js的核心,负责连接 View 和 Model数据的中转,保证视图和数据的一致性,所以前面代码中,data里面的数据被显示中p标签中就是vm对象自动完成的(双向数据绑定:JS中变量变了,HTML中数据也跟着改变)

在这里插入图片描述

② MVVM的特性

  • 低耦合视图(View)可以独立于Model变化和修改,1个ViewModel可以绑定到不同的View上,当View变化的时候 Model可以不变,当Model变化的时候 View也可以不变
  • 可复用:可以把一些视图逻辑放在1个ViewModel中,让很多View重用这端视图的逻辑(以此减少代码冗余)
  • 独立开发开发人员可以专注于业务逻辑数据的开发(ViewModel),设计人员可以专注于页面设计
  • 可测试:界面元素是比较难以测试的,而现在的测试可以针对ViewModel来编写

③ MVVM的逻辑

在这里插入图片描述

10、Vue的源码

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

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

  • 这里推荐通过 git clone 的方式下载;

第二步:安装Vue源码项目相关的依赖;

  • 执行 yarn install

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

  • 执行yarn dev(执行前修改脚本)
"scripts": {
	"dev": "node scripts/dev.js --sourcemap"
}

第四步:通过 packages/vue/dist/vue.global.js 调试代码

二、Vue2和Vue3区别

Vue3+TypeScript从入门到进阶(二)——Vue2和Vue3的区别——附沿途学习案例及项目实战代码

三、Vue知识点学习

Vue3+TypeScript从入门到进阶(三)——Vue3基础知识点(上)——附沿途学习案例及项目实战代码

Vue3+TypeScript从入门到进阶(四)——Vue3基础知识点(中)——附沿途学习案例及项目实战代码

Vue3+TypeScript从入门到进阶(五)——Vue3基础知识点(下)——附沿途学习案例及项目实战代码

四、TypeScript知识点

Vue3+TypeScript从入门到进阶(六)——TypeScript知识点——附沿途学习案例及项目实战代码

五、项目实战

Vue3+TypeScript从入门到进阶(七)——项目实战——附沿途学习案例及项目实战代码

六、项目打包和自动化部署

Vue3+TypeScript从入门到进阶(八)——项目打包和自动化部署——附沿途学习案例及项目实战代码

七、沿途学习代码地址及案例地址

1、沿途学习代码地址

https://gitee.com/wu_yuxin/vue3-learning.git

2、项目案例地址

https://gitee.com/wu_yuxin/vue3-ts-cms.git

在这里插入图片描述
在这里插入图片描述

八、知识拓展

1、ES6数组与对象的解构赋值详解
数组的解构赋值

基本用法

ES6允许按照一定的模式,从数组和对象中提取值,对变量进行赋值,这被称之为解构(Destructuring)

// 以前为变量赋值,只能直接指定值
var a = 1;
var b = 2;
var c = 3;
// ES6允许写成这样
var [a,b,c] = [1,2,3];

本质上,这种写法属于“模式匹配”,只要等号两边的模式相同,左边的变量就会被赋予对应的值。

下面是一些使用嵌套数组进行解构的例子:

let [foo,[[bar],baz]] = [1,[[2],3]];
foo // 1
bar // 2
baz // 3
let [,,third] = ["foo","bar","baz"];
third // "baz"
let [head,...tail] = [1,2,3,4];
head // 1
tail // [2,3,4]
let [x,y,...z] = ['a'];
x // "a"
y // undefined
z // []

默认值

解构赋值允许制定默认值

var [foo = true] = [];
foo // true
[x,y='b'] = ['a'];
// x='a', y='b'

注意,ES6内部使用严格相等运算符(===),判断一个位置是否有值。

所以,如果一个数组成员不严格等于undefined,默认值是不会生效的。

var [x=1] = [undefined];
x //1
var [x=1] = [null];
x // null

如果默认值是一个表达式,那么这个表达式是惰性求值的,即只有在用到的时候,才会求值:

function f(){
 console.log('aaa');
}
let [x=f()] = [1];

上面的代码中,因为x能取到值,所以函数f()根本不会执行。上面的代码其实等价于下面的代码:

let x;
if([1][0] === undefined){
 x = f();
}else{
 x = [1][0];
}

默认值可以引用解构赋值的其他变量,但该变量必须已经声明:

let [x=1,y=x] = [];
// x=1; y=1
let [x=1,y=x] = [2];
// x=2; y=2
let [x=1,y=x] = [1,2];
// x=1; y=2
let [x=y,y=1] = []; // ReferenceError

上面最后一个表达式,因为x用到默认值是y时,y还没有声明。

对象的解构赋值

1、最简单的案例

看下面的案例

 let person = {
     name: 'yhb',
     age: 20
 }
 /*
 注意:下面虽然看起来是创建了一个对象,对象中有两个属性 name 和 age
 但是:其实是声明了两个变量
 name:等于对象person 中的name属性的值
 age:等于对象person 中的 age属性的值
 */
 let { name, age } = person
 console.log(name,age)

如上面注释中所说,声明了变量 name和age,然后分别从对象person中寻找与变量同名的属性,并将属性的值赋值给变量

所以,这里的关键,就是首先要知道对象中都有哪些属性,然后再使用字面量的方式声明与其同名的变量

2、属性不存在怎么办
如果不小心声明了一个对象中不存在的属性怎么办?

或者,实际情况下,可能是我们就是想再声明一个变量,但是这个变量也不需要从对象中获取值,这个时候,此变量的值就是 undefined

let person = {
    name: 'yhb',
    age: 20
}   
let { name, age,address } = person
console.log(name,age,address)

此时,可以给变量加入一个默认值

let { name, age,address='北京' } = person

3、属性太受欢迎怎么办

当前声明了 name 和 age 变量,其值就是person对象中name和age属性的值,如果还有其他变量也想获取这两个属性的值怎么办?

 let { name, age, address = '北京' } = person
 console.log(name, age, address)
 let { name, age } = person
 console.log(name, age)

上面的方法肯定不行,会提示定义了重复的变量 name 和 age

那怎么办呢?

难道只能放弃结构赋值,使用老旧的方式吗?

let l_name=person.name
let l_age=person.age
console.log(l_name,l_age)

其实不然!

let {name:l_name,age:l_age}=person
console.log(l_name,l_age)

说明:

声明变量 l_name 并从对象person中获取name属性的值赋予此变量
声明变量 l_age, 并从对象person中获取age属性的值赋予此变量
这里的重点是下面这行代码

let {name:l_name,age:l_age}=person

按照创建对象字面量的逻辑,name 为键,l_name 为值。但注意,这里是声明变量,并不是创建对象字面量,所以争取的解读应该是

声明变量 l_name,并从person 对象中找到与 name 同名的属性,然后将此属性的值赋值给变量 l_name

所以,我们最后输出的是变量 l_name和l_age

console.log(l_name,l_age)

当然这种状态下,也是可以给变量赋予默认值的

let { name:l_name, age:l_age, address:l_address='北京' }=person

4、嵌套对象如何解构赋值

let person = {
 name: 'yhb',
 age: 20,
 address: {
     province: '河北省',
     city: '保定'
 }
}
// 从对象 person 中找到 address 属性,并将值赋给变量 address
let {address}=person
// 从对象 address 中找到 province 属性,并将值赋给变量 province
let {province}=address
console.log(province)

上面代码一层层的进行结构赋值,也可以简写为如下形式

let {address:{province}}=person  

从peson 对象中找到 address 属性,取出其值赋值给冒号前面的变量 address,然后再将 变量address 的值赋值给 冒号 后面的变量 {province},相当于下面的写法

let {province}=address
字符串的解构赋值

1、字符串也可以解构赋值。这是因为此时,字符串被转换成了一个类似数组的对象。

const [a, b, c, d, e] = 'hello';
a // "h"
b // "e"
c // "l"
d // "l"
e // "o"

类似数组的对象都有一个length属性,因此还可以对这个属性解构赋值。

let {length : len} = 'hello';
len // 5
2、JavaScript的 …(展开运算符)

三个连续的点具有两个含义:展开运算符(spread operator)和剩余运算符(rest operator)。

展开运算符

展开运算符允许迭代器在接收器内部分别展开或扩展。迭代器和接收器可以是任何可以循环的对象,例如数组、对象、集合、映射等。你可以把一个容器的每个部分分别放入另一个容器。

const newArray = ['first', ...anotherArray];

剩余参数

剩余参数语法允许我们将无限数量的参数表示为数组。命名参数的位置可以在剩余参数之前。

const func = (first, second, ...rest) => {};

用例

定义是非常有用的,但是很难仅从定义中理解概念。我认为用日常用例会加强对定义的理解。

复制数组

当我们需要修改一个数组,但又不想改变原始数组(其他人可能会使用它)时,就必须复制它。

const fruits = ['apple', 'orange', 'banana'];
const fruitsCopied = [...fruits]; // ['apple', 'orange', 'banana']

console.log(fruits === fruitsCopied); // false

// 老方法
fruits.map(fruit => fruit);

它正在选择数组中的每个元素,并将每个元素放在新的数组结构中。我们也可以使用 map 操作符实现数组的复制并进行身份映射。

唯一数组

如果我们想从数组中筛选出重复的元素,那么最简单的解决方案是什么?

Set 对象仅存储唯一的元素,并且可以用数组填充。它也是可迭代的,因此我们可以将其展开到新的数组中,并且得到的数组中的值是唯一的。

const fruits = ['apple', 'orange', 'banana', 'banana'];
const uniqueFruits = [...new Set(fruits)]; // ['apple', 'orange', 'banana']

// old way
fruits.filter((fruit, index, arr) => arr.indexOf(fruit) === index);

串联数组
可以用 concat 方法连接两个独立的数组,但是为什么不再次使用展开运算符呢?

const fruits = ['apple', 'orange', 'banana'];
const vegetables = ['carrot'];
const fruitsAndVegetables = [...fruits, ...vegetables]; // ['apple', 'orange', 'banana', 'carrot']
const fruitsAndVegetables = ['carrot', ...fruits]; // ['carrot', 'apple', 'orange', 'banana']

// 老方法
const fruitsAndVegetables = fruits.concat(vegetables);
fruits.unshift('carrot');

将参数作为数组进行传递

当传递参数时,展开运算符能够使我们的代码更具可读性。在 ES6 之前,我们必须将该函数应用于 arguments。现在我们可以将参数展开到函数中,从而使代码更简洁。

const mixer = (x, y, z) => console.log(x, y, z);
const fruits = ['apple', 'orange', 'banana'];

mixer(...fruits); // 'apple', 'orange', 'banana'

// 老方法
mixer.apply(null, fruits);

数组切片

使用 slice 方法切片更加直接,但是如果需要的话,展开运算符也可以做到。但是必须一个个地去命名其余的元素,所以从大数组中进行切片的话,这不是个好方法。

const fruits = ['apple', 'orange', 'banana'];
const [apple, ...remainingFruits] = fruits; // ['orange', 'banana']

// 老方法
const remainingFruits = fruits.slice(1);

将参数转换为数组
Javascript 中的参数是类似数组的对象。你可以用索引来访问它,但是不能调用像 map、filter 这样的数组方法。参数是一个可迭代的对象,那么我们做些什么呢?在它们前面放三个点,然后作为数组去访问!

const mixer = (...args) => console.log(args);
mixer('apple'); // ['apple']

将 NodeList 转换为数组
参数就像从 querySelectorAll 函数返回的 NodeList 一样。它们的行为也有点像数组,只是没有对应的方法。

[...document.querySelectorAll('div')];

// 老方法
Array.prototype.slice.call(document.querySelectorAll('div'));

复制对象
最后,我们介绍对象操作。复制的工作方式与数组相同。在以前它可以通过 Object.assign 和一个空的对象常量来实现。

const todo = { name: 'Clean the dishes' };
const todoCopied = { ...todo }; // { name: 'Clean the dishes' }
console.log(todo === todoCopied); // false

// 老方法
Object.assign({}, todo);

合并对象
合并的唯一区别是具有相同键的属性将被覆盖。最右边的属性具有最高优先级。

const todo = { name: 'Clean the dishes' };
const state = { completed: false };
const nextTodo = { name: 'Ironing' };
const merged = { ...todo, ...state, ...nextTodo }; // { name: 'Ironing', completed: false }

// 老方法
Object.assign({}, todo, state, nextTodo);

需要注意的是,合并仅在层次结构的第一级上创建副本。层次结构中的更深层次将是相同的引用。

将字符串拆分为字符
最后是字符串。你可以用展开运算符把字符串拆分为字符。当然,如果你用空字符串调用 split 方法也是一样的。

const country = 'USA';
console.log([...country]); // ['U', 'S', 'A']

// 老方法
country.split('');
3、export ‘defineEmit’ (imported as ‘defineEmit’) was not found in ‘vue’

在这里插入图片描述
在这里插入图片描述
在学习vue3的顶层编写方式时的父子组件通信的时候,我们会看到一些比较老(2020、2021年初)的博客里面会有使用defineEmit的,但是如果我们用比较新版本的Vue3的话,就会报错。原因是,新版本的Vue3将defineEmit改成了defineEmits了

九、其他知识学习

1、Webpack学习

Webpack从入门到进阶(一)—附沿路学习案例代码

Webpack从入门到进阶(二)—附沿路学习案例代码

Webpack从入门到进阶(三)—附沿路学习案例代码

2、数据可视化-echarts

数据可视化-echarts入门、常见图表案例、超详细配置解析及项目案例

3、预备知识与后续知识及项目案例

HTML入门与进阶以及HTML5
CSS
JS-上
JS-下
jQuery
Node.js + Gulp 知识点汇总
MongoDB + Express 入门及案例代码

Bootstrap入门与简述

4、Vue2学习

Vue项目开发-仿蘑菇街电商APP

Vue 知识点汇总(上)–附案例代码及项目地址

Vue 知识点汇总(下)–附案例代码及项目地址

5、JavaScript面向对象和设计模式

JavaScript面向对象编程浅析

JavaScript设计模式浅析

6、微前端学习

SingleSpa及qiankun入门、源码分析及案例

Logo

前往低代码交流专区

更多推荐