前端面试题大乱斗
一.vue3相比vue2升级了哪些功能?
-
性能提升:vue3使用了新的编译器和响应式系统(proxy)
-
组合式API:vue3引入了组合式API可以让开发者更加灵活的书写代码和复用逻辑,避免了vue2中代码冗余和可读性问题,组合式api使用setup函数来定义组件的状态和行为,使用ref和reactive函数来创建响应式数据,使用computed,watch函数来创建计算属性和监听器,使用provide和inject来实现跨组件通信
-
多根节点:vue3允许开发者书写多个根节点,不需要使用额外的div包裹,减少不必要的dom元素,来提高渲染效率
-
片段:vue3支持在模板中返回多个子元素,而不需要使用v-for,v-if指令,避免创建多余的数据或对象,简化模板结构
-
teleport:新增了一个新的内置组件,可以将子元素渲染到任意位置,如弹出层,可以防止子元素受到父元素的事件样式影响,更加方便的控制子元素的显示与隐藏
-
Suspense:新增了一个新的内置组件,异步组件加载占位符,提高用户体验,可以自动检测异步依赖,并在所有依赖都解析完后渲染默认插槽内容,否则渲染fallback插槽内容
-
全局api的变化:vue3对全局api进行了重构,将其从vue构造函数中移除,改用应用实例来注册和使用,避免全局api污染命名空间,也可以让不同应用实例拥有不同配置
-
自定义渲染器api:vue3暴露了一个更低层次的渲染器API,让开发者可以自定义渲染行为,甚至创建自己的渲染器,让vue适应不同的平台和环境
二.vue3中的proxy vs Object.defineProperdy
-
proxy可以拦截更多的操作:Object.defineProperdy只能拦截属性的读取和赋值,而proxy还可以拦截对象的增删改查等多种操作,这样可以更准确的检测到数据的变化,避免不必要的更新
-
proxy可以递归处理嵌套对象:Object.defineProperdy只能处理对象的第一层属性,遇到所层属性嵌套,需要递归遍历属性添加getter,seter这样会消耗更多性能,proxy可以直接处理嵌套对象,不需要递归遍历,只有访问到某属性时才会创建proxy对象,这样可以节省内存和性能
-
proxy是语言层面的特性:Object.defineProperty是一个函数,需要在运行时执行,而proxy是一个语言层面的特性,可以在编译时优化,这样可以提高执行效率
三.你是如何看待组合式api和选项式api
-
组合式API更适合复杂的组件:组合式API让开发者可以使用函数式的风格来编写组件,可以更灵活地组织和复用代码逻辑,避免了选项式API中的代码冗余和可读性问题。组合式API也可以更方便地实现逻辑的抽象和封装,提高代码的可维护性和可测试性
-
选项式API更适合简单的组件:选项式API是vue的传统方式,它使用一系列的选项来定义组件的状态和行为,例如data, methods, computed等。选项式API更符合开发者的直觉,也更容易上手和理解。选项式API也有一定的结构性和规范性,可以让代码更清晰和一致
-
两种API可以共存和互补:vue3并没有强制开发者使用一种API,而是允许两种API共存和互补。开发者可以根据自己的喜好和项目情况选择合适的API,甚至可以在一个组件中混合使用两种API。vue3也提供了一些工具函数来帮助开发者在两种API之间进行转换,例如toRefs, toRaw等
四.ref, toRef, toRefs有什么区别
-
ref:ref可以将一个基本类型的值转换为一个响应式的对象,这个对象有一个value属性,指向原始值。ref可以用来创建单个的响应式变量,例如数字、字符串、布尔值等。例如:const count = ref(0)。
-
toRef:toRef可以将一个响应式对象的某个属性转换为一个响应式的对象,这个对象也有一个value属性,指向原始属性。toRef可以用来创建单个的响应式属性,例如对象或数组的某个元素。例如:const state = reactive({name: ‘Alice’, age: 18}); const nameRef = toRef(state, ‘name’)。
-
toRefs:toRefs可以将一个响应式对象转换为一个普通对象,这个对象的每个属性都是一个响应式的对象,指向原始对象的对应属性。toRefs可以用来创建多个的响应式属性,例如对象或数组的所有元素。例如:const state = reactive({name: ‘Alice’, age: 18}); const stateRefs = toRefs(state)
五.watch和watchEffect
-
watch:可以监听一个或多个响应式数据源,当数据源发生改变时执行内部的回调函数,watch可以指定侦听的数据源,访问变化前后的值。watch可以用来处理一些有条件或有副作用的逻辑,例如根据某个属性的变化发起异步请求或执行动画等。例如:watch(count, (newCount, oldCount) => {console.log(
count changed from ${oldCount} to ${newCount}
)})。 -
watchEffect:watchEffect可以自动追踪一个函数内部使用的所有响应式数据源,当任何一个数据源发生变化时,重新执行这个函数。watchEffect不需要指定侦听的数据源,也不能访问变化前后的值。watchEffect可以用来处理一些无条件或无副作用的逻辑,例如根据多个属性的变化更新DOM或计算属性等。例如:watchEffect(() => {console.log(
count is ${count.value}
)})。
六.vue3生命周期相比vue2区别
-
生命周期钩子的命名变化:vue3的生命周期钩子在vue2的基础上,增加了一个on前缀,例如mounted变为onMounted,updated变为onUpdated,destroyed变为onUnmounted等。这样可以避免与组件自身的方法名冲突,也可以与组合式API中的其他函数区分开
-
新增的生命周期钩子:vue3新增了两个生命周期钩子,分别是onRenderTracked和onRenderTriggered。这两个钩子可以让开发者追踪和调试组件的渲染依赖,了解哪些数据源导致了组件的重新渲染
-
废弃的生命周期钩子:vue3废弃了两个生命周期钩子,分别是beforeDestroy和destroyed。这两个钩子在vue3中被替换为beforeUnmount和onUnmounted。这样可以与其他钩子的命名保持一致,也可以避免与JavaScript中的destroy关键字混淆。
七.cookie,session,jwt的区别
-
cookie是一种客户端储存用户信息的机制,它以键值对的的形式保存在浏览器中每次请求同一域名都会带上cookie
-
session是一种在服务器端储存用户信息的机制,它以session_id为键,用户信息储存在服务器中,同时把session_id作为cookie发送给客户端,客户端每次请求都会带上这个session_id用来识别用户
-
jwt是一种基于token的认证协议,它由header,payload,signature组成,header包含token类型和加密算法,payload包含了用户的状态信息和其他数据,signature包含由header,payload,服务器的密钥加密生成的签名
优缺点如下:
-
cookie优点结构简单,储存时间长,缺点是大小受到限制,非常不安全,容易受到csrf攻击
-
session优点是数据储存在服务器相对安全,缺点是增加了服务器开销,不利于分布式应用的拓展
-
jwt的优点是支持跨语言请求,可以自身储存一些数据便于传输,不需要在服务器保存会话信息缺点是登录状态信息续签问题,用户主动注销问题
八.了解websocket,项目中使用过websocket吗
它是一种在单个TCP连接上进行全双工通信的协议,可以让服务器主动向客户端推送数据,适合实时交互的场景。我在项目中使用过websocket,比如实现了一个简单的聊天室功能,让用户可以通过websocket发送和接收消息
九.发布订阅和观察者模式的区别
-
发布订阅模式和观察者模式都是一种一对多的通信方式,可以实现事件的广播和监听,但是它们的实现方式不同
-
观察者模式中,观察者和目标对象直接交互,观察者需要订阅目标对象的状态变化,目标对象在发生变化时会通知所有的观察者
-
发布订阅模式中,发布者和订阅者之间通过一个调度中心进行通信,订阅者需要订阅调度中心的主题,发布者在发布主题事件时会通过调度中心通知所有订阅该主题的订阅者
-
发布订阅模式相比观察者模式,解耦了发布者和订阅者之间的依赖关系,可以更灵活地组织和管理事件的发布和订阅
-
发布订阅模式相比观察者模式,可以更容易地实现跨进程或跨网络的通信
十,项目的性能优化
-
网络层面的优化:例如减少htttp的请求次数和大小,使用cdn加速静态资源的加载,开启Gzip压缩,使用HTTP缓存机制,使用DNS预解析等
-
前端层面的优化:例如使用代码分割,和懒加载技术,优化图片和字体资源的加载,例如使用web worker和service worker处理耗时任务,避免不必要的Dom操作和重排重绘,使用虚拟列表和分页渲染大量数据等
-
后端层面的优化,例如使用缓存存储热点数据,减少数据库查询次数和复杂度,优化接口逻辑和响应时间,使用负载均衡和集群提高并发能力等
-
项目架构层面的优化,例如根据业务场景选择合适的技术方案,比如SSR、CSR、BigPipe、BigRender等,使用微前端或者微服务拆分复杂的项目模块,使用性能监控工具定位和解决性能瓶颈等
十一.webpack优化
-
优化开发体验:例如使用HMR和DevServer实现热更新和自动刷新,使用source-map方便调试源码,使用eslint和prettier等工具规范代码风格等
-
构建速度优化:例如使用多进程和多线程处理任务,使用缓存提高二次构建效率,使用DLLPlugin和DLLReferencePlugin预编译第三方模块,优化loader的配置和范围,优化resolve的配置和别名等
-
优化输出质量:例如使用代码分割和懒加载技术,使用Tree Shanking和Scope Hoisting消除无用代码,使用MiniCssExtractPlugin提取CSS文件,使用OptimizeCssAssetsPlugin压缩CSS文件,使用HtmlWebpackPlugin压缩HTML文件,使用CompressionPlugin开启Gzip压缩,使用externals引入CDN资源等
十二.什么是虚拟DOM
-
虚拟DOM是一种使用javascript来直接描述真实DOM的和结构属性,而不影响真实的DOM
-
虚拟DOM的作用是提高页面的渲染性能,它通过比较新旧dom的差异,来计算出最小的dom操作,然后批量更新到真实dom上从而避繁和不必要的DOM操作
-
虚拟DOM的算法主要包括三个步骤:用JavaScript对象结构表示DOM树的结构;当状态变更时,重新构造一棵新的对象树,并和旧的树进行比较,记录两棵树的差异;把记录的差异应用到真正的DOM树上,更新视图
十三.什么是指令
-
指令就是dom功能的抽象封装,给元素或组件绑定一些特殊的行为或功能
-
作用是简化代码,让我们不需要直接操作DOM而是通过声明的方式来控制元素或组件的渲染、显示、事件等
十四.什么是自定义指令
-
vue自定义指令是一种可以注册和使用的自定义行间属性,以v-开头给元素或组件绑定一些特殊的行为或功能
-
vue自定义指令可以通过Vue.directive()方法来全局注册,也可以通过directives选项来局部注册,还可以在setup()函数中通过directive()方法来注册
-
vue自定义指令由一个包含类似组件生命周期钩子的对象来定义,常用的钩子有created、beforeMount、mounted、beforeUpdate、updated、beforeUnmount、unmounted等,钩子函数会接收到指令所绑定元素和一个包含value、oldValue、arg、modifiers等属性的binding对象作为参数
-
项目中有一些常用的DOM功能需要复用,建议封装成指令这就是自定义指令
十五.你有封装过vue插件吗,怎么封装的?封装过什么?
vue插件是一种可以为vue应用或组件添加全局功能或特性的扩展,比如路由、状态管理、UI组件库、自定义指令等
vue插件封装的过程主要包括以下几个步骤:
-
定义一个插件对象,它必须有一个install方法,该方法接收一个Vue构造器和一个可选的选项对象作为参数
-
在install方法中,可以通过Vue的全局方法或属性来扩展vue的功能,比如Vue.directive()、Vue.component()、Vue.mixin()、Vue.prototype等
-
在使用插件时,可以通过Vue.use()方法来全局注册插件,也可以通过createApp().use()方法来局部注册插件
-
在注册插件时,可以传递一个选项对象给插件,用来自定义插件的行为或配置
十六.谈一下vue.nextTick()的理解?有什么作用
-
vue.nextTick()是一个方法,它可以在下次DOM更新循环结束之后执行一个回调函数,这样就可以在回调函数中获取更新后的DOM
-
vue.nextTick()的作用是解决vue的异步更新策略导致的DOM更新延迟问题,因为vue会把数据变化的watcher推入一个队列中,然后在下一个事件循环中才清空队列并更新DOM,所以如果我们在数据变化后立即操作DOM,可能会得到旧的DOM
-
vue.nextTick()的用法有两种,一种是传入一个回调函数作为参数,另一种是返回一个promise对象,然后使用then方法添加回调函数
vue.nextTick()的使用场景有以下几种:
-
在created钩子函数中进行DOM操作,因为此时DOM还没有渲染,所以需要使用vue.nextTick()来等待DOM渲染完成
-
在数据变化后进行基于新DOM的操作,比如获取新DOM的高度、宽度、位置等
-
在使用第三方插件时,如果需要在vue生成的某些DOM动态变化时重新应用插件,也需要使用vue.nextTick()来保证插件能正确应用到新DOM上
十七.简述vuex的工作流程
-
vuex是一个专为vue应用开发的状态管理模式,它可以让我们在组件之间共享数据和状态,以及实现一些高级功能,如撤销/重做、持久化等
-
vuex的工作流程主要包括以下几个步骤:
1.客户端操作事件,dispatch调用一个action
2.action接收到这个事件之后,在action中可以执行一些异步或同步操作,根据不同的情况去分发给不同的mutation,action通过commit去触发mutation
3.mutation接收到一个type类型触发对应的函数,修改state值
4.state更改后对应的view视图在render的作用下重新渲染 vuex的工作流程可以用下面的图示来表示¹:
十八.了解浏览器缓存吗?什么是强缓存,什么是协商缓存?有哪些相关的头
浏览器缓存是指浏览器在本地保存资源的一种机制,可以提高网页的加载速度和用户体验。浏览器缓存分为强缓存和协商缓存,它们的区别和相关的头如下:
-
强缓存是指浏览器直接从本地缓存中读取资源,不需要向服务器发送请求。强缓存的相关头有 Cache-Control 和 Expires。Cache-Control 用于控制缓存的有效期,例如
Cache-Control: max-age=3600
表示资源可以在 3600 秒内使用缓存。Expires 用于指定资源的过期时间,例如Expires: Wed, 21 Oct 2020 07:28:00 GMT
表示资源在该时间之前可以使用缓存。Cache-Control 的优先级高于 Expires。 -
协商缓存是指在强缓存失效后,浏览器携带缓存标识向服务器发送请求,由服务器根据缓存标识来决定是否使用缓存。协商缓存的相关头有 Last-Modified,If-Modified-Since,ETag 和 If-None-Match。Last-Modified 用于表示资源的最后修改时间,例如
Last-Modified: Wed, 21 Oct 2020 07:28:00 GMT
表示资源在该时间被修改过。If-Modified-Since 用于向服务器发送上次获取资源时的 Last-Modified 值,例如If-Modified-Since: Wed, 21 Oct 2020 07:28:00 GMT
表示如果资源在该时间之后没有被修改过,则返回 304 状态码,表示使用缓存。ETag 用于表示资源的唯一标识,例如ETag: "5d8c72a5edda"
表示资源的哈希值。If-None-Match 用于向服务器发送上次获取资源时的 ETag 值,例如If-None-Match: "5d8c72a5edda"
表示如果资源的 ETag 值没有变化,则返回 304 状态码,表示使用缓存。ETag 的优先级高于 Last-Modified¹³。
十九.HTTPS为什么安全?怎么加密的
- HTTPS是一种安全的网络传输协议,它可以防止数据在传输过程中被窃取、篡改或伪造,确保数据的完整性和机密性
HTTPS的加密过程可以分为以下几个步骤:
-
客户端向服务器发送一个HTTPS请求,请求建立一个安全连接
-
服务器向客户端发送一个数字证书,数字证书包含了服务器的公钥和其他信息,如证书的颁发机构、有效期等
-
客户端验证数字证书的有效性,如果验证通过,就生成一个随机的对称密钥,并用服务器的公钥加密后发送给服务器
-
服务器用自己的私钥解密得到对称密钥,然后用对称密钥加密一个握手消息,发送给客户端
-
客户端用对称密钥解密握手消息,如果正确,就表示握手成功,双方可以开始用对称密钥加密通信了
这个过程中,非对称加密只用于传输对称密钥,而对称加密用于传输实际的数据。这样既保证了数据的安全性,又提高了数据的传输效率。
二十.session和jwt鉴权 session和jwt是两种常用的登录鉴权机制,它们的原理和区别如下:
-
session是一种基于cookie的服务器端鉴权机制,它的基本流程是:用户登录时,服务器验证用户的身份信息,如果通过,就生成一个sessionID,并通过set-cookie的方式写入到客户端的cookie中;用户再次访问时,携带cookie中的sessionID,服务器根据sessionID找到对应的用户信息,进行鉴权;用户退出或超时时,服务器销毁sessionID
-
jwt是一种基于token的客户端鉴权机制,它的基本流程是:用户登录时,服务器验证用户的身份信息,如果通过,就生成一个token,并返回给客户端;客户端将token存储在localStorage或sessionStorage中,并在每次请求时携带在header中;服务器根据token解析出用户信息,进行鉴权;用户退出或超时时,客户端删除token
session和jwt的区别主要有以下几点:
-
存储位置不同:session存储在服务器端,jwt存储在客户端。
-
安全性不同:session依赖于cookie,可能受到CSRF攻击;jwt依赖于token,可能受到XSS攻击。
-
资源消耗不同:session需要占用服务器的内存或数据库空间,可能影响服务器的性能;jwt不需要占用服务器资源,但是token本身比较长,可能增加网络传输的开销
-
扩展性不同:session不适合分布式场景,因为需要保证同一个用户访问同一个服务器或共享session数据;jwt适合分布式场景,因为token可以在任何服务器上验证
-
有效期不同:session可以随时修改或销毁,方便控制会话的有效期;jwt一旦生成,除非过期或删除,否则一直有效,不方便控制会话的有效期
二十一.常用的状态码有哪些
状态码是HTTP协议中用来表示服务器对客户端请求的处理结果的一种机制,它由三位数字和一个原因短语组成,根据第一位数字可以分为五类:
- 1xx:信息类,表示服务器已接收到请求,需要继续处理。
- 2xx:成功类,表示服务器已成功处理请求,返回响应内容。
- 3xx:重定向类,表示请求的资源已被移动或需要进一步操作才能完成。
- 4xx:客户端错误类,表示客户端的请求有语法错误或无法被服务器满足。
- 5xx:服务器错误类,表示服务器在处理请求时发生了内部错误。
常用的状态码有以下几种:
- 200 OK:表示请求成功,返回响应内容。
- 301 Moved Permanently:表示请求的资源已被永久重定向到另一个URI,客户端应使用新的URI访问资源。
- 302 Found:表示请求的资源已被临时重定向到另一个URI,客户端应使用原有URI访问资源。
- 304 Not Modified:表示请求的资源未被修改,客户端可以使用缓存中的资源。
- 400 Bad Request:表示客户端的请求有语法错误或无法被服务器理解。
- 401 Unauthorized:表示请求需要用户身份认证。
- 403 Forbidden:表示服务器拒绝执行请求,通常是因为客户端没有权限访问资源。
- 404 Not Found:表示请求的资源不存在,或者服务器不想让客户端知道该资源的存在。
- 500 Internal Server Error:表示服务器在处理请求时发生了内部错误,通常是因为程序异常或配置错误。
- 503 Service Unavailable:表示服务器暂时无法处理请求,通常是因为过载或维护。
二十二.浏览器输入一个网址看到页面的整个过程
浏览器输入一个网址看到页面的整个过程涉及到以下几个方面:
-
浏览器的输入和解析:浏览器根据用户输入的网址,判断是否是合法的URL,如果是,就进行URL解析,获取协议,域名,端口,路径等信息;如果不是,就将输入作为搜索关键词,使用默认的搜索引擎进行搜索。
-
DNS域名解析:浏览器根据域名获取对应的IP地址,这个过程涉及到本地缓存,系统缓存,路由器缓存,ISP缓存,根域名服务器,顶级域名服务器,权威域名服务器等多个环节。
-
TCP连接建立:浏览器根据IP地址和端口号(默认为80或443)向服务器发起TCP连接请求,这个过程涉及到三次握手,即客户端发送SYN包,服务器回复SYN+ACK包,客户端再发送ACK包。
-
HTTP请求发送:浏览器在TCP连接建立后,向服务器发送HTTP请求报文,这个报文包含了请求行,请求头和请求体等信息。
-
HTTP响应接收:服务器在收到HTTP请求后,根据请求内容进行处理,并返回HTTP响应报文,这个报文包含了状态行,响应头和响应体等信息。
-
TCP连接释放:浏览器在接收完HTTP响应后,根据响应头中的Connection字段判断是否需要关闭TCP连接,如果是,则发起四次挥手,即客户端发送FIN包,服务器回复ACK包,服务器发送FIN包,客户端回复ACK包。
-
HTTP缓存处理:浏览器根据响应头中的缓存相关字段(如Cache-Control, Expires, ETag, Last-Modified等)判断响应内容是否可以缓存,如果可以,则将其存储在本地缓存中,以便下次访问时直接使用。
-
HTML文档解析:浏览器根据响应体中的HTML文档进行解析,构建DOM树和CSSOM树,并合并为渲染树。在解析过程中,如果遇到外部资源(如图片,样式表,脚本等),则会发起额外的HTTP请求,并根据资源类型进行相应的处理。
-
页面渲染展示:浏览器根据渲染树计算每个节点的布局和样式,并绘制到屏幕上。在渲染过程中,如果遇到脚本执行或者用户交互等事件,则可能会触发重排或重绘。
二十三.什么是bfc,有哪些应用场景
BFC是块级格式化上下文(Block Formatting Context)的缩写,是一种CSS渲染模式,它决定了元素如何对其内容进行布局,以及与其他元素的关系和相互作用。BFC有以下几个特点:
-
BFC内部的元素会在垂直方向上一个接一个地排列。
-
BFC内部的元素不会影响外部元素,外部元素也不会影响BFC内部的元素。
-
BFC内部的元素会形成一个独立的盒子,不会与浮动元素重叠。
-
BFC内部的元素的垂直外边距会发生折叠。
BFC有以下几种应用场景:
-
防止外边距折叠:如果两个相邻的元素都处于同一个BFC中,它们的垂直外边距会发生折叠,即取两者之间较大的值。如果想要避免这种情况,可以将两个元素分别放在不同的BFC中,这样它们的外边距就不会重叠了
-
清除浮动影响:如果一个元素内部有浮动元素,而该元素没有设置高度或者底边距,那么该元素的高度会塌陷,导致其不能包裹住浮动元素。如果想要解决这个问题,可以将该元素设为一个BFC,这样它就会根据浮动元素的高度自动扩展,而且不会与其他浮动元素重叠
-
阻止文字环绕:如果一个容器内部有浮动元素,而容器中的文字内容想要避免被浮动元素环绕,那么可以将文字内容放在一个BFC中,这样文字内容就会形成一个独立的盒子,不受浮动元素的影响
-
实现多列布局:如果想要实现多列布局,并且每一列之间有一定的间隙,那么可以将每一列设为一个BFC,并设置适当的外边距。这样每一列就会形成一个独立的盒子,并且不会与其他列重叠
二十四.计算属性有什么作用?能不能绑定到v-model上
计算属性是Vue中一种特殊的属性,它可以根据其他的响应式数据进行计算并返回一个值,这个值会被缓存起来,只有当依赖的数据发生变化时才会重新计算。计算属性有以下几个作用:
-
简化模板表达式:如果模板中有一些复杂的逻辑运算,可以将其封装成一个计算属性,这样可以让模板更简洁和易读。
-
提高性能:如果一个表达式的结果依赖于多个数据,而这些数据经常发生变化,那么每次变化都会触发表达式的重新求值,这可能会影响性能。如果将这个表达式改为一个计算属性,那么只有当依赖的数据发生变化时才会重新求值,否则会直接使用缓存的值,这样可以提高性能。
-
实现双向绑定:计算属性默认只有getter方法,但是也可以提供一个setter方法,这样就可以实现双向绑定。例如,如果一个计算属性是根据两个数据进行拼接的,那么在setter方法中可以将新的值分解为两个数据,并更新到原始数据中。
计算属性可以绑定到v-model上,但是需要注意以下几点:
-
计算属性必须提供一个setter方法,否则v-model无法修改计算属性的值。
-
计算属性的setter方法必须能够将新的值反映到依赖的数据上,否则会导致数据不一致。
-
计算属性的getter方法和setter方法必须保持逻辑一致,否则会导致数据混乱。
二十五.响应式原理发生在vue哪些生命周期阶段
响应式原理是Vue的核心特性之一,它可以让Vue实例的数据变化自动反映到视图上,而无需手动操作DOM。响应式原理主要发生在Vue的以下生命周期阶段:
-
beforeCreate:在这个阶段,Vue实例还没有创建,也没有初始化响应式数据,所以无法访问data和props等属性。
-
created:在这个阶段,Vue实例已经创建,响应式数据也已经初始化,所以可以访问data和props等属性,但是还没有挂载到DOM上,所以无法访问$el等属性。
-
beforeMount:在这个阶段,Vue实例已经完成编译模板,但是还没有挂载到DOM上,所以可以访问$el等属性,但是还不能看到渲染结果。
-
mounted:在这个阶段,Vue实例已经挂载到DOM上,所以可以看到渲染结果,并且可以进行一些DOM操作。
-
beforeUpdate:在这个阶段,Vue实例的数据发生变化,触发响应式系统更新视图之前,会调用这个钩子函数,可以在这里做一些数据变化前的处理。
-
updated:在这个阶段,Vue实例的数据已经更新,视图也已经重新渲染,会调用这个钩子函数,可以在这里做一些数据变化后的处理。
-
beforeDestroy:在这个阶段,Vue实例即将被销毁,会调用这个钩子函数,可以在这里做一些清理工作,如移除事件监听器或定时器等。
-
destroyed:在这个阶段,Vue实例已经被销毁,响应式系统也已经停止工作,会调用这个钩子函数。
二十六.虚拟DOM在哪个阶段产生的
虚拟DOM是Vue用来提高渲染性能的一种技术,它可以将真实的DOM结构抽象为一个普通的JS对象,然后通过比对新旧虚拟DOM树的差异,来更新必要的真实DOM节点,从而减少对真实DOM的操作。
虚拟DOM在Vue的生命周期中主要产生在以下两个阶段:
-
beforeMount:在这个阶段,Vue会将模板编译为render函数,然后调用render函数生成一个虚拟DOM树,这是第一次生成虚拟DOM树。
-
beforeUpdate:在这个阶段,Vue会在响应式数据发生变化时,重新调用render函数生成一个新的虚拟DOM树,然后与旧的虚拟DOM树进行对比,找出差异,并更新到真实DOM上。
二十七.什么是diff运算
Vue diff运算是Vue用来实现虚拟DOM的更新的一种算法,它可以快速地比较新旧虚拟DOM树之间的差异,并将差异应用到真实DOM上,从而减少对真实DOM的操作。Vue diff运算有以下几个特点:
-
只比较同级节点:Vue diff运算不会跨层级地比较节点,而是只比较同一层级的节点,如果节点类型不同,就直接替换整个子树,如果节点类型相同,就继续比较子节点。
-
采用双端比较:Vue diff运算会同时从新旧虚拟DOM树的两端开始比较,即头头比较和尾尾比较,如果头头相同,就移动指针继续比较;如果尾尾相同,就移动指针继续比较;如果头尾相同,就交换位置并移动指针继续比较;如果都不相同,就用新节点的key在旧节点中查找匹配的节点,如果找到就移动到正确的位置,如果没找到就插入新节点。
-
使用key优化:Vue diff运算会使用key属性来标识每个节点的唯一性,这样可以避免重复创建或销毁节点,提高性能。因此,在使用v-for循环渲染列表时,最好给每个节点添加一个唯一的key属性。¹²³
二十八.原生AJax步骤
原生AJax步骤是指使用JavaScript的XMLHttpRequest对象来实现与服务器的异步通信的过程,原生AJax步骤大致如下:
- 创建一个XMLHttpRequest对象,用于发送和接收数据。
- 使用open方法设置请求的方式(GET或POST)、URL、是否异步等参数。
- 使用onreadystatechange方法设置一个回调函数,用于处理服务器的响应。
- 使用send方法发送请求,如果是POST请求,还需要设置请求头和请求体。
- 在回调函数中,根据readyState和status属性判断请求是否成功,如果成功,就可以获取responseText或responseXML属性中的数据,并进行相应的处理。
这是一个简单的原生AJax步骤示例:
// 1. 创建一个XMLHttpRequest对象
var xhr = new XMLHttpRequest();
// 2. 使用open方法设置请求参数
xhr.open("GET", "https://example.com/api/data", true);
// 3. 使用onreadystatechange方法设置回调函数
xhr.onreadystatechange = function() {
// 判断请求是否完成
if (xhr.readyState == 4) {
// 判断请求是否成功
if (xhr.status == 200) {
// 获取响应数据
var data = xhr.responseText;
// 处理数据
console.log(data);
}
}
};
// 4. 使用send方法发送请求
xhr.send();
二十九.箭头函数注意点
箭头函数是一种简洁的函数表达式,它可以让代码更简洁,也可以避免this指向的问题。但是,箭头函数也有一些使用注意点,主要有以下几点:
-
箭头函数的this指向是固定的,它指向定义时所在的对象,而不是调用时所在的对象。这意味着箭头函数不能用作构造函数,也不能用作对象的方法。
-
箭头函数没有arguments对象,也就是说,在箭头函数内部不能访问函数的实际参数。如果需要使用参数,可以用剩余参数(...args)代替。
-
箭头函数没有原型(prototype)属性,也没有super关键字。这意味着箭头函数不能继承其他函数,也不能作为父类使用。
-
箭头函数的解析顺序相对靠前,也就是说,在同一个作用域内,箭头函数在定义之前就可以使用。
-
箭头函数不支持重名参数,也就是说,在箭头函数内部不能有两个同名的参数。
-
箭头函数不能使用yield命令,因此箭头函数不能用作生成器(generator)函数。
三十.for in 和 for of的区别
for in 和 for of 是两种不同的循环语句,它们的区别主要在于它们的迭代方式,可以总结如下:
-
for in 语句可以遍历一个对象的所有可枚举属性,包括原型链上的属性。它的迭代顺序是任意的,不一定按照属性的定义顺序。它的迭代变量是属性的键名(字符串)。
-
for of 语句可以遍历一个具有迭代器接口(iterator)的对象,例如数组、字符串、Map、Set等。它的迭代顺序是按照数据的定义顺序。它的迭代变量是属性的键值(任意类型)。
这是一个简单的比较示例:
// 定义一个对象
var obj = {
a: 1,
b: 2,
c: 3
};
// 定义一个数组
var arr = [4, 5, 6];
// 使用for in遍历对象
for (var key in obj) {
console.log(key, obj[key]); // a 1, b 2, c 3 (不一定按照这个顺序)
}
// 使用for in遍历数组
for (var index in arr) {
console.log(index, arr[index]); // 0 4, 1 5, 2 6 (不一定按照这个顺序)
}
// 使用for of遍历对象
// for (var value of obj) {
// console.log(value); // 报错,obj不是可迭代对象
// }
// 使用for of遍历数组
for (var value of arr) {
console.log(value); // 4, 5, 6 (按照这个顺序)
}
三十一.你如何理解浏览器事件环
浏览器事件环是指浏览器在处理JavaScript代码时,使用的一种循环机制,用于协调同步任务和异步任务的执行顺序,可以简单地理解为以下几个步骤:
-
浏览器有一个主线程,用于执行同步任务,例如渲染UI、解析DOM、执行JS等。
-
浏览器有一个任务队列(task queue),用于存放异步任务,例如定时器回调、网络请求回调、用户交互事件等。
-
当主线程空闲时,浏览器会从任务队列中取出一个任务,放到主线程中执行。
-
这个过程会不断重复,直到任务队列为空或者浏览器关闭。
这就是浏览器事件环的基本原理。
微任务和宏任务是异步任务的两种分类,它们的区别主要在于它们的执行时机和优先级,可以总结如下:
-
微任务是由JavaScript引擎自身发起的异步任务,例如Promise.then、process.nextTick等。它们的执行时机是在当前宏任务结束后,下一个宏任务开始前,也就是在同一个事件循环中。它们的执行优先级高于宏任务,也就是说,如果有多个微任务和宏任务在等待执行,那么浏览器会先执行所有的微任务,再执行一个宏任务。
-
宏任务是由浏览器或者其他宿主环境发起的异步任务,例如setTimeout、setInterval、I/O、用户交互事件等。它们的执行时机是在每个事件循环的开始,也就是在上一个事件循环结束后,下一个事件循环开始前。它们的执行优先级低于微任务,也就是说,如果有多个宏任务在等待执行,那么浏览器会按照一定的顺序(不一定是定义顺序)执行一个宏任务,然后检查是否有微任务需要执行,如果有,就先执行所有的微任务,再执行下一个宏任务。
三十二.vue的组件通信
Vue的组件通信是指不同的Vue组件之间如何传递数据或者事件,以实现组件之间的协作和交互。根据¹²⁴,Vue的组件通信方式有以下几种:
-
父子组件通信:父组件通过props向子组件传递数据,子组件通过$emit触发事件向父组件传递数据。这种方式适用于直接的父子关系,但是不适用于跨级或者兄弟关系。
-
子父组件通信:子组件通过$emit触发事件向父组件传递数据,父组件通过v-on监听子组件事件并处理数据。这种方式与父子组件通信类似,只是方向相反,也适用于直接的父子关系。
-
事件总线(Event Bus):通过一个空的Vue实例作为中央事件总线,用它来触发事件和监听事件,实现任何组件间的通信,包括父子、兄弟、跨级。这种方式简单灵活,但是不利于维护和调试。
-
Vuex:通过一个全局的状态管理对象,来存储和管理所有组件的状态,实现任何组件间的通信,包括父子、兄弟、跨级。这种方式结构清晰,易于维护和调试,但是需要引入额外的库和概念。
-
parent/parent/parent/children:通过访问父组件或者子组件的实例或者数据,来实现组件间的通信。这种方式简单直接,但是破坏了组件的封装和复用性。
-
attrs/attrs/attrs/listeners:通过访问祖先或后代组件传递下来的属性或者事件监听器,来实现跨级组件间的通信。这种方式可以避免多层嵌套的props传递,但是也破坏了组件的封装和复用性。
-
provide/inject:通过祖先组件向后代组件提供数据或者方法,后代组件通过注入来使用提供的数据或者方法,来实现跨级组件间的通信。这种方式可以避免多层嵌套的props传递,但是也破坏了组件的封装和复用性。
-
$refs:通过访问其他组件的实例或者DOM元素,来实现组件间的通信。这种方式简单直接,但是破坏了组件的封装和复用性。
-
slots/slots/slots/scopedSlots:通过插槽(slot)向子组件传递内容或者作用域数据,来实现父子组件间的通信。这种方式可以实现内容分发和作用域绑定,但是只适用于直接的父子关系。
-
自定义指令(Custom Directive):通过在自定义指令中访问其他组件的实例或者数据,来实现组件间的通信。这种方式可以实现自定义功能和交互效果,但是也破坏了组件的封装和复用性。
-
自定义事件(Custom Event):通过在DOM元素上触发或者监听自定义事件,来实现任何组件间的通信。这种方式可以利用原生DOM事件机制,但是需要注意浏览器兼容性和事件冒泡问题。
-
Web Worker是一种在后台运行的JavaScript脚本,它可以在不影响主线程的情况下执行复杂的任务。Web Worker可以通过postMessage和onmessage方法来与主线程或者其他Web Worker通信,从而实现组件间的通信。这种方式可以利用多核CPU的优势,提高性能和用户体验,但是也有一些限制和缺点,例如不能访问DOM、window、document等对象,不能使用某些全局变量和函数,需要额外的内存和开销等
三十三.深浅拷贝,jsonsrting的bug
-
深拷贝和浅拷贝是指在复制对象或数组时,浅拷贝只复制它的第一层属性,而不会复制它的属性的值(如果属性的值还是对象或数组的话)。因此,浅拷贝得到的新对象或数组与原对象或数组之间仍然存在引用关系
-
JSON.parse
和JSON.stringify
可以用于深拷贝对象,但是可能会不太注意一些缺陷。例如,它们不会拷贝对象上的值为undefined
和函数的键值对。NaN
、无穷大、无穷小会被转为null
。它们也无法获取原型上面的方法和属性,只能获取Object
原型的内容。
三十四.es6特性 ES6是ECMAScript 6的简称,是JavaScript语言的下一代标准,于2015年6月正式发布。ES6有许多新特性,例如let和const、箭头函数、模板字符串、解构赋值、类和继承、模块化、Promise和async/await等¹²⁴。这些特性可以让JavaScript代码更简洁、优雅和高效。
三十五.primise方法
Promise是一个ES6提供的类,用于更优雅地处理异步任务。Promise有三种状态:pending(等待)、fulfilled(成功)和rejected(失败)。Promise的构造函数接受一个函数作为参数,该函数有两个参数:resolve和reject,分别表示异步任务成功或失败时的回调函数。Promise对象有then、catch和finally三个方法,用于处理Promise的不同状态的回调函数。¹²³
例如,我们可以用Promise来封装一个异步请求的函数:
function request(url) {
return new Promise((resolve, reject) => {
// 创建一个XMLHttpRequest对象
let xhr = new XMLHttpRequest();
// 设置请求方法和URL
xhr.open('GET', url);
// 设置响应类型为JSON
xhr.responseType = 'json';
// 监听请求状态变化
xhr.onreadystatechange = function () {
// 如果请求完成
if (xhr.readyState === 4) {
// 如果响应状态码为200
if (xhr.status === 200) {
// 调用resolve函数并传递响应数据
resolve(xhr.response);
} else {
// 调用reject函数并传递错误信息
reject(new Error(xhr.statusText));
}
}
};
// 发送请求
xhr.send();
});
}
然后我们可以用then、catch和finally来处理请求的结果:
request('https://jsonplaceholder.typicode.com/todos/1')
.then(data => {
// 处理成功的结果
console.log(data);
})
.catch(error => {
// 处理失败的原因
console.error(error);
})
.finally(() => {
// 无论成功还是失败都会执行的操作
console.log('Done');
});
三十六.obejectdefinty监听数组怎么监听
-
首先,Vue会遍历data对象中的所有属性,并用Object.defineProperty将它们转换为getter和setter,从而实现数据的响应式。
-
然后,Vue会创建一个Watcher对象,用于收集依赖和触发更新。当一个属性被访问时,它的getter函数会将当前的Watcher对象添加到该属性的依赖列表中。当一个属性被修改时,它的setter函数会通知该属性的所有依赖进行更新。
-
接着,Vue会检查data对象中的每个属性是否是数组,如果是,就会调用一个函数来重写数组的原型方法。这个函数会先保存数组原来的原型方法,然后用自定义的方法替换它们。这些自定义的方法会在调用原来的方法之前或之后执行一些操作,比如通知依赖更新或拦截参数。
-
最后,当我们使用数组的原型方法来修改数组时,Vue就能通过Object.defineProperty和重写的方法来监听数组的变化,并触发视图更新。
Vue使用Object.defineProperty来监听对象属性的变化,但是它不能直接监听数组的变化,因为数组的索引和长度并不是属性。
为了解决这个问题,Vue采用了两种方法:
-
一种是提供了set和delete方法,用于向对象或数组中添加或删除属性或元素,并触发视图更新。这种方法的缺点是需要手动调用这些方法,而不能直接使用赋值操作。
-
另一种是重写了数组的原型方法,比如push、pop、splice等,让它们在修改数组时触发依赖更新。这种方法的缺点是只能监听这些方法的调用,而不能监听数组索引或长度的变化。
例如,我们可以用Vue来创建一个响应式的数组:
let arr = [1, 2, 3];
// 创建一个Vue实例
let vm = new Vue({
data: {
arr: arr
}
});
// 修改数组元素
vm.arr[0] = 4; // 不会触发视图更新
vm.$set(vm.arr, 0, 4); // 会触发视图更新
// 添加数组元素
vm.arr[3] = 5; // 不会触发视图更新
vm.arr.push(5); // 会触发视图更新
// 删除数组元素
vm.arr.length = 2; // 不会触发视图更新
vm.arr.pop(); // 会触发视图更新
三十七.多次网络请求点击按钮禁用,除了防抖还有什么方法
多次网络请求点击按钮禁用,除了防抖还有什么方法?根据搜索结果,有以下几种方法:
-
节流:当持续触发事件时,保证一定时间段内只调用一次事件处理函数
-
按钮禁用或者loading:当第一次点击按钮后,立即禁用该按钮或者显示一个加载动画,直到请求返回后再恢复按钮的可点击状态或者隐藏加载动画
这些方法可以避免用户在短时间内频繁多次点击按钮,造成数据的重复提交或异常。
三十八.keepalive原理
keepalive原理有以下几种含义:
-
keepalive是一种网络技术,用于检测网络连接的状态,防止连接因为长时间不活动而被断开,keepalive的原理是每隔一段时间发送一个探测包,如果对方没有回应,就认为连接已经断开,并尝试重新建立连接
-
keepalive是一种HTTP协议的头部字段,用于控制持久连接的行为,减少建立和关闭连接的开销。 keepalive的原理是在一个TCP连接上发送多个HTTP请求和响应,而不是每次请求都重新建立连接。 keepalive可以指定连接的最大请求数和超时时间。
-
keepalive是一种Vue组件,用于缓存不活动的组件实例,避免重复渲染和销毁。keepalive的原理是使用一个LRU缓存来存储被包裹的组件实例,并根据组件的激活和失活状态来决定是否渲染或销毁组件keepalive可以指定缓存的最大数量和匹配条件
-
keepalived是一种软件,用于实现高可用性、负载均衡和故障转移。keepalived的原理是使用VRRP协议来维护虚拟IP地址的所有权,并使用健康检查来监控后端服务器的状态, keepalived可以配置多个主备节点,当主节点故障时,备节点会自动接管虚拟IP地址和服务
Vue组件的keepalive是一个抽象组件,用于缓存不活动的组件实例,避免重复渲染和销毁。 Vue组件的keepalive的原理是:
-
keepalive使用一个LRU缓存来存储被包裹的组件实例,缓存的键是组件的唯一标识,缓存的值是组件的VNode对象。
-
keepalive可以使用include和exclude属性来指定哪些组件可以被缓存,哪些不能被缓存。
-
keepalive可以使用max属性来指定缓存的最大数量,当缓存满了时,会根据LRU策略淘汰最近最少使用的组件实例。
-
keepalive会监听被包裹的组件的激活和失活状态,当组件激活时,会从缓存中取出对应的VNode对象,并将其渲染到DOM中。当组件失活时,会将其从DOM中移除,并将其放入缓存中。
-
keepalive会在被包裹的组件上触发两个生命周期钩子:activated和deactivated,分别表示组件被激活和失活时的回调函数。
三十九.Vue除了$set还有什么方法
-
$forceUpdate:强制Vue实例重新渲染,无论数据是否变化。这个方法可以用于处理一些Vue无法检测到的数据变化,但是不推荐使用,因为它会影响性能和可维护性。
-
Object.assign:用于将一个或多个源对象的属性复制到目标对象中,并返回目标对象。这个方法可以用于修改整个对象的值,而不是单个属性,但是它会改变原对象的引用,可能会导致一些意想不到的问题。
-
Vue提供的数组变异方法:如push、pop、splice、sort等,用于修改数组的内容,并触发视图更新。² 这些方法可以用于处理数组的变化,但是它们不能检测数组索引或长度的变化。
四十.axios二次封装大概思路,10条数据请求,全局一般怎么处理,promise.all不好用在
axios二次封装大概思路是:
-
创建一个axios实例,使用axios.create方法,传入一些通用的配置,如baseURL、timeout、headers等
-
使用axios实例的拦截器,对请求和响应进行统一的处理,如添加token、处理错误、显示loading等
-
封装一些通用的请求方法,如get、post、put、delete等,根据不同的业务需求,传入不同的参数和配置
-
导出封装好的axios实例或请求方法,供其他模块使用
10条数据请求,全局一般怎么处理?根据搜索结果,有以下几种方法:
-
使用Promise.all或Promise.allSettled方法,将10条数据请求封装成一个Promise数组,然后等待所有请求都完成或者有结果后,再进行后续的处理。 这种方法的优点是可以并发发送请求,提高效率,也可以统一处理请求的结果或错误。这种方法的缺点是如果其中一个请求失败或超时,就会影响整个Promise数组的状态,导致其他请求的结果被忽略。
-
使用async/await语法,将10条数据请求放在一个async函数中,然后使用await关键字等待每个请求的结果,再进行后续的处理。这种方法的优点是可以使用同步的方式编写异步代码,简化逻辑,也可以单独处理每个请求的结果或错误。 这种方法的缺点是会阻塞后续的代码执行,降低效率,也需要使用try/catch语句来捕获错误。
-
使用RxJS库,将10条数据请求转换成一个Observable对象,然后使用各种操作符来对数据流进行处理和变换。这种方法的优点是可以使用函数式编程的方式来处理异步数据流,提供了丰富的操作符和工具函数,也可以灵活地控制数据流的订阅和取消。³ 这种方法的缺点是需要引入额外的库,学习曲线较高,也需要注意内存泄漏和错误处理。
四十一.vuex的缺点
vuex的缺点有以下几点:
-
vuex会增加项目的复杂度,需要额外的学习成本和维护成本。vuex不适合小型项目或者简单的数据流,可能会造成代码冗余和过度设计。
-
vuex的状态是全局的,容易造成命名冲突或者数据污染。vuex的状态也不易于调试和追踪,需要借助一些工具或者规范来辅助
-
vuex的状态在刷新浏览器后会丢失,需要使用一些插件或者手动保存到本地存储中vuex的状态也不易于持久化或者同步到服务器,需要额外的逻辑和接口来实现
-
vuex的状态是响应式的,会触发组件的重新渲染,可能会影响性能和内存占用。vuex的状态也不易于进行垃圾回收,需要手动清理或者重置
四十二.多页面应用和单页面应用的缺点
多页面应用和单页面应用的缺点有以下几点:
- 多页面应用的缺点:
- 每次进入新的页面,都需要向服务器发送请求,加载整个页面的所有资源,导致页面切换缓慢,流畅度不够,用户体验较差
- 对后端的依赖性较强,需要使用URL传参、Cookie、LocalStorage等方式来传递数据和状态。
- 前后端耦合度较高,不利于分工和维护
- 单页面应用的缺点:
- 首屏加载时间较长,需要加载整个应用的资源和逻辑。
- SEO不友好,因为单页面应用是动态渲染的,搜索引擎无法获取到完整的内容。
- 状态管理较复杂,需要使用一些工具或者框架来管理组件之间的数据和状态。
四十三.localstorage
localStorage是一种Web存储技术,用于在浏览器中存储键值对的数据。
localStorage的特点有以下几点:
-
localStorage的数据没有过期时间,除非手动删除,否则会一直保存在浏览器中。
-
localStorage的数据是以域名为单位进行存储的,不同的域名不能共享数据。
-
localStorage的数据是只读的,不能被修改或删除。
-
localStorage的数据是字符串类型的,如果要存储其他类型的数据,需要进行转换。
-
localStorage的数据大小限制在5MB左右,不同的浏览器可能有所差异。
localStorage的使用方法有以下几种:
-
使用localStorage对象的setItem、getItem、removeItem和clear方法来存储、读取、删除和清空数据。
-
使用localStorage对象的属性或者中括号语法来存储和读取数据。
-
使用localStorage对象的length属性和key方法来获取数据的数量和键名。
四十四.浏览器垃圾回收
浏览器垃圾回收机制是指浏览器对不再使用的内存进行自动释放的过程。
浏览器垃圾回收机制的原理有以下几点:
-
浏览器会根据数据的存储方式,将内存分为栈内存和堆内存。
-
栈内存主要用于存储基本类型的数据,如字符串、数字、布尔值等,以及函数的执行上下文。
-
堆内存主要用于存储引用类型的数据,如对象、数组、函数等,以及一些大型的数据结构。
-
浏览器会使用不同的算法来对栈内存和堆内存进行垃圾回收。
-
栈内存的垃圾回收主要依赖于执行上下文栈,当一个函数执行完毕后,它的执行上下文会从栈中弹出,同时释放该函数占用的栈内存空间。
-
堆内存的垃圾回收主要依赖于引用计数和标记清除两种算法,引用计数是指记录每个对象被引用的次数,当一个对象的引用次数为零时,就表示该对象不再被使用,可以被回收。标记清除是指从根对象开始遍历所有可达的对象,并将它们标记为活动对象,然后清除所有未被标记的对象。
-
浏览器会定期或者在特定时机触发垃圾回收操作,如页面关闭、空闲时间、内存占用达到阈值等。
四十五.Vue如何实现组件按需加载
-
使用组件单独分包 + 按需导入 + babel-plugin-component插件,这是一种经典的方法,可以实现组件库的按需引入功能。这种方法的原理是将每个组件打包成一个单独的文件,然后在项目中只导入需要的组件,使用babel-plugin-component插件来自动化地转换导入语句,避免手动引入样式文件
-
使用ESModule + Treeshaking + unplugin-vue-components插件,这是一种次时代的方法,可以实现组件库的按需引入功能。¹ 这种方法的原理是利用ESModule的静态导入特性和Treeshaking的优化机制,来实现组件库的按需加载和代码分割。使用unplugin-vue-components插件来自动化地扫描项目中使用的组件,并生成对应的导入语句
-
使用Vue CLI命令行工具和glup工具来封装和打包组件库,并实现按需加载。² 这种方法的原理是使用Vue CLI命令行工具来创建和开发组件库,使用glup工具来对组件库进行打包和压缩,生成单独的组件文件和样式文件。然后在项目中根据需要导入对应的组件和样式文件
四十六.前端权限管理
前端权限设计方案的目的是为了让不同权限的用户看到的内容和可实现的操作是不同的,从而提高系统的安全性和用户体验。一般来说,前端权限设计方案需要和后端配合,后端负责根据用户的角色和权限返回相应的数据,前端负责根据数据动态渲染页面和组件。
-
登录权限控制是最基本的一种权限控制,它主要通过路由的 meta 属性和 router.beforeEach 钩子函数来实现。路由的 meta 属性可以用来标记哪些路由需要登录才能访问,router.beforeEach 钩子函数可以用来在每次路由跳转之前检查用户是否已经登录,如果没有登录就重定向到登录页面,并把原来想要访问的页面作为参数传递过去,等到用户登录成功后再跳转回去。
-
页面权限控制是一种更高级的权限控制,它主要通过后端返回的角色和权限列表来动态生成路由和菜单,并在路由守卫中进行校验。角色和权限列表可以用来表示不同角色能够访问或操作的页面或功能,比如普通会员只能看到列表页和详情页,管理员可以看到列表页、详情页和管理页,超级管理员可以看到所有页面。动态生成路由和菜单可以用 router.addRoute 方法和 v-for 指令来实现,路由守卫可以用 router.beforeEach 钩子函数和 to.matched 属性来实现。
-
内容权限控制是一种最细粒度的权限控制,它主要通过后端返回的按钮或字段级别的权限列表来动态渲染或隐藏组件,并在请求拦截器中进行校验。按钮或字段级别的权限列表可以用来表示不同角色在同一页面上能够看到或操作的内容或功能,比如普通会员只能看到商品名称和价格,管理员可以看到商品名称、价格、库存和编辑按钮,超级管理员可以看到所有内容和功能。动态渲染或隐藏组件可以用 v-if 指令或者自定义指令来实现,请求拦截器可以用 axios.interceptors.request.use 方法和 store.state.user_info 属性来实现。
转载自:https://juejin.cn/post/7226001971802554425