2023前端面试题及答案 汇总

1.盒子水平垂直居中方法(常用)

// 方法一、通常用法
.parent{
	  position:relitive;
	}
.son{
	  position:absolute;
	  transfrom:translate(-50%,-50%);
	  top:50%;
	  left:50%;
	}

// 方法二、不考虑兼容的情况下直接使用flex
.parent{
	display: flex;
	justify-content: center; //内容水平居中
	align-items: center; //垂直居中
}

2.var let const 的区别

var 具有变量提升, let const 具有块级作用域,const 无法重新赋值, 如果 const 声明的变量是一个对象或数组,那么该对象或数组的属性和元素是可以被修改的。

3. JS数据类型有哪些以及检测方法

  • 基本数据类型:String,Number,Undefined, Null, Boolean,Symbol
  • 复杂数据类型:Object, Array, Function,Regular Expression,Date,Map 和 Set
    Typeof——基本数据类型检测
    Instanceof——复杂数据类型检测
    Constructor——基本、复杂类型都可以检测
    Object.prototype.toString.call()

4. 什么是闭包?

闭包就是能够读取其他函数内部变量的函数,闭包基本上就是一个函数内部返回一个函数

  • 优点:隔离作用域,保护私有变量安全,防止全局变量污染
  • 缺点:滥用闭包会导致内存泄漏(手动释放,使用后将函数的引用赋null即可)

5. 深拷贝与浅拷贝的区别?

  • 浅拷贝:Object.assign
  • 深拷贝:JSON.stringify和JSON.parse
    JSON的stringify和parse处理的缺点?
    如果对象中有属性是function或者undefined,处理后会被过滤掉;
    如果属性值是对象,且由构造函数生成的实例对象,会丢弃对象的constructor;
    如需完全拷贝需使用递归函数进行拷贝

6. cookie sessinonStorage localStorage的区别?

cookie、sessionStorage、localStorage都是浏览器的本地存储。

  • 区别:cookie是由服务端写入的, 而sessionStorage、localStorage都是由前端写入的,
    cookie的生命周期是由服务端写入的时候就设置好的,localStorage是写入就一直存在,除非手动清除,sessionStorage是页面关闭就会自动清除,cookie的存储空间比较小,大概4KB,sessionStorage和loaclStorage的存储空间比较大,大概5M,cookie、sessionStorage、localStorage数据共享都遵循同源原则,sessionStorage还限制必须同一个标签页面,在前端给后端发送请求会自动携带cookie中的数据,但是sessionStorage、localStorage不会。
  • 应用场景不同:cookie一般用于存储登录验证信息,sessionId或者token。localStorage常用于存储不易变动的数据,减轻服务器压力,sessionStorage可以用来检测用户是否刷新进入页面

7. 用户输入url到浏览器 渲染完成的过程

  • URL解析和DNS查询:
    浏览器会解析输入的URL,提取出协议、域名、端口、路径等信息。
    浏览器向DNS服务器发起域名解析请求,将域名解析为对应的IP地址。
  • 建立TCP连接:
    浏览器通过IP地址建立与服务器的TCP连接,这涉及三次握手的过程,确保双方连接稳定。
  • 发起HTTP请求:
    浏览器使用建立的TCP连接向服务器发送HTTP请求。
    请求头中包含了请求方法(GET、POST等)、请求路径、请求参数、用户代理信息等。
  • 服务器响应:
    服务器接收到请求后,处理请求并返回HTTP响应。
    响应头中包含了状态码、响应内容类型、缓存信息等。
  • 接收响应数据:
    浏览器开始接收服务器响应的数据,这可能是HTML、CSS、JavaScript等资源。
    数据通过TCP连接传输,并根据响应头中的Content-Length或分块传输等机制进行处理。
  • 解析HTML:
    浏览器解析接收到的HTML内容,构建DOM(文档对象模型)树。
    解析过程中,浏览器会处理HTML标记、元素关系等。
  • 加载外部资源:
    浏览器会解析HTML中的外部资源链接,如CSS、JavaScript、图片等。
    浏览器并行加载这些资源,以提高页面加载速度。
  • CSS解析和渲染:
    浏览器解析已加载的CSS样式,构建CSSOM(CSS对象模型)树。
    浏览器根据DOM和CSSOM树计算出渲染树,用于确定页面的布局和样式。
  • JavaScript解析和执行:
    浏览器解析并执行已加载的JavaScript代码,可以修改DOM、CSSOM和处理交互逻辑。
  • 页面渲染:
    浏览器根据渲染树绘制页面的内容,将内容显示在屏幕上。
  • 完整加载和显示:
    当所有资源加载完成,页面会完整地显示给用户。

