前端高频面试题Vue3、TypeScript
■ 符号说明
💘 课题
🐝 企业级面试题
⭐️ 重要知识点
🌛 需要有影响
神龙教主
💘 初探、模板与指令
⭐️ 谈谈你对vue的理解,有哪些重要的版本,vue3新增了哪些新特性
渐进式javascript框架
2013诞生 =》 2016发布2.0 =》 2019发布2.6 =》 2020.9 3.0 海贼王 =》 2021.8 3.2 script setup语法
vue3发展史:先是和vue2类似的语法选项式API、和原生js类似的语法组合式API 方便封装组合
setup函数中写 const a = 1
直接script脚本中写 const a= 1
<Teleport> 是一个内置组件,它可以将一个组件内部的一部分模板“传送”到该组件的 DOM 结构外层的位置去。Vue 3 现在正式支持了多根节点的组件,也就是片段!
- [Emits 组件选项](https://cn.vuejs.org/api/options-state.html## emits)**
用于声明由组件触发的自定义事件, .native 修饰符已被移除。默认官方事件,通过emits声明自定义事件 否则多次触发- 来自
@vue/runtime-core的createRendererAPI 用来创建自定义渲染函数 - [单文件组件中的状态驱动的 CSS 变量 (
<style>中的v-bind)](https://cn.vuejs.org/api/sfc-css-features.html## v-bind-in-css)* - SFC
<style scoped>新增全局规则和针对插槽内容的规则 - Suspense 实验性
🐝🐝🐝 写出vue常用的命令(目前学了9个)
{{}} 大括号内就是JS环境按照JS思想去写代码比如三元/拼接
v-text/v-html 工作普遍都不用,然后留心是覆盖
v-cloak/v-pre/v-once 工作普遍都不用
v-bind 当属性需要使用模型数据,可以减少DOM操作去写特效 简写冒号
v-on 事件(1-函数名推荐on开头,2-去methods中定义,3-事件修饰符stop/prevent/键盘修饰符/系统修饰符,4-event事件对象)
v-for 1-可以遍历数组/对象/数字,2-key的作用和原理,3-和if优先级
v-if/v-show 区别
v-memo 了解
🐝🐝🐝 写出v-for中key的作用和原理 简单版
key是什么:唯一标识
key得作用:1-避免出现bug、2-提升性能(修改差异)
key原理:底层diff算法【同层】比较 根据key决定 是替换还是修改或者删除
🐝🐝🐝 判断循环v-if、v-for优先级
- 在 vue 2.x 中,在一个元素上同时使用
v-if和v-for时,v-for会优先作用。 - 在 vue 3.x 中,
v-if总是优先于v-for生效。
追问1:为什么vue3要让if优先
回答1:减少不必要渲染
追问2:vue2如何解决不必要的重复渲染
回答2:判断提升在父元素
🐝🐝🐝 写出v-if、v-show区别、如何选、具体场景
相同点:都可以用户判断控制元素隐藏显示
不同点:1-v-if语法更强、2-v-if控制DOM、v-show控制CSS
如何选:高频切换例如二维码、登录弹框、提示框、删除提示框、tab选项卡,推荐使用v-show 来减少DOM频繁删除创建所产生的额外性能开销
高逼格
v-if 是真正的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建;也是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块。 v-show 就简单得多——不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 的 “display” 属性进行切换。 所以,v-if 适用于在运行时很少改变条件,不需要频繁切换条件的场景;v-show 则适用于需要非常频繁切换条件的场景。 额外衍生:visibility、和display区别 => 就算隐藏了也占用网页空间
🐝 谈谈你对v-memo理解
参考react memo有缓存功能
主要用来指定盒模型缓存 避免重复渲染
🐝🐝🐝 vue2和vue3区别
思考:如果你是面试官你问 v2和v3区别 vue和react区别 你想听到什么或者可以从几个维度去回答
回答:
- 第一种:拿出语法区别挨个说 例如 v3相对v2不支持过滤器、混入;…
- 第二种:框架层面思想上设计上、语法层面、底层原理
框架层面思想上设计上 - v2不贴近原生很多封装好了 理解起来抽象 不方便二阶段学完很好吸收;v3 定义变量就是模型数据视图可以显示,但是没有响应式 ref、reactive 再比如方法 不需要写个抽象的methods 直接写方法 - 还有去掉了抽象的过滤器、混入 而是通过hooks 其实就是函数 - composition api、 hooks - ts - webapck 改成 vite - vuex 改成 pinia 切记细品pinia发展史 先去掉mutations 后来直接里面写composition api 等等 语法层面:双向绑定、侦听器watch/watchEffect、组件实例需要暴露属性才可以外部使用public/private、生命周期、样式:deep/:global、增加teleport、emit、Fragments、Composition API、sfc script setup等等 底层原理:Object.defineProperty、Proxy; diff算法区别 🐝🐝 分别谈谈你对MVVM、MVC的理解
🐝 写出MVVM和MVC的区别
- 谈谈你对MVC的理解
MVC是软件开发中常见的开发模式,主要应用于后端,神龙教主将程序划分为M模型、V视图、C控制器从而便于团队协作开发,减少代码冗余 - 谈谈你对MVVM理解
MVVM是Model-View-ViewModel缩写,也就是将MVC中的Controller演变成ViewModel Model层代表数据模型、 View层代表UI组件 ViewModel是Model、View层的桥梁,数据会绑定到ViewModel并自动将数据渲染到页面,视图变化会通知ViewModel层更新数据。 或者 随着移动互联网的发展,MVVM思想借鉴MVC、MVP思想演变而来,M模型负责数据维护,V视图负责数据展示,VM则是M和V的桥梁,监控M模型数据变化自动更新V视图,从而解决传统前后端分离JQ架构弊端 开发者在代码中大量调用相同的 DOM API, 处理繁琐 ,操作冗余,使得代码难以维护。 大量的DOM 操作使页面渲染性能降低,加载速度变慢,影响用户体验。 当 Model 频繁发生变化,开发者需要主动更新到View ;当用户的操作导致 Model 发生变化,开发者同样需要将变化的数据同步到Model 中,这样的工作不仅繁琐,而且很难维护复杂多变的数据状态。 - 谈谈MVVM和MVC区别
相同点:都是软件开发常见的开发模式或者开发思想 不同点: 1- MVC后端居多,MVVM前端 2- MVC单向通信 目的将M和V代码分离,MVVM则是双向通信,不需要手动操作DOM 或 最初MVC最早出现在后端 M代表模型负责数据处理、V代表视图负责数据战士、C代表控制器负责调度 后来前端也有了MVC库,最早实现的就是backbone.js 但是V和M并没有很好的解耦神龙教主 因此出现了MVVM模式, MVVM是Model-View-ViewModel缩写,也就是将MVC中的Controller演变成ViewModel Model层代表数据模型、 View层代表UI组件 ViewModel是Model、View层的桥梁,数据会绑定到ViewModel并自动将数据渲染到页面,视图变化会通知ViewModel层更新数据。 多说一嘴:VUE不是纯MVVM框架
https://cn.vuejs.org/v2/guide/instance.html## %E5%88%9B%E5%BB%BA%E4%B8%80%E4%B8%AA-Vue-%E5%AE%9E%E4%BE%8B
虽然没有完全遵循 MVVM 模型,但是 Vue 的设计也受到了它的启发。因此在文档中经常会使用vm(ViewModel 的缩写) 这个变量名表示 Vue 实例。
💘 选项式API:表单输入绑定、类与样式绑定、自定义指令
⭐️ 写出你对class与style绑定的理解(能干嘛、好处、场景)
- 简介/是什么/目的:class/style两个属性使用模型数据,只不过升级了这两个语法可以写数组或对象(减少DOM操作)
- 语法
:class=" data中的键 "
:class=" data中的键 + 拼接 "
:class=" {类名: 布尔,… } "
:class=" [类名, …, 类名] "
:style=" {css属性名:属性值,…,} "
- 场景:tab选项卡、文章字体、后台管理菜单切换等等
🐝🐝 写出你对自定义指令的理解(能干嘛、好处、场景)
能干嘛:封装DOM操作
好处:减少代码冗余 提高代码复用
场景:全屏、拖拽、复制、水印、登录按钮鉴权等等
🐝🐝 🐝 写出双向绑定v-model原理
它是 :value 和 @input的 语法糖
🐝🐝🐝 写出vue2响应式原理 简单
通过Object.defineProperty劫持模型数据变化神龙教主
🐝🐝 写出vue2响应式失效场景、如何解决
1 模型未定义
2 通过数组索引修改
通过数组常用方法push、pop等等
强制刷新 $forceUpdate
或者$set单独写一个数据劫持 =》 底层原理 单独 Object.defineProperty
🐝🐝 🐝 写出vue3响应式原理、并说出为什么vue3要升级语法
通过Proxy劫持模型数据变化
Object.defineProperty拦截的是对象的属性。Proxy是拦截整个新对象。proxy特性更强,可以监听未定义的,针对于属性是对象类型则get时判断添加新的proxy拦截即可proxy语法更强,拦截方式除了上面的 get 和 set ,还有 11 种,以前就6个神龙教主
💘 选项式API:响应式、生命周期
⭐️ 写出计算属性的概念、好处、语法、场景
为啥有:1-减少视图操作、2-提升性能 缓存
是什么:用来减少视图操作、提升性能得技术
啥语法:下面👇🏻
哪里用:1-一个数据依赖另一个数据计算得来的结果(桌子腿子/购物车总价)、2-缓存、3-vuex等等
⭐️ 写出侦听器的概念、好处、语法、场景
为啥有:1-减少视图层操作、2-避免优先级问题
是什么:用来减少视图层操作的技术
啥语法:下面👇🏻
哪里用:二维码切换登录、监控地址栏改变、百度搜索、日期筛选、全选&全不选等等
⭐️ watch两大属性应用场景
deep基于elementui二次封装的form编辑默认显示数据要监控row变化、immediate面包屑首次打开显示对应的菜单
🐝watch监控失效
针对于对象类型的数据,需要加deep属性深度监听/侦听
追问:如何解决
回答:deep属性开启深度监听 或者 " 对象.键"
🐝🐝🐝计算属性和侦听器区别、使用场景
计算属性:计算属性有缓存、并且是响应式依赖缓存,调用不加小括号
侦听器:侦听器无缓存,侦听模型数据变化,不能调用
# 计算属性 为啥有:1-减少视图操作、s2-提升性能 缓存 是什么:用来减少视图操作、提升性能得技术 啥语法:下面👇🏻 哪里用:1-一个数据依赖另一个数据计算得来的结果(桌子腿子/购物车总价)、2-缓存、3-vuex等等 # 侦听器 为啥有:1-减少视图层操作、2-避免优先级问题 是什么:用来减少视图层操作的技术 啥语法:下面👇🏻 哪里用:二维码切换登录、监控地址栏改变、百度搜索、日期筛选等等 🐝说出浏览器运行机制
浏览器主进程,负责创建和销毁tab进程、负责交互前进后退、负责网页文件下载等
渲染进程:每个tab对应一个渲染进程,下面有GUI渲染线程、JS引擎线程、事件线程、定时器线程、异步请求线程
GPU进程:负责3D图绘制
第三方插件进程:负责第三方插件处理,例如跨域、广告拦截插件等
🐝🐝说出浏览器输入网址干了啥
浏览器输入网址回车
去DNS服务器找网址对应的IP地址
根据IP地址加端口访问服务器软件 神龙教主
服务器返回数据
浏览器通过renderer是渲染进程处理,
其中GUI线程主要负责页面布局,解析HTML、CSS构建DOM树、CSS规则树、然后结合成渲染树、最终绘制显示
JS引擎线程负责解析JS代码遇到异步代码交给其他线程处理
https://pan.baidu.com/s/1YDqT3-8W05_Q6B7ThmC9rw?pwd=8sxs
仅仅看video里面:同步异步
仅仅看video2里面:面试题
🌛说出JS为什么是单线程
先看一个比喻
进程就是一个公司,每个公司都有自己的资源可以调度;公司之间是相互独立的;而线程就是公司中的每个员工(你,我,他),多个员工一起合作,完成任务,公司可以有一名员工或多个,员工之间共享公司的空间什么是进程?
进程:是cpu分配资源的最小单位;(是能拥有资源和独立运行的最小单位)什么是线程?
线程:是cpu调度的最小单位;(线程是建立在进程的基础上的一次程序运行单位,一个进程中可以有多个线程)浏览器是多进程的
放在浏览器中,每打开一个tab页面,其实就是新开了一个进程,在这个进程中,还有ui渲染线程,js引擎线程,http请求线程等。 所以,浏览器是一个多进程的。大家都在说js是单线程的,但是为什么要设计成单线程?
这主要和js的用途有关,js是作为浏览器的脚本语言,主要是实现用户与浏览器的交互,以及操作dom;这决定了它只能是单线程,否则会带来很复杂的同步问题。 举个例子:如果js被设计了多线程,如果有一个线程要修改一个dom元素,另一个线程要删除这个dom元素,此时浏览器就会一脸茫然,不知所措。所以,为了避免复杂性,从一诞生,JavaScript就是单线程,这已经成了这门语言的核心特征,将来也不会改变.为了利用多核CPU的计算能力,HTML5提出Web Worker标准,允许JavaScript脚本创建多个线程,但是子线程完全受主线程控制,且不得操作DOM。所以,这个新标准并没有改变JavaScript单线程的本质。
神龙教主
🌛说出JS是单线程 为什么不存在执行效率问题
JS是单线程执行程序代码,形成一个执行栈,挨个处理;
但是遇到特别耗费时间的代码 ,例如异步请求,事件等,
不会堵塞等待执行,而是交给浏览器其他线程处理后,再丢到执行栈中处理,从而保证还行效率
🐝谈谈你对回流重绘的理解
回流/重排:页面布局流发生改变就叫做回流,例如:width、height、border、top等
重绘:重绘元素自身的样式发生改变但是不会影响布局流,例如:color、background、box-shadow等
🐝哪些属性导致回流、哪些属性导致重绘
例如:width、height、border、top等
例如:color、background、box-shadow等
1、添加或删除可见的DOM元素 2、元素的位置发生变化 3、元素的尺寸发生变化(包括外边距、内边框、边框大小、高度和宽度等) 4、内容发生变化,比如文本变化或图片被另一个不同尺寸的图片所替代。 5、页面一开始渲染的时候(这肯定避免不了) 6、浏览器的窗口尺寸变化(因为回流是根据视口的大小来计算元素的位置和大小的) 而重绘是指在布局不变得情况下,比如background-color,或者改动一下字体颜色的color等。 🐝如何避免或减少回流重绘
JavaScript优化法
CSS优化法
🐝🐝🐝谈谈你对虚拟DOM的理解
通过js对象来描述真实的DOM,从而减少回流重绘
减少了同一时间内的页面多处内容修改所触发的浏览器reflow和repaint的次数,可能把多个不同的DOM操作集中减少到了几次甚至一次,优化了触发浏览器reflow和repaint的次数。。
🐝🐝🐝说出VUE有哪些生命周期并说出应用场景
before开头的实际不用
非before开头
created 异步请求 mounted 异步请求、DOM操作(swiper、echarts、聊天默认滚到底部) updated 监控数据变化进一步DOM操作,例如聊天窗口到底部、订单可视化图表重置等等 destroyed 清理非vue资源防止内存泄露,例如登陆倒计时定时器 剩余
activated 组件被keep-alive缓存后,执行场景场景数据,例如添加后列表更新最新数据 deactivated 组件被keep-alive缓存后代替destroyed工作 errorCaptured 当页面发生错误是优雅降级,显示友好提示页面,react框架提示就是参考这一做法 tips
优雅降级(graceful degradation):一开始就构建站点的完整功能,然后针对浏览器测试和修复。
ive enhancement`):一开始只构建站点的最少特性,然后不断针对各浏览器追加功能。
渐进增强:针对低版本浏览器进行构建页面,保证最基本的功能,然后再针对高级浏览器进行效果、交互等改进,达到更好的用户体验。
优雅降级:一开始就构建完整的功能,然后再针对低版本浏览器进行兼容。
2109班面试追问
问1:created、和mounted区别 答1:created不可以dom操作 问2:真的不可以吗 答2:可以通过 this.$nextTick() 问3:父子组件嵌套、生命周期执行顺序 created、mounted 答2:大方向 父created、子created、子mounted、父mounted 🌛vue3新增了哪些弃用了哪些生命周期
vue3选项式:改1 destroyed unMount、增3 (这种语法和vue2几乎一样)
vue3组合式:改1 destroyed unMount 、增3 、并都加on、删created 改setup
<div> <h1>{{msg}}</h1> <button @click="msg = '中国China🇨🇳'">更新</button> </div> <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script> <script> const { createApp } = Vue; const app = createApp({ data() { return { msg: "hello", }; }, methods: {}, renderTracked(event) { console.group("renderTracked 【首次】响应式依赖被组件渲染触发"); console.log(event); console.groupEnd(); }, renderTriggered(event) { console.group("renderTriggered 【后续重新渲染】响应式依赖被组件渲染触发"); console.log(event); console.groupEnd(); }, }); app.mount("#app"); </script> 🐝created里面可以操作DOM吗
通过ref不行,原生JS可以,因为该钩子函数触发还没有编译(不推荐
非要通过ref操作,可以写this.$nextTick来实现
<div> <button ref="btn">a</button> </div> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script> const vm = new Vue({ el: "#root", data: {}, created() { let btnObj = document.querySelector("button"); console.log("js可以", btnObj); console.log("ref不行🚫 神龙教主", this.$refs.btn); this.$nextTick(() => { console.log("ref可以", this.$refs.btn); }); }, }); </script> 追问1:created 定时器打印1 this.$nextTick 打印2 定时器打印3
回答1: 2、1、3
追问2:created Promise.then打印1 this.$nextTick 打印2 定时器打印3
回答2:1、 2、 3
// 追问1:created 定时器打印1 this.$nextTick 打印2 定时器打印3 // 回答1: 2、1、3 // setTimeout(() => console.log(1), 1000) // // Promise.resolve().then(() => console.log(2)) // this.$nextTick(() => console.log(2)) // setTimeout(() => console.log(3), 1000) // 追问2:created Promise.then打印1 this.$nextTick 打印2 定时器打印3 神龙教主 // 回答2:1、 2、 3 // Promise.resolve().then(() => console.log(1)) // this.$nextTick(() => console.log(2)) // setTimeout(() => console.log(3), 1000) 🐝created、和mounted区别
暂无
🐝父子组件嵌套、生命周期执行顺序 created、mounted
挂载:父created、子created、子mounted、父mounted
更新:
🐝watch与created() 哪个先执行?
watch 中的 immediate 会让监听在初始值声明的时候去执行监听计算,否则就是 created 先执行
<div> <h1>{{msg}}</h1> </div> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script> const vm = new Vue({ el: "#root", data: { msg: "hello", }, created() { console.log("后created"); }, watch: { msg: { handler() { console.log("先watch"); }, immediate: true, }, }, }); </script> 🐝🐝谈谈你对keep-alive的理解,并说出应用场景
vue中内置组件,主要将组件相关数据缓存到内存中,避免重复挂载卸载产生的性能开销
场景:tab选项卡、锋域详情页返回列表、锋域排行榜等
周边问题
1-缓存组件使用哪个属性?
2-此时多的哪两个钩子函数?
3-页面加载刷新的时候,被缓存的组件,会执行其中的方法吗?
🐝🐝🐝谈谈你对$nextTick的理解,并说出应用场景
理解:vue中用来确保,在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。
场景:对话框放登录二维码,放表单选项获取数据、获取焦点,点击事件修改对话框状态后开始加载DOM,为确保能获取并操作DOM使用$nextTick包起来。
语法:
// 修改数据 vm.msg = 'Hello' // DOM 还没有更新 Vue.nextTick(function () { // DOM 更新了 }) // 作为一个 Promise 使用 (2.1.0 起新增,详见接下来的提示) Vue.nextTick() .then(function () { // DOM 更新了 }) vue确保模型数据更新完毕之后执行$nextTick里面的callback代码
🐝说出$nextTick原理
Vue 在更新 DOM 时是异步执行的。只要侦听到数据变化,Vue 将开启一个队列,并缓冲在同一事件循环中发生的所有数据变更。如果同一个 watcher 被多次触发,只会被推入到队列中一次。这种在缓冲时去除重复数据对于避免不必要的计算和 DOM 操作是非常重要的。然后,在下一个的事件循环“tick”中,Vue 刷新队列并执行实际 (已去重的) 工作。Vue 在内部对异步队列尝试使用原生的 Promise.then、MutationObserver 和 setImmediate,如果执行环境不支持,则会采用 setTimeout(fn, 0) 代替。
Vue底层监控的数据更新会开启一个队列进行优化处理,然后在下一个的事件循环中去触发nextTick的callback执行,也就是会把nextTick的callback依次尝试放到用原生的 Promise.then、MutationObserver 和 setImmediate、setTimeout中,底层核心代码大致思路如下
1. 把回调函数放入callbacks等待执行 2. 将执行函数放到微任务或者宏任务中 3. 事件循环到了微任务或者宏任务,执行函数依次执行callbacks中的回调 https://github.com/vuejs/vue/blob/dev/src/core/global-api/index.js#L46
https://github.com/vuejs/vue/blob/dev/src/core/util/next-tick.js#L87
export function nextTick (cb?: Function, ctx?: Object) { let _resolve callbacks.push(() => { // 将拿到的回调函数存放到数组中 if (cb) { try { // 错误捕获 cb.call(ctx) } catch (e) { handleError(e, ctx, 'nextTick') } } else if (_resolve) { _resolve(ctx) } }) if (!pending) { // 如果当前没有在pending的时候,就会执行timeFunc pending = true timerFunc() // 多次执行nextTick只会执行一次,timerFunc就是一个异步方法 } if (!cb && typeof Promise !== 'undefined') { return new Promise(resolve => { _resolve = resolve }) } } // https://github.com/vuejs/vue/blob/dev/src/core/util/next-tick.js#L33
const callbacks = [] let pending = false function flushCallbacks () { pending = false const copies = callbacks.slice(0) callbacks.length = 0 for (let i = 0; i < copies.length; i++) { copies[i]() } } let timerFunc //判断1:是否原生支持Promise if (typeof Promise !== 'undefined' && isNative(Promise)) { const p = Promise.resolve() timerFunc = () => { p.then(flushCallbacks) if (isIOS) setTimeout(noop) } isUsingMicroTask = true } else if (!isIE && typeof MutationObserver !== 'undefined' && ( //判断2:是否原生支持MutationObserver isNative(MutationObserver) || MutationObserver.toString() === '[object MutationObserverConstructor]' )) { let counter = 1 const observer = new MutationObserver(flushCallbacks) const textNode = document.createTextNode(String(counter)) observer.observe(textNode, { characterData: true }) timerFunc = () => { counter = (counter + 1) % 2 textNode.data = String(counter) } isUsingMicroTask = true } else if (typeof setImmediate !== 'undefined' && isNative(setImmediate)) { //判断3:是否原生支持setImmediate timerFunc = () => {// 神龙教主 setImmediate(flushCallbacks) } } else { //判断4:上面都不行,直接用setTimeout timerFunc = () => { setTimeout(flushCallbacks, 0) } } 💘 04-Vue3基础-选项是API:组件编程
⭐️ 写出组件概念、好处、语法
概念:用来封装HTML代码便于后期维护; 是vue中非常重要的一个思想,让我们通过独立的、或可复用的组件来构建网站
好处:可以相互调用,减少代码冗余,便于后期维护
⭐️ 谈谈你对UI组件库的理解、种类
是什么:一堆提前封装好的,项目开发常见的公共组件(指公共布局界面)
能干嘛:1-统一开发规范、页面布局 2-减少代码冗余,便于后期维护
有哪些:pc elementui(饿了么)、pc iview(北京)、m vant ui(杭州有赞)、m mint ui(饿了么
⭐️ 写出公共组件、页面组件的封装意义
公共组件价值:增加代码【复用性】,便于后期维护
逻辑/页面组件价值:增加代码【可读性】,便于后期维护
⭐️ 写出props语法&类型限制 、作用、场景
app.component(组件名, { // 核心目的获取属性数据 -> 自动注入到模型中 -> 调用 props: [属性名, ..., 属性名], props: { 属性名: 类型, // 情况1:单类型 属性名: [类型,...,类型], // 情况2:多类型 属性名: { // 情况3:对象既可以检查类型又可以验证还有默认数等 type: String, required: true, default: 100, validator: function (value) { return bool } } }, template: ``, data() {}, methods: {}, .... }) 作用:获取组件属性数据
场景:按钮组件、分页组件、对话组件等等
⭐️ 写出$emit语法、作用、场景
作用:组件内产生动作/交互,通知 父进一步处理 例如按钮、搜索、返回上一步
场景:navBar组件返回、分页等等,所有组件内部时事件产生要通知父组件的
🐝谈谈你对单向数据流的理解
单向数据流指在组件化思想,开发的项目中,数据由根或者父组件传递给子组件,禁止🈲子组件中直接更改,而是由父更改后重新传递给子数据使用
// 在vue中 只能父数据传递给子 父修改后会自动同步到子 // 不允许子修改父 // 生活中:你妈给你多少钱 就用多少,不允许你直接去拿 否则长大了完犊子 // 代码中:父给你就用,你自己直接改 容易后期搞懵逼谁串改了数据 🐝🐝 为啥data要写函数里面返回对象
说明1
或说法2
或说法3
🐝 在组件上使用v-model原理
简写:<组件名 v-model=“num2”></组件名>
底层:<标签名 :model-value=“num2” @update:model-value=“data => num2=data”></标签名>
简写:<组件名 v-model:a=“num2”></组件名>
底层:<标签名 :a=“num2” @update:a=“data => num2=data”></标签名>
🐝🐝🐝 如何实现组件通信?
常用:状态管理工具 pinia、vuex
常用:父传子 props、子传父$emit、兄弟 eventBus
常用:slot插槽
概率:通过组件对象/实例 ref获取、 =》 p a r e n t 获取、 parent获取、 parent获取、root获取、$children获取
概率:v-model
了解:利用provide、inject
💘 05-Vue3基础-选项式API:查缺补漏、和vue2的区别
都在其他课件中
💘 06-Vue3基础-组合式API
🐝🐝🐝 ref、reacive区别
说法1
reaciveref
说法2
1、 从定义数据方面
2、从原理方面
3、从使用方面
🐝 watch和watchEffect区别
核心1:watch懒执行、watchEffect立马执行
核心2:watch写谁监控谁, watchEffect就一个实参函数类型里面用了哪个模型数据监控谁 (类似于计算属性响应式依赖缓存模型里面写谁则监控谁)
🐝🐝🐝 和vue2区别
如上
💘 07-Vue3进阶-路由
⭐️ 写出路由的作用、和对象里面的键语法
{
path,
component,
name,
redirect,
alias
children,
components
meta
…
}
🐝🐝🐝 你说下vue路由模式有几种?
vue2 vue-router@3
https://router.vuejs.org/zh/api/#mode
常用路由模式有2个,分别为hash和history 直接修改路 由构造函数加个mode键即可
准确说有3个,hash/history用于客户端,abstract用户服务端
vue3 vue-router@4 就多了些hooks api而已
createWebHashHistory() createWebHistory() 🐝🐝🐝 你说下vue路由原理?
首先vue路由是基于SPA单页面应用思想去开发的
利用BOM API 来使用
hash模式 通过 BOM location对象的hash属性来改变路由 window.onhashchange
history模式 通过BOM history对象的pushState方法来改变路由 window.onpopstate
🐝🐝🐝 history有什么问题,如何解决?
刷新无法加载网页问题
可以通过服务器配置来解决
🐝🐝🐝 说一下hash和history 区别
hash有一个#号相对丑 、部署上线不需要配置
history没有#号、存在部署上线刷新丢失问题、需要服务器配置
🐝🐝🐝 那你说下什么是单页面应用SPA优缺点,如何选择
SPA优点:减少HTTP请求、加载响应数据、提高用户体验度,方便增加动画
SPA缺点:首屏加载过慢、不利于SEO优化(就是百度可以搜到你)
如何选择
根据项目需求,老板没有明确说就不管,
但是老板说需要seo优化则通过:Vue.js 服务器端渲染(nuxt.js)
tips
1-为什么单页面(SPA)网站无法被seo?:https://www.zhihu.com/question/416192007/answer/1424413130
2-多页面应用(MPA)也就是二升三锋团PC项目也是不利于seo优化,最终是否利于seo主要还是看页面数据是直接和html一起返回的、还是要重新发送ajax请求的。
3-vue中想利于seo则通过nuxt.js技术,react则通过next.js
🐝🐝 参数周边种类、方式
参数种类:query、params
传参方式
query、path router.push( {query, path} ) 定义路由时【不用管】刷新【不丢失】 params、name 写冒号 router.push( {params, name} ) 定义路由时【需要管】刷新【不丢失】 params、name 不写冒号(组合式API弃用) router.push( {params, name} ) 定义路由时【不用管】刷新【丢失】 🐝 谈谈你对编程式导航的理解
作用:就是利用js跳转网页
留心:声明式就是用a标签跳转
场景:登陆、添加按钮、删除按钮等
语法
router.push( { path:'/路径', query: {参数名:值} } ) router.push( { name:'名称', params: {参数名:值} } ) route.query/params.参数名 🐝🐝🐝🐝 说出嵌套路由&命名视图的场景
嵌套路由
概念:一个路由,显示多个组件,并且有父子关系所以通过children来定义 语法:子路由通过children来定义,然后父的组件内容通过router-view来显示匹配的子组件 场景:后台管理系统经典两栏布局 点击左侧菜单,右侧显示子组件内容 命名视图
概念:一个路由,显示多个组件,并且有兄弟关系所以component改为components 语法:定义路由把component改为components,然后视图给router-view 加name属性 场景:移动端navBar、tabBar 🐝🐝🐝 全局导航守卫登陆鉴权
作用;没登陆不可以访问会员中心、后台首页
语法:router.beforeEach 判断h5 next
// 全局前置守卫 // 导航守卫:导航/地址栏门卫,监控路由变化 router.beforeEach((to, from, next) => { // ... // to 存放新的路由数据 // from 存放旧的路由数据 // next() 写- 允许后续代码执行,可以看到组件内容 // next() 不写- 阻止后续代码执行,因此组件不渲染看不到内容 // next({path: '/login'}) 跳转到login页面 // console.log(to); // 检查当前访问的路径 // 在数组中就直接next 不用检查是否登录 // 白名单 if (["/login", "/404"].includes(to.path)) { next(); } else { // 上述白名单直接忽略不用判断 // 但是其他得判断 let token = localStorage.getItem("token"); if (token) { next(); } else { next({ path: "/login" }); } } 🐝🐝🐝 导航守卫种类有哪些,怎么用
种类:全局、路由、组件
vue3 21年8月份 script setup语法中把beforeRouteEnter弃用,把beforeRouteUpdate、beforeRouteLeave升级了
全局
全局前置守卫 beforeEach
全局解析守卫beforeResolve 2.5.0+
全局后置钩子afterEach
路由
组件
🐝 导航守卫执行顺序
导航被触发。 在失活的组件里调用 beforeRouteLeave 守卫。神龙教主 调用全局的 beforeEach 守卫。 在重用的组件里调用 beforeRouteUpdate 守卫 (2.2+)。 在路由配置里调用 beforeEnter。 解析异步路由组件。 在被激活的组件里调用 beforeRouteEnter。 调用全局的 beforeResolve 守卫 (2.5+)。 导航被确认。 调用全局的 afterEach 钩子。 触发 DOM 更新。 调用 beforeRouteEnter 守卫中传给 next 的回调函数,创建好的组件实例会作为回调函数的参数传入。 beforeRouteLeave 组件离开
beforeEach 全局
beforeRouteUpdate 组件更新
afterEach 全局
beforeRouteEnter 组件进入
🐝 🐝 🐝 动态路由如何实现
面试提问
如何实现权限控制 如何实现菜单权限神龙教主 如何实现动态路由 如何动态添加路由规则 项目是前端路由还是后端路由 实战项目回答
见下面👇 作用&语法
作用:不同角色,权限菜单看到的不一样
步骤1:页面菜单导航根据接口数据渲染
步骤2:路由不能全部写死,而是全部注释掉,利用addRoutes或addRoute动态添加路由规则
🐝🐝🐝 元信息有啥用
meta 存放面包屑、也可以加标识控制是否缓存组件
实现1:页面菜单导航根据接口数据渲染神龙教主
实现2:路由不能全部写死,利用addRoutes或addRoute动态添加路由规则
router.addRoute("admin", { path: twoMenu.url, component: () => import("@/views/" + twoMenu.component), meta: { name1: twoMenu.auth_pname, name2: twoMenu.auth_name, keep_alive: twoMenu.keep_alive, }, }); 🐝过渡特效场景
项目中会用到
<transition class-enter-class="animated 类名"> <router-view></router-view> </transition> 💘 08-Vue3进阶-异步请求:axios、fetch数据请求
⭐️ xhr、fetch区别
xhr、fetch 相同点:1-都可以发送异步请求、2-都是ECMA定义的神龙教主 不同点:前者异步回调地狱,后者promise 其他了解
⭐️ fetch、axios区别
相同点:1 都可以发送异步请求,2 都是promise 不同点:1 fetch官方、axios社区,2 axios更强并发、拦截器等 🐝🐝🐝 axios之前有没有封装过
- 封装axios导出request实例对象(timeout、baseURL、headers content-type - 请求拦截器(开启Loading、token - 响应拦截器-成功(关闭Loading、res.data.data过滤 、 接口权限、TOKEN过期等等 - 响应拦截器-失败(关闭Loading、timeout处理 、404等等 🐝🐝🐝 跨域如何解决
常用的
谷歌命令
谷歌插件
前端代理 http-proxy-middleware
JSONP
留心:不管前端咋操作最终上线都得后端或者服务器配置
追问:项目中如何配置
vue中配置 devServer 配置就可以了 追问:在哪个文件中
vue.config.js 中 module.exports = { // ... devServer: {} // ... } 🌛 axios原理
基于xmlhttprequest构造函数、和node中的http模块封装实现,动态判断浏览器环境、还是服务端环境
去选择对应语法返回promise对象
🐝🐝🐝谈谈你对HTTP理解
超文本传输协议、规定客户端和服务端如何通信, 他是是请求行,响应行,请求头,响应头,请求体,响应体组成, 之前我做项目的回收 请求行你们主要查看请求地址、请求状态、请求方式、请求体头里面主要放cookie、token、content-type等,请求体主要看参数有没有传递给后端、响应体后端返回的数据进行项目调试。 🐝🐝🐝 谈谈你对状态码的理解
2xx 200成功 201成功并创建新资源 3xx 301永久重定向 302临时重定向 304浏览器缓存 4xx 400参数有误 401密码错误 403无权访问 404文件不存在 405请求方式有误 5xx 500服务器错误 🐝🐝🐝 post、get区别
安全角度 post对象安全 get地址栏 后期可以通过历史记录查看登陆密码 数据角度 get地址栏 不同浏览器地址栏长度限制 post后端规定 2M 8M 💘 typescript
🐝🐝🐝 any、unknown类型区别
相同点: const a: any = 任意类型数据 const a: unknown = 任意类型数据 不同点:unknown更安全,例如any/unknown赋值数字后用点语法 - 说法1:unknown 需要先进行类型判断,才可以执行相应的类型操作。所以 unknown 可以被看成是更安全的 any - 说法2:在执行大多数操作之前,会进行某种形式的检查。。所以 unknown 可以被看成是更安全的 any 🐝🐝🐝 any、void、never区别
any(任意类型) void(无类型 与 any 类型相反,它表示没有任何类型。当一个【函数】没有返回值,通常使用它表示) never(永不存在的值的类型 。通常是抛出异常或者永远不会有返回值的类型) 🐝🐝🐝 ts新增了哪些数据类型
| js 原有类型 | ts 新增数据类型 | | ----------- | ------------------------------------------------------------ | | null | ✨✨✨string |number (联合类型) | | undefined | ✨✨✨any(任意类型) | | boolean | unknown(不详的/未知类型) | | number | ✨✨✨type 类型别名( 自定义类型) | | string | tuple(元组 表示一个已知元素数量和类型的数组,各元素的类型不必相同) | | symbol | ✨enum(枚举 使用枚举类型可以为**一组数值**赋予**友好的名字**) ORDER_PAY 0 ORDER_NO_PAY 1 | | bigint | ✨✨✨ void(无类型 与 any 类型相反,它表示没有任何类型。当一个函数没有返回值,通常使用它表示) | | object | never(永不存在的值的类型 。通常是抛出异常或者永远不会有返回值的类型) | | | 字面量类型 | | | 等 | 🐝🐝🐝ts会不会用?
会
🐝🐝🐝interface、type区别
面试题:区别
项目用:如何选择
type语法:类型别名不仅可以用来表示基本类型,还可以用来表示对象类型、联合类型、元组和交叉类型
type Type1 = string; // 基本类型 type Type2 = { a:numer, b: number} // 对象类型 type Type21 = any[] type Type22 = (data1:string)=>any type Type3 = string | number // 联合类型 type Type4 = [number, string] // 元组 type Type5 = {a:number} & {b:number} // 交叉(类似于继承) type Type6<T> = { value: T } // 泛型 // 实现 type Animal = { eat(food: string): void } class Dog implements Animal { eat(food: string): void { console.log('eat:', food) } } interface语法:接口 是命名数据结构(例如对象)的另一种方式;与type 不同,interface仅限于描述对象类型。
interface Type2 { a:number,b:number } // 对象类型 interface Type22 { [index:number]:any } interface Type23 { (data1:string)=>any } interface Type5 extends 父类型 interface Type6<T> { a:T,b:number } // 实现 interface Animal { eat(food: string): void } class Dog implements Animal { eat(food: string): void { console.log('eat:', food) } } 🐝🐝🐝 ts的泛型应用场景?
vue ref
vue reacive
vue useAxios Promise 后端返回数据
vue API.Result {}
react useState<类型>()
react Component<Props, State>
react FC
🌛 修饰符public/protected/private/readonly
public 默认修饰符,TypeScript中类中的成员默认为public神龙教主
private 类的成员不能在类的外部访问,子类也不可以
protected 类的成员不能在类的外部访问,但是子类中可以访问。如果一个类的构造函数,修饰符为protected,那么此类只能被继承,无法实例化。
readonly 关键字readonly可以将实例的属性,设置为只读
public 自身 子类 外部 protected 自身 子类 private 自身 class Animal { public a = 1 protected b = 2 private c = 3 } class Dog extends Animal { readonly d = 4 constructor() { super() console.log(1, this.a) } } const dog1 = new Dog console.log(2, dog1.a) console.log(3, dog1.d) // dog1.d = 44