一、HTML篇
该文章主要用于自我巩固
1、HTML5新增了那些标签
布局标签、表单元素改进、多媒体标签、图形标签等
(1) 布局标签(语义化标签)
| 标签 | 释义 |
|---|---|
| header | 头部标签 |
| nav | 导航标签 |
| article | 内容标签 |
| section | 定义文档某个区域 |
| aside | 侧边栏标签 |
| footer | 底部标签 |
| main | 主体内容;每个文件只能有一个main标签 |
(2)表单元素的改进
| 标签 | 释义 |
|---|---|
| input | type=“email、data、tel、url” |
| datalist | 提供一个预定义的选项列表给 元素 |
| output | 用于展示计算结果或反馈信息 |
(3)多媒体标签
| 标签 | 释义 |
|---|---|
| video | 用于嵌入视频文件,支持多种格式,如 MP4、WebM、Ogg 等 |
| audio | 用于嵌入音频文件,支持多种格式,如 MP3、OGG 等 |
| track | 用于为 video 或 audio 添加字幕、描述等辅助内容 |
(4)图形标签
| 标签 | 释义 |
|---|---|
| canvas | 用于在网页中绘制图形,通过 JavaScript 绘制图形、动画等 |
| svg | 用于创建可缩放矢量图形,可以绘制图形、路径等 |
(5)其他标签
| 标签 | 释义 |
|---|---|
| progress | 用于显示任务的进度条,常用于文件上传或下载进度等 |
| mark | 用于突出显示文本,通常用于高亮搜索结果 |
2、HTML、XML、XHTML它们之间有什么区别
| 语言 | 中文名 | 说明 |
|---|---|---|
| HTML4 | 超文本标记语言 | 主要用于做界面呈现。HTML是现有实现,后面才慢慢指定标准的导致HTML非常混乱和松散,语法非常不严谨 |
| XML | 可拓展标记语言 | 主要用于存储数据和结构。语法严谨可拓展性强。由于JSON也有类似作用但更轻量高效,XML市场越来越小 |
| XHTML | 可拓展文本标记语言 | 属于HTML加强版,为解决HTML的混乱问题而生在语法方面变得和XML一样严格 |
| HTML5 | 超文本标记语言 | 在HTML的基础上进行的拓展,用于页面的呈现也是目前的标准 |
3、localStorage、sessionStorage、cookie 三者明细区别?
- cookie是网站为了标示用户身份而储存在用户本地终端(Client Side)上的数据(通常经过加密)。
- cookie数据始终在同源的http请求中携带(即使不需要),记会在浏览器和服务器间来回传递。
- sessionStorage和localStorage不会自动把数据发给服务器,仅在本地保存。存储大小虽然也有限制,但比cookie大得多,可以达到5M或更大。
- localStorage 存储持久数据,浏览器关闭后数据不丢失除非主动删除数据;
- sessionStorage 数据在当前浏览器窗口关闭后自动删除。
- cookie 设置的cookie过期时间之前一直有效,即使窗口或浏览器关闭
4、TDK与SEO优化
- TDK :是 Title(标题)、Description(描述)、Keywords(关键词)这三个网页的重要元信息标签,对于 SEO(搜索引擎优化)至关重要。
1、Title(标题):
作用: Title 标签用于定义网页的标题,是搜索引擎显示在搜索结果中的标题文字,同时也是浏览器标签页上显示的标题。
SEO 优化建议:
确保每个网页都有唯一且描述准确的标题,突出页面的主题和关键信息。使用主要关键词在标题中,但避免过度堆砌关键词,保持标题简洁有吸引力。控制标题长度在 50-60 个字符之间,以便在搜索结果中完整显示
2、Description (描述):
作用: Description 标签用于定义网页的描述,是搜索引擎显示在搜索结果中的网页描述文字,帮助用户了解页面内容。
SEO 优化建议:
编写吸引人的描述文本,简洁明了地概括页面内容和亮点,鼓励用户点击访问网页。在描述中包含主要关键词,但不要过度堆砌关键词,保持自然流畅。控制描述长度在 150-160 个字符之间,以便在搜索结果中完整显示。
3、Keywords (关键词):
作用: Keywords 标签曾经被用于定义网页的关键词,但由于被滥用和误解,目前大多数搜索引擎已不再依赖于 Keywords 标签。
SEO 优化建议:
尽管 Keywords 标签的权重较低,但仍可以在其中列出网页的主要关键词,以便搜索引擎了解页面的主题。不要过度堆砌关键词,而是选择适当的关键词集中体现页面的主题和内容。 - SEO优化其他项
img 标签添加 alt - SEO的注意事项
(1)避免使用黑帽SEO技术
黑帽SEO技术是指通过作弊手段提高网站排名的方法。例如,使用关键词堆砌、隐藏链接等手段都是不道德且可能受到搜索引擎惩罚的行为。我们应该始终遵循搜索引擎的规则和道德标准进行SEO优化。
(2)不要过度优化
过度优化是指过度强调关键词的使用或外链的建设等行为。这可能导致搜索引擎认为网站存在作弊行为而对其进行惩罚。我们应该在合理的范围内进行SEO优化,避免过度追求短期效果而忽略长远发展。
(3)SEO是一个长期的过程
SEO是一个需要长期坚持的过程。通过持续优化网站的内容和结构、提高外链的质量和数量等手段,我们可以逐步提高网站的排名和流量。因此,我们应该保持耐心和毅力,持续进行SEO优化工作。
5、iframe
- iframe的缺点:
1、页面样式调试麻烦,出现多个滚动条;
2、浏览器的后退按钮失效;
3、过多会增加服务器的HTTP请求;
4、小型的移动设备无法完全显示框架;
5、产生多个页面,不易管理;
6、不容易打印;
7、代码复杂,无法被一些搜索引擎解读。
8、搜索引擎的检索程序无法解读这种页面,不利于SEO; - iframe的优点:
1、iframe能够原封不动的把嵌入的网页展现出来。
2、如果有多个网页引用iframe,那么你只需要修改iframe的内容,就可以实现调用的每一个页面内容的更改,方便快捷。
3、网页如果为了统一风格,头部和版本都是一样的,就可以写成一个页面,用iframe来嵌套,可以增加代码的可重用。
4、如果遇到加载缓慢的第三方内容如图标和广告,这些问题可以由iframe来解决。
5、重载页面时不需要重载整个页面,只需要重载页面中的一个框架页(减少了数据的传输,增加了网页下载速度) - 总而言之:
运维性网站或继承性开发的网站,可以使用iframe;
销售内,官网、展示性网站等建议不使用iframe;
标准的网页设计是不使用iframe的。
二、css篇
1、link与@import有什么不同
页面导入外部css文件的方法通常有两种,一种在网页中直接link标签加入,另一种在页面中@import引入css文件。两种引入形式如下:
// link引入形式
<link href="styles.css" type="text/css" />
// @import引用形式:
<style type="text/css">
@import url("styles.css");
</style>
(1)适用范围不同
@import可以在网页页面中使用,也可以在css文件中使用,用来将多个css文件引入到一个css文件中;而link只能将css文件引入到网页页面中。
(2)功能范围不同
link属于XHTML标签,而@import是CSS提供的一种方式,link标签除了可以加载CSS外,还可以定义rel连接属性,定义RSS等,@import就只能加载CSS。
(3)加载顺序不同
页面被加载的时候,link引用的CSS会同时被加载,而@import引用的CSS会等到页面全部被下载完再被加载。所以有时候浏览@import加载CSS的页面时开始会没有样式(就是闪烁)
(4)兼容性
由于@import是css2.1提出的,所以老的浏览器不支持,@import只有在IE5以上的才能识别,而link标签无此问题。
(5)控制样式时的差别
使用link方式可以让用户切换CSS样式.现代浏览器如Firefox,Opera,Safari都支持rel=”alternate stylesheet”属性(即可在浏览器上选择不同的风格),当然你还可以使用Javascript使得IE也支持用户更换样式。
(6)使用DOM控制样式时的差别
当使用JavaScript控制DOM去改变样式的时候,只能使用link标签,因为@import不是DOM可以控制的。
2、rgba和opacity的透明效果有什么不同
- opacity
opacity是一个属性。opacity属性的值,可以被其子元素继承,给父级div设置opacity属性,那么所有子元素都会继承这个属性,并且,该元素及其继承该属性的所有子元素的所有内容透明度都会改变。 - rgba
rgba是一个属性值。rgba设置的元素,只对该元素的背景色有改变,并且,该元素的后代不会继承该属性。
补冲:rgba只是一个属性值,在background 里用改变背景色,在color里是改字体颜色,shadow里是改阴影色,不止是能够改元素的背景色,要看具体是在哪个属性上用
3、display:none与visibility:hidden的区别
这两个属性都是让元素隐藏,不可见。两者区别如下:
(1)在渲染树中
display:none会让元素完全从渲染树中消失,渲染时不会占据任何空间;
visibility:hidden不会让元素从渲染树中消失,渲染的元素还会占据相应的空间,只是内容不可见。
(2)是否是继承属性
display:none是非继承属性,子孙节点会随着父节点从渲染树消失,通过修改子孙节点的属性也无法显示;
visibility:hidden是继承属性,子孙节点消失是由于继承了hidden,通过设置visibility:visible可以让子孙节点显示;
(3)修改常规文档流中元素的 display 通常会造成文档的重排,但是修改visibility属性只会造成本元素的重绘;
(4)如果使用读屏器,设置为display:none的内容不会被读取,设置为visibility:hidden的内容会被读取。
(5)display:none 隐藏对应的元素,在文档布局中不再给它分配空间,它各边的元素会合拢,就当他从来不存在。
(6)visibility:hidden 隐藏对应的元素,但是在文档布局中仍保留原来的空间。
4、伪元素和伪类的区别和作用
伪元素:在内容元素的前后插入额外的元素或样式,但是这些元素实际上并不在文档中生成。它们只在外部显示可见,但不会在文档的源代码中找到它们,因此,称为“伪”元素。例如:
p::before {content:"第一章:";}
p::after {content:"Hot!";}
p::first-line {background:red;}
p::first-letter {font-size:30px;}
伪类:将特殊的效果添加到特定选择器上。它是已有元素上添加类别的,不会产生新的元素。例如:
a:hover {color: #FF00FF}
p:first-child {color: red}
5、 flex 的各个属性值
Flexbox 提供了多种属性来控制布局:
flex-direction: 定义主轴的方向,可以是row, row-reverse, column, column-reverse。
flex-wrap: 控制如果一行内的项超过容器的宽度,是否应该换行,nowrap, wrap, wrap-reverse。
justify-content: 定义了项目在主轴上的对齐方式,如flex-start, flex-end, center, space-between, space-around。
align-items: 在交叉轴上如何对齐项目,如flex-start, flex-end, center, baseline, stretch。
align-content: 多行/列的对齐方式,如stretch, center, flex-start, flex-end, space-between, space-around。
flex-grow: 定义项目的放大比例。
flex-shrink: 定义项目的缩小比例。
flex-basis: 定义在分配多余空间之前,项目占据的主轴空间。
flex: 是flex-grow, flex-shrink和flex-basis的简写。
order: 允许你重新排序容器内的项目。
6、css 如何实现让一个元素旋转并横向移动,如果只用一个 css 属性
要同时让一个元素旋转并沿水平方向移动,可以使用transform属性结合rotate和translateX函数:
.element {
transform: rotate(45deg) translateX(100px);
}
这里,.element将沿X轴移动100像素并旋转45度。这种组合允许在单一的属性中执行多重变形。
7、怎么实现响应式布局的
实现响应式布局的方法有几种,常用的技术:
媒体查询: CSS 中的媒体查询允许你根据不同的屏幕尺寸和特性应用不同的样式规则。
流式布局: 使用百分比而不是固定单位(如像素)来指定宽度,使布局能够适应不同大小的屏幕。
弹性布局: CSS 的 Flexbox 模块提供了一种更有效的方式来布置、对齐和分配容器内元素的空间,即使它们的大小未知或是动态的。
网格布局: CSS 网格布局允许开发者创造复杂的布局结构,更适合大型应用。
三、jsvaScript篇
1、JS基础类型和复杂类型
-
JS数据基础类型有:
String、Number、Boolean、Null、undefined五种基本数据类型,加上新增的两种ES6的类型Symbol、BigInt -
JS有三种 复杂类型:
Object(对象)、Array(数组)、function(函数)
2、ES6 Symbol如何使用与使用场景
在 ES6 中,Symbol 是一种新的原始数据类型,它被用来创建唯一的标识符。Symbol 的主要用途是作为对象的属性键,这些属性是唯一的,可以防止属性名的冲突。这对于大型项目或者多个库和框架一起使用时尤其有用,因为它可以减少不同代码库间命名冲突的可能性。
使用场景
(1)私有属性:
Symbols 可以用来模拟私有属性,因为直接通过对象属性名无法访问到使用 Symbol 作为键的属性(除非你拥有这个 Symbol):
let age = Symbol();
class Person {
constructor(name, ageValue) {
this.name = name;
this[age] = ageValue;
}
displayAge() {
console.log(this[age]);
}
}
let person = new Person("Alice", 30);
person.displayAge(); // 输出: 30
console.log(person.age); // 输出: undefined
这里的 age 属性在类的外部是无法直接访问的,从而实现了一种简单的封装。
(2)使用 Symbol 实现迭代器:
使用 Symbol.iterator 可以自定义对象的迭代行为:
let collection = {
items: [1, 2, 3],
[Symbol.iterator]: function* () {
for (let item of this.items) {
yield item;
}
}
};
for (let item of collection) {
console.log(item); // 输出 1, 2, 3
}
(3)防止属性覆盖:
当使用第三方库或者在大型项目中,可能会有多个模块操作同一个对象。使用 Symbol 作为属性键可以防止无意中覆盖已有的属性:
let id = Symbol("id");
obj[id] = "Module1";
console.log(obj[id]); // 输出: "Module1"
3、箭头函数与普通函数的区别?
(1) 箭头函数比普通函数更加简洁
如果没有参数 , 就直接写一个空括号即可 , 如果只有一个参数 , 可以省去参数的括号 如果有多个参数 , 用逗号分割 , 如果函数体的返回值只有一句 , 可以省略大括号。
(2) 箭头函数没有自己的this
箭头函数不会创建自己的this, 所以它没有自己的this, 它只会在自己作用域的上一层继承this。所以箭头函数中this的指向在它在定义时已经确定了, 之后不会改变。
(3) 箭头函数继承来的this指向永远不会改变
(4) call()、apply()、bind()等方法不能改变箭头函数中this的指向
(5) 箭头函数不能作为构造函数使用
由于箭头函数时没有自己的this,且this指向外层的执行环境,且不能改变指向,所以不能当做构造函数使用。
(6) 箭头函数没有自己的arguments对象。在箭头函数中访问arguments实际上获得的是它外层函数的arguments值。
(7) 箭头函数没有prototype
(8) 补充:箭头函数的this指向哪⾥?
箭头函数不同于传统JavaScript中的函数,箭头函数并没有属于⾃⼰的this,它所谓的this是捕获其所在上下⽂的 this 值,作为⾃⼰的 this 值,并且由于没有属于⾃⼰的this,所以是不会被new调⽤的,这个所谓的this也不会被改变。
4、原型链
前提须知:
(1) prototype:所有的函数都有原型prototype属性,这个属性指向函数的原型对象。
(2) proto,这是每个对象(除null外)都会有的属性,叫做__proto__,这个属性会指向该对象的原型。
(3) constructor: 每个原型都有一个constructor属性,指向该关联的构造函数。
原型链:获取对象时,如果这个对象上本身没有这个属性时,它就会去它的原型__proto__上去找,如果还找不到,就去原型的原型上去找…一直直到找到最顶层(Object.prototype)为止,Object.prototype对象也有__proto__属性,值为null
此外,每一个prototype原型上都会有一个constructor属性,指向它关联的构造函数。
5、闭包
通俗的来说:闭包是在一个函数内部在定一个函数,然后内部函数访问外部函数的一个变量就会形成闭包,闭包的话会形成一个私有空间,然后避免全局变量的一个污染,然后会持久化存储数据到内存中,但是闭包也有弊端,它会导致内存泄漏
闭包优点:
(1)变量会一直在内存中;
(2)避免全局变量的污染;
(3)私有变量的存在;
闭包缺点:
变量长期储存在内存中,会增大内存的使用量,使用不当会造成内存泄露
6、js列举和数组操作相关的方法(常用)
filter(): 创建一个新数组,包含通过所提供函数实现的测试的所有元素
find(): 查找第一个满足测试函数的元素。
findIndex(): 查找第一个满足测试函数的元素的索引。
indexOf(): 查找元素在数组中的索引。
push(): 在数组的末尾添加一个或多个元素,并返回新的长度。
unshift(): 在数组的开头添加一个或多个元素,并返回新的长度
pop(): 删除数组的最后一个元素,并返回那个元素。
splice(): 通过删除、替换或添加新元素来改变数组的内容。
forEach(): 对数组的每个元素执行一次提供的函数。不能中断
map(): 创建一个新数组,其结果是该数组中的每个元素都调用一次提供的函数后的返回值。
concat(): 合并两个或多个数组。
join(): 将数组(或一个类数组对象)的所有元素连接成一个字符串并返回这个字符串。
some(): 如果数组中存在符合条件的就返回true否则就返回false
includes(str) 数组中包含str的话就返回true否则false
slice(): 提取原数组的一部分,返回一个新数组。
7、typeof和instanceof的区别
(1)typeof 的返回值是一个字符串,用来说明变量的数据类型;
typeof用于数据类型的判断,返回值有number、string、boolean、function、undefined、object 六个。但是,在其中你会发现,typeof判断null、array、object以及函数的实例(new + 函数)时,它返回的都是object。这就导致在判断这些数据类型的时候得不到真实的数据类型。所以,typeof 存在的弊端——它虽然可以判断基本数据类型(null 除外),但是引用数据类型中,除了function 类型以外,其他的也无法判断。
(2)instanceof的返回值是布尔值,用于判断一个变量是否属于某个对象的实例。instanceof 可以准确地判断复杂引用数据类型,但是不能正确判断基础数据类型。
8、var、let和const的区别
(1)块级作用域: 块作用域由 { }包括,let和const具有块级作用域,var不存在块级作用域。
块级作用域解决了 ES5 中的两个问题:
内层变量可能覆盖外层变量
用来计数的循环变量泄露为全局变量
(2)变量提升: var存在变量提升,let和const不存在变量提升,即在变量只能在声明之后使用,否在会报错。
(3)给全局添加属性: 浏览器的全局对象是window,Node的全局对象是global。var声明的变量为全局变量,并且会将该变量添加为全局对象的属性,但是let和const不会。
(4)重复声明: var声明变量时,可以重复声明变量,后声明的同名变量会覆盖之前声明的遍历。const和let不允许重复声明变量。
(5)暂时性死区: 在使用let、const命令声明变量之前,该变量都是不可用的。这在语法上,称为暂时性死区。使用var声明的变量不存在暂时性死区。
(6)初始值设置: 在变量声明时,var 和 let 可以不用设置初始值。而const声明变量必须设置初始值。
(7)指针指向: let和const都是ES6新增的用于创建变量的语法。 let创建的变量是可以更改指针指向(可以重新赋值)。但const声明的变量是不允许改变指针的指向。
9、讲解js的call、apply和bind区别
call apply bind三个方法都可以用来改变函数的this指向,具体区别如下:
- call( ) 是接收一个及其以上的参数,第一个参数表示this要指向的对象,其余参数表示调用函数需要传入的参数,返回调用函数的返回结果,属于立即执行函数;
- apply( ) 是接收两个参数,第一个参数表示this要指向的对象,第二参数表示调用函数需要传入的参数所组成的数组,返回调用函数的返回结果,属于立即执行函数;
- bind( ) 是接收一个及其以上的参数,和call()一致,但是其返回是一个函数,而不是调用函数的返回结果
- call、apply、bind相同点: 都是改变this的指向,传入的第一个参数都是绑定this的指向,在非严格模式中,如果第一个参数是nul或者undefined,会把全局对象(浏览器是window)作为this的值,要注意的是,在严格模式中,null 就是 null,undefined 就是 undefined
- call和apply唯一的区别是: call传入的是参数列表,
apply传入的是数组,也可以是类数组 - bind和call、apply的区别: bind返回的是一个改变了this指向的函数,便于稍后调用,不像call和apply会立即调用;bind和call很像,传入的也是参数列表,但是可以多次传入,不需要像call,一次传入
- 注意: 当 bind 返回的函数 使用new作为构造函数时,绑定的 this 值会失效,this指向实例对象,但传入的参数依然生效 (new调用的优先级 > bind调用)
Promise 与 async/await 篇
Promise 理解
1、Promise含义
Promise是一个对象,它代表了一个异步操作的最终完成或者失败。所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。
2、Promise用法
- 一个 Promise 必然处于以下几种状态之一:
(1)待定(pending):初始状态,既没有成功,也没有失败。
(2)已处理(fulfilled/resolved):意味着操作成功完成。
(3)已拒绝(rejected):意味着操作失败。
一个 Promise 的状态只能由 pending 变为 fulfilled,或变为 rejected,且只能改变一次。 - 链式调用: Promise 对象具有 .then 和 .catch 方法来处理下一步的操作。因为 Promise.prototype.then 和 Promise.prototype.catch 方法返回的是 Promise,所以它们可以被链式调用
3、基础用法
// 创建Promise对象:
const promise = new Promise(function(resolve, reject) {
// 异步操作
if (/* 异步操作成功 */){
resolve(value);
} else {
reject(error);
}
});
promise.then(function(value) {
// 处理fulfilled状态
}, function(error) {
// 处理rejected状态
});
promise
.then((value) => {
// 处理fulfilled状态
return value2;
})
.then((value2) => {
// 处理fulfilled状态
})
.catch((error) => {
// 处理rejected状态
});
4、Promise并发
Promise 类提供了四个静态方法来促进异步任务的并发:
| 方法 | 简介 |
|---|---|
| Promise.all(). | 在所有传入的 Promise 都被兑现时兑现;在任意一个 Promise 被拒绝时拒绝。 |
| Promise.allSettled(). | 在所有的 Promise 都被敲定时兑现。 |
| Promise.any(). | 在任意一个 Promise 被兑现时兑现;仅在所有的 Promise 都被拒绝时才会拒绝。 |
| Promise.race(). | 在任意一个 Promise 被兑现时兑现;在任意一个的 Promise 被拒绝时拒绝。 |
- Promise.all().
let p1 = new Promise((resolve, reject) => {
resolve('成功了')
})
let p2 = new Promise((resolve, reject) => {
resolve('success')
})
let p3 = Promise.reject('失败')
Promise.all([p1, p2]).then((result) => {
console.log(result)
}).catch((error) => {
console.log(error)
}) // 打印 ['成功了‘,'success']
Promise.all([p1, p3, p2]).then((result) => {
console.log(result)
}).catch((error) => {
console.log(error)
}) // 打印 '失败'
- Promise.race().
const promise1 = new Promise((resolve, reject) => {
setTimeout(resolve, 500, 'one');
});
const promise2 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 'two');
});
Promise.race([promise1, promise2]).then((value) => {
console.log(value);
// 都resolve, 但是promise2更快 打印‘two’
});
Promise面试
1、Promise解决了什么问题?
Promise解决了回调地狱的问题。在以前的JavaScript代码中,多个异步操作嵌套过深,难以维护和理解,这就是所谓的回调地狱。而Promise可以让异步操作按照顺序执行,并且可以链式调用,使得代码更加清晰和易于管理。同时,Promise还可以处理异步操作的成功和失败,使得错误处理更加方便。
2、setTimeout、Promise、Async/Await 的区别
- settimeout
它的回调函数放到宏任务队列里,等到执行栈清空以后执行 - Promise
它本身是同步的立即执行函数,当在executor中执行resolve或者reject的时候,此时是异步操作,会先执行then/catch等,当主栈完成后,才会去调用resolve/reject中存放的方法执行。 - Async/Await
它们返回一个 Promise对象,当函数执行的时候,一旦遇到 await 就会先返回,等到触发的异步操作完成,再执行函数体内后面的语句。可以理解为,是让出了线程,跳出了 async 函数体。
async function async1(){
console.log('async1 start');
await async2();
console.log('async1 end')
}
async function async2(){
console.log('async2')
}
console.log('script start');
async1();
console.log('script end')
// 输出顺序:script start->async1 start->async2->script end->async1 end
Vue2 篇
1、$route 和 $router的区别
$router 是VueRouter的实例,在script标签中想要导航到不同的URL,使用 $router.push方法
$route为router跳转对象,里面可以获取当前路由的name,path,query,parmas等。
2、scoped作用与原理
作用: 组件css作用域,避免子组件内部的css样式被父组件覆盖
原理: 给元素添加一个自定义属性 v-data-xxxxx, 通过属性选择题来提高css权重值
2、常用的组件通信方式
- 通过 props 传递
- 通过 $emit 触发自定义事件
- EventBus
- 使用 ref
- vuex
3、vuex理解
Vuex 是一个专为 Vue 应用程序开发的状态管理模式。每一个 Vuex 应用的核心就是 store(仓库)。
Vuex 的状态存储是响应式的;当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新。改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation, 这样使得我们可以方便地跟踪每一个状态的变化
Vuex主要包括以下几个核心模块:
- State:定义了应用的状态数据
- Getter:在 store 中定义“getter”(可以认为是 store 的计算属性),就像计算属性一样,getter 的返回值会根据它的依赖被缓存起来, 且只有当它的依赖值发生了改变才会被重新计算
- Mutation:是唯一更改 store 中状态的方法,且必须是同步函数
- Action:用于提交 mutation,而不是直接变更状态,可以包含任意异步操作
- Module:允许将单一的 Store 拆分为多个 store 且同时保存在单一的状态树中
4、vue中的data为什么是一个函数?起到什么作用?
- 在Vue组件中,data选项必须是一个函数,而不能直接是一个对象。这是因为Vue组件可以同时存在多个实例,如果直接使用对象形式的data选项,那么所有的实例将会共享同一个data对象,这样就会造成数据互相干扰的问题。
- 因此,将data选项设置为函数可以让每个实例都拥有自己独立的data对象。当组件被创建多次时,每个实例都会调用该函数并返回一个新的data对象,从而保证了数据的隔离性。
- 另外,data选项作为一个函数还具有一个重要的特性,就是它可以接收一个参数,这个参数是组件实例本身。这个特性在一些场景下非常有用,例如在定义组件时需要使用组件实例的一些属性或方法来计算初始数据。
- 因此,为了避免数据共享和保证数据隔离性,以及方便使用组件实例的属性和方法,Vue组件中的data选项必须是一个函数。
5、自定义指令的用法
作用: 通过这指令可以对 dom 元素进行底层操作。
用法: 通过 Vue.directive 全局注册一个指令,或者组件内部通过 directives 进行局部注册,它常用的钩子有 inserted,表示被绑定元素插入父节点时调用,还有 update,它表示指令所在组件的 VNode 更新时调用。
6、双向绑定的原理
采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。
具体话其实就是组件初始化时通过Obeject.defineProperty() 重新定义data中的所有属性(setter和getter)来监听属性变动实现Observer进行数据的监听然后就是通知订阅者,那么订阅者其实就是简单的一个数组,这个数组中的内容就是我门使用了的一个数据的集合,使用了的数据可以通过getter得到,其实就是在调用的时候给数组里面添加一个订阅者这样就是实现了一个Watcher(需要监听的数据的集合),然后在实现一个Compile其作用就是解析模板指令,将模板中的变量替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,更新视图,
其实vue的数据双向绑定就是MVVM作为数据绑定的入口,整合Observer、Compile和Watcher三者,通过Observer来监听自己的model数据变化,通过Compile来解析编译模板指令,最终利用Watcher搭起Observer和Compile之间的通信桥梁,达到数据变化 -> 视图更新;视图交互变化(input) -> 数据model变更的双向绑定效果。
具体步骤:
第一步: 需要Observer(数据劫持)对数据对象进行递归遍历,包括子属性对象的属性,被重新定义为 setter和getter,给这个对象的某个值赋值,就会触发setter,那么就能监听到了数据变化
第二步: Compiler(订阅者)解析模板指令,将模板中的变量替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,更新视图
第三步: Watcher(观察者)是Observer和Compiler之间通信的桥梁,主要做的事情是:
-
在自身实例化时往属性订阅器(dep)里面添加自己
-
自身必须有一个update()方法
-
待属性变动dep.notice()通知时,能调用自身的update()方法,并触发Compile中绑定的回调,则功成身退。
第四步: MVVM作为数据绑定的入口,整合Observer、Compiler和Watcher三者,通过Observer来监听自己的model数据变化,通过Compile来解析编译模板指令,最终利用Watcher搭起Observer和Compile之间的通信桥梁,达到数据变化 -> 视图更新;视图交互变化(input) -> 数据model变更的双向绑定效果。
7、diff算法
Diff 算法是一种对比算法。对比两者是 旧虚拟 DOM 和新虚拟 DOM,对比出是哪个 虚拟节点更改了,找出这个 虚拟节点并只更新这个虚拟节点所对应的 真实节点而不用更新其他数据没发生改变的节点,实现 精准地更新真实 DOM,进而 提高效率
在新老虚拟 DOM 对比时:
- 首先,对比节点本身,判断是否为同一节点,如果不为相同节点,则删除该节点重新创建节点进行替换
- 如果为相同节点,进行 patchVnode,判断如何对该节点的子节点进行处理,先判断一方有子节点一方没有子节点的情况(如果新的 children 没有子节点,将旧的子节点移除)
- 比较如果都有子节点,则进行 updateChildren,判断如何对这些新老节点的子节点进行操作(diff 核心)。
- 匹配时,找到相同的子节点,递归比较子节点
8、vue中hash和history的区别
(1)hash方式:
hash方式是指url中存在 # 的一种方式,是vueRouter的默认模式,
当#后面的url地址发生变化时,浏览器不会向服务器发送请求,故不会刷新页面
当#后面的url地址发生变化时,会触发hashChange(hash模式得核心实现原理)事件,从而,我们可以通过监听hashChange事件来知道路由发生变化,从而进一步去更新我们的页面
只可修改hash部分,
当浏览器刷新时,浏览器只会向服务器去请求# 前面的域名服务器下根目录下的index.html文件
hash模式会创建hashHistory对象,hashHistory对象有两个方法,push() 和 replace()
HashHistory.push()会将新的路由添加到浏览器访问的历史的栈顶,而HasHistory.replace()会替换到当前栈顶的路由
(2)history模式:
history模式得路由和域名之间直接通过/连接,无#符分隔,就是普通url形式
history模式当发生路由跳转时,通过HTML5的history.pushState()方法或者history.replaceState() 方法改变地址栏地址,并将地址的改变记录到浏览器访问栈中。(这里有一点需要注意,它只改变了浏览器地址栏中的地址,但并不会像服务器去发送请求)
当浏览器前进,后台,或者调用back(),forward(), go()等方法时,会触发popstate事件。故,我们可以通过监听popstate事件来获取最新的路由地址,从而更新页面
通过pushstate() 修改的url可以是与当前url同源的任意url。
需要和服务器配合使用,否则容易出现页面404的情况
(3)总结:
- hash模式带#号比较丑,history模式比较优雅;
- pushState设置的新的URL可以是与当前URL同源的任意URL;而hash只可修改#后面的部分,故只可设置与当前同文档的URL;
- pushState设置的新URL可以与当前URL一模一样,这样也会把记录添加到栈中;而hash设置的新值必须与原来不一样才会触发记录添加到栈中;
- pushState通过stateObject可以添加任意类型的数据到记录中;而hash只可添加短字符串;
- pushState可额外设置title属性供后续使用;
- hash兼容IE8以上,history兼容IE10以上;
- history模式需要后端配合将所有访问都指向index.html,否则用户刷新页面,会导致404错误。
9、路由守卫作用/对比axios拦截器
相同点:
- 都是钩子函数(回调函数的一种,到某个时机了自动触发)
- 都是起到拦截作用
不同点: - 功能不同 :axios拦截器拦截网络请求, 导航守卫拦截路由跳转
- 应用场景不同 :axios拦截器一般用于发送token,导航守卫用于页面跳转权限管理(有的页面可以无条件跳转,例如登录注册页可以无条件跳转。有的页面需要满足条件才能跳转,例如购物车页面就需要用户登录才可以跳转)
10、vue2与vue3的区别
- 性能更高了,主要得益于响应式的原理换成了 proxy,VNode diff 的算法进行了优化。
- 体积更小了,删除了一些没必要或不常用到的 API,例如 filter、EventBus 等;按需导入,能配合 Webpack 支持 Tree Shaking。
- 对 TS 支持更好,因为它本身源码就是用 TS 重写的。
- Vue2和vue3的初始化就存在着⼀定区别,⽐如vue3.0可以在安装脚⼿架同时提前安装好⼀些项⽬开发必备的插件,并且3.0提供了可视化创建脚⼿架,可以更加⽅便的对插件和依赖进⾏管理和配置,同时两个版本的⽬录结构也是有些许差别的。(比如:Vue3相对于Vue2,打包工具Vite替代了webpack;TS替代了JS,pinia替代了vuex;Element-plus替代了Element等等)
- 在开发过程中两个版本的使⽤⽅法虽然在表⾯上没有太⼤的⼀个区别,但是在他的底层⽅⾯去看的话区别还是很⼤的,其中就包括渲染⽅式,数据监听,双向绑定,⽣命周期,vue3更精准变更通知,这⾥着重说⼀下关于双向绑定的更新,
- vue2 的双向数据绑定是利⽤ES5的⼀个 API ,Object.definePropert()对数据进⾏劫持 结合发布订阅模式的⽅式来实现的。
- vue3 中使⽤了 ES6 的 ProxyAPI 对数据代理,通过 reactive() 函数给每⼀个对象都包⼀层 Proxy,通过 Proxy 监听属性的变化,从⽽实现对数据的监控。
Vue3 篇
1、Vue3带来了什么改变
性能的提升
- 打包大小减少41%
- 初次渲染快55%, 更新渲染快133%
- 内存减少54%
源码的升级
- 使用Proxy代替defineProperty实现响应式
- 重写虚拟DOM的实现和Tree-Shaking
拥抱TypeScript
-Vue3可以更好的支持TypeScript
新的特性
(1)Composition API(组合API)
- setup配置
- ref与reactive
- watch与watchEffect
- provide与inject
(2)新的内置组件
- Fragment
- Teleport
- Suspense
(3)其他改变
- 新的生命周期钩子 beforeunmoumt、unmoumted
- data 选项应始终被声明为一个函数
- 移除keyCode支持作为 v-on 的修饰符
2、Vue3.0中的响应式原理是什么
实现原理:
-
通过Proxy(代理): 拦截对象中任意属性的变化, 包括:属性值的读写、属性的添加、属性的删除等。
-
通过Reflect(反射): 对源对象的属性进行操作。
-
MDN文档中描述的Proxy与Reflect:
new Proxy(data, {
// 拦截读取属性值
get (target, prop) {
return Reflect.get(target, prop)
},
// 拦截设置属性值或添加新属性
set (target, prop, value) {
return Reflect.set(target, prop, value)
},
// 拦截删除属性
deleteProperty (target, prop) {
return Reflect.deleteProperty(target, prop)
}
})
proxy.name = ‘tom’ -
vue3响应式数据的判断
isRef: 检查一个值是否为一个 ref 对象
isReactive: 检查一个对象是否是由 reactive 创建的响应式代理
isReadonly: 检查一个对象是否是由 readonly 创建的只读代理
isProxy: 检查一个对象是否是由 reactive 或者 readonly 方法创建的代理
2、vue3的常用 Composition API有哪些
1.拉开序幕的setup
(1)理解:Vue3.0中一个新的配置项,值为一个函数。
(2)setup是所有Composition API(组合API)“ 表演的舞台 ”。
(3)组件中所用到的:数据、方法等等,均要配置在setup中。
(4)setup函数的两种返回值:
- 若返回一个对象,则对象中的属性、方法, 在模板中均可以直接使用。(重关注!)
- 若返回一个渲染函数:则可以自定义渲染内容。(了解)
(5)setup的几个注意点
- setup执行的时机
- 在beforeCreate之前执行一次,this是undefined。
- setup的参数
- props:值为对象,包含:组件外部传递过来,且组件内部声明接收了的属性。
context:上下文对象 - attrs: 值为对象,包含:组件外部传递过来,但没有在props配置中声明的属性, 相当于 this.$attrs。
- slots: 收到的插槽内容, 相当于 this.$slots。
- emit: 分发自定义事件的函数, 相当于 this.$emit。
- 尽量不要与Vue2.x配置混用
React篇
1、什么是 JSX
- 可以将HTML语言直接写在JavaScript语言之中,不加任何引号,这就是JSX的语法,它允许HTML与JavaScript的混写。
- JSX允许直接在模板插入JavaScript变量。如果这个变量是一个数组,则会展开这个数组的所有成员。
- 防注入攻击, 在JSX中嵌入用户输入是安全的;
- React DOM在渲染之前默认会过滤所有传入的值。它可以确保应用不会被注入攻击。所有的内容在渲- 染之前都被转换成了字符串。这样可以有效地防止XSS(跨站脚本攻击)
- Babel转译器会把JSX转换成一个名为React.createElement()的方法调用。
2、React的diff算法是如何运作的?
React的diff算法是为了节省性能而设计的,它主要通过同层级进行比较,不跨层级,使得性能更加高效。diff算法主要分为tree层、component层和element层三个层次进行比较。
3、React的生命周期有哪些阶段?每个阶段对应的方法是什么?
创建阶段: 包括constructor、getDerivedStateFromProps、render和componentDidMount等方法;
更新阶段: 包括getDerivedStateFromProps、shouldComponentUpdate、render、getSnapshotBeforeUpdate和componentDidUpdate等方法;
卸载阶段: 只有componentWillUnmount方法。
4、React的Hooks详解
- useState:用于在函数组件中添加状态。
- useEffect:用于在函数组件中执行副作用操作。
- useContext:用于在函数组件中访问React的上下文。
- useReducer:用于在函数组件中使用Reducer模式来管理状态。
- useRef:用于在函数组件中创建可变的引用。
- useMemo:用于在函数组件中缓存计算的值。
- useCallback:用于在函数组件中缓存函数。
- useLayoutEffect:类似于useEffect,但在DOM更新之后同步执行。
- useImperativeHandle:用于在函数组件中自定义外部组件实例的暴露。
- useDebugValue:用于在自定义Hooks中显示自定义的调试值。
5、Redux
Redux是一个用于JavaScript应用的状态管理库,它遵循Flux架构的核心理念,即单向数据流。Redux通过action、reducer和store等核心概念来实现状态的管理和更新。action是一个描述要执行什么操作的普通JavaScript对象;reducer是一个纯函数,它接收当前的state和action作为参数,并返回一个新的state;store则是Redux的核心,它保存了应用的整个状态树,并提供了一系列方法来访问和更新状态。
6、如何使用Redux中间件来处理异步操作?
Redux中间件是一个用于拦截和扩展action处理流程的函数。通过中间件,开发者可以在action被发送到reducer之前执行一些额外的操作,如处理异步请求、记录日志等。Redux-thunk是一个常用的中间件,它允许开发者在action中返回函数来处理异步操作。
uniapp篇
1、uniapp优缺点
优点
- 一套代码可以生成多端
- 学习成本低,语法是vue的,组件是小程序的
- 拓展能力强
- 使用HBuilderX开发,支持vue语法
- 突破了系统对H5调用原生能力的限制
缺点
- 问世时间短,很多地方不完善
- 社区不大
- 官方对问题的反馈不及时
- 在Android平台上比微信小程序和iOS差
- 文件命名受限
2、uniApp中如何进行页面跳转
可以使用uni.navigateTo、uni.redirectTo和uni.reLaunch等方法进行页面跳转。其中,uni.navigateTo可以实现页面的普通跳转,uni.redirectTo可以实现页面的重定向跳转,uni.reLaunch可以实现关闭所有页面,打开到应用内的某个页面。
3、uniApp中如何实现页面的下拉刷新和上拉加载更多
可以使用uni.onPullDownRefresh方法实现页面的下拉刷新,使用uni.onReachBottom方法实现页面的上拉加载更多。
4、生命周期
(1)应用的生命周期
1.onLaunch——当uni-app 初始化完成时触发(全局只触发一次)
2.onShow——当 uni-app 启动,或从后台进入前台显示
3.onHide——当 uni-app 从前台进入后台
4.onError——当 uni-app 报错时触发
5.onUniNViewMessage——对 nvue 页面发送的数据进行监听,可参考 nvue 向 vue 通讯
6.onUnhandledRejection——对未处理的 Promise 拒绝事件监听函数(2.8.1+)
7.onPageNotFound——页面不存在监听函数
8.onThemeChange——监听系统主题变化
(2)页面的生命周期
1.onInit——监听页面初始化,其参数同 onLoad 参数,为上个页面传递的数据,参数类型为 Object(用于页面传参),触发时机早于 onLoad
2.onLoad——监听页面加载,其参数为上个页面传递的数据,参数类型为 Object(用于页面传参),参考示例
3.onShow——监听页面显示。页面每次出现在屏幕上都触发,包括从下级页面点返回露出当前页面
4.onReady——监听页面初次渲染完成。注意如果渲染速度快,会在页面进入动画完成前触发
5.onHide——监听页面隐藏
6.onUnload——监听页面卸载
7.onResize——监听窗口尺寸变化
(3)组件的生命周期
uni-app 组件支持的生命周期,与vue标准组件的生命周期相同
Webpack篇
1、Webpack是什么
- webpack 是一个静态模块打包器,当 webpack 处理应用程序时,会递归构建一个依赖关系图,其中包含应用程序需要的每个模块,然后将这些模块打包成一个或多个 bundle。
- webpack 就像一条生产线,要经过一系列处理流程(loader)后才能将源文件转换成输出结果。 这条生产线上的每个处理流程的职责都是单一的,多个流程之间有存在依赖关系,只有完成当前处理后才能交给下一个流程去处理。
- 插件就像是一个插入到生产线中的一个功能,在特定的时机对生产线上的资源做处理。 webpack 在运行过程中会广播事件,插件只需要监听它所关心的事件,就能加入到这条生产线中,去改变生产线的运作。
2、如何提高webpack的构建速度
-
代码压缩
-
按需加载
-
代码分割 splitChunks - 在optimization配置项中配置
1.可以将node__mudules中代码单独打包成一个chunk输出(比如使用了jqury?)
2.会自动分析多入口chunk中,有没有公共的文件,如果有会打包成单独的一个chunk不会重复打包 -
使用Dll进行分包
正常情况下node_module会被打包成一个文件
使用dll技术,对可以将那些不常更新的框架和库进行单独打包,生成一个chunk
-
-
使用路由懒加载
在代码中所有被 import()函数引用的模块,都将打成一个单独的包,放在 chunk 存储的目录下。在浏览器运行到这一行代码时,就会自动请求这个资源,实现异步加载。
3、Webpack的打包过程/打包原理/构建流程
1. 初始化编译参数:从配置文件和shell命令中读取与合并参数
2. 开始编译:根据上一步得到的参数初始化Compiler对象,加载所有配置的Plugin,执行对象的 run 方法开始执行编译。
3. 确定入口:根据配置中的 entry 找出所有的入口文件
4. 编译模块:从入口文件触发,调用所有配置的Loader对模块进行翻译,再找出该模块依赖的模块,然后递归本步骤直到所有入口依赖的文件都进行翻译。
5. 完成模块编译:在经过第4步使用 Loader 翻译完所有模块后,得到了每个模块被翻译后的最终内容以及它们之间的依赖关系图。
6. 输出资源:根据依赖关系图,组装成一个个包含多个模块的Chunk,再把每个Chunk转化成一个单独的文件加入到输出列表,根据配置确定输出的路径和文件名输出。
总结归纳:
-
初始化:从配置文件和shell命令中读取与合并参数,根据参数初始化Compiler实例,加载Plugin(注册所有配置的插件),调用Compiler实例的run方法开始执行编译。
Compiler编译对象掌控者webpack生命周期,不执行具体的任务,只是进行一些调度工作。比如执行模块创建、依赖收集、分块、打包等 调用run之后,创建Compiltation实例,每次构建都会新创建一个Compiltation实例,包含了这次构建的基本信息 Webpack 会在特定的时间点广播出特定的事件,插件在监听到感兴趣的事件后会执行特定的逻辑。
编译: 从entry 触发,对每个Module 串行调用对应的 Loader对模块进行翻译,再找出该模块依赖的模块,递归进行编译处理。
从配置文件( webpack.config.js )中指定的 entry 入口,开始解析文件构建 AST 语法树
输出: 根据依赖关系图,组装成包含多个模块的Chunk,将个Chunk转换成文件输出。
不同entry生成不同chunk,动态导入也会生成自己的chunk
4、plugin和loader的区
Loader: Webpack将一切文件视为模块,但是默认只能解析 JavaScript 文件,如果想将其他类型的文件(如CSS、图片)也视作模块并进行打包,就会用到loader。Loader可以将不同格式的文件转换为模块,这样这些文件就可以被添加到依赖图中,最终一起打包到指定的文件中。常见的Loader有babel-loader用于将ES6/ES7转换为ES5、css-loader用于处理CSS文件等。
Plugin: Plugin用于扩展Webpack的功能,它通过在整个构建过程中的特定时机挂载钩子实现,以实现对构建过程的干预和定制。Plugin可以用于执行更广泛的任务,比如打包优化、资源管理、环境变量注入等。常见的Plugin有HtmlWebpackPlugin用于生成HTML文件、MiniCssExtractPlugin用于提取CSS文件等。
总的来说,Loader主要是用于对模块的源代码进行转换,而Plugin则用于解决loader无法实现的其他事。在Webpack的打包过程中,Plugin的作用更加广泛,可以实现对整个构建过程的控制和定制
5、打包压缩
UglifyJS: vue-cli 默认使用的压缩代码方式,它使用的是单线程压缩代码,打包时间较慢
ParallelUglifyPlugin: 开启多个子进程,把对多个文件压缩的工作分别给多个子进程去完成
6、Webpack的基本功能有哪些?
| 名称 | 内容 |
|---|---|
| 代码转换 | TypeScript编译成JavaScript、SCSS编译成CSS等。 |
| 文件优化 | 压缩JavaScript、csS、html代码,压缩合并图片等。 |
| 代码分割 | 提取多个页面的公共代码、提取首屏不需要执行部分的代码让其异步加载。 |
| 模块合并 | 在采用模块化的项目有很多模块和文件,需要构建功能把模块分类合并成一个文件。 |
| 自动刷新 | 监听本地源代码的变化,自动构建,刷新浏览器。 |
| 代码校验 | 在代码被提交到仓库前需要检测代码是否符合规范,以及单元测试是否通过。 |
7、Webpack如何配置压缩代码?压缩了什么?
- 在optimization配置项中来配置该插件作为压缩器进行压缩。
- 在plugins里使用该插件进行压缩
- js压缩:利用terser-webpack-plugin
- css压缩:利用了optimize-css-assets-webpack-plugin 插件
- 删除了console、注释、空格、换行、没有使用的css代码等
8、说说webpack中常见的Loader?解决了什么问题?
- babel-loader: 用于将ES6+语法转换为ES5代码,解决了不同浏览器之间的兼容性问题。
- css-loader: 用于处理CSS文件,包括解析@import和url()语句、将CSS模块化等。
- style-loader: 用于将CSS添加到HTML中,使得样式生效。
- file-loader: 用于处理静态资源文件,比如图片、字体等。它将这些文件复制到输出目录,并返回文件路径。
- url-loader: 是file-loader的升级版,支持将小文件以DataURL的形式直接内嵌到代码中,减少了HTTP请求,提高了性能。
- sass-loader: 用于处理Sass和SCSS文件,将它们转换为CSS。
- postcss-loader: 用于自动添加CSS前缀、压缩CSS、代码分离等功能,使得开发者可以更加高效地编写CSS代码。
- less-loader: 用于处理Less文件,将它们转换为CSS。
9、Vite为什么比webpack要快
- 快速的冷启动: Vite 使用了一种称为「按需编译」的模式,它仅在启动时编译正在编辑的文件,而不是像 Webpack 那样要编译整个项目。这意味着在启动开发服务器时,Vite 的冷启动速度更快,因为它只需编译少量的文件。
- 通过 ES 模块进行原生导入: Vite 基于原生 ES 模块的导入方式,而不是像 Webpack 那样需要将所有模块打包成一个或多个捆绑包。这使得 Vite 不需要进行大量的代码分析和重新构建工作,并且可以更快地处理模块的导入过程。
- 高效的 HMR(热模块替换)机制: Vite 在开发过程中使用了高效的 HMR 机制。它通过直接将更新的模块推送到浏览器,而无需重新刷新整个页面来实时更新应用程序。这样可以节省重新加载的时间,提高开发体验。
- 优化的构建过程: 在生产构建方面,Vite 通过使用 Rollup 进行优化,将每个模块作为单独的文件进行输出。这样可以提高浏览器的缓存命中率,并减少构建后的文件大小。Vite 也支持代码分割和按需加载,以进一步优化性能。
10、webpack和vite的区别
Webpack 和 Vite 都是前端构建工具,它们有一些区别和特点:
打包方式:
- Webpack 是一个传统的静态模块打包工具,通过构建一个完整的依赖图,将所有模块打包成一个或多个 bundle。
- Vite 则采用了现代化的开发模式,利用原生 ES 模块的特性,在开发过程中只对需要的模块进行即时编译,而不是将整个项目打包成一个 bundle。
开发体验:
- 在开发环境下,Vite 以快速的冷启动速度和热模块替换(HMR)为特点,能够在保存文件时快速更新相关模块,提供更好的开发体验。
- Webpack 在开发环境下也支持热更新,但相较于 Vite,它的启动速度可能会慢一些。
构建速度:
- Vite 的独特之处在于使用了 ES 模块的原生导入方式,避免了传统的依赖图构建过程,因此在构建速度上更快。
- Webpack 在处理大型项目时,由于需要构建完整的依赖图,可能会相对较慢。
插件生态系统:
- Webpack 有一个庞大且成熟的插件生态系统,提供了丰富的插件和加载器来满足各种需求,如代码分割、压缩、优化等。
- 目前,Vite 的插件生态系统相对较小,但它能够兼容大部分现有的 Rollup 和 Webpack 插件。
生产环境构建:
- 在生产环境下,Webpack 能够做更多的优化和压缩工作,生成高度优化的静态资源文件,适用于复杂项目的打包需求。
- Vite 在生产环境下会将所有模块预构建为静态文件,类似于传统的打包工具,以确保在浏览器中的兼容性和性能。
25万+

被折叠的 条评论
为什么被折叠?