8. 简述下三次握手四次挥手
三次握手和四次挥手是TCP协议中用来建立和终止TCP连接的过程。

  • 三次握手是建立一个TCP连接的过程,需要三个步骤:客户端发送连接请求报文段,服务器收到请求并发送确认报文段,客户端收到确认并发送确认报文段。
  • 四次挥手是终止一个TCP连接的过程,需要四个步骤:客户端发送终止请求报文段,服务器收到请求并发送确认报文段,客户端收到确认并发送确认报文段,服务器收到确认并终止连接。

9.常用的数组方法有哪些?
改变原数组:push、pop、shift、unshift、sort、splice、reverse
不会改变原数组:indexOf 、lastIndexOf 、every 、some 、filter 、map 、concat 、slice
slice和splice的区别?
slice:取起始和终止的下标范围进行元素移除(该方法不会修改原数组,只是返回一个新的子数组。)
splice: 可根据传入参数个数不同实现删除、插入操作,第1个参数为起始下标,第2个为删除个数,第3个为要增加的数据(该方法会改变原数组)

两种场景都存在:forEach
如果数组中都是基础数据类型forEach()不会改变原数组。
如果数组中有是引用数据类型(对象(Object)、数组(Array)、函数(Function)。 ),forEach()改变了引用数据类型的值,原数组的也会改变,其原理就是指针指向问题。

10.什么是DOM事件流?
DOM事件流是指在网页中发生交互事件时,事件在各个元素之间传播和触发的过程。当用户在网页上进行点击、输入、滚动等操作时,这些事件会按照特定的顺序从被点击的元素一直传递到根元素,并且触发相应的事件处理函数。

前端事件流分为两种类型:事件冒泡和事件捕获(事件委托)。
事件捕获(Event Capturing):
在事件捕获阶段,事件从根元素开始传播,沿着DOM树向下传递,直到达到触发事件的目标元素。
事件冒泡(Event Bubbling):
在事件冒泡阶段,事件从目标元素开始传播,沿着DOM树向上冒泡,直到达到根元素。这意味着目标元素会先接收事件,然后再依次传递给父级元素。

11.什么是事件循环?

  • 事件循环是指在浏览器或Node环境中事件同步和异步的处理机制,这个机制确保JavaScript代码能够以非阻塞的方式运行,同时处理用户交互和其他异步任务,保证用户体验流畅。
  • 执行顺序:同步代码–>异步任务,异步任务 分为宏任务和微任务,先执行微任务再执行宏任务
  • 宏任务:script 、setTimeout、setInterval 、setImmediate 、I/O 、UI rendering
  • 微任务:MutationObserver、Promise.then()或.catch()或.finally() 、async\await
  • 注意:遇到async函数的时候,await之后的代码属于微任务,相当于promise.then

12.说说你对SPA单页面的理解,它的优缺点分别是什么?
SPA(单页面应用)是指整个应用程序只有一个HTML页面,所有的内容都通过异步加载或动态生成的方式在这个页面中进行展示。SPA通常基于前端框架(如Vue.js、React等)来实现,通过前端路由来控制页面的展示和切换,从而实现快速、流畅的用户体验。

优点:

  • 用户体验好:SPA可以在页面之间快速切换,避免了传统多页面应用的刷新加载,提供了更流畅的用户体验。
  • 前后端分离:SPA采用前后端分离的架构,前端负责页面渲染和交互逻辑,后端负责数据处理和接口提供,使开发更加灵活和高效。
  • 更快的加载速度:SPA在首次加载时会请求较大的JS和CSS文件,但后续页面切换只需要加载数据,因此整体加载速度更快。
  • 代码复用:SPA中的组件化开发使得代码可以更好地复用,减少了重复开发的工作量。
  • 前端路由:SPA采用前端路由管理页面状态,可以实现更灵活的页面切换和导航。

缺点:

  • 首次加载较慢:SPA在首次加载时需要加载较大的JS和CSS文件,可能导致首屏加载时间较长。
  • SEO不友好:由于SPA只有一个HTML页面,搜索引擎难以获取完整的页面内容,对SEO不太友好。虽然现在搜索引擎对SPA的处理能力有所提升,但仍然存在一定的SEO挑战。
  • 内存占用较高:由于SPA在用户使用过程中始终保持一个页面状态,会占用较多的内存,对于资源有限的设备可能会影响性能。
  • 前进后退问题:SPA的前进后退功能通常需要前端路由的支持,某些情况下可能会导致页面状态出现不一致的问题。

