Set与Map的区别
- map是键值对,set是值的集合。键,值可以是任何类型
- map可以通过get获取,map不能。
- 都能通过迭代器进行for…of遍历
- set的值是唯一的,可以***********做数组去重,map,没有格式限制,可以存储数据类型
数组去重方法
- set
- for嵌套
- indexOf,includes
watch和watchEffect
watch的配置项
deep:是否深度监听
immediate :表示在watch中首次绑定的时候,是否执行handler。
watch和watchEffect的区别
- watch可以访问新值和旧值,watchEffect不能访问
- watchEffect有副作用,DOM挂载或者更新之前就会触发,需要我们自己去清除副作
- watch是惰性执行,也就是只有监听的值发生变化的时候才会执行,但是watchEffect不同,每次代码加载watchEffect都会执行。
- watch需要指明监听的对象,也需要指明监听的回调。watchEffect不用指明监视哪一个属性,监视的回调函数中用到哪个属性,就监视哪个属性。
层叠上下文
就是对这些 HTML 元素的一个三维构想
产生,层叠上下文
position
z-index
opacity属性值小于1的元素
transform不为none
重绘、回流
重绘:DOM树没有元素的增加和删除,只是样式改变,针对浏览器对某一元素进行单独渲染。这个过程叫重绘。
回流:DOM树中的元素被增加或者删除,导致浏览器需要重新的去渲染整个DOM树,回流比重绘更消耗性能,发生回流必定重绘,重绘不一定会导致回流。
解决浏览器消耗性能,vue和react都用虚拟DOM
深拷贝和浅拷贝
“浅层拷贝”拷贝的是属性值的地址。
- Object.assign 拷贝最外层
- JSON实现的深拷贝。
- JSON.parse()和JSON.stringify()实现深拷贝:
- 会忽略 undefined和symbol;不可以对Function进行拷贝;不支持循环引用对象的拷贝
- 递归实现
- lodash的_.cloneDeep()
混入
mixins
方法和参数在各组件中不共享
缺点:
- 变量来源不明确(隐式传入),不利于阅读,使代码变得难以维护。
- mixins和组件可能出现多对多的关系,复杂度较高
- 多个mixins的生命周期会融合到一起运行,但是同名属性、同名方法无法融合,可能会导致冲突或覆盖。
vue生命周期
beforeCreate、created、
beforMount、mounted、
beforeUpdate、updated、
beforeDestory、destoryed
与动态组件有关的钩子:activated(激活)、deactivated(休眠)
与组件异常捕获有关的钩子:errorCaptured
在beforeCreate之前会声明methods中的方法和声明生命周期钩子函数
在created之前会注入一些数据,初始化响应式系统,我们通常在这个钩子函数中调接口,获取路由参数等
在beforeMount之前会通过el $meount template找模板,会把模块变成render函数 调用render函数创建虚拟DOM,虚拟DOM转化成真实DOM,进行挂载,通常这个钩子函数我们也用不到
在mounted时,已表示真实DOM已挂载完毕,我们在这个钩子中通常调接口,开定时器,DOM操作,建立websocket连接 实例化echarts实例等。
当数据变化时,会触发beforeUpdate钩子
在updated之前,要生成新的虚拟DOM,新的虚拟DOM和老的虚拟DOM进行对比,会执行patch运算,diff算法,找到两个虚拟DOM的最小差异,找到后,进行异步更新,key的目的就是最快找到最小差异,这个钩子也不常用,但是有点类似于watch侦听器或类似于$nextTick(),我们不能在这个钩子中更新数据,会导致死循环。
当我们手动调用$destory()或路由切换时,会调用beforeDestroy这个钩子函数,我们可以在这个钩子函数中清空定时器,解除事件绑定,清除缓存…
当组件销毁时,就会移除当前组件的watcher,DOM就无法再更新,移除所有子组件,移除事件监听器,响应式系统就会失效,组件就死亡了,这个钩子函数我们用的也不多。
第一次页面加载会触发哪几个钩子
beforeCreate, created, beforeMount, mounted
封装过什么组件
弹窗
props参数
slot定制插槽
event自定义事件
修饰符
表单修饰符
.lazy 光标离开更新
.trim 过滤首尾的空格
.number数字
事件修饰符
.stop 阻止事件冒泡
.prevent 阻止事件的默认行为
.self 点击元素本身触发
如何在vue自定义组件中使用 v-model指令
父组件绑定v-model,子组件接受value默认值。在子组件上,绑定v-model和@input事件。
在methods里,定义input函数,使用`$emit.改变value得值。
静态提升
当 Vue 的编译器在编译过程中,发现了一些不会变的节点或者属性,就会给这些节点打上标记。然后编译器在生成代码字符串的过程中,会发现这些静态的节点,并提升它们,将他们序列化成字符串,以此减少编译及渲染成本。有时可以跳过一整棵树。
render函数
构建虚拟DOM所需要的工具,createElement
路由守卫
执行顺序
全局前置守卫beforeEach (路由器实例内的前置守卫)
路由独享守卫beforeEnter(激活的路由)
组件内守卫beforeRouteEnter(渲染的组件)
全局解析守卫beforeResolve(路由器实例内的解析守卫)
全局后置钩子afterEach(路由器实例内的后置钩子)
next() 放行
完整的导航解析流程
导航被触发。
在失活的组件里调用 beforeRouteLeave 守卫。
调用全局的 beforeEach 守卫。
在重用的组件里调用 beforeRouteUpdate 守卫 (2.2+)。
在路由配置里调用 beforeEnter。
解析异步路由组件。
在被激活的组件里调用 beforeRouteEnter。
调用全局的 beforeResolve 守卫 (2.5+)。
导航被确认。
调用全局的 afterEach 钩子。
触发 DOM 更新。
调用 beforeRouteEnter 守卫中传给 next 的回调函数,创建好的组件实例会作为回调函数的参数传入。
v-for和v-if优先级
vue2 v-for优先级高。 不推荐一起使用
vue3 v-if优先级高。
路由
路由模式
- hash模式:
hash模式的url地址上有’#’ - history 模式
url地址上没有’# - abstract模式:
https://juejin.cn/post/7086021202866602021
router和route区别
router是路由实例对象,用来进行页面跳转router.push、后退router.go(-1)
route是代表的当前路由规则 拿参数 获取当前路由信息
params传参合query传参的区别
params参数在地址栏中不会显示,query会显示
网页刷新后params参数会不存在
https://juejin.cn/post/7045875372553928740
路由的四种跳转方式
- router-link
- this.$router.push()
- this.$router.replace()
- this.$router.go(n)
vue3 为什可以有多个根节点
引入了 Fragment 的概念
浏览器有多少的进程
浏览器进程
GPU进程
网络进程
插件进程
渲染进程
rem原理
指相对于html根元素的字体大小的单位
750设计稿
为什么vue data是一个函数
1.vue中组件是用来复用的,为了防止data复用,将其定义为函数。
2.vue组件中的data数据都应该是相互隔离,互不影响的,组件每复用一次,data数据就应该被复制一次,之后,当某一处复用的地方组件内data数据被改变时,其他复用地方组件的data数据不受影响,就需要通过data函数返回一个对象作为组件的状态。
3.当我们将组件中的data写成一个函数,数据以函数返回值形式定义,这样每复用一次组件,就会返回一份新的data,拥有自己的作用域,类似于给每个组件实例创建一个私有的数据空间,让各个组件实例维护各自的数据。
4.当我们组件的date单纯的写成对象形式,这些实例用的是同一个构造函数,由于JavaScript的特性所导致,所有的组件实例共用了一个data,就会造成一个变了全都会变的结果。
vue2和vue3的区别
- vue2和vue3双向数据绑定原理发生了改变
-
vue2 的双向数据绑定是利用ES5 的一个 API Object.definePropert()对数据进行劫持 结合 发布订阅模式的方式来实现的。
-
vue3 中使用了 es6 的 ProxyAPI 对数据代理。
-
相比于vue2.x,使用proxy的优势如下
- defineProperty只能监听某个属性,不能对全对象监听
- 可以省去for in、闭包等内容来提升效率(直接绑定整个对象即可)
- 可以监听数组,不用再去单独的对数组做特异性操作 vue3.x可以检测到数组内部数据的变化
-
从源码层面来说,使用Proxy代替Object.defineProperty的API,一个是代理的对象,一个是递归监控的属性,从而在性能上有了很大的进步,并且,也解决了对象动态属性增加、数组改变监听上的缺陷;对diff算法进行优化,增加了静态标记,大大提高了Vue的执行效率;还有静态提升、事件监听缓存等一系列提升效率的手段。
- Vue3支持碎片(Fragments)
- 组件可以拥有多个根节点
- Composition API
- Vue2与Vue3 最大的区别 — Vue2使用选项类型API(Options API)对比Vue3合成型API
- 建立数据 data
- Vue2 - 这里把数据放入data属性中
- 在Vue3.0,我们就需要使用一个新的setup()方法,此方法在组件初始化构造的时候触发。
https://zhuanlan.zhihu.com/p/410951679
- 生命周期钩子 — Lifecyle Hooks
Vue2--------------vue3
beforeCreate -> setup()
created -> setup()
beforeMount -> onBeforeMount
mounted -> onMounted
beforeUpdate -> onBeforeUpdate
updated -> onUpdated
beforeDestroy -> onBeforeUnmount
destroyed -> onUnmounted
activated -> onActivated
deactivated -> onDeactivated
setup() :开始创建组件之前,在beforeCreate和created之前执行。创建的是data和method
onBeforeMount() : 组件挂载到节点上之前执行的函数。
onMounted() : 组件挂载完成后执行的函数。
onBeforeUpdate(): 组件更新之前执行的函数。
onUpdated(): 组件更新完成之后执行的函数。
onBeforeUnmount(): 组件卸载之前执行的函数。
onUnmounted(): 组件卸载完成后执行的函数
若组件被包含,则多出下面两个钩子函数。
onActivated(): 被包含在中的组件,会多出两个生命周期钩子函数。被激活时执行 。
onDeactivated(): 比如从 A组件,切换到 B 组件,A 组件消失时执行。
- 父子传参不同,setup() 函数特性
1、setup 函数时,它将接受两个参数:(props、context(包含attrs、slots、emit))
2、setup函数是处于 生命周期函数 beforeCreate 和 Created 两个钩子函数之前的函数
3、执行 setup 时,组件实例尚未被创建(在 setup() 内部,this 不会是该活跃实例的引用,即不指向vue实例,Vue 为了避免我们错误的使用,直接将 setup函数中的this修改成了 undefined)
4、与模板一起使用:需要返回一个对象 (在setup函数中定义的变量和方法最后都是需要 return 出去的 不然无法再模板中使用)
5、使用渲染函数:可以返回一个渲染函数,该函数可以直接使用在同一作用域中声明的响应式状态
垃圾回收机制
- 标记清除
- 首先它会遍历堆内存上所有的对象,分别给它们打上标记,然后在代码执行过程结束之后,对所使用过的变量取消标记。在清除阶段再把具有标记的内存对象进行整体清除,从而释放内存空间。
- 引用计数
- 当变量进行声明并赋值后,值的引用数为1。
- 当同一个值被赋值给另一个变量时,引用数+1
- 当保存该值引用的变量被其它值覆盖时,引用数-1
- 当该值的引用数为0时,表示无法再访问该值了,此时就可以放心地将其清除并回收内存。
内存泄漏与优化
过多的缓存。及时清理过多的缓存。
滥用闭包。尽量避免使用大量的闭包。
定时器或回调太多。与节点或数据相关联的计时器不再需要时,DOM节点对象可以清除,整个回调函数也不再需要。可是,计时器回调函数仍然没有被回收(计时器停止才会被回收)。当不需要setTimeout或setInterval时,定时器没有被清除,定时器的糊掉函数以及其内部依赖的变量都不能被回收,会造成内存泄漏。解决方法:在定时器完成工作时,需要手动清除定时器。
太多无效的DOM引用。DOM删除了,但是节点的引用还在,导致GC无法实现对其所占内存的回收。解决方法:给删除的DOM节点引用设置为null。
**滥用全局变量。**全局变量是根据定义无法被垃圾回收机制进行收集的,因此需要特别注意临时存储和处理大量信息的全局变量。如果必须使用全局变量来存储数据,请确保将其指定为null或在完成后重新分配它。解决方法:使用严格模式。
**从外到内执行appendChild。**此时即使调用removeChild也无法进行释放内存。解决方法:从内到外appendChild。
反复重写同一个数据会造成内存大量占用,但是IE浏览器关闭后会被释放。
注意程序逻辑,避免编写『死循环』之类的代码。
DOM对象和JS对象相互引用。
vue自定义指令给元素绑定事件,却没有解绑事件
通过v-if删除了父级元素,但是并没有移除父级元素里的dom片段
vue-router跳转到别的组件
时间如果在mounted/created 钩子中使用了$on
,需要在beforeDestroy 中做对应解绑($off
)处理
继承
继承之原型继承
- 原型链技术: 改造原型链, 实现继承方法
Student.prototype = new Person() - 实例属性的构造过程没有得到复用, 可以用借用构造函数的方式, 实现复用
Person.call(this, name, age) - 类继承
nextTick
在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。
简单的理解是:当数据更新了,在dom中渲染后,自动执行该函数,
应用:created()钩子函数进行的DOM操作一定要放在Vue.nextTick()的回调函数中
dom和bom
dom: document object model,也就是文档对象模型。
bom:browser object model,浏览器对象模型
dom操作的是html中的元素,bom是浏览器的api、操作的是浏览器
性能优化
页面首屏加载时间
计算加载时间performance.getEntriesByName
优化:
- 网络延时
- 资源重复加载,加载脚本出现阻塞,如死循环
- 前端的资源动态加载:
- 路由动态加载
- 组件动态加载
- 图片懒加载(offScreen Image),越来越多的浏览器支持原生的懒加载,通过给img标签加上loading="lazy来开启懒加载模式。
- 合并请求
- 资源过大,可以压缩
- 缓存(keep-alive)
weback
自定义指令
图片懒加载
input自动聚焦
按钮权限的是实现
vue通信
1)父子组件通信:父传子使用自定义属性(props),子传父使用自定义事件($emit()
)。
2)状态提升:当兄弟组件之间需要共享数据时,我们通常的做法是把这个数据定义它们的共同的父组件中,再通过自定义属性实现数据共享。
3)provide/inject:这是在组件树中,自上而下的一种数据通信方案,也就是说只能父级组件中向后代组件传递。需要注意的是,当provide提供动态数据(声明式变量)时,动态数据发生变化,后代组件们不会自动更新。这是为什么呢?你自己从生命周期流程的角度去思考。
4)ref通信:ref是Vue内置的一个属性,每一个HTML元素或组件都有这个属性;ref作用在HTML元素上得到DOM实例,ref作用在组件上得到组件实例。使用ref访问组件实例,进一步可以访问组件中的数据和方法。(说明:ref是一种快速的DOM的访问方式,当然ref也可作用在组件上得到组件实例。这些ref得到的DOM实例或组件实例,使用this.$refs来访问它们。ref尽量少用,除非某些难搞的需求。)
5)插槽通信:借助<slot>组件实现从子组件向父组件传递数据,借助this. s l o t s 访问父组件中的插槽实例。 ( 在自定义组件中使用 t h i s . slots访问父组件中的插槽实例。(在自定义组件中使用this. slots访问父组件中的插槽实例。(在自定义组件中使用this.slots访问父组件给的插槽实例;在父组件插槽中使用#default='scoped’访问子组件<slot>回传的数据。这种通信在组件库中、工作中,非常常见!)
6)$parent/$children
:借助$parent/$children
可以实现,在任一组件中访问组件树中的其它任意组件实例,可以做到在组件中随意穿梭。($parent
表示的是当前组件的父组件实例,$children
表示的是当前组件的子组件们。)
7)$attrs/$listeners
:借助$attrs
可访问父组件传递过来的自定义属性(除了class和style外),借助$listenrs
可以访问父组件给的自定义事件。在某些场景下,$attrs/$listeners
可以替代props/$emit()
这种通用的通信方案。
8)事件总线:借助于Vue内置的事件系统($on/$emit/$off/$once
)实现“订阅-发布”式的通信,这种通信方式是一种与组件层级无关的“一对多”的通信。(工作中很少用,一些特殊的Vue项目才用得到事件总线。)
9)Vuex通信:这是Vue架构中终极的通信方案,也是Vue架构中用的最多的一种通信方案。
vuex
5大概念:
创建store时要用的五个概念(state/getters/mutations/actions/modules)
- state: {} 用于定义可被组件共享数据,是具有响应式的;在组件中使用this.$store.state来访问它们。
- getters: {fn} 用于计算state,相当于Vue的计算属性,当state发生变化时getters方法自动自动重新计算;在组件中使用this.$store.getters来访问它们。
- mutations: {fn} 专门用于修改state的,所以mutations方法是这样fn(state,payload)定义的;mutations方法在actions中或组件中使用,使用$store.commit(‘mutations方法’,payload)
- actions: {fn} 专门用于调接口的,所以actions方法是这样fn(store,payload)定义的;在组件中使用this.$store.dispatch(‘actions方法’, payload)。
- modules: {子store} 是一个Vuex架构层面的概念,用于拆分子store。大家在拆分子store务必在子store中使用namespaced:true开启命名空间。
4个map:
mapState/mapGetters,必须写在computed计算属性中,用于访问state/getters数据。映射进来后,就可以用this来访问这些数据了。
mapActions/mapMutations 必须写在methods选项中,用于访问mutations/actions方法。映射进来后,可以用this调用这些方法。
它们的语法是相同的:map*(‘命名空间’, [‘k1’, ‘k2’])
3个原则:
原则1:只要使用Vuex一定要拆分store,拆分store后在根store上不要再使用state/mutations/actions。
原则2:在子store务必开启命名空间namespaced:true。
原则3:在组件中尽可能不要使用$store
,建议使用四个map*方法。
pinia
Pinia 是 Vue 的存储库,它允许您跨组件/⻚⾯共享状态。
Pinia适⽤于Vue2和Vue3,并不需要使⽤ Composition API。
Pinia的处理安装之后,它的API也同样适⽤于SSR的应⽤程序。
Pinia⼏个核⼼概念:
state
1)state是⼀个选项,这个选项的值需要是⼀个函数,函数返回⼀个对象,对象中存储数据
2)在组件中拿到当前的store直接使⽤即可,store.xxx
getters
1)getters也是⼀个选项,这个选项的值是⼀个对象,对象中存储着⼀个个函数,每个函数可以有⼀个参数state,通过state可以获取到当前store的state
2)除此之外每个函数还可以拿到⼀个this,这个this就是当前的整个store实例
3)通过这个this,可以想⽤谁就⽤谁
4)在组件中使⽤也是拿到store直接store.xxx即可
actions
1)在actions中,主要存放⼀个个函数,每个函数最主要的⼯作发送异步请求,获取到数据后直接修改state
2)每个action函数并不像getter函数⼀样,第⼀个参数是state,它可以没有参数
3)需要通过this拿到state然后再修改state中的值
4)在组件中拿到store后直接调⽤即可,store.xxx()
5)如果你在此时传递参数,那么就可以在action中拿到参数
没有模块modules的概念。
vue-element-admin难点以及解决办法
uniapp难点以及解决办法
横屏会错乱。禁止横屏。
uniapp支付流程
权限
前端登录换取token,在导航守卫中,实现权限设计,首先判断有没有token,没有token,直接跳到登录页面。有token会进一步判断vuex中有没有用户信息。如果没有用户信息,拿着token,调用接口获取用户信息,用户信息中保存了最重要的字段,就是角色,有了角色后,通过算法生成当前用户可访问的动态路由规则(算法大至是使用后端返回的角色和路由元信息中的角色进行对比,得到可以访问的动态路由规则),有了动态访问的路由规则,再通过addRoutes方法,把得到的动态访问的路由规则添加到路由系统。
Webpack
https://juejin.cn/post/7160596941452574727#heading-1
Loader
file-loader:
把文件输出到一个文件夹中,在代码中通过相对URL去引用输出的文件
url-loader:
和file-loader类似,但是能在文件很小的情况下以base64的方式把文件内容注入到代码中去
source-map-loader:
加载额外的Source Map文件,以方便断点调试
image-loader:
加载并且压缩图片文件
babel-loader:
把ES6转换成ES5
css-loader:
加载 CSS,支持模块化、压缩、文件导入等特性
style-loader:
把CSS代码注入到JavaScript中,通过DOM操作去加载 CSS
eslint-loader:
通过ESLint检查JavaScript 代码
webpack 打包速度优化
-
优化 loader 搜索范围
对于 loader 来说,影响打包效率首当其冲必属 Babel 了。因为 Babel 会将代码转为字符串生成 AST,然后对 AST 继续进行转变最后再生成新的代码,项目越大,转换代码越多,效率就越低。优化正则匹配、使用 include 和exclude 指定需要处理的文件,忽略不需要处理的文件 -
多进程/多线程
受限于 node 是单线程运行的,所以 webpack 在打包的过程中也是单线程的,特别是在执行 loader 的时候,长时间编译的任务很多,这样就会导致等待的情况。我们可以使用一些方法将 loader 的同步执行转换为并行,这样就能充分利用系统资源来提高打包速度了 -
分包
webpack 只需要打包我项目本身的文件代码,而不会再 去编译第三方库,那么第三方库在第一次打包的时候只打包一次,以后只要我们不升级第三方包的时候,那么 webpack 就不会 对这些库去打包,这样可以快速提高打包的速度。 -
开启缓存
当设置 cache.type:“filesystem”时,webpack 会在内部以分层方式启用文件系统缓存和内存缓存,将处理结果结存放到内存中, 下次打包直接使用缓存结果而不需要重新打包 -
打包分析工具
这是 webpack 内置插件, 它的作用是忽略第三方包指定目录,让这些指定目录不要被打包进去,防止在 import 或 require 调用时,生成以下正则表达式匹配的模块 -
ignorePlugin
-
优化文件路径
alias:省下搜索文件的时间,让 webpack 更快找到路径
mainFiles:解析目录时要使用的文件名
extensions:指定需要检查的扩展名,配置之后可以不用在 require 或是 import 的时候加文件扩展名,会依次尝试添加扩展名进行匹配
webpack 打包体积优化
-
构建体积分析
-
项目图片资源优化压缩处理 对打包后的图片进行压缩和优化,降低图片分辨率,压缩图片体积等
-
删除无用的 css 样式
可以使用 purgecss-webpack-plugin插件,该插件可以去 除未使用的 css。 -
代码压缩
对 js 文件进行压缩,从而减小 js 文件的体积,还可以压缩 html、css 代码。 -
开启 Scope Hoisting
Scope Hoisting又译作“作用域提升”。只需在配置文件中添加一个新的插件,就可以让 webpack 打包出来的代码文件更小、运行的更快, Scope Hoisting会分析出模块之间的依赖关系,尽可能的把打包出来的模块合并到一个函数中去,然后适当地重命名一些变量以防止命名冲突。
new webpack.optimize.ModuleConcatenationPlugin();
-
提取公共代码
将项目中的公共模块提取出来,可以减少代码的冗余度,提高代码的运行效率和页面的加载速度。new webpack.optimize.CommonsChunkPlugin(options);
-
代码分离
代码分离能够将工程代码分离到各个文件中,然后按需加载或并行加载这些文件,也用于获取更小的 bundle,以及控制资源加 载优先级,在配置文件中配置多入口,输出多个 chunk。 //多入口配置 最终输出两个chunk -
Tree-shaking
移除 JavaScript 上下文中的未引用代码 -
CDN 加速
CDN 的全称是 Content DeliveryNetwork,即内容分发网络。CDN 是构建在网络之上的内容分发网络,依靠部署在各地的边缘
服务器,通过中心平台的负载均衡、内容分发、调度等功能模块,使用户就近获取所需内容,降低网络拥塞,提高用户访问响
应速度和命中率。CDN 的关键技术主要有内容存储和分发技术。在项目中以 CDN 的方式加载资源,项目中不需要对资源进行
打包,大大减少打包后的文件体积
- 生产环境关闭 sourceMap
- 按需加载
防抖和节流
防抖: n 秒后在执行该事件,若在 n 秒内被重复触发,则重新计时(设置定时器)
节流: n 秒内只运行一次,若在 n 秒内重复触发,只有一次生效(设置时间)
闭包
闭包让开发者可以从内部函数访问外部函数的作用域
闭包就是能够读取其他函数内部变量的函数
- 变量私有化,延长变量的生命周期
- 立即执行函数
- getter和setter
- 函数防抖
闭包原理
- 利用作用作用域链的特性
作用域链就是在当前执行环境下访问某个变量时,如果不存在就一直向外层寻找,最终寻找到最外层也就是全局作用域,这样就形成了一个链条。
key作用
key 是 VNode 的唯⼀标记,通过这个 key, diff 操作可以更准确、更快速的达到复⽤节点,更新视图的⽬的。复⽤节点就需要通过移动元素的位置来达到更新的⽬的。
keep-alive
keep-alive 是 Vue 内置的⼀个组件,可以使被包含的组件保留状态,避免重新渲染 ,其有以下特性:
1)⼀般结合路由和动态组件⼀起使⽤,⽤于缓存组件。
2)提供 include 和 exclude 属性,两者都⽀持字符串或正则表达式。include 表示只有名称匹配的组件会被缓存。exclude 表示任何名称匹配的组件都不会被缓存。其中 exclude 的优先级⽐ include ⾼。
3)对应两个钩⼦函数 activated 和 deactivated 。当组件被激活时,触发钩⼦函数 activated。当组件被移除时,触发钩⼦函数 deactivated。
keep-alive的生命周期
- 初次进入时:created > mounted > activated;退出后触发 deactivated
- 再次进入:会触发 activated;事件挂载的方法等,只执行一次的放在 mounted 中;组件每次进去执行的方法放在 activated 中
LRU 缓存淘汰算法
LRU(Least recently used)算法根据数据的历史访问记录来进行淘汰数据,其核心思想是“如果数据最近被访问过,那么将来被访问的几率也更高”
父子组件生命周期执行顺序
-
创建与挂载
父beforeCreate > 父created > 父beforeMount > 子beforeCreate > 子created > 子beforeMount > 子mounted > 父mounted -
更新
父beforeUpdate > 子beforeUpdate > 子updated > 父updated -
销毁
父beforeDestroy > 子beforeDestroy > 子destroyed > 父destroyed -
在父组件中引入了mixin,生命周期顺序如下:
mixin的beforeCreate > 父beforeCreate > mixin的created > 父created > mixin的beforeMount > 父beforeMount > 子beforeCreate > 子created > 子beforeMount > 子mounted > mixin的mounted >父mounted
解决跨域
-
跨域是指浏览器允许向服务器发送跨域请求,从而克服Ajax只能同源使用的限制
-
所谓同源是指"协议+域名+端口"三者相同,即便两个不同的域名指向同一个ip地址,也非同源。
-
同源策略限制以下几种行为:
Cookie、LocalStorage 和 IndexDB 无法读取
DOM和JS对象无法获得
AJAX 请求不能发送
跨域解决方案
1、JSONP跨域
jsonp的原理就是利用<script>标签没有跨域限制,通过<script>
标签src属性,发送带有callback参数的GET请求,服务端将接口返回数据拼凑到callback函数中,返回给浏览器,浏览器解析执行,从而前端拿到callback函数返回的数据。
缺点:只支持 GET。
2、CORS(配置后端)
3、vue.config.js 文件中配置devServer配置项下的proxy配置项,
module.exports = {
devServer: {
// 设置代理
proxy: {
"/api": {
// 类似于前缀
target: 'http://127.0.0.1:8888/api/xxx', // 目标服务器地址
wx: true, // 是否启用 websocket
chageOrigin: true, // 开启代理:在本地会创建一个虚拟服务器,然后发送请求的数据,
// 同时接收响应的数据,这样服务端和服务端之间进行数据交互就不会有跨域的问题
pathRewrite: {
"^/api": "/"
}
}
}
}
}
插槽
默认插槽、具名插槽、作用域插槽
插槽的作用,就是组件预留出位置,当有需要不充实可以使用插槽插入。
搜索网站的具体过程
git如何解决合并冲突
- git status 查看冲突文件
- vim src/main/java/a.txt (假设a.txt为冲突文件,这里需要为文件的全路径),手动修改冲突部分
- git add src/main/java/a.txt 告诉Git冲突解决了
- git commit -m ‘解决冲突’ (解决冲突为注释,可自定义)
两个已经提交的分支的相同文件相同位置的的不同操作进行了合并.
cookie和localStorage以及sessionStorage的区别
- 存储大小
cookie:一般不超过4k
sessionStorage:5M甚至更多
localStorage:5M甚至更多 - 数据有效期
cookie:一般由服务器生成,可以设置失效时间;若没有设置时间,关闭浏览器cookie失效,如果设置了时间,cookie就会存储在硬盘中,过期失效
sessionStorage:仅在当前浏览器窗口关闭之前有效,关闭页面或者浏览器会被清除
localStorage:永久有效,窗口或者浏览器关闭也会一直保存,除非手动永久删除
- 作用域
cookie:在所有同源窗口中都是共享的
sessionStorage:在同一个浏览器窗口是共享的(不同浏览器,即使是统一页面也不共享)
localStorage:在所有同源窗口中共享
- 通信
cookie:cookie在浏览器和服务器之间来回传递,如果使用cookie保存过多数据会造成性能问题
sessionStorage:仅在客户端(浏览器)中保存,不参与服务器的通信
localStorage:仅在客户端(浏览器)中保存,不参与服务器的通信
- 应用场景
cookie:判断用户是否登录过网站,以便实现下次自动登录或记住密码;保存事件信息
sessionStorage:敏感账号一次性登录,单页面用的较多
localStorage:用于长期登录,适于长期保存在本地的数据
单向数据流
对于 Vue 来说,组件之间的数据传递具有单向数据流这样的特性。
- 优点
- 所有状态的改变可记录、可跟踪,源头易追溯;
- 所有的数据,具有唯一出口和入口,使得数据操作更直观更容易理解,可维护性强;
- 当数据变化时,页面会自动变化
- 当你需要修改状态,完全重新开始走一个修改的流程。这限制了状态修改的方式,让状态变得可预测,容易调试。
异步promise(多重请求的问题,用Promise.all())
resolve内部定义成功时我们调用的函数
reject内部定义失败时我们调用的函数
Promise.all()
mvc和mvvm区别
- MVC思想 :Controller负责将Model的数据用View显示出来。
- M V VM——视图模型双向绑定,双向数据绑定的模式,实现了View和Model的自动同步,因此开发者只需要专注对数据的维护操作即可,而不需要一直操作 dom。
MVVM与MVC区别:
MVVM与MVC最大的区别就是:它实现了View和Model的自动同步,也就是当Model的属性改变时,我们不用再自己手动操作Dom元素,来改变View的显示,而是改变属性后该属性对应View层显示会自动改变
font-size: 0的作用和用途
代码自动格式化的时候,往往会设置一些适当的缩进、换行,但当元素的display为inline或者inline-block的时候,这些缩进、换行就会产生空白,导致前端页面展示变形。
解决行行内块产生的空隙
uniapp中onshow,onload,onready的执行顺序
onload
onshow
onready
什么方法能判断出null的真实类型
Object.prototype.toString.call(null);
vue的template的渲染过程
vue的模版编译过程主要如下:template -> ast -> render函数 -> 虚拟DOM -> 真实DOM
读取模板:Vue 会读取 HTML 模板并将其转换为字符串。
解析模板:Vue 使用编译器将字符串模板转换为抽象语法树(AST),其中包含模板中的每个元素和它们的属性。
生成 render 函数:Vue 使用抽象语法树生成 render 函数。
数据响应:Vue 将数据绑定到 render 函数,并使用 Object.defineProperty 监听数据的变化,在数据更改时重新生成 render 函数。
虚拟 DOM:Vue 通过 render 函数生成虚拟 DOM,该数据结构是真实 DOM 的内存版本。
更新 DOM:Vue 通过对比虚拟 DOM 和真实 DOM 的差异,仅更新需要更新的部分,从而生成最终的真实 DOM。
封装的自定义指令
input的自动聚焦
图片的懒加载
权限到按钮,用的也是自定义指令。
自定义组件
Dialog 对话框
Pagination 分页
ECharts 图表
wangEditor 富文本编辑器
EventLoop(事件循环)
- 同步任务执行完毕,查看微任务队列
若存在微任务,将微任务队列全部执行(包括执行微任务过程中产生的新微任务)
若无微任务,查看宏任务队列,执行第一个宏任务,宏任务执行完毕,查看微任务队列,重复上述操作,直至宏任务队列为空
微任务:promise、async/await
浏览器兼容问题
https://juejin.cn/post/7067808335034220574
1、不同浏览器的标签默认的内外边距不同
解决方案:*{margin: 0; padding: 0;}
清除浏览器自带的默认样式
2、IE6及更低版本中,部分块元素拥有默认高度
解决方案:给元素设置font-size: 0;
输入url到返回内容的整个过程
- 输入www.baidu.com网址, DNS解析(域名映射的过程), 将域名转换成ip地址 (计算机在网络中的标识)
- 根据ip地址, 就可以找到服务器, 尝试建立TCP连接, 三次握手
三次握手: 一次发起连接, 两次 => 双方确认 - 发起 http 请求, 服务器端做出响应, 响应index.html
- 浏览器解析 index.html, 加载其他的一些资源 图片, js等
- 浏览器完成渲染
- http服务结束, 断开TCP连接, 四次挥手
http和https
- https协议需要CA申请整数,一般免费整数较少,因而需要一定费用
- http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl/tls加密传输协议
- http和https使用的是完全不同的连接方式,用的端口不一样,http是80,https是443
- http的连接很简单,是无状态; https协议是由SSLTLS+HTTP协议构建的可进行加密传输、身份认证的网络协议,比如http协议安全
GET方法和POST方法有何区别
状态码
1xx正在处理
2xxxok
3xx重定向
4xx服务器不能处理
5xx服务器出错误
兼容问题
GET方法和POST方法有何区别
- POST比GET 安全,因为数据在地址栏上不可见
- 对于GET方式的请求,浏览器会把http header和data一并发送出去,服务器响应200(返回数据)
对于POST,浏览器先发送header,服务器响应100 continue,浏览器再发送data,服务器响应200 ok - 并不是所有浏览器都会在POST中发送两次包,Firefox就只发送一次
this指向
- 绑定一:默认绑定;
独立函数调用就是所谓的默认绑定,独立的函数调用我们可以理解成函数没有被绑定到某个对象上进行调用 - 绑定二:隐式绑定;
谁调用就指向谁 - 绑定三:显示绑定;
call,apply,bind- call(函数执行,参数加逗号)
- appay(函数执行,参数数组形式)
- bind(函数不执行,参数和call一样)
- 绑定四:new绑定;
- 新建一个对象obj
- 把obj的和构造函数通过原型链连接起来
- 将构造函数的this指向obj
- 如果该函数没有返回对象,则返回this
封装axios
- 封装目的
实现请求拦截
实现响应拦截
常见错误信息处理
请求头设置
api 集中式管理 - 初始化 axios 实例
// 创建 axios 请求实例
const serviceAxios = axios.create({
baseURL: "", // 基础请求地址
timeout: 10000, // 请求超时设置
withCredentials: false, // 跨域请求是否需要携带 cookie
});
- 设置请求拦截
// 创建请求拦截
serviceAxios.interceptors.request.use(
(config) => {
// 如果开启 token 认证
if (serverConfig.useTokenAuthorization) {
config.headers["Authorization"] = localStorage.getItem("token"); // 请求头携带 token
}
// 设置请求头
if(!config.headers["content-type"]) {
// 如果没有设置请求头
if(config.method === 'post') {
config.headers["content-type"] = "application/x-www-form-urlencoded"; // post 请求
config.data = qs.stringify(config.data); // 序列化,比如表单数据
} else {
config.headers["content-type"] = "application/json"; // 默认类型
}
}
console.log("请求配置", config);
return config;
},
(error) => {
Promise.reject(error);
}
);
- 设置响应拦截
// 创建响应拦截
serviceAxios.interceptors.response.use(
(res) => {
let data = res.data;
// 处理自己的业务逻辑,比如判断 token 是否过期等等
// 代码块
return data;
},
(error) => {
let message = "";
if (error && error.response) {
switch (error.response.status) {
case 302:
message = "接口重定向了!";
break;
case 400:
message = "参数不正确!";
break;
case 401:
message = "您未登录,或者登录已经超时,请先登录!";
break;
case 403:
message = "您没有权限操作!";
break;
case 404:
message = `请求地址出错: ${
error.response.config.url}`;
break;
case 408:
message = "请求超时!";
break;
case 409:
message = "系统已存在相同数据!";
break;
case 500:
message = "服务器内部错误!";
break;
case 501:
message = "服务未实现!";
break;
case 502:
message = "网关错误!";
break;
case 503:
message = "服务不可用!";
break;
case 504:
message = "服务暂时无法访问,请稍后再试!";
break;
case 505:
message = "HTTP 版本不受支持!";
break;
default:
message = "异常问题,请联系管理员!";
break;
}
}
return Promise.reject(message);
}
);
https://zhuanlan.zhihu.com/p/509680724
link和@import
1.从属关系区别. @import 是 CSS 提供的语法规则,只有导入样式表的作用; link 是HTML提供的标签,不仅可以加载 CSS 文件,还可以定义 RSS、rel 连接属性等。.
2.加载顺序区别. 加载页面时, link 标签引入的 CSS 被同时加载; @import 引入的 CSS 将在页面加载完毕后被加载。.
3.兼容性区别. @import 是 CSS2.1 才有的语法,故只可在 IE5+ 才能识别; link 标签作为 HTML 元素,不存在兼容性问题。.
4.DOM可控性区别. 可以通过 JS 操作 DOM ,插入 link 标签来改变样式;由于 DOM 方法是基于文档的,无法使用 @import 的方式插入样式。.
css实现元素隐藏的方式
- .display: none:
- visibility: hidden
- .opacity: 0
浏览器解析并渲染页面的过程
- 渲染过程
- 浏览器获取到 html 资源后开始解析 html (dom tree)
- 解析到 css 后根据 css 生成 css 规则树 (style rules)
- 在 dom 树和 css 规则树都生成完后,通过 dom 树和 css 规则树生成渲染树( render tree )
- 渲染树构建完成后,浏览器开始计算元素的大小和位置( layout )
- 根据计算好的节点信息将内容绘制到屏幕上( painting )
如何实现边框0.5px
- 定位+缩放
.button::before {
content: "";
position: absolute;
top: 0;
left: 0;
min-width: 200%;
height: 200%;
border: 1px solid $color-black54;
transform-origin: 0 0;
transform: scale(.5, .5);
}
- 利用的是 box-shadow 的扩散半径可以设置为 0.5px 原理
box-shadow: 0px 0px 0px 0.5px #f00;
支持的浏览器: Firefox: Safari: Chrome: Firefox: Safari:
- 线性渐变
.box {
height: 1px;
background: linear-gradient(#f00 50%, transparent 50%);
}
- SVG
.HalfPixelLine{
background: repeat-x top left url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='1' height='1'><rect fill='red' x='0' y='0' width='1' height='0.5'/></svg>");
height: 1px;
width: 100%;
}
- 直接使用border属性
border: 0.5px solid #f00;
支持的浏览器: Firefox: Safari: Chrome:
H5和C3的新特性
H5新特性
- 语义化标签
header,footer,nav,section,article,aside,detailes,summary,dialog - 表单input 的 type
color,date,datetime,email,month,number,range,search,tel,time,url,week - html5 新增的表单属性
placehoder,required,pattern,min 和 max,step,height 和 width,autofocus,multiple - html5 新事件
onresize,onscroll
CSS3 新特性
背景和边框
文本效果
2D/3D 转换
动画、过渡
多列布局
用户界面
- 选择器
伪类和伪元素: - 背景和边框
- 文本效果
- 2D/3D 转换
2D 转换(transform) - 动画、过渡
- CSS 兼容内核
rpx
- rpx 即响应式px,是一种根据屏幕宽度自适应的动态单位。uni-app规定屏幕的基准宽度为750rpx。
- 设计稿 1px / 设计稿基准宽度 = 框架样式 1rpx / 750rpx
- rpx不支持横屏切换,如果使用rpx 建议锁定屏幕方向
- rpx单位规定如果在iPhone6下,也就是屏幕宽度375px,则
- 750rpx = 375px = 750物理像素
- 1rpx = 0.5px = 1物理像素
flex布局的元素会自适应页面
float产生高度塌陷
vite和weback的优缺点
- vite优点:
webpack服务器启动速度比vite慢
由于vite启动的时候不需要打包,也就无需分析模块依赖、编译,所以启动速度非常快。当浏览器请求需要的模块时,再对模块进行编译,这种按需动态编译的模式,极大缩短了编译时间,当项目越大,文件越多时,vite的开发时优势越明显
vite热更新比webpack快
vite在HRM方面,当某个模块内容改变时,让浏览器去重新请求该模块即可,而不是像webpack重新将该模块的所有依赖重新编译;
vite使用esbuild(Go 编写) 预构建依赖,而webpack基于nodejs, 比node快 10-100 倍 - vite缺点:
生态不及webpack,加载器、插件不够丰富
打包到生产环境时,vite使用传统的rollup进行打包,生产环境esbuild构建对于css和代码分割不够友好。所以,vite的优势是体现在开发阶段
没被大规模重度使用,会隐藏一些问题
项目的开发浏览器要支持esmodule,而且不能识别commonjs语法
冒泡和捕获
捕获阶段:事件从父元素开始向目标元素传播,从 Window 对象开始传播。
目标阶段:该事件到达目标元素或开始该事件的元素。
冒泡阶段:这时与捕获阶段相反,事件向父元素传播,直到 Window 对象。
事件委托。
停止冒泡 event.stopPropagation();
行内标签
行内元素: a、span、b、img、strong、input、select、lable、em、button、textarea 、selecting
块级元素:div、ul、li、dl、dt、dd、p、h1-h6、blockquote、form
空元素: br、hr、link、input、img
居中
文字居中
text- align: center;
line-height:高度
盒子居中
margin:0 auto
position: relative;
left:50%;
transform:translateX(-50%);
display: flex;
/实现垂直居中/
align-items: center;
/实现水平居中/
justify-content: center;
BFC
- BFC:block formatting context 块状格式化上下文
BFC元素可以理解成被隔离的区间(BFC的子元素不会对外面的元素产生影响) - BFC如何触发
- float:left | right
- overflow:hidden | scroll | auto; (不是visible)
- display:inline-block | table-cell | table-caption | flex | grid ;( 非none 非inline 非block)
- position: absolute | fiexed ;( 非relative)
- BFC能解决什么问题
- margin 重合问题
- margin 塌陷问题
- 高度塌陷问题
打包流程,上线打包,小程序打包
问面试官的问题
公司业务项目
和技术栈
团队人员
薪资待遇
文章评论