目录
1. 前端工程化
1.1. 概述
1.2. 前端工程化实现技术栈
2. ECMA6Script
2.1. es6的介绍
2.2. es6 变量 / 模版字符串
2.2.1. let 与 var 的差别
2.2.2. const 与 var 的差异
2.2.3. 模板字符串
2.3. 解构表达式 / 赋值
2.3.1. 数组解构赋值
2.3.2. 对象解构赋值
2.3.3. 函数参数解构赋值
2.4. 箭头函数
2.4.1. 箭头函数的基本语法
2.4.2. 箭头函数的特点
2.4.3. 应用场景
2.4.4. rest和spread
2.5. 对象创建与拷贝
2.5.1. 对象创建的语法糖
2.5.2. 对象的深拷贝和浅拷贝
3. 前端工程化环境搭建
3.1. Nodejs
3.1.1. Nodejs 概述
3.1.2. 安装 Nodejs
3.2. npm
3.2.1. npm 概述
3.2.2. npm 安装和配置
3.2.3. npm常用指令
4. Vue3简介和快速体验
4.1. Vue3 概述
4.2. Vue3 快速体验(非工程化方式)
5. Vue3通过Vite实现工程化
5.1. Vite 概述
5.2. Vite创建Vue3工程化
5.2.1. 项目的创建、启动、停止
5.2.1.1. 创建一个项目
5.2.1.2. 启动一个项目
5.2.1.3. 停止一个项目
5.2.2. 项目的结构
5.2.2.1. Vite 项目结构
5.2.2.2. vite的运行界面
5.2.3. 关于JS和TS选择的问题
5.2.4. 项目组件(SFC入门)
5.2.5. css 样式导入方式
5.2.5.1. 在单个.vue文件内
5.2.5.2. 在独立的CSS文件中
5.2.5.3. 全局样式的导入
5.2.6. 响应式入门和setup函数
1. 前端工程化
1.1. 概述
前端工程化是一种将软件开发的方法和流程应用到前端开发中的做法。它通过采用模块化、组件化、规范化和自动化等策略,旨在简化前端开发过程,提高开发效率,并减少可能出现的错误和成本。简单来说,就像是在建房子时使用预制板和自动化工具,让建造过程更加快速、高效且质量有保障。
你可以将其理解为一套高效“建房”的规则和工具,帮助你更好地搭建网站和应用程序的前端部分。
1.2. 前端工程化实现技术栈
前端工程化实现技术栈是一套用于开发现代网站和应用程序前端的工具和规范的集合。可以将这些技术想象成一套用于搭建和装饰房子的工具箱。
- ECMAScript 6 (ES6): 这是一种编程语言的规范,它为开发者提供了更简洁、更强大的编程语法。在Vue 3中,ES6的语法被广泛使用,使得代码更加易读和易写。
- Node.js: 这是一个可以让开发者在服务器端运行JavaScript的平台。它为前端工程化提供了一个强大的运行环境,使得开发者可以更高效地进行构建和测试。
- npm (Node Package Manager): 这是一个依赖管理工具,可以帮助开发者轻松地管理和下载项目中需要的第三方库和模块,就像是一个大型的在线图书馆,你可以从中找到并使用各种书籍(代码)。
- Vite: 这是一个现代化的前端构建工具,它可以快速地打包和优化你的代码,使其在浏览器中运行得更快。Vite通过预编译和优化,减少了开发过程中的等待时间。
- Vue 3: 这是一个流行的前端框架,它提供了一套系统化的方法来构建用户界面。Vue 3以其轻量级、灵活性和易用性而受到许多开发者的喜爱。
- router: 这是Vue.js中的一个功能,用于处理前端路由,即页面之间的导航和切换。它使得单页面应用(SPA)的页面跳转变得更加流畅和高效。
- pinia: 这是一个状态管理库,用于Vue 3应用程序中。它帮助你管理应用中的数据状态,使得数据在不同的组件之间传递和共享变得更加简单。
- axios: 这是一个基于Promise的HTTP客户端,用于浏览器和node.js。它提供了一种简单的方式来发送HTTP请求,从而实现前后端之间的数据交互。
- Element-plus: 这是一个基于Vue 3的UI组件库,提供了一系列的预制组件,可以帮助开发者快速构建高质量的用户界面。
将这些工具和技术结合起来,就像是一个全能的工具箱,可以帮助你在前端开发中更加高效、规范地工作。
2. ECMA6Script
2.1. es6的介绍
ES6是JavaScript语言的一个重要版本,它在2015年推出,带来了很多新的特性和改进,使得编写JavaScript代码更加方便和高效。下面是一些ES6主要特点的简化版介绍:
- 箭头函数:这是一种更简洁的写法来定义函数。例如,传统的函数写法是
function add(a, b) { return a + b; }
,在ES6中可以简化为(a, b) => a + b
。 - 模板字符串:这是一种新的字符串表示方式,可以让你更容易地创建包含变量的字符串。例如,
let name = "Kimi";
传统的字符串拼接是"Hello, " + name
,在ES6中可以写成Hello, ${name}
。 - let和const:这两个新的关键字让你可以声明变量,其中
let
允许你在代码块内重新赋值,而const
声明的变量是只读的,一旦赋值后不能改变。 - 解构赋值:这是一种新的赋值方式,可以从数组或者对象中提取值并赋给变量。例如,
let [a, b] = [1, 2];
会创建两个变量a和b,分别赋值为1和2。 - 默认参数值:在函数定义中,可以给参数指定默认值。如果调用函数时没有提供某个参数,就会使用默认值。例如,
function greet(name = "Kimi") { console.log("Hello, " + name); }
如果调用greet()
而不传参数,会打印出Hello, Kimi
。 - 模块化:ES6引入了模块的导入和导出功能,使得代码的组织更加清晰,便于维护和重用。例如,你可以在一个文件中写
export default function() { ... }
来导出一个函数,然后在另一个文件中用import myFunction from './myModule'
来导入它。
ES6的这些新特性让JavaScript编程变得更加简洁和强大,也更适合开发大型应用程序。随着现代浏览器对ES6的支持越来越好,学习和使用ES6是非常有价值的。
2.2. es6 变量 / 模版字符串
ES6 中引入了 let
和 const
关键字来声明变量,它们与传统的 var
存在许多差异。以下是 let
和 var
以及 const
的主要区别:
2.2.1. let
与 var
的差别
- 不能重复声明:
使用let
声明的变量在同一作用域内不允许被再次声明。尝试这样做会引发错误。 - 块级作用域:
let
声明的变量具有块级作用域,这意味着变量仅在其所在的代码块(如花括号{}
内)内有效。一旦离开该代码块,变量将无法访问。 - 无变量提升:
与var
不同,let
声明的变量不会在它所在的作用域顶部被提前“声明”。在声明之前访问let
变量会导致错误。 - 不作为全局对象属性:
全局作用域下用let
声明的变量不会自动成为window
对象的属性(在浏览器环境中)。 - 循环中的优势:
在for
循环等场景中,推荐使用let
声明循环变量,因为它能确保每次迭代时都创建一个新的变量副本,避免了因循环变量共享同一作用域导致的问题。
2.2.2. const
与 var
的差异
- 常量性质:
const
声明的是常量,一旦赋值后其值就不能被更改。试图改变const
声明的变量的值会导致错误。 - 值的不可变性:
注意,对于对象或数组类型的const
常量,虽然不能直接修改其引用(即不能将其重新赋值给另一个对象或数组),但可以修改其内部属性或元素。
2.2.3. 模板字符串
模板字符串是一种新型字符串字面量,由反引号(`)包围,提供了更灵活的字符串处理能力:
- 多行字符串:
模板字符串可以轻松跨越多行,不需要使用转义字符或连接操作。 - 插值表达式:
在模板字符串中,使用${expression}
结构可以嵌入变量或任何可求值的 JavaScript 表达式。这些表达式的值将被替换到最终字符串中。
示例:
<script>
// 使用 let 声明并演示块级作用域
{
let myVariable = "Local scope";
console.log(myVariable); // 输出: Local scope
}
console.log(myVariable); // 报错: myVariable is not defined
// 使用 const 声明常量
const PI = 3.1415926;
//PI = 4; // 报错: Assignment to constant variable.
// 模板字符串示例
const name = "张小明";
const infoStr1 = `${name}被评为本年级优秀学员`;
console.log(infoStr1);
// 多行模板字符串
const multiLineString = `
第一行文本
第二行文本
`;
console.log(multiLineString);
</script>
2.3. 解构表达式 / 赋值
解构赋值是一种在JavaScript中提取数组或对象中数据的方法,它可以快速地将数据分配给新的变量。
简单来说,就是把一个复杂的数据结构(如数组或对象)拆分成单个的元素,并将这些元素赋值给指定的变量。
举个例子
想象一下,你有一个水果篮子,里面有苹果、香蕉和橘子。现在,你想要把每种水果分别放到三个不同的盘子里。在JavaScript中,你通常会这样做:
let fruits = ['apple', 'banana', 'orange']; // 这是一个包含三种水果的数组
let apple = fruits[0]; // 取第一个水果
let banana = fruits[1]; // 取第二个水果
let orange = fruits[2]; // 取第三个水果
现在,我们可以使用解构赋值来做同样的事情,但是用更少的代码:
let [apple, banana, orange] = ['apple', 'banana', 'orange']; // 使用解构赋值,直接从数组中取出水果放到变量里
在这个例子中,我们告诉JavaScript:“我们有一个数组,里面有三个元素。我们想要创建三个变量(apple、banana和orange),并且让它们分别等于数组中的三个元素。”
解构赋值就是这样一种方式,它允许我们快速地从数组或对象中提取数据,并将它们放入我们已经命名的变量中。这样做可以让代码更短,也更易于理解。
2.3.1. 数组解构赋值
数组解构赋值是JavaScript中一种非常方便的语法,它允许你快速地从数组中提取值并赋给指定的变量。这种语法简化了代码,使得代码更加易读和高效。下面我会用简单易懂的方式来解释这个概念。
- 基本数组解构赋值
假设我们有一个数组 [1, 2, 3]
,我们想要将这个数组中的值分别赋给变量 a
、b
和 c
。使用数组解构赋值,我们可以这样做:
let [a, b, c] = [1, 2, 3];
这行代码的意思是:创建三个变量 a
、b
和 c
,并将数组中的第一个元素(1)赋值给 a
,第二个元素(2)赋值给 b
,第三个元素(3)赋值给 c
。之后,你可以通过 console.log
来查看这些变量的值:
console.log(a); // 输出 1
console.log(b); // 输出 2
console.log(c); // 输出 3
- 使用默认值
有时候,数组中可能没有足够的元素来赋值给所有的变量。在这种情况下,我们可以为变量指定一个默认值。如果数组中没有对应的元素,那么变量就会使用这个默认值。
例如,如果我们有一个数组 [1, 2]
并且我们想要创建四个变量,但是只提供了两个值,我们可以这样做:
let [a, b, c, d = 4] = [1, 2];
这里,c
没有在数组中找到对应的值,所以它会被赋予默认值 4
。而 d
由于有默认值,也会被赋值为 4
。如果数组中有第四个元素,d
将会使用数组中的值而不是默认值。
通过这种方式,数组解构赋值提供了一种简洁且灵活的方法来处理数组数据,使得代码更加直观和易于管理。
2.3.2. 对象解构赋值
对象解构赋值是JavaScript中一种强大的语法特性,它允许你从对象中提取属性并赋值给变量。这种特性使得代码更加简洁和易于理解。
- 基本对象解构赋值
假设我们有一个对象 {a: 1, b: 2}
,我们想要将这个对象中的 a
属性的值赋给变量 a
,b
属性的值赋给变量 b
。使用对象解构赋值,我们可以这样做:
let {a, b} = {a: 1, b: 2};
这行代码的意思是:创建两个变量 a
和 b
,并将对象中的 a
属性的值(1)赋值给变量 a
,将对象中的 b
属性的值(2)赋值给变量 b
。之后,你可以通过 console.log
来查看这些变量的值:
console.log(a); // 输出 1
console.log(b); // 输出 2
- 为变量指定不同的名称
有时候,你可能希望变量的名称与对象的属性名称不同。在这种情况下,你可以在对象解构赋值中使用冒号 :
来为变量指定一个新的名称。新名称将用于创建变量,而原属性名将被用来从对象中获取值。
例如,如果我们想要将 a
属性的值赋给一个名为 x
的变量,将 b
属性的值赋给一个名为 y
的变量,我们可以这样做:
let {a: x, b: y} = {a: 1, b: 2};
这里,x
和 y
是新创建的变量,它们的值分别来自于对象 {a: 1, b: 2}
中的 a
和 b
属性。所以,x
的值是 1,y
的值是 2。你可以使用 console.log
来查看变量的值:
console.log(x); // 输出 1
console.log(y); // 输出 2
对象解构赋值不仅使得代码更加简洁,而且提高了代码的可读性和维护性。
2.3.3. 函数参数解构赋值
函数参数解构赋值是JavaScript中一种在函数定义时,直接从传递给函数的参数中提取数据并赋给特定变量的方法。这种方式可以让我们在函数内部更容易地处理参数,并且使得函数调用更加灵活和直观。
- 基本的函数参数解构赋值
假设我们有一个函数 add
,它的目的是用来计算两个数的和。在不使用解构赋值的情况下,我们可能会这样定义这个函数:
function add(array) {
var x = array[0];
var y = array[1];
return x + y;
}
add([1, 2]); // 返回 3
现在,我们可以使用参数解构赋值来简化这个过程。我们只需要在函数定义的参数列表中,按照数组解构赋值的语法来指定参数名即可:
function add([x, y]) {
return x + y;
}
add([1, 2]); // 返回 3
在这个例子中,add
函数接受一个数组作为参数。当调用 add([1, 2])
时,数组 [1, 2]
中的第一个元素(1)会被赋值给参数列表中的 x
,第二个元素(2)会被赋值给 y
。然后函数内部直接使用这两个变量来计算它们的和并返回结果。
- 为什么使用函数参数解构赋值
使用函数参数解构赋值有几个好处:
- 代码简洁:解构赋值让函数的参数列表更加简洁,易于阅读。
- 提高可读性:通过在参数列表中直接使用变量名,你可以清楚地知道函数接收的是什么数据,以及如何使用这些数据。
- 减少错误:解构赋值确保了函数接收到正确数量和类型的参数。如果传入的参数不符合预期,将会抛出错误。
2.4. 箭头函数
箭头函数是ES6(ECMAScript 2015)引入的一种新的函数语法,它提供了一种更简洁的方式来编写函数表达式。箭头函数的语法比传统的函数表达式或函数声明更简短,并且它们在处理 this
关键字时有一些独特的行为。它和 Java 中的 lambda 表达式类似。
2.4.1. 箭头函数的基本语法
- 无参数的函数
- 传统函数形式:
let fn1 = function() {
// 函数体
};
- 箭头函数形式:
let fn1 = () => {
// 函数体
};
- 单个参数的函数
- 传统函数形式:
let fn2 = function(x) {
// 函数体
};
- 箭头函数形式:
let fn2 = (x) => {
// 函数体
}
// 或者这样
let fn2 = x => {
// 函数体
};
注意:在箭头函数中,当只有一个参数时,可以省略参数周围的括号。
- 多个参数的函数
- 传统函数形式:
let fn3 = function(x, y) {
// 函数体
};
- 箭头函数形式:
let fn3 = (x, y) => {
// 函数体
};
- 函数体只有一条语句的函数
- 传统函数形式:
let fn4 = function(x) {
console.log(x);
};
- 箭头函数形式:
let fn4 = x => {
console.log(x);
}
// 或者这样
let fn4 = x => console.log(x);
在这里,由于箭头函数的函数体只有一条语句,我们可以省略花括号和 return
语句。
- 函数体是一条返回值语句的函数
- 传统函数形式:
let fn5 = function(x) {
return x + 1;
};
- 箭头函数形式:
let fn5 = x => x + 1;
同样地,由于箭头函数的函数体只有一条语句,这里是一个返回值的表达式,我们可以省略花括号和 return
语句。
通过这些对比示例,你可以看到箭头函数在语法上更加简洁,尤其是在没有参数或只有一个参数时,以及当函数体只包含一个表达式时。然而,需要注意的是,箭头函数不适用于需要多条语句或需要使用 this
、arguments
、new.target
等关键字的复杂函数,这些情况下应使用传统的函数表达式或函数声明。
2.4.2. 箭头函数的特点
- 简洁的语法:箭头函数的语法比传统的函数表达式更简洁,特别是当你有一个简单的函数时,你可以省略
function
关键字和return
语句。 - this 关键字的特殊行为:在普通的函数中,
this
关键字的值取决于函数的调用方式。然而,在箭头函数中,this
关键字的值在函数定义时就已经确定,并且它指向定义时的上下文环境。这意味着箭头函数不绑定自己的this
,它们捕获其所在上下文的this
值。
举个例子
想象一下,你在一个大城市里有一个广播站,这个广播站可以发送消息给整个城市。现在,你有两个人,一个是普通市民,另一个是广播员。
- 普通市民(普通函数)
当普通市民想要发送消息时,他需要直接去广播站。每次他去广播站,广播站都会检查是谁来了,然后根据这个市民的身份发送消息。所以,每次普通市民去广播站,消息的内容都可能不一样,这取决于是谁去的。
在JavaScript中,普通函数就像是普通市民。每次函数被调用时,JavaScript都会检查是谁调用了这个函数,然后 this 就会指向那个调用者。
- 广播员(箭头函数)
而广播员有特殊的权限,他们不需要去广播站就可以发送消息。他们有一个特殊的设备,可以让他们在家里就能发送消息。这个设备很特别,因为它总是记得广播员第一次使用它时广播站的位置。所以,不管广播员在哪里,他们发送的消息都会和他们第一次使用设备时的广播站有关。
在JavaScript中,箭头函数就像是广播员。this 的值在箭头函数创建的时候就已经被设定了,而且不会改变。不管箭头函数在哪里被调用,this 总是指向函数创建时的环境。
// 假设这是在城市中心,也就是全局作用域
let cityCenter = {
message: "Hello from the city center!"
};
// 普通市民(普通函数)
function announce() {
console.log(this.message); // 这里输出的是 "Hello from the city center!",因为这是在 cityCenter 对象内部调用的
}
// 广播员(箭头函数)
let broadcast = () => {
console.log(this.message); // 这里输出的也是 "Hello from the city center!",因为箭头函数记得它被创建时的环境
};
// 现在我们把 announce 和 broadcast 函数放到另一个对象里
let newsStation = {
announce: announce,
broadcast: broadcast
};
// 现在我们通过 newsStation 调用这两个函数
newsStation.announce(); // 输出 "Hello from the city center!"
newsStation.broadcast(); // 依然输出 "Hello from the city center!",即使它是箭头函数
在这个例子中,无论是普通函数 announce 还是箭头函数 broadcast,它们都输出了相同的消息。这是因为箭头函数 broadcast 记住了它被创建时的环境(城市中心),即使它后来被放在了 newsStation 对象里。而普通函数 announce 则是因为它是在 cityCenter 对象内部被调用的,所以 this 指向了 cityCenter。
2.4.3. 应用场景
箭头函数特别适合用于那些不需要自己的 this
绑定,且需要简洁语法的场合。例如,在设置定时器或使用回调函数时,箭头函数可以让代码更加清晰:
function Counter() {
this.count = 0;
setInterval(() => {
this.count++; // 这里的 this 指向 Counter 构造函数的实例化对象
console.log(this.count);
}, 1000);
}
let counter = new Counter();
在这个例子中,我们使用箭头函数来定义定时器的回调函数,这样 this
就指向了外部的 Counter
实例化对象,而不是全局对象或 undefined。
2.4.4. rest和spread
JavaScript中的rest参数和spread操作符都是为了让我们能够更方便地处理函数参数和数组
- Rest 参数
举个例子
想象一下,你要举办一个聚会,你可以邀请任意数量的朋友。在JavaScript中,你可以创建一个函数,就像你的聚会一样,它可以接收任意数量的“朋友”(参数)。
function myParty( ...friends ) {
console.log("欢迎", friends);
}
当你调用这个函数时,你可以传入任意数量的名字:
myParty("小明", "小红"); // 输出: 欢迎 ["小明", "小红"]
myParty("小明", "小红", "小刚", "小丽"); // 输出: 欢迎 ["小明", "小红", "小刚", "小丽"]
在这里,...friends 就是rest参数,它表示函数可以接收任意数量的参数,并将它们作为一个数组处理。
Rest参数使用三个点(...)作为前缀,它允许我们表示一个不确定数量的参数。这意味着你可以传递任意数量的参数给一个函数,这些参数会被收集到一个数组中。这个特性在你需要创建一个可以接受任意数量参数的函数时非常有用。
例如,你可以定义一个函数来计算任意数量数字的总和:
function sum(...numbers) {
return numbers.reduce((total, num) => total + num, 0);
}
console.log(sum(1, 2, 3, 4, 5)); // 输出:15
在这个例子中,...numbers就是一个rest参数,它可以接收任意数量的数字,并将它们作为数组处理。
- spread
举个例子
现在,假设你有两袋糖果,你想把它们合并到一个袋子里。在JavaScript中,你可以使用spread操作符来“展开”一袋糖果中的所有糖果到另一个袋子中。
let bag1 = ["糖果1", "糖果2"];
let bag2 = ["糖果3", ...bag1]; // 我们将bag1中的糖果展开到bag2中
console.log(bag2); // 输出: ["糖果3", "糖果1", "糖果2"]
在这个例子中,...bag1 是spread操作符的使用,它将bag1中的所有糖果展开并添加到bag2数组中。
Spread操作符也是使用三个点(...),但它的作用是在对象或数组的上下文中“展开”它们。这意味着你可以将一个数组或对象的所有可枚举属性放入到另一个数组或对象中。
例如,如果你想复制一个数组并添加一些额外的元素,你可以这样做:
let originalArray = [1, 2, 3];
let newArray = [...originalArray, 4, 5];
console.log(newArray); // 输出:[1, 2, 3, 4, 5]
在这个例子中,...originalArray使用spread操作符将originalArray中的所有元素展开,然后添加了额外的元素4和5到新数组newArray中。
同样的,spread操作符也可以用于对象:
let originalObject = { a: 1, b: 2 };
let newObject = { c: 3, ...originalObject };
console.log(newObject); // 输出:{ c: 3, a: 1, b: 2 }
在这个例子中,...originalObject将originalObject的所有属性展开并添加到newObject中。
2.5. 对象创建与拷贝
2.5.1. 对象创建的语法糖
- 语法糖
在JavaScript的ES6版本中,"语法糖"一词通常用来描述那些让代码看起来更像传统面向对象编程语言(如Java或C#)的新特性,尽管JavaScript本质上是一种基于原型的脚本语言。这些特性让开发者能够以一种更熟悉和直观的方式来编写对象和类的代码。
- ES6中的对象创建相关的语法糖
- 类(Class): 类是JavaScript中的一种新的语法糖,它提供了一种更加清晰和简洁的方式来定义对象的模板。类可以包含属性和方法,并且可以通过extends关键字实现继承。
- 构造器(Constructor): 在类中,构造器是一个特殊的方法,当创建一个新的实例时会自动调用。它通常用来初始化对象的属性。
- 私有属性(Private Properties): 私有属性使用#前缀标识,它们只能在类的内部访问和修改,不能被外部直接访问。这有助于保护对象的内部状态,防止外部的直接修改。
- 访问器(Accessors): 访问器包括 getter 和 setter 方法,它们允许你控制对对象属性的读取(get)和写入(set)。在你的例子中,name属性通过getter和setter方法来控制对其的访问。
- 继承(Inheritance): 通过extends关键字,一个类可以继承另一个类的属性和方法。子类可以覆盖父类的方法,也可以添加新的方法和属性。
- 静态方法(Static Methods): 静态方法是类的方法,而不是实例的方法。它们可以在不创建类的实例的情况下调用,并且不会接收类的实例作为隐式参数。
- 代码示例
// 定义一个Person类,包含属性、方法和构造器
class Person {
// 私有属性,只能在类的内部使用
#n;
age;
// 获取器和设置器控制name属性的访问
get name() {
return this.#n;
}
set name(n) {
this.#n = n;
}
// 实例方法,可以被对象实例调用
eat(food) {
console.log(this.age + "岁的" + this.#n + "用筷子吃" + food);
}
// 静态方法,可以在不创建实例的情况下调用
static sum(a, b) {
return a + b;
}
// 构造器,用于初始化对象的属性
constructor(name, age) {
this.#n = name; // 使用私有属性
this.age = age;
}
}
// 使用new关键字创建Person类的实例
let person = new Person("张三", 10);
// 访问对象的属性和方法
console.log(person.name); // 通过getter访问name属性
console.log(person.#n); // 错误,私有属性不能在类外部直接访问
person.name = "小明"; // 通过setter设置name属性
console.log(person.age); // 访问age属性
person.eat("火锅"); // 调用实例方法eat
// 调用静态方法sum
console.log(Person.sum(1, 2));
// 定义一个Student类,继承自Person类
class Student extends Person {
grade;
score;
study() {
// 方法的实现
}
// 构造器,调用父类的构造器来初始化继承的属性
constructor(name, age) {
super(name, age);
}
}
// 创建Student类的实例
let stu = new Student("学生小李", 18);
stu.eat("面条"); // 调用从父类继承来的实例方法eat
2.5.2. 对象的深拷贝和浅拷贝
- 对象拷贝
在编程中,有时候我们需要复制一个对象,创建一个新的对象,这个新对象和原始对象有着相同的属性和值,但是它们是完全独立的,对一个对象的修改不会影响到另一个对象。这就是对象拷贝的目的。
- 浅拷贝(Shallow Copy)
浅拷贝是指创建一个新的对象,但是这个新对象的属性指向的是原始对象中属性的引用。换句话说,如果原始对象的属性是一个基本数据类型(如字符串、数字、布尔值),那么新对象将会有一个与原始对象相同的值;如果原始对象的属性是一个复合类型(如数组、对象),那么新对象将会“共享”原始对象中的引用,而不是创建一个新的副本。
举个例子,我们有一个包含姓名和语言数组的对象person,如果我们对person进行浅拷贝,创建一个新的对象person2,那么person2的name属性会有一个新值,但是language属性仍然是指向同一个数组。所以,如果我们修改person2的name属性为"小黑",那么person的name属性不会改变,但是如果我们修改person2的language数组,那么person的language数组也会发生变化,因为它们引用的是同一个数组。
<script>
let arr =['java','c','python']
let person ={
name:'张三',
language:arr
}
// 浅拷贝, person2和person共享同一个language数组
// 换句话说, person2和person指向相同的内存
let person2 = person;
person2.name="小黑"
console.log(person.name) // 输出 "小黑"
person2.language.push('javascript')
console.log(person.language) // 输出 ["java", "c", "python", "javascript"]
</script>
- 深拷贝(Deep Copy)
深拷贝是指创建一个新的对象,并且这个新对象和原始对象的属性没有任何引用关系。也就是说,如果原始对象的属性是一个复合类型,深拷贝会递归地拷贝这些属性,直到所有的属性都变成了新对象的属性,而不是原始对象的引用。
继续上面的例子,如果我们对person进行深拷贝,创建一个新的对象person2,那么person2将会有一个全新的language数组,与person的language数组完全独立。所以,即使我们修改person2的language数组,person的language数组也不会受到影响。
<script>
let arr =['java','c','python']
let person ={
name:'张三',
language:arr
}
// 深拷贝,创建一个全新的language数组
let person2 = JSON.parse(JSON.stringify(person)) // 拷贝person对象
person2.name="小黑"
person2.language.push('javascript')
console.log(person.name) // 输出 "张三"
console.log(person.language) // 输出 ["java", "c", "python"]
console.log(person2.language) // 输出 ["java", "c", "python", "javascript"]
</script>
通过这种方式,深拷贝确保了新对象和原始对象的完全独立性,使得对新对象的任何修改都不会影响到原始对象。这对于保持数据的完整性和避免意外修改原始数据非常有用。
3. 前端工程化环境搭建
3.1. Nodejs
3.1.1. Nodejs 概述
Node.js 是一个非常流行的工具,它允许我们使用 JavaScript 这门语言来编写运行在服务器上的程序。通常,JavaScript 被用来创建网页上的互动效果,但是有了 Node.js,开发者可以利用 JavaScript 来构建整个网络应用程序,包括后端服务器和前端用户界面。
Node.js 的主要优势在于它的非阻塞(异步)处理能力。这意味着,当程序在等待某些任务完成,比如读取文件或者接收网络数据时,它不会停下来等待,而是继续执行其他任务。这样可以大大提高程序处理多个请求的能力,使其非常适合构建需要同时服务很多用户的应用程序。
此外,Node.js 还具有模块化的特点,这意味着我们可以重用其他人编写的代码模块,或者自己编写模块供他人使用。这使得开发过程更加高效,因为我们可以利用社区的力量,而不是每次都从头开始编写所有的代码。
Node.js 还可以在不同的操作系统上运行,包括 Windows、Linux 和 macOS,这使得它具有很好的灵活性和广泛的适用性。
3.1.2. 安装 Nodejs
上链接查看(我曾经自己写的)
Node.js安装及环境配置_node安装与配置-CSDN博客
3.2. npm
3.2.1. npm 概述
npm 是一个帮助开发者在 Node.js 项目中安装和管理代码的工具。你可以把它想象成一个大型的图书馆,里面存放着许多别人已经写好的代码片段,这些代码片段被称为“包”。
使用 npm,你可以很容易地做到:
- 安装包:当你需要某个功能时,你可以告诉 npm,它会帮你找到并安装这个功能。
- 管理包:如果你的项目中用到了很多包,npm 会帮你跟踪这些包,确保它们都是你需要的版本。
- 分享你的代码:如果你写了一些有用的代码,你也可以通过 npm 分享给其他开发者使用。
简单来说,npm 就是一个让 Node.js 开发更简单、更高效的工具,相当于后端的Maven。
3.2.2. npm 安装和配置
- 安装
安装node,自动安装npm包管理工具
- 配置依赖下载使用阿里镜像
更换阿里镜像
npm 安装依赖包时默认使用的是官方源,由于国内网络环境的原因,有时会出现下载速度过慢的情况。为了解决这个问题,可以配置使用阿里镜像来加速 npm 的下载速度
npm config set registry https://registry.npmmirror.com
注意:老域名 http://npm.taobao.org 和 http://registry.npm.taobao.org 将于 2022 年 05 月 31日零时起停止服务。所以老命令也不要使用了:
npm config set registry http://npm.taobao.org
npm config set registry http://registry.npm.taobao.org
查看当前配置源
npm get registry
如果输出结果为 https://registry.npmmirror.com,说明配置已成功生效。
3.2.3. npm常用指令
先挖个坑,等我把相关博客写完了更新链接(`・ω・´)
4. Vue3简介和快速体验
4.1. Vue3 概述
Vue.js 是一个流行的前端 JavaScript 框架,它旨在帮助开发者以一种简单而高效的方式构建用户界面。Vue 的核心优势在于它的声明式渲染和响应性,这两个特性使得开发者能够更加专注于应用逻辑,而不是底层的 DOM 操作。
- 声明式渲染:
- 所谓声明式渲染,是指开发者可以通过简洁的模板语法来描述界面应该如何根据数据变化而变化。在 Vue 中,你可以使用特殊的标签和指令来告诉框架,当数据发生变化时,应该如何更新 HTML 元素。这种方式让开发者无需手动操作 DOM,从而提高了开发效率和代码的可维护性。
- 举个例子,假设你有一个变量
message
,它的值是 "Hello Vue!"。在 Vue 的模板中,你可以直接使用{{ message }}
来显示这个变量的值。当message
的值发生变化时,Vue 会自动更新显示在页面上的内容,而无需你手动去操作 DOM。
- 响应性:
- Vue 的响应性系统意味着当应用的状态发生变化时,界面会自动更新以反映这些变化。这是通过 Vue 的响应式系统实现的,它会追踪数据对象的属性变化,并在检测到变化时触发相应的更新。
- 举个例子,如果你有一个名为
count
的响应式变量,初始值为 0。当你调用一个增加count
的函数时,Vue 会自动更新所有依赖于count
的地方,比如显示在页面上的数字。这样,你就可以专注于业务逻辑,而不用担心视图的更新。
Vue.js 还提供了组件系统、过渡效果、事件处理等其他功能,使得开发者可以构建模块化、可复用的 UI 组件,并通过过渡效果增强用户体验。同时,Vue 也易于上手,拥有良好的文档和社区支持,是初学者和专业开发者的理想选择。
4.2. Vue3 快速体验(非工程化方式)
<!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>
<!-- 这里也可以用浏览器打开连接,然后将获得的文本单独保存进入一个vue.js的文件,导入vue.js文件即可 -->
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<div id="app">
<!-- 给style属性绑定colorStyle数据 -->
<!-- {{插值表达式 直接将数据放在该位置}} -->
<h1 v-bind:style="colorStyle">{{headline}}</h1>
<!-- v-text设置双标签中的文本 -->
<p v-text="article"></p>
<!-- 给type属性绑定inputType数据 -->
<input v-bind:type ="inputType" value="helloVue3"> <br>
<!-- 给按钮单击事件绑定函数 -->
<button @click="sayHello()">hello</button>
</div>
<script>
//组合api
const app = Vue.createApp({
// 在setup内部自由声明数据和方法即可!最终返回!
setup(){
//定义数据
//在VUE中实现DOM的思路是: 通过修改修数据而影响页面元素
// vue3中,数据默认不是响应式的,需要加ref或者reactive处理,后面会详细讲解
let inputType ='text'
let headline ='hello vue3'
let article ='vue is awesome'
let colorStyle ={'color':'red'}
// 定义函数
let sayHello =()=>{
alert("hello Vue")
}
//在setup函数中,return返回的数据和函数可以在html使用
return {
inputType,
headline,
article,
colorStyle,
sayHello
}
}
});
//挂载到视图
app.mount("#app");
</script>
</body>
</html>
5. Vue3通过Vite实现工程化
这部分建议结合视频一起看
134.Vue3_Vite构建工程化前端项目_哔哩哔哩_bilibili
5.1. Vite 概述
Vite 是一个现代的前端构建工具,它旨在解决在开发大型应用时遇到的一些性能问题。
Vite 的关键点
- ES 模块支持:随着现代浏览器开始支持 ES 模块,Vite 利用这一特性,允许开发者以模块化的方式直接在浏览器中运行 JavaScript 代码,而无需传统的打包过程。
- 性能提升:传统的打包工具(如 webpack、Rollup 和 Parcel)在处理大型项目时可能会变得缓慢,因为它们需要处理大量的模块并生成一个庞大的打包文件。Vite 通过避免在开发过程中进行打包,从而显著提高了开发服务器的启动速度和响应速度。
- 模块热替换(HMR):尽管传统的打包工具也支持 HMR,但 Vite 通过更高效的实现,使得在代码修改后,浏览器中的更新几乎可以即时反映出来,提供了更快的反馈循环。
- 利用编译型语言:Vite 内部使用了一些用编译型语言(如 Rust)编写的工具,这些工具相比传统的 JavaScript 工具在性能上有很大的提升。
前端工程化的作用
- 快速项目搭建:使用前端工程化工具(如脚手架)可以快速生成项目的基础结构,避免了从零开始搭建项目的繁琐过程。
- 统一规范:工程化工具可以帮助团队建立统一的代码规范、项目结构和工作流程,这样不同的开发者可以遵循相同的规则进行开发,提高了团队协作的效率。
- 代码复用:工程化工具通常包含一些常用的代码模板和组件库,使得开发者可以轻松地复用已有的代码,避免了重复劳动。
- 自动化构建与部署:前端工程化工具可以自动完成代码的打包、压缩、合并等构建任务,并且可以集成自动化部署流程,简化了从开发到上线的过程。
简而言之,Vite 是一个利用现代浏览器特性来提升开发体验的构建工具,而前端工程化则是一系列旨在提高开发效率、统一开发规范、促进代码复用和自动化构建部署的实践和工具。
5.2. Vite创建Vue3工程化
5.2.1. 项目的创建、启动、停止
5.2.1.1. 创建一个项目
使用 VScode 打开 / 创建 一个空白文件夹
~ + Shift + Ctrl 键打开终端,并输入以下代码
npm create vite@latest
第一次使用vite时会提示下载vite,输入y回车即可,下次使用vite就不会出现了
设置项目名称,也可以默认选择 vite-project
选择vue+JavaScript选项即可
5.2.1.2. 启动一个项目
根据提示输入以下代码,即可运行一个基本基于 vite 的 vue3 项目
cd vite-project
npm install
npm run dev
cd vite-projectcd 是 "change directory" 的缩写,用于改变当前工作目录。vite-project 是一个假设的项目文件夹名称,这个命令的意思是要你切换到名为 vite-project 的目录中。这通常是你存放项目文件的地方。
npm installnpm 是 Node.js 的包管理器,install 命令用于根据项目根目录下的 package.json 文件中定义的依赖关系,自动下载并安装所有需要的依赖包。这个过程是项目设置的一部分,确保你的项目拥有所有运行所需的库和模块。
npm run dev这个命令是用来启动项目的 "开发模式"。npm run 是 npm 的一个功能,允许你运行在 package.json 文件的 scripts 部分定义的脚本。dev 是脚本的名称,通常是 "development" 的缩写,表示这是一个用于开发环境的脚本。这个脚本可能配置了 Vite 或其他构建工具来启动一个本地开发服务器,使得你可以在浏览器中实时查看和调试你的代码更改。
Ctrl + 鼠标左键对应的地址,即可浏览器打开项目
5.2.1.3. 停止一个项目
- 命令行上 ctrl+c
5.2.2. 项目的结构
相关视频链接
136.Vue3_工程结构和单文件组件概念_哔哩哔哩_bilibili
5.2.2.1. Vite 项目结构
- .vscode:表示现在用的是VS code这款软件来开发项目的。
- node_modules:前端框架依赖,依赖文件所存储的目录。
- public/ 目录:用于存放一些公共资源,如 HTML 文件、图像、字体等,这些资源会被直接复制到构建出的目标目录中。
- src/ 目录:存放项目的源代码,包括 JavaScript、CSS、Vue 组件、图像和字体等资源。在开发过程中,这些文件会被 Vite 实时编译和处理,并在浏览器中进行实时预览和调试。以下是src内部划分建议:
-
assets/
目录:用于存放一些项目中用到的静态资源,如图片、字体、样式文件等。components/
目录:用于存放组件相关的文件。组件是代码复用的一种方式,用于抽象出一个可复用的 UI 部件,方便在不同的场景中进行重复使用。layouts/
目录:用于存放布局组件的文件。布局组件通常负责整个应用程序的整体布局,如头部、底部、导航菜单等。pages/
目录:用于存放页面级别的组件文件,通常是路由对应的组件文件。在这个目录下,可以创建对应的文件夹,用于存储不同的页面组件。plugins/
目录:用于存放 Vite 插件相关的文件,可以按需加载不同的插件来实现不同的功能,如自动化测试、代码压缩等。router/
目录:用于存放 Vue.js 的路由配置文件,负责管理视图和 URL 之间的映射关系,方便实现页面之间的跳转和数据传递。store/
目录:用于存放 Vuex 状态管理相关的文件,负责管理应用程序中的数据和状态,方便统一管理和共享数据,提高开发效率。utils/
目录:用于存放一些通用的工具函数,如日期处理函数、字符串操作函数等。
- vite.config.js 文件:Vite 的配置文件,可以通过该文件配置项目的参数、插件、打包优化等。该文件可以使用 CommonJS 或 ES6 模块的语法进行配置。
- package.json 文件:标准的 Node.js 项目配置文件,包含了项目的基本信息和依赖关系。其中可以通过 scripts 字段定义几个命令,如 dev、build、serve 等,用于启动开发、构建和启动本地服务器等操作。
- Vite 项目的入口为 src/main.js 文件,这是 Vue.js 应用程序的启动文件,也是整个前端应用程序的入口文件。在该文件中,通常会引入 Vue.js 及其相关插件和组件,同时会创建 Vue 实例,挂载到 HTML 页面上指定的 DOM 元素中。
main.js 代码
/**
* 创建并挂载 Vue 应用
*
* 本脚本执行以下操作:
* 1. 导入 Vue 创建应用的函数和应用的样式。
* 2. 创建 Vue 应用实例,并指定应用的根组件。
* 3. 将应用实例挂载到 HTML 页面中指定的元素上。
*/
import { createApp } from 'vue' // 导入 Vue 创建应用的函数
import './style.css' // 导入并应用应用的全局样式
import App from './App.vue' // 导入应用的根组件
// 创建 Vue 应用实例,并将根组件挂载到页面中 id 为 'app' 的元素上
createApp(App).mount('#app')
5.2.2.2. vite的运行界面
- npm scripts
package.json
文件中的 scripts
部分是定义命令的地方,这些命令可以通过在终端中运行 npm run <script-name>
来执行。这是一些常用的 npm scripts:
"dev"
:这个命令启动一个开发服务器。当你在开发过程中对代码做出更改时,服务器会自动重新加载页面,让你立即看到更改的效果。"build"
:这个命令用于准备将你的应用程序部署到生产环境。它会优化你的代码,比如压缩文件、提取 CSS、合并 JavaScript 等,以提高应用程序的性能。"preview"
:这个命令允许你查看生产环境中构建的应用程序。这通常是在部署之前,确保一切都按预期工作。
- 配置文件
vite.config.js
vite.config.js
是 Vite 的配置文件,它允许你自定义 Vite 的行为。以下是一些常见的配置:
plugins
:这里可以添加插件,扩展 Vite 的功能。server
:这个对象包含了服务器的配置。例如,server.port
允许你设置开发服务器使用的端口号。
默认情况下,Vite 使用 3000 端口启动开发服务器。如果你的 3000 端口已经被其他服务占用,或者你只是想改变这个端口,你可以在 vite.config.js
文件中修改它:
export default defineConfig({
plugins: [vue()],
server: {
port: 3000 // 这里将端口号设置为 3000
}
});
在这个配置中,vue()
是一个插件,用于支持 Vue 单文件组件。port: 3000
表示开发服务器将在 3000 端口上运行。
package.json
中的scripts
允许你定义可执行的命令。"dev"
命令启动开发服务器。"build"
命令准备生产环境的构建。"preview"
命令预览生产构建。vite.config.js
是 Vite 的配置文件,可以自定义 Vite 的行为,如设置端口号。
5.2.3. 关于JS和TS选择的问题
在前端开发中,我们面临一个选择:是使用 JavaScript (JS) 还是使用 TypeScript (TS) 进行编程。TypeScript 是 JavaScript 的一个增强版,它添加了一些新的特性,让代码更加结构化和易于维护。
- 降低难度和提高效率:选择 JavaScript 是为了简化开发过程。JavaScript 作为基础语言,学习起来更直接,不需要额外的概念和规则。这可以帮助我们更快地开始项目和完成任务。
- 学习曲线:虽然 TypeScript 对于有 Java 等静态类型语言背景的人来说相对容易学习,但它仍然需要投入时间来掌握。对于初学者来说,首先专注于 JavaScript 可以避免一开始就面对太多复杂的概念。
- 灵活性:TypeScript 不是强制性的选择。即使不使用 TypeScript,我们仍然可以使用 JavaScript 来完成前端工程化项目的开发。这意味着我们可以根据项目的需要和团队的熟悉程度来决定是否采用 TypeScript。
总结来说,对于初学者,建议首先专注于学习 JavaScript,因为它是前端开发的基础,学习起来相对简单,可以快速上手。在掌握了前端开发的基本概念和技能之后,可以根据项目的需要和个人兴趣,再学习 TypeScript,以增加代码的类型安全性和可维护性。这样的学习路径可以帮助我们逐步建立前端开发的知识体系,避免一开始就陷入复杂的技术细节。
5.2.4. 项目组件(SFC入门)
此章节建议结合视频一起学习
136.Vue3_工程结构和单文件组件概念_哔哩哔哩_bilibili
- Vue组件是什么?
在Vue中,组件是构成应用程序的基本单元。你可以将组件想象成一个可重用的小部件,它有自己的HTML结构、样式和逻辑。每个组件都可以独立于其他组件存在,并且可以在多个地方重复使用。
举个例子,想象一下你在玩乐高积木。每个积木块都是独立的,可以拼在一起构建更复杂的模型。在Vue中,组件就像这些乐高积木块。每个组件都是网页上的一个小部分,比如一个按钮、一个图片展示或者一个表单输入框。你可以在网页上多次使用同一个组件,就像多次使用同一个乐高积木块一样。
- .vue文件是什么?
在传统的Web开发中,HTML、CSS和JavaScript通常分布在不同的文件中。Vue通过.vue文件格式,将这三种技术整合到一个文件中,这种格式称为单文件组件(Single-File Component, SFC)。一个.vue文件由三个主要部分组成:
- <template>:这部分包含组件的HTML结构,相当于传统的HTML文件。
- <script>:这部分包含组件的JavaScript逻辑,相当于传统的JavaScript文件。
- <style>:这部分包含组件的CSS样式,相当于传统的CSS文件。
.vue文件里面看起来像这样:
<template>
<!-- 这里是HTML结构 -->
</template>
<script>
// 这里是JavaScript代码
</script>
<style>
/* 这里是CSS样式 */
</style>
- Vue项目的组件是如何组织的?
一个Vue项目通常包含以下关键文件和结构:index.html / main.js / App.vue
- index.html:这是项目的入口点,其中包含一个特殊的<div>元素,用于“挂载”Vue应用。挂载意味着Vue将在这个<div>元素内开始管理页面的部分内容。
<!doctype html>
<html lang="en">
<head>
<!-- 定义文档类型和语言 -->
<meta charset="UTF-8" />
<!-- 设置页面的图标 -->
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<!-- 设置页面在不同设备上的显示方式 -->
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<!-- 页面标题 -->
<title>Vite + Vue</title>
</head>
<body>
<!-- 应用程序容器 -->
<div id="app"></div>
<!-- 引入应用程序的主JS文件 -->
<script type="module" src="/src/main.js"></script>
</body>
</html>
- main.js:这是一个JavaScript文件,它负责创建Vue应用实例,并指定挂载点(即上面提到的<div>元素)。此外,它还负责导入项目所需的其他依赖和组件。
/**
* 创建并挂载 Vue 应用
*
* 本脚本执行以下操作:
* 1. 导入 Vue 创建应用的函数和应用的样式。
* 2. 创建 Vue 应用实例,并指定应用的根组件。
* 3. 将应用实例挂载到 HTML 页面中指定的元素上。
*/
import { createApp } from 'vue' // 导入 Vue 创建应用的函数
import './style.css' // 导入并应用应用的全局样式
import App from './App.vue' // 导入应用的根组件
// 创建 Vue 应用实例,并将根组件挂载到页面中 id 为 'app' 的元素上
createApp(App).mount('#app')
- App.vue:这是项目的根组件,可以认为是整个应用的“容器”。所有其他的组件都会通过这个组件导入,并根据需要显示。
- 总结
- Vue组件是构成应用程序的可重用单元,每个组件都有自己的结构、样式和逻辑。
- .vue文件是Vue的单文件组件格式,它将HTML、CSS和JavaScript整合在一个文件中。
- Vue项目通过index.html作为入口点,main.js用于创建Vue应用实例并指定挂载点,App.vue作为根组件。
5.2.5. css 样式导入方式
该部分的相关视频链接
138.Vue3_关于CSS样式的导入方式_哔哩哔哩_bilibili
5.2.5.1. 在单个.vue
文件内
这种方式是最简单的,你只需要在.vue
文件的<style>
标签中编写CSS代码。这些样式只会应用到这个.vue
文件内的元素。
<template>
<div>
<span class="greeting">你好!</span>
</div>
</template>
<script>
export default {
name: 'MyComponent',
};
</script>
<style scoped>
.greeting {
color: blue;
font-size: 20px;
}
</style>
在上面的例子中,scoped
属性确保了样式只应用于这个组件内的元素。
5.2.5.2. 在独立的CSS文件中
你可以创建一个CSS文件,比如styles.css
,然后在需要的.vue
文件中导入它。
a. 使用<script>
标签导入
<template>
<div>
<span class="greeting">你好!</span>
</div>
</template>
<script>
import './styles.css'; // 导入CSS文件
export default {
name: 'MyComponent',
};
</script>
b. 使用<style>
标签导入
<template>
<div>
<span class="greeting">你好!</span>
</div>
</template>
<script>
export default {
name: 'MyComponent',
};
</script>
<style>
@import './styles.css'; /* 导入CSS文件 */
</style>
注意:在使用<style>
标签导入时,你需要使用@import
规则。
5.2.5.3. 全局样式的导入
如果你想让某个CSS样式在应用的所有组件中都生效,可以在应用的入口文件(通常是main.js
或main.ts
)中导入。
import { createApp } from 'vue';
import App from './App.vue';
import './global-styles.css'; // 导入全局CSS文件
const app = createApp(App);
app.mount('#app');
在这个例子中,global-styles.css
中的样式将应用到整个应用的任何地方。
5.2.6. 响应式入门和setup函数
相关视频
139.Vue3_响应式数据和setup语法糖_哔哩哔哩_bilibili
- 响应式系统
在Vue中,响应式系统允许你创建数据,当这些数据变化时,Vue会自动更新DOM(文档对象模型,即网页的HTML结构)以反映这些变化。
Vue 2与Vue 3的响应式差异:
- Vue 2:在Vue 2中,当你在组件的
data
选项中声明数据时,这些数据默认就是响应式的。 - Vue 3:在Vue 3中,基础的JavaScript数据类型(如数字、字符串、布尔值)不再是默认响应式的。你需要使用特定的方法来创建响应式的数据。这就是
ref
和reactive
的用途。
ref
函数
ref
是Vue 3中用于创建响应式引用的一个函数。它返回一个响应式引用对象,你可以通过.value
属性来获取或修改它的值。
let counter = ref(1); // 创建一个初始值为1的响应式引用
当你在JavaScript代码中修改这个值时,你需要使用.value
来修改它:
function increase() {
counter.value++; // 通过.value来修改响应式引用的值
}
然而,当你在模板中使用这个响应式引用时,你不需要.value
:
<template>
<div>
<button @click="decrease">-</button>
{{ counter }} <!-- 直接使用,Vue 3会自动处理 -->
<button @click="increase">+</button>
</div>
</template>
Vue 3会处理counter
的显示,使其在变化时自动更新DOM。
<script setup>
<script setup>
是Vue 3.0推出的一种新的语法糖,它允许你直接在<script>
标签中写组件的逻辑,而不需要编写export default
。
使用<script setup>
之前:
<script>
import { ref } from 'vue';
export default {
setup() {
let counter = ref(1);
function increase() {
counter.value++;
}
// ...
return {
counter,
increase,
// ...
};
},
};
</script>
使用<script setup>
之后:
<script setup>
import { ref } from 'vue';
let counter = ref(1);
function increase() {
counter.value++;
}
// 这里的变量和函数可以直接在模板中使用,无需return
</script>
使用<script setup>
后,你不需要在setup
函数中返回对象,因为所有的变量和函数都默认是可被模板访问的。
总结
- Vue 3中,基础数据类型不是默认响应式的,需要使用
ref
或reactive
来创建响应式数据。 ref
用于创建响应式引用,通过.value
来获取或修改值。<script setup>
提供了一种更简洁的编写组件逻辑的方式,无需编写export default
或在setup
中返回一个对象。
<script setup>
// 存储 Vue 页面逻辑 JavaScript 代码
// 引入 Vue 3 的 `ref` 函数,用于创建响应式数据
import { ref } from "vue";
// 非响应式数据:修改后 Vue 不会更新 DOM
// 响应式数据: 修改后 Vue 会更新 DOM
// Vue 2 中数据默认是响应式的
// Vue 3 中数据要经过 `ref` 或 `reactive` 处理后才是响应式的
// `ref` 是 Vue 3 框架提供的一个函数,用于将普通值包装成响应式引用对象
// 使用 `ref` 创建一个响应式变量 `counter`,初始值为 1
// 注意:对 `ref` 包装的响应式数据进行修改时,需通过 `.value` 属性访问和更新其内部值
let counter = ref(1);
// 增加计数器值的函数,内部通过 `counter.value++` 实现递增
function increase() {
counter.value++;
}
// 减少计数器值的函数,内部通过 `counter.value--` 实现递减
function decrease() {
counter.value--;
}
</script>
<template>
<!-- 组件模板部分 -->
<div>
<!-- 减少按钮,点击时触发 `decrease()` 函数 -->
<button @click="decrease()">-</button>
<!-- 直接在模板中展示 `counter` 值,Vue 会自动追踪并渲染其变化 -->
{{ counter }}
<!-- 增加按钮,点击时触发 `increase()` 函数 -->
<button @click="increase()">+</button>
</div>
</template>
<style scoped>
/* 组件样式部分 */
button {
border: 1px solid red;
}
</style>