13.Vue的优点

  • 易于学习和上手:Vue.js具有简单直观的API和清晰的文档,使得初学者能够快速上手,降低了学习门槛。
  • 渐进式框架:Vue.js是一个渐进式框架,允许开发者逐渐采用其特性,不需要一次性全盘接受整个框架。这使得Vue.js非常灵活,可以与其他库和项目集成使用。
  • 数据绑定和响应式:Vue.js提供了双向数据绑定和响应式系统,使得数据和视图保持同步,数据变化时页面自动更新,简化了数据管理和UI更新的过程。
  • 组件化开发:Vue.js鼓励组件化开发,将页面拆分为多个独立的组件,使代码可复用、可维护性增强,同时也方便团队协作。
  • 虚拟DOM:Vue.js使用虚拟DOM技术,通过比较虚拟DOM树的差异,最小化实际DOM操作,提高了页面渲染效率和性能。
  • 指令和插件:Vue.js提供了丰富的指令和插件,可以轻松实现各种功能,如条件渲染、事件处理、动画效果等。
  • 生态系统丰富:Vue.js拥有庞大的社区和生态系统,有大量的第三方插件、组件和工具可供选择,便于快速开发。
  • 文档和社区支持:Vue.js拥有完善的官方文档和活跃的开发者社区,开发者可以轻松找到解决问题的资源和支持。
  • 性能优化:由于Vue.js的轻量级设计和优化机制,它在性能方面表现出色,能够快速加载和渲染页面,提供更好的用户体验。

综上所述,Vue.js具有简单易学、灵活高效、组件化开发和优秀的性能等众多优点,这些特点使其成为一种非常受欢迎的前端框架,适用于各种规模的Web应用开发。

14.SPA首屏加载速度慢的怎么解决?

  • 代码拆分:将SPA的代码进行拆分,将不同页面或功能模块的代码分开打包成不同的文件,利用Webpack等构建工具的代码分割功能。这样在首次加载时只需要加载当前页面所需的代码,减少了首屏的加载时间。
  • 按需加载:根据用户访问的实际需求,对部分资源进行按需加载。可以利用Vue.js的异步组件或Vue Router的懒加载功能,仅在用户需要时加载对应的组件或页面。
  • 图片优化:对图片进行优化,使用合适的图片格式(如webp,webp是一种同时提供了有损压缩与无损压缩的图片文件格式)和压缩方式,减少图片的大小,提高加载速度。
  • 资源缓存:利用浏览器的缓存机制,将常用的静态资源(如CSS、JS、图片等)进行缓存,避免重复加载。
  • 服务端渲染(SSR):采用服务端渲染的方式,在服务器端将首屏内容渲染为HTML,减少客户端的渲染时间。Vue.js有相应的SSR解决方案,如Nuxt.js。
  • 延迟加载:将非关键性的资源进行延迟加载,等页面主要内容加载完毕后再加载这些资源,从而提高首屏加载速度。
  • 压缩和缓存:对JS、CSS、HTML等资源进行压缩,减少文件大小,同时设置适当的缓存策略,避免重复请求。
  • 代码优化:优化前端代码,减少不必要的操作和重复的计算,提高代码的执行效率。
  • 预加载:利用标签的preload或prefetch属性,预加载后续页面所需的资源,以提前缓存这些资源,优化后续页面的加载速度。

15.Vue初始化过程中(new Vue(options))都做了什么?

  • 创建Vue实例:通过new Vue()来创建一个Vue实例,这是Vue.js的核心对象,用于管理和控制整个应用程序的数据和行为。
  • 数据绑定和响应式:在Vue实例中,通过data属性定义数据对象,这些数据将会与页面上的模板进行绑定。Vue.js提供了响应式系统,当数据发生变化时,页面自动更新,实现数据和视图的同步。
  • 模板编译:Vue.js会将HTML模板中的指令、表达式等进行编译,生成真正的渲染函数。这样,当数据发生变化时,Vue可以根据渲染函数更新视图,实现数据驱动的UI更新。
  • 挂载Vue实例:通过el属性指定Vue实例要挂载到的HTML元素上,或者使用$mount()方法手动挂载。这样,Vue实例就会管理这个HTML元素及其内部的所有内容。
  • 生命周期钩子:Vue实例有一系列的生命周期钩子函数,如created、mounted、updated等,在初始化过程中会依次执行这些钩子函数。这些钩子函数提供了对实例在不同阶段的控制和操作。
  • 监听事件和指令:在初始化过程中,Vue会监听绑定在模板上的事件和指令,以便在相应的时机执行相应的操作,如处理用户的点击事件、触发动画效果等。
  • 虚拟DOM:Vue.js使用虚拟DOM技术,在渲染过程中,Vue会先生成虚拟DOM树,并通过比较虚拟DOM树的差异,最小化实际DOM操作,提高了页面渲染效率和性能。
  • 注册组件:在初始化过程中,Vue会注册全局组件和局部组件,使得组件可以在页面中进行使用,实现模块化开发和代码复用。
  • 初始化路由:如果应用中使用了Vue Router进行路由管理,Vue会在初始化过程中初始化路由配置,使得页面之间可以通过路由进行切换。

总体来说,Vue初始化过程主要包括创建Vue实例、数据绑定、模板编译、挂载实例到HTML元素上以及初始化生命周期钩子等过程。通过这些步骤,Vue实例就能够成功运行和管理应用程序,并实现数据驱动的UI更新。

16.对MVVM的理解?
MVVM是一种软件架构模式,它是Model-View-ViewModel的缩写。MVVM将应用程序划分为三个主要部分,每个部分负责不同的功能,Model 层代表数据模型,也可以在Model中定义数据修改和操作的业务逻辑;View 代表UI 组件,它负责将数据模型转化成UI 展现出来;ViewModel 是一个同步View 和 Model的对象。

MVVM的优点包括:

  • 分离关注点:MVVM将视图和模型分离,使得前端开发人员可以专注于用户界面的开发,后端开发人员可以专注于业务逻辑和数据处理,提高了代码的可维护性和可扩展性。
  • 数据驱动:MVVM通过数据绑定机制实现数据与视图的自动同步,减少了手动操作DOM的复杂性和潜在的错误。
  • 可测试性:MVVM的视图模型是独立于视图的,使得逻辑代码可以更容易地进行单元测试。

总的来说,MVVM是一种使得前端开发更加高效、可维护和可测试的软件架构模式,它在现代前端框架如Vue.js和Angular中得到了广泛的应用。

17.说说vue的生命周期的理解
Vue.js组件的生命周期是指在组件创建、挂载、更新和销毁的过程中,Vue实例会依次触发一系列的钩子函数。这些钩子函数允许你在不同的阶段执行自定义的操作,以适应不同的业务需求。
以下是每个生命周期阶段通常做的事情:

  • beforeCreate:
    – 初始化数据和事件。
    – 进行一些非响应式的数据初始化,如计算属性、方法等。
    – 不能访问到 this.$el 和组件的数据。
  • created:
    – 完成数据的初始化和事件的绑定。
    – 可以访问到 this.$el,但尚未挂载到DOM。
    – 适合进行一些异步操作,如请求数据。
  • beforeMount:
    – 模板编译完成,但未渲染到DOM。
    – 可以访问到 this.$el 和组件的数据。
    – 适合进行一些DOM操作和数据准备。
  • mounted:
    – 组件已经挂载到DOM。
    – 可以访问到 this.$el 和组件的数据。
    – 适合进行DOM操作,初始化第三方库,进行数据请求等。
  • beforeUpdate:
    – 数据即将更新,但DOM尚未重新渲染。
    – 可以访问到组件的数据。
    – 适合进行数据的准备和处理。
  • updated:
    – 数据已经更新,DOM已重新渲染。
    – 可以访问到组件的数据。
    – 适合进行DOM操作,如更新后的DOM状态、手动操作等。
  • beforeDestroy:
    – 组件即将销毁。
    – 可以进行资源的清理,如定时器的销毁、取消事件监听等。
  • destroyed:
    – 组件已经销毁,DOM上的元素已经被解绑。
    – 适合进行最后的清理操作,如取消异步请求、释放内存等。

Vue.js 3.x 在生命周期方面有一些变化,具体的钩子函数和执行顺序可能有所不同,例如新增了beforeUnmount和unmounted钩子。

生命周期的使用让你能够在组件的不同阶段执行相应的操作,例如在created阶段初始化数据、在mounted阶段执行DOM操作、在beforeDestroy阶段进行资源清理等。这些钩子函数使你能够更好地控制和定制组件的行为,以满足不同的业务需求。

18.Vue数据双向绑定原理?
Vue的数据双向绑定是其核心特性之一,它使得模型(Model)中的数据与视图(View)之间能够自动保持同步,即当数据发生变化时,视图会自动更新;当用户在视图中进行交互操作时,数据也会相应地更新。
Vue的数据双向绑定原理可以简单概括为以下几个步骤:

  • 初始化:在Vue实例创建时,会通过观察者(Watcher)对象对模型中的数据进行监听。
  • 模板编译:Vue会对模板(HTML)进行编译,解析模板中的指令和表达式,生成渲染函数。
  • 渲染函数:渲染函数根据模型中的数据生成虚拟DOM(Virtual DOM)。
  • 首次渲染:首次渲染会将虚拟DOM转化为真实DOM,并将其插入到页面中。
  • 数据更新:当模型中的数据发生变化时,观察者会检测到变化,并通知视图进行更新。
  • 视图更新:视图更新会重新生成虚拟DOM,并与之前的虚拟DOM进行对比(Diff算法),找出变化的部分,然后将变化的部分更新到真实DOM中。
  • 用户交互:当用户在视图中进行交互操作(比如输入框输入文字)时,视图会触发事件,并通知观察者。
  • 数据更新:观察者会更新模型中的数据,保持数据与视图的同步。

整个过程中的关键是虚拟DOM和Diff算法。虚拟DOM是一个轻量级的JavaScript对象,它对真实DOM进行抽象,通过虚拟DOM的比对,可以最小化真实DOM的操作,从而提高性能。Diff算法是Vue中用于比较新旧虚拟DOM的算法,它能够找出变化的部分,只更新需要更新的部分,减少不必要的DOM操作。

总体来说,Vue的数据双向绑定原理是通过观察者、虚拟DOM和Diff算法相互配合,使得模型中的数据与视图保持同步,实现了数据驱动的UI更新,提供了更高效、响应迅速的用户体验。

19.Vue2.x的响应式原理?

Vue的响应式原理是实现数据双向绑定的核心机制,它使得模型(数据)和视图(DOM)能够自动保持同步。Vue的响应式原理主要依赖于以下几个关键概念:

  • 响应式数据对象:在Vue中,通过data属性定义的数据对象是响应式的。当Vue实例创建时,Vue会遍历data中的所有属性,将它们转换为响应式数据对象。
  • 响应式转换:Vue使用Object.defineProperty方法将数据对象的每个属性转换为响应式属性。在这个过程中,Vue重写了属性的getter和setter方法,使得属性的读取和修改都会被监听到。
  • 依赖追踪:当视图渲染时,会访问数据对象的属性。在这个过程中,Vue会通过getter捕获对属性的依赖。Vue利用一个全局的依赖管理器(Dep)来记录响应式数据对象的所有依赖关系。
  • 依赖更新:当响应式数据对象的属性发生变化时,其setter方法会被触发。setter会通知依赖管理器,然后依赖管理器会通知所有依赖该属性的地方,使得相关的视图进行更新。
  • 虚拟DOM和Diff算法:当数据发生变化时,Vue会通过虚拟DOM和Diff算法,找出真实DOM中需要更新的部分,并进行最小化的DOM操作,提高性能。

总的来说,Vue的响应式原理是通过Object.defineProperty方法将数据对象的属性转换为响应式属性,然后通过依赖追踪和依赖更新机制实现数据与视图的自动同步。这样,当数据发生变化时,相关的视图会自动更新,实现了数据驱动的UI更新,提供了更高效、灵活的开发方式。

// Vue的data对象中的每个属性都会被转化为getter和setter,这样Vue能够监听属性的变化,并在变化时执行相应的操作。
const obj = {};
Object.defineProperty(obj, 'count', {
  get() {
    console.log('Getting count');
    return this._count;
  },
  set(value) {
    console.log('Setting count to', value);
    this._count = value;
  }
});

obj.count = 666; // 触发setter,输出"Setting count to 666"
console.log(obj.count); // 触发getter,输出"Getting count" 和 666

20.Vue中data的属性可以和methods中方法同名吗,为什么?
在Vue中,data属性和methods中的方法可以同名,但不推荐这样做。如果出现同名的情况,Vue会发出警告,并且methods中的方法将会覆盖data中的属性。

原因是因为在Vue实例中,data对象中的属性和methods对象中的方法是在同一个命名空间中的。当Vue实例进行初始化时,会将data中的属性和methods中的方法合并到Vue实例中,所以如果出现同名的情况,methods中的方法会覆盖data中的属性。

举个例子:

var app = new Vue({
  el: '#app',
  data: {
    message: 'Hello',
    count: 0 // 同名属性
  },
  methods: {
    count: function() {
      this.count++; // 会调用methods中的count方法,而不是data中的count属性
    }
  }
});

21.vue中created与mounted区别?
在Vue中,created和mounted是两个生命周期钩子函数,用于在Vue实例的不同生命周期阶段执行特定的操作。它们之间有一些区别,下面进行详细说明:
created:
created生命周期钩子在Vue实例被创建后立即被调用,此时实例已经完成了数据的观测,但DOM元素尚未挂载到页面上,因此此时无法访问或操作DOM。
created钩子通常用于进行一些初始化的操作,如数据的预处理、异步请求数据、监听事件等,但不能保证所有子组件已经被挂载。
在created钩子中,可以访问实例的数据和方法,但还不能操作页面上的DOM元素。
mounted:
mounted生命周期钩子在Vue实例的挂载阶段被调用,此时Vue实例已经将DOM元素挂载到页面上,可以进行DOM操作。
mounted钩子通常用于需要进行DOM操作、和其他框架或库进行交互的情况,例如设置定时器、初始化第三方插件、获取DOM元素的尺寸等。
在mounted钩子中,可以访问实例的数据和方法,同时也可以操作页面上的DOM元素。

综上所述,created钩子在Vue实例创建后立即执行,适用于数据初始化和数据请求等操作;而mounted钩子在Vue实例挂载到页面后执行,适用于DOM操作和和其他框架交互等操作。在使用这两个钩子时,需要根据具体需求选择合适的时机执行相应的操作。

22.Vue中computed与method的区别?
computed:
computed用于定义计算属性,它是一个函数,但在Vue中使用时,像是一个响应式的数据属性。
computed是基于它所依赖的响应式数据的值进行缓存的,只有在依赖的响应式数据发生变化时,才会重新计算,否则会直接使用缓存的计算结果。
computed适用于需要根据响应式数据进行计算得出结果的场景,比如对数据进行过滤、排序、求和等操作。
methods:
methods用于定义普通方法,它也是一个函数,但在Vue中使用时,它是一个普通的方法,每次调用都会重新执行。
methods适用于需要主动触发的操作,或者操作中不依赖响应式数据的场景。

23.虚拟DOM中key的作用

在虚拟DOM中,key是一个特殊的属性,用于帮助Vue或其他前端框架在进行DOM Diff(差异对比)时更高效地更新视图。
虚拟DOM通过比较新旧虚拟DOM树的差异来确定需要更新的部分,并最小化对实际DOM的操作,以提高渲染性能。在进行Diff算法时,如果新旧虚拟DOM的节点顺序发生变化,可能会导致一系列的节点删除和插入操作,而这些操作可能会引起不必要的性能开销。
这就是key的作用所在。key是给每个虚拟DOM节点添加的唯一标识符。通过key,Vue可以更准确地追踪每个节点的变化,从而在更新时能够最小化操作。当新旧虚拟DOM的节点顺序发生变化时,Vue会通过key来识别节点的对应关系,而不是简单地按顺序进行比较。这样,在对比时可以准确找到需要移动的节点,而不是删除和插入节点,大大减少了DOM操作的开销,提高了渲染性能。
要注意的是,key应该是唯一且稳定的。在使用key时,不应该使用随机数、时间戳等不稳定的值作为key,因为这可能导致不必要的DOM操作。应该使用每个节点在列表中的唯一标识符,比如数据中的ID值作为key。

用index作为key可能会引发的问题
若对数据进行:逆序添加/逆序删除等破坏顺序的操作,会产生没有必要的真实DOM更新,界面效果虽然没有问题,但是数据过多的话,会效率过低;
如果结构中还包含输入类的DOM,会产生错误DOM更新,界面有问题;
注意!如果不存在对数据的逆序操作,仅用于渲染表用于展示,使用index作为key是没有问题的。

24.Vue中watch用法详解
当你在Vue中使用watch来监听数据的变化时,你可以在组件的选项对象中使用watch属性来定义观察者。watch属性接受一个对象,对象的每个属性都是要观察的数据属性,而属性的值是一个处理数据变化的回调函数。这些回调函数会在被观察的数据发生变化时被调用。
用法如下:

export default {
  data() {
    return {
      user: {
        name: 'Alice',
        age: 25,
      },
    };
  },
  watch: {
    user: {
      handler(newValue, oldValue) {
        console.log('user属性发生变化:', newValue, oldValue);
      },
      immediate: true, // 在watch定义时立即触发回调
      deep: true, // 启用深度观察
    },
  },
};

通过watch,你可以更精细地处理数据变化时的逻辑,例如数据的验证、异步操作等。

25.vue中对mixins的理解和使用
在Vue中,Mixins(混入)是一种用于组件复用的特性,它允许你将一些通用的选项、数据、方法等抽离出来,然后在多个组件之间进行复用。通过Mixins,你可以在不同的组件中共享相同的代码,从而提高代码的复用性和可维护性。
Mixins的理解和使用包括以下几点:

  • Mixins是一种将通用功能抽象为可重用代码块的方式。它可以包含组件选项、数据、方法、生命周期钩子等。
  • 当一个组件使用了一个或多个Mixins,它会继承这些Mixins中的选项和代码。
  • 可以通过创建一个普通的JavaScript对象来定义Mixins。这个对象可以包含任意的组件选项,例如data、methods、computed、created等。
    示例:
// mixins.js
export const myMixin = {
  data() {
    return {
      count: 0,
    };
  },
  methods: {
    increment() {
      this.count++;
    },
  },
};

使用Mixins:
在组件选项中使用mixins属性来引入Mixins。可以引入一个或多个Mixins,它们会被合并到组件中。
Mixins的合并规则:当多个Mixins和组件具有相同的选项(如data、methods等)时,它们会按照一定的合并策略进行合并,通常是通过数组合并、覆盖、合并钩子等方式。
示例:

// MyComponent.vue
import { myMixin } from './mixins';

export default {
  mixins: [myMixin],
  // 其他组件选项...
};

Mixins的注意事项:

  • Mixins能够提高代码复用,但过度使用Mixins可能会导致代码变得难以维护和理解。适度使用Mixins,尽量避免过多的嵌套,以保持代码的清晰性。
  • 注意Mixins之间的命名冲突,确保各个Mixins中的选项名称不会产生冲突。

总之,Mixins是Vue提供的一种强大的组件复用机制,可以帮助你更好地组织和管理代码,提高开发效率。但需要谨慎使用,以避免混乱和冲突。

26.vue中的插槽
插槽(Slot)是Vue中用于组件内容分发的一种机制,它允许你在组件的模板中定义一些“占位符”,然后在使用该组件时,将具体内容插入到这些占位符中。插槽使得组件的结构更加灵活,能够更好地适应不同的使用场景。

Vue中的插槽分为两种类型:

  • 默认插槽:默认插槽用于接收未命名的内容。当一个组件没有具名插槽时,传入的内容会被放置在默认插槽中。在组件的模板中,使用元素来表示默认插槽的位置。
// 子组件的模板: 
<template>
  <div>
    <h2>默认插槽示例</h2>
    <slot></slot> <!-- 默认插槽的位置 -->
  </div>
</template>

// 父组件使用子组件
<template>
  <div>
    <my-component>
      <p>This is the default slot content.</p>
    </my-component>
  </div>
</template>

  • 具名插槽:具名插槽允许你在子组件中定义多个插槽,并为每个插槽指定一个名字。在子组件的模板中,使用元素的name属性来表示具名插槽的位置。
// 子组件的模板: 
<template>
  <div>
    <h2>子组件</h2>
    <slot name="header"></slot> <!-- 名为"header"的具名插槽位置 -->
    <slot></slot> <!-- 默认插槽的位置 -->
    <slot name="footer"></slot> <!-- 名为"footer"的具名插槽位置 -->
  </div>
  </template>
// 父组件使用子组件
  <template>
  <div>
    <my-component>
      <template v-slot:header>
        <h3>This is the header slot content.</h3>
      </template>
      <p>This is the default slot content.</p>
      <template v-slot:footer>
        <footer>This is the footer slot content.</footer>
      </template>
    </my-component>
  </div>
</template>

27.$nextTick的理解
$nextTick是Vue.js中的一个异步方法,它的作用是在下次DOM更新循环结束之后执行指定的回调函数。在Vue中,数据的更新是异步的,所以有时候在修改数据后立即获取更新后的DOM状态可能会出现问题。nextTick允许你在DOM更新之后执行一些操作,以确保你操作的是最新的DOM状态。

使用的场景包括:

  • 操作DOM元素:如果你修改了数据后需要立即操作更新后的DOM元素,可以使用$nextTick来确保操作的时机。
  • 获取更新后的计算属性或DOM状态:当你修改数据后,可能会需要获取计算属性或DOM状态,使用$nextTick可以确保你获取到的是更新后的值或状态。
  • 在更新后执行某些逻辑:有时候你需要在数据更新后执行一些逻辑,例如触发事件、调用方法等,可以使用$nextTick来确保逻辑在DOM更新之后执行。

28.Vue中常用的一些指令
Vue中常用的一些指令是用于在模板中控制DOM渲染和行为的特殊标记。这些指令以"v-"开头,可以在HTML模板中直接使用,用于绑定数据、控制显示/隐藏、循环、条件判断等操作。
以下是一些常用的Vue指令:

  • v-bind:用于绑定HTML属性或组件props到Vue实例的数据。( 简写 :src=“url” )
  • v-model:用于实现双向数据绑定,将表单元素和数据属性双向关联。
  • v-for:用于循环渲染一组元素或组件。
  • v-if / v-else-if / v-else:用于条件渲染,根据条件来显示/隐藏元素。
  • v-show:类似于v-if,但使用CSS的display属性来控制元素的显示/隐藏。
  • v-on:用于监听DOM事件,并在触发时执行相应的方法。 (简写 @click=“handleClick” )
  • v-once:只渲染元素和组件一次,后续的更新将被忽略。
  • v-text:更新元素的文本内容,类似于插值语法{{}}。

29.vue的自定义指令
在Vue中,你可以创建自定义指令来扩展模板中的功能。自定义指令允许你在DOM元素上添加额外的行为或逻辑,使得你可以在模板中复用这些行为。自定义指令以v-开头,后面跟着指令的名称,例如v-mydirective。

在Vue中,你可以通过Vue.directive方法来定义自定义指令。这个方法接受两个参数:指令名称和一个对象,该对象包含了指令的一些钩子函数和属性。

// 自定义指令
Vue.directive('mydirective', {
  // 指令的绑定时调用
  bind(el, binding) {// 在绑定时执行一些逻辑
    // 在绑定时设置元素的背景颜色
    el.style.backgroundColor = binding.value;
  },
  // 指令的更新时调用
  update(el, binding) {
    // 在更新时执行一些逻辑
  },
  // 指令的解绑时调用
  unbind(el, binding) {// 在解绑时执行一些逻辑
    // 在解绑时清理样式
    el.style.backgroundColor = '';
  }
});

// 在模板中使用自定义指令时,将指令名称作为属性添加到DOM元素上,并可以使用指令表达式传递参数。
<template>
  <div>
    <p v-mydirective="'Hello, Vue!'">Custom directive example</p>
  </div>
</template>

自定义指令的钩子函数:
自定义指令可以定义多个钩子函数,用于不同的生命周期阶段执行不同的逻辑。

  • bind:在元素和指令绑定时执行。可以用来初始化一些数据或设置初始状态。
  • inserted:在元素被插入到父节点时执行。
  • update:在元素和指令所在组件的VNode更新时执行。
  • componentUpdated:在元素和指令所在组件的VNode以及子组件的VNode更新时执行。
  • unbind:在元素和指令解绑时执行,清理绑定的事件监听器等。

自定义指令的常见应用场景:

  • 权限控制指令:你可以创建一个自定义指令,用于根据用户权限动态控制元素的显示或隐藏。这可以帮助你在模板中根据用户角色来控制访问权限。
  • 表单验证指令:自定义指令可以用于实现自定义的表单验证逻辑。你可以创建一个自定义指令,根据不同的验证规则来验证表单输入,并在错误时显示相应的提示信息。
  • 滚动加载指令:如果你需要实现滚动加载更多内容的功能,可以创建一个自定义指令,监听滚动事件并在滚动到底部时触发加载更多数据的操作。
  • 自定义样式指令:你可以创建一个自定义指令,用于根据某些条件动态添加或移除元素的样式类,实现特定的样式效果。
  • 剪贴板复制指令:自定义指令可以帮助你实现点击复制文本到剪贴板的功能,从而简化用户操作。
  • 自定义动画指令:如果需要在特定条件下触发动画效果,你可以创建一个自定义指令,用于在元素插入或更新时触发自定义的动画效果。
  • 自定义事件指令:你可以创建一个自定义指令,用于简化事件的绑定和解绑操作,从而使代码更加简洁。
  • 第三方库的集成指令:有时候你可能需要将第三方库(如地图库、日期选择器等)集成到Vue应用中,可以通过自定义指令来封装这些库的功能。

总的来说,自定义指令可以用于各种各样的场景,帮助你实现特定的交互效果、优化代码结构,以及集成第三方功能,从而让你的Vue应用更加强大和灵活。

30.v-show和v-if指令的共同点和不同点

v-show和v-if都是Vue中用于控制元素显示与隐藏的指令
共同点:

  • 都用于条件渲染:v-show和v-if都可以根据特定的条件来控制元素的显示或隐藏。
  • 响应式:无论是v-show还是v-if,都是响应式的,当数据发生变化时,元素的显示或隐藏状态会自动更新。
  • DOM结构:v-show和v-if都会影响DOM结构,但它们的影响程度略有不同。

不同点

  • 渲染方式:v-show:使用CSS的display属性来控制元素的显示与隐藏,元素仍然在DOM中存在,只是在视觉上不可见。
    v-if:通过在DOM中插入或移除元素来控制元素的显示与隐藏,元素的存在与否会影响DOM结构。
  • 初始渲染性能: v-show:初始渲染时,v-show的元素会被渲染,但通过CSS的display属性进行隐藏,因此初始渲染性能相对较高。 v-if:初始渲染时,v-if的元素只有在条件为满足时才会被渲染,初始渲染性能相对较低。
  • 切换开销:v-show:切换显示与隐藏时,不会销毁和重新创建元素,只是通过CSS来切换,因此切换开销较低。
    v-if:切换显示与隐藏时,会销毁和重新创建元素,切换开销相对较高。

适用场景:
v-show:适用于频繁切换显示状态的情况,或者在初始渲染时需要保持较好的性能。
v-if:适用于条件较少变化、或者在切换时涉及较复杂操作的情况。

31.为什么避免v-if和v-for一起使用
Vue中,尽量避免在同一个元素上同时使用v-if和v-for是因为这样的组合可能会导致意外的行为和性能问题。虽然不是绝对禁止,但需要小心使用,并理解其中的潜在问题。
一起使用的情况下,vue2.x版本中,v-for 具有比 v-if 更高的优先级;vue3.x版本中,v-if 具有比 v-for 更高的优先级。

  • 性能问题:当v-if和v-for一起使用时,Vue会在每次渲染循环时都重新创建和销毁元素,这会对性能产生不良影响。因为v-if会在每次循环迭代中检查条件,从而可能导致不必要的DOM操作和重复计算。
  • 可读性和维护性:将v-if和v-for一起使用可能会让模板变得复杂,降低代码的可读性和维护性。代码难以理解,不容易推断出元素的显示与隐藏逻辑。
  • 逻辑混淆:v-if用于条件渲染,而v-for用于循环渲染,将它们结合使用可能会混淆代码逻辑。你可能会不小心在循环内部或外部添加条件逻辑,导致出现预期之外的结果。

避免v-if和v-for一起使用的方法:

  • 使用计算属性:如果需要同时进行条件渲染和循环渲染,可以使用计算属性来处理逻辑,将条件判断放在计算属性中,然后在模板中只使用单个指令。
  • 使用