vue2面试题
1.阐述事件捕获与事件冒泡
- 事件的概念:事件,是文档或浏览器窗口中发生的一些特定的交互瞬间。事件流,指的是事件发生的顺序。
- 事件捕获:由外向内,事件从最外层向目标元素传播
- 事件冒泡:由内向外,事件从目标元素向最外层传播
- 阻止事件冒泡的方法:event.stopPropagation()
- 阻止事件默认行为:比如a链接点击会自动打开超链接,event.preventDefault();
2.页面回流与重绘
-
浏览器的渲染过程
解析HTML,生成DOM树,解析CSS,生成CSS树,将DOM树与CSS树结合起来生成渲染树。根据生成的渲染树,进行页面回流,得到元素的几何信息(位置,大小),根据得到渲染树和几何信息,得到具体的像素点,进行页面的重绘。将像素发给GPU,在页面上进行显示。 -
回流
构造了渲染树,可以将DOM元素与它对应的样式结合起来,得到对应dom元素在视口内的位置和大小。只要页面布局发生变化就会触发回流 -
重绘
上面我们知道了渲染树以及回流知道了对应元素的具体位置及大小信息,得到具体的像素值这时候将渲染树上的节点根据大小位置信息,渲染到页面上,叫做重绘。只要改变某个元素的背景色,文字颜色,边框颜色等不影响它周围或内部布局的属性,就会发生重绘 -
性能优化
尽量减少页面的回流和重绘
1.操作dom时,尽量操作低层级的dom元素
2.不要频繁操作样式,对于静态页面可以修改类名
3.使用position设置属性为absolute或者fixed,使元素脱离文档流,不会影响页面布局
3.输入url到浏览器上进行页面展示发生了什么
- 首先浏览器开始查找域名的ip地址,请求发起后浏览器会解析这个域名,首先它会查看本地硬盘的hosts文件,看看有没有这个ip地址和这个域名之间的对应规则,如果有就用hosts文件里的ip地址。如果没有,浏览器会发送dns请求到本地dns服务器。(本地dns服务器一般由服务商提供,比如中国电信、中国移动),当请求到达dns服务器的时候,本地dns服务器会首先查询它的缓存请求,如果缓存里有这条记录,则直接返回结果,如果本地dns没有,则继续像根服务器去查询。 然后进行DNS域名解析:DNS将域名解析成ip地址
- 建立TCP连接(三次握手):三次的目的是建立可靠的通信
- HTTP请求:浏览器将http请求数据发给服务器(客户端–>服务器)
- HTTP响应:服务器收到客户端的请求,返回响应结果给到浏览器(服务器–>客户端)
- 关闭TCP链接:数据传输完成后,通过第四次握手终止连接
- 页面渲染:浏览器解析响应结果,进行页面渲染
4.px、em、rem、%、vw、vh
- px 绝对像素单位
- em 参考父元素的font-size的大小
- rem 相对于根结点html的font-size的大小
- % 相对长度单位,相对于父元素的尺寸的取值
- vw 相对于浏览器视口宽度的单位
- vh 相对于浏览器视口高度的单位
5.盒子模型
- border-box:盒子的宽高 = width + padding + border
- content-box 盒子的宽高 = width
6.BFC
-
概念:BFC(块级格式化上下文)是一块独立渲染的区域,独立且不会影响外部元素
-
怎样形成BFC:
1.设置浮动float
2.设置定位,absoulte或者fixed
3.行内块显示模式,inline-block
4.设置overflow,即hidden,auto,scroll
5.表格单元格,table-cell
6.弹性布局,flex -
利用BFC解决什么问题
1.解决margin塌陷(垂直方向)
2.清除浮动
3.BFC可以阻止标准流元素被浮动元素覆盖
7.div垂直水平居中
- 水平居中
1.为该行级元素的父元素设置text-align:center配合line-height样式
2.定宽块级元素:为其自身设置margin:auto样式 - 水平垂直居中
1.利用flex布局使内部块级元素水平,垂直居中(display:flex;justify-content: center; align-items:center;)
2.利用定位实现,父元素:position:relative; ,子元素:position: absolute;top:50%;left:50%;transform:translate(-50%,-50%);
3.父元素:position:relative; ,子元素:position: absolute; left:50%,top: 50% + margin-left:-(自身宽度的一半),margin-top:-(自身高度的一半)
4.grid布局 父元素设置display:grid,justify-content:center,align-content:center,grid-templaet-columns:100px,grid-template-rows:100px
8.js数据类型以及类型判断
-
数据类型
1.基本数据类型:Number、Boolean、String、undefined、null
2.复杂数据类型:数组、对象、函数 -
数据类型判断方法
1.typeof 可以检测string、Boolean、number、undefined、function,其中null和array(检测出来是object),原因在于,null和数组被当作一个空对象去引用
2.instanseof(推荐使用)
用来判定对象的具体类型,用法:a instanse of A ,意思是判断a是否是A的实例,返回值是布尔值
3.Array.isArray(需要检测的数组)可以检测一个数据是否是数组
4.Object.prototype.toString.call(),会返回一个形如 “[object XXX]” 的字符串
9.v-for中为何要使用唯一的key
1.若使用数组index当作key,当向数组中新插入一个元素后,这时会更新索引,对应着后面的虚拟dom的key都会全部更新,这些更新都是不必要的
2.如果没有key的话,默认的是就地复用的策略,如果数据项的顺序发生改变,vue不是移动dom来匹配数据项的改变,而是简单复用原来位置的每个元素,当比较到这个元素的值不一样的时候,将新的值放到该位置,以此类推,key的作用主要是为了高效的更新虚拟DOM
10.px2rem禁止某些px转rem
#box {
height: 44px //用postcss-px2rem插件配置后相当于0.44rem
width: 100%
font-size: 24px;/*no*/ //如果不想用插件转换可以用/*no*/标识符
}
11.vue的生命周期
创建:beforecreate、created
beforecreate:
第一个钩子,这个阶段的data、methods、computed以及watch的数据和方法不能被访问
created:
这个阶段完成数据观测,数据初始化完成,可以使用数据,更改数据
无法与dom进行交互,想要的话可以用过nextTick来访问,nextTick延迟回调,更新数据后立即操作dom
挂载:beforeMount、mounted
beforeMount:
发生在页面渲染之前,当前阶段虚拟Dom已经创建完成,即将开始渲染。
在此时也可以对数据进行修改,不会触发updated
mounted:
数据挂载到dom上,数据完成双向绑定,可以访问到dom节点,使用$refs属性对dom进行操作
补:第一次页面加载就会触发 创建和挂载钩子
更新 beforeUpdate、updated
beforeUpdate:
发生在更新之前,也就是响应式数据发生更新,虚拟dom重新渲染之前被触发
可以在当前阶段进行更改数据,不会造成重复渲染
uodated:
发生在更新完成以后,当前阶段组件dom已完成更新
需注意的是避免在此期间更改数据,因为这可能导致无限循环的更新
销毁 beforeDestory、destroyed
beforeDestory:
发生在市里销毁之前,在当前阶段实例完全可以被使用
可以在这进行善后收尾工作,如清楚定时器
destroyed:
发生在实例销毁之后,这个时候只剩下了dom空壳。组件已被拆解,数据绑定被清除,监听被移出,子实例也统统被销毁
补充:
activited:
keep-alive专属,组件被激活时调用 include 包含的组件 exclude 排除的组件 max 缓存的组件最大值
deactivited:
keep-alive专属,组件被销毁时调用
12.v-show与v-if的区别
v-if 只有条件为真的时候才会真正渲染标签,不适合频繁渲染
v-show 基于display切换 适合频繁渲染
不推荐v-if与v-for使用,因为会把每个元素都增加v-if,造成性能问题
13.组件间通信
1.父传子:
父组件使用 :参数名=要传递的参数 :num=1000
子组件使用props接收 (props:[属性名])
子组件接收的另一种方式:
props:{
num:{
type:NUmber,//数据类型
required:true,//必须传值
default:{
100
},//默认携带的数字
}
}
2.子传父
1.**传递**:在调用子组件的位置,添加自定义事件,子组件使用$emit传递数据
3.父组件调用子组件的方法获取子组件的参数
父组件上面定义ref="child"
父组件里调用子组件的方法:this.$refs.child.showPhone() showPhone是子组件里面的方法
父组件里获取到子组件的参数:this.$refs.child.phone phone是子组件里的变量
4.子组件直接调取父组件数据参数和方法
子组件中获取数据参数:this.$parent.parentData parentData为父元素的变量
子组件中获取方法:this.$parent.showParent() showParent为父元素的方法
14.computed和watch的区别:
1.computed属性
1.支持缓存,只在依赖的数据发生变化时,才会重新计算,得到的为一个数据结果
2.不支持异步,当computed内有异步操作时无效,无法监听数据的变化
3.使用方式
- 模版
用插值表达式{{计算属性名}}
- 在实例内
this.计算属性名
代码演示:
{
data(){
},
methods:{},
computed:{
计算属性名1(){
//对依赖的属性进行处理,且进行return
return
},
计算属性2(){
//对依赖的属性进行处理,且进行return
return
}
}
}
2.watch监听
1.不支持缓存,每调用一次就计算一次
2.支持异步
3.用于监听data里面的数据是否被修改,一旦修改就可以执行一些其他的操作【方法】
4.在监听的时候,可以有二次参数,第一次参数为新数据,第二次为旧数据
5.高级监听:可以监听单数据、数组,但是当监听对象的时候,明明数据修改了,却没有触发监听,此时需要开启深度监听,watch只会监听第一层
{
data:{},
watch:{
//监听器的作用就是监听数据是否发生了变化,变化后可以进行一些其他的操作
//只要没有发生变化,就没有办法进行其他操作
text(newValue,oldValue){
},
deep: true, // 是否深度监听
immediate: true, // 是否在组件创建时立即执行回调函数
}
}
15.vue中的$set方法
1.由于vue会在初始化实例的时候进行双向数据绑定,所以属性必须是在data对象存在才能让他响应,如果要给对象添加新的属性,此时新属性并没有进行上述过程,不是响应式的,所以会出现数据变化,页面不变的情况,此时需要用到$set
2.实例
myInfo:{
name:'xiaohua',
age:'18'
}
this.$set(this.myInfo,'age',24)
16.vue路由
1.概念:路由指的是应用程序中的一个页面,是一个js对象
2.vue-router路由模式有几种?
- hash路由:在地址栏会有一个#号,hash发生变化的url都会被浏览器记录下来,浏览器的前进后退可以用
- history路由:
history ——利用了HTML5 History Interface 中新增的pushState() 和replaceState() 方法。提供了对历史记录进行修改的功能。它能让开发人员在不刷新网页的情况下改变站点的 URL。History 有 URL 重定向问题,需要在服务端去配置 url 重定向,否则会报 404 错误。
3.router与route的区别
- $router 路由实例,用来操作路由,包括push、replace、go、forward等方法,可以动态更改url,从而实现页面间的无刷新跳转
- $route 路由信息对象 包括URL 路径、查询参数、路径参数等信息,path、params、query参数,只读对象
4.params传参与query传参
- params传参类似于post请求,参数不会写到地址栏中(但是不能刷新),params只能配合name使用,假如使用动态路由'/user:id',则可以解决这个问题。
- query传参类似于get传参,传过去的参数会显示在地址栏中,query既可以配合name使用,又可以配合path使用
- 接收参数this.$route.query.id this.$route.params.id
// 路由配置
{
path: '/user',
component: User,
props: { id: userId }
}
然后再目标页面里使用props去接收参数
// 在目标组件中获取传递的参数
export default {
props: ['id'],
created() {
console.log(this.id)
}
}
需要注意的是,在使用属性传参时,必须在目标组件中声明`props`,否则会抛出警告。同时,在使用属性传参时,可以使用`props: true`来将路由参数自动注入到目标组件的props中。
5.路由跳转
- 声明式路由router-link to=`/path?参数名=参数值`
- 编程式路由跳转
this.$router.push({name:'hello',query:{id:1}})
this.$rouer.push({name:'hello',params:{id:1}})
this.$router.push({path:'/hello',query:{id:1}})
6.vue路由重定向
const routes = [
{ path: '/', redirect: '/index'},
{ path: '/index', component: index }
]
7.路由守卫
to为目标路由、from为当前路由 next()为跳转 可以用来做登录拦截
router.beforeEach((to, from, next) => {
document.title = to.meta.title || '卖座电影';
if (to.meta.needLogin && !$store.state.isLogin) {
next({
path: '/login'
})
} else {
next(
{
path:'/',
query:{
redirect: to.fullPath
}
})
}
})
8.路由懒加载
- 为什么需要懒加载,像vue这种单页面应用,如果没有懒加载,运用webpack打包后的文件将会异常的打,造成首页加载长时间的白屏,并且加载时间长。运用懒加载可以减少首页加载用时
{
path: '/login',
name: 'Login',
component: () => import('../views/login/login.vue')
},
9.路由监听
watch:{$route(to,from){ to代表的是当前路由,from指的是上一个页面路由,监听到路由变化后可以拿参数等东西 比如to.query.name等 }}
17.vue的内置组件keep-alive
页面切换的时候会进行销毁,当我们不想让它销毁的时候就需要用keep-alive包裹着组件
在组件切换过程中将状态保留在内存中,防止重复渲染dom,减少加载时间以及性能消耗,提高用户体验
根据条件缓存页面
APP.js页面
<keep-alive>
<!-- 添加meta的则添加 keep-alive -->
<router-view v-if="$route.meta.keep"></router-view>
</keep-alive>
<!-- 不添加 -->
<router-view v-if="!$route.meta.keep"></router-view>
路由页面给需要的添加meta
{
path: '/',
name: 'home',
alias: '/home',
components:{ home },
meta:{
keep:true //需要缓存
}
},
18.数组常见API
concat :连接两个或多个数组,并返回结果
join:将数组的所有元素放入一个字符串,元素通过指定的分隔符进行分割
pop:删除并返回数组的最后一个元素
push:向数组的末尾添加一个或者更多元素,并返回新的长度
shift:删除并返回数组的第一个元素
unshift:向数组的开头添加一个或者更多元素,并返回新的长度
reverse:颠倒数组中元素的排列顺序
slice:从某个已有的数组返回截取的元素,返回是新数组,不改变原数组
sort:对数组的元素进行排序
splice:删除元素,并向数组中添加新元素。返回截取的参数改变原数组
toString:将数组转换成字符串,并返回结果
indexOf:查找是否有符合的元素,无则输出-1
map:调用每个元素进行运算,返回新的数组
foreach:列出数组的每个元素,并不会改变原数组
filter:过滤出一个新的子数组,返回条件为true的值
some:查询是否有元素符合条件,输出布尔值
every:查询是否所有元素符合条件,输出布尔值
reduce:计算数组元素相加后的总和
reduceRight:同上,从数组的末尾向前相加
19.Promise详解
1.解释一下Promise的概念
promis是一种处理异步操作的一种方式,它代表着一个异步操作的最终的处理结果。具有3种状态:pending(进行中)、reject(已失败)、fulfilled(已成功),可以通过promise.then或者catch方法来处理成功或者失败的返回结果.它可以解决回调地狱,即多层嵌套的回调函数导致代码难以理解和维护的情况。如果需要处理多个异步操作,那么可以使用promise.all去处理
20.async await 是什么?它有哪些作用?
async 用于申明一个 function 是异步的,而 await是用来等待异步方法执行。 实际上async函数返回一个 Promise 对象,可以使用then方法添加回调函数。
21.普通函数与箭头函数的this详解
- 普通函数的this总是指向其函数的直接调用者,改变this的指向方向call、apply、bind
- 箭头函数是没有this的,他的this永远指向其调用环境,任何方法都改变不了他的指向。箭头函数的this是由定义时外围最接近一层的非箭头函数的 this来决定的,也就是平常所说的箭头函数的this是从上层作用域中去找的,一直找不到的话即为 window
22.js中的同步与异步
- 众所周知,js是一门单线程语言,前一个任务执行完,才能继续执行下一个任务,但是,如果前一个任务的执行时间很长,后一个任务就不得不等着,这样会使得用户体验极差。所以js在设计的时候就考虑到了这个问题,任务就可以分为同步任务和异步任务。
- 无论如何,做事情的时候都是只有一条流水线(单线程),同步和异步的差别就在于这条流水线上各个流程的执行顺序不同。
- 同步任务是指在主线程上排队执行的任务,只有前一个任务执行完毕,才能继续执行下一个任务
- 异步任务是指不进入主线程,而进入任务队列的任务,只有任务队列通知主线程,某个异步任务可以执行了,该任务才会进入主线程,
1. 先执行执行栈中的同步任务
2. 遇到异步任务(回调函数)就放入任务队列中
3. 一旦执行栈中的同步任务执行完毕,系统就会按次序读取任务队列中的异步任务,被读取的异步任务结束等待状态,进入执行栈开始执行。
23.面试中的自我介绍
面试官你好,我是今天的面试者XX,应聘贵公司的web前端一职。我有3年的工作经验,擅长使用vue、jquery、js、微信小程序腾讯api、uni-app进行项目开发,在项目中负责封装公共组件、负责从0-1的架构和开发,快速还原设计稿,熟练运用elmentUI、ant-design、vant、iview等第三方框架,熟练运用echrts制作图表,具有大屏开发数据经验。对前端性能优化也有一定的涉猎。除了专业的前端技能外,我还具有良好的代码风格和团队合作精神。在遇到问题的时候,也能快速的去定位问题所在,并把问题解决掉。以上是我的自我介绍,请问下还有什么需要了解的吗,我们可以在详细沟通一下
24.vuex与localStorage的区别
- vuex 中的数据是存储在内存中的,页面刷新就会丢失。而 localstorage 则是存储在计算机本地,刷新并不会丢失;sessionStorage 生存于应用会话期间。
- vuex用于组件之间的传值,(响应式的),localstorage则主要用于不同页面之间的传值(其他页面更新数据了,当前页面要刷新才能相应更新,非响应式的)
25.小程序的传参方式
- 通过url传参 url后边拼接参数 在另一个页面的onload进行接收、
- 通过在元素身上定义data-变量名 接收的时候利用e.currentTarget.dataset.变量名即可取到
- 在app.js里面定义globalData 然后在页面上需要使用的时候利用 const app = getApp() 利用app.globalData.变量名 去修改或者取到对应的参数变量的值
- Storage本地存储
26.rpx的实现原理
鉴于不同设备屏幕的大小不同,为了实现屏幕的自动适配,rpx 把所有设备的屏幕,在宽度上等分为 750 份(即:当前屏幕的总宽度为 750rpx),在较小的设备上,1rpx 所代表的宽度较小,在较大的设备上,1rpx 所代表的宽度较大
27.在项目中你都用过哪些组件
- uni.css官方样式库:
- uni-nav-bar 头部导航
- title 导航栏的标题
- shadow 导航栏下是否开启阴影
- dark 是否开启暗黑主题
- color 修改导航栏背景色
- left-text 导航栏左侧文字
- right-text 导航栏右侧文字
- left-icon 导航栏左侧图标
- right-icon 导航栏右侧图标
- height 设置导航栏高度
- statusBar 是否包含状态栏
- fixed 是否固定在顶部
- scroll-view 滚动视图组件
- scroll-y scroll-x 开启横向或者竖向滚动
- 定义的height可以是具体的px值,也可以是百分比
- scroll-into-view 值为子元素id(其中id不能用数字开头)
- 上拉加载更多数据的实现:首先在页面上写上拉加载更多数据的样式(loadtext),在scroll-view上写@scrolltolower滚动到底部触发,将得到的数据push到之前显示数据的数组中
- 上拉刷新功能实现:refresher-enabled开启下拉刷新 refresher-triggered 设置当前下拉刷新状态 @refresherrefresh 自定义下拉刷新被触发 首先判断是不是最后一页,如果是最后一页的话那就设置自定义下拉刷新为false 并给予用户提示 如果不是最后一页的话 设置num+1去请求数据
- swiper滑动视图 一般用于轮播图 swiper-item
- indicator-dots 是否显示面板指示点
- autoplay 是否自动切换
- interval 自动切换时间间隔
- duration 滑动动画时长
- circular 是否采用衔接滑动
- current 当前所在滑块的 index
- uni-list
28.防抖和节流有没有用过?两者的区别
- 两者的目的都是减少事件触发的频率,优化性能
- 防抖:防抖是指在一段时间内只要有事件触发,就重新计算时间,直到这段时间内没有事件触发,才真正执行事件,比如在用户进行关键字搜索的时候,只有当用户输入结束后才去发送请求,大大的优化了性能
- 节流:节流是在某一段时间内最多触发一次事件,比如当用户进行鼠标滚轮滚动的时候,浏览器每隔100ms触发一次事件处理函数,此时不管用户滚动的速度如何,在100ms内最多触发一次滚动事件
- 节流适合持续的触发,防抖适用于短时间的大量触发
//防抖:
function dobounce(fn,delay=500){
let timer = null
return function(){
let context = this
let args = arguments
clearTimeout(timer)
timer = setTimeout(function()){
fn.apply(context,args)
},delay)
}
}
//节流:
export function throttle(callback, duration = 500) {
// 最后执行函数时的时间戳
let lastTime = 0
//闭包、this指向
return function () {
// 获取当前时间戳
const now = new Date().getTime()
// 判断当前时间距离上一次执行函数的时间是否超过了duration设定的毫秒数
if (now - lastTime >= duration) { // 超过了
// 因为我们需要在 page 中做 this.setData(),所以需要借助 call()
// 利用 call()方法,实现保留原函数的 this 指向,利用JavaScript的arguments对象实现动态接收参数
callback.call(this, ...arguments);
// callback(...arguments)
// 更新最后执行函数时的时间戳
lastTime = now;
}
// 没超过,啥也不干
}
}
29.清除浮动的方法
- 原因:主要解决由于子元素浮动,导致父元素高度为0的问题
- 使用clear属性,在浮动元素后面添加一个元素,并且给他设置style,clear:both
- 父级添加overflow属性(父元素添加overflow:hidden)=>通过触发BFC方式,清除浮动
- 使用after伪元素清除浮动,给父元素增加一个class:clearfix
.clearfix:after{
display:block;
content:'';
height:0;
clear:botn;
visibility:hidden
}
30.flex布局常用的属性
div{
display:flex;
align-items:center;//垂直方向居中
justify-content:center;//水平方向居中
flex-direction:column;//设置主轴的方向、
flex:1;//flex-shrink:1(缩小) flex-grow:1(放大) flex-basis:0%(设置盒子的基准宽度,与width同时存在的话会把width干掉)、
flex-wrap:wrap;//设置子元素是否换行
align-self:flex-end;//允许单个项目有与其他项目不一样的排列方式
order:0;//属性定义子项的排列顺序,数值越小,排列越靠前
}
31.如果页面加载速度很慢,请问你如何解决
性能优化主要从以下3个维度去分析
- 提高资源的请求速度
http缓存,提升二次请求的响应速度
cdn缓存,CDN内容分发网络缓存静态资源,在多个位置部署服务器。用户访问时,CDN根据网络情况、负载情况等将会用请求导向到最近的服务器,提升响应速度
- 减少资源请求量
图片懒加载 当图片没有处于被看到的时候就不必要进行加载 实现方式 给图片一个data-src属性用来存放图片的真实地址 在vue项目里下载vue-lazyload插件 然后在main.js里面进行引入然后配置 图片上设置v-lazy 如果是数组的话,需要在div上面添加 v-lazy-container=“{ selector: ‘img’ }” 然后下面的图片img路径都用data-src
webpack资源压缩,
1.js:去掉无效代码、去掉日志输出代码、缩短变量名等优化 uglifyjs-webpack-plugin插件
2. css:删除无效代码,css语义合并 css-minimizer-webpack-plugin插件
3.html压缩 html-webpack-plugin插件除了帮助我们简化HTML文件的创建,也可以压缩HTML文件
4.图片压缩 url-loader:css内联图片小于尺寸图片转为base64编码
路由懒加载
服务端开始gzip压缩
- 浏览器渲染的优化
进行代码分割
首先了解一下客户在打开页面的时候,请求index.html文件,index.html文件里又引入了app.js和vendor.js文件,因此优化的时候考虑减少app.js和vendor.js的文件的大小,app.js里面包含我们所有写的业务代码,vendor是我们开发所需要的一些依赖库,比如vue、element等。减少vendor.js文件的大小,将使用到代码分割,在webpack里面利用webpack-bundle-analyzer去分析哪块占比比较多,从而更好的进行优化,利用optimization.splitChunks去把一些依赖的第三方库单独打包出来,可以有效的减少vendor.js文件的大小。
依赖模块采用第三方cdn资源
利用externals去将第三方依赖分离打包,其中key为依赖包名称,value是远吗抛出来的全局变量,对于其他的一些工具库,尽量采用按需引入的方式,然后在index.html添加cdn去引入,记得去除vue.use相关代码
另外想要优化性能的话,还可以添加一些骨架屏以及loading去优化用户性能体验
HTTP缓存
通过设置响应头以及请求头来控制缓存策略,分为强制缓存和协商缓存
强制缓存在意的是本次请求资源有没有过期 协商缓存在意的是本次缓存是否有更新
强制缓存有两个相关的字段
1. Expires字段 浏览器在收到此字段的时候,对内容进行缓存,控制缓存失效日期,发送相同资源请求的时候,会对比Exipires中的时间与本地时间进行对比,如果没有过期,直接使用缓存,缺点是对于本地时间依赖过高
2. Cache-Control字段的max-age属性 控制响应资源的有效期、
Cache-Control: no-cache 表示强制协商缓存
Cache-Control: no-store 表示禁止使用任何缓存策略
32.浏览器缓存localstorage/sessionstorage/cookie
- localstorage本地存储,存储在客户的浏览器中,除非主动去清除缓存,否则它将永久放在客户端中,存储大小5MB左右
- sessionStorage 存储的数据会在浏览器窗口关闭后被清除 大小无限制
- cookie可以设置过期时间,并且大小为4KB左右
33.promise与async/await详解
- 含义:promise是ES6提出的一个新的异步编程的解决方案,之前都是使用回调函数,有3种状态,pending(进行中)、resolve(已完成)、reject(已失败),支持链式调用,能够解决回调地狱的问题
- 方法有.then .all .catch
- async声明一个函数是异步的 await等待异步函数执行完成
34.this.$nextTick的用法和原理
当修改data里面的数据的时候 dom并不会立马进行更新,而是等同一事件循环中的所有数据变化完成之后,再统一进行视图更新。总体来说vue是异步执行dom更新的 具体来说异步执行的运行机制如下:
- 所有的同步任务都在主线程上执行,形成一个执行栈
- 主线程之外还存在一个任务队列,只要异步任务有了执行结果,就在任务队列中放置一个事件
- 一旦执行栈中的所有同步任务执行完毕,系统就会读取任务队列,异步任务再进入执行栈
- 主线程一直不停的重复上面的3步
35.什么是虚拟dom
谈起来虚拟dom,就不得不说真实dom,我们在浏览器上看到的html节点均为真实dom节点,在react、vue等框架出来之前都是操作真实dom,都是通过遍历查询dom树的方式找到所要修改的dom节点修改样式行为或者结构,来达到更新ui的目的。这样就会频繁触发回流与重绘,对性能造成了很大的影响,如果这时候构造一个与dom相对应的js对象,操作js对象肯定要比操作dom要性能好的多。虚拟dom实际上就是使用js原生对象去模拟实际的dom节点
36.什么是原型链
原型链指的是实例对象和原型对象之间的连接。
js中没有class类这个属性,所以用构造函数实现继承
每个函数都有prototype属性,这个prototype属性就是我们的原型对象,我们拿这个函数通过new构造函数创建出来的实例对象,这个实例对象会有一个指针(proto)指向他的构造函数的原型对象,这样构造函数与实例对象之间就通过(proto)指针链接在一起形成了链条
37.provide/inject
通过provide/inject可以轻松实现跨级访问祖先组件的数据
其中祖先组件上面利用provide去书写一个数据,子孙组件使用inject去接收数据
38.js跨域
因为浏览器的同源策略(协议、域名、端口号必须一致),导致出现跨域问题
解决跨域的方式:
- cros跨域资源共享。后端设置 Acces-Control-Allow-Orgin 设置允许跨域访问
- 通过jsonp跨域。jsonp的原理:通过script标签引入一个js文件,用js动态加载一个script文件,同时定义一个callback函数给script执行
- 通过修改document.domain来跨子域
- vue配置代理服务器devServe proxy 属性里面有一个target changeOrgin 还有pathRewrite
39.请介绍一下你的项目
在20年毕业以后入职于XXXX有限公司,主要担任核保组负责人,负责核保相关系统如江泰公众号、新华小程序、天机搜pc端、智能核保、AI体验工具、知识图谱等系统的开发、迭代和维护,负责需求的跟进以及功能可行性评估,下面我将介绍一下我最近在做的一些项目
1.江泰公众号项目,该项目主要使用uniapp框架,搭配vuex去进行开发,项目里我主要负责搭建以及uni.request二次封装以及价格、省市区三级联动、卡片、单选等公共组件的开发。首页、个人中心、支付等相关模块的开发,其中首页主要使用scroll-view包裹swiper去进行滑动切换,实现触底刷新,上拉加载,滑动主要依靠scroll-into-view属性,refresher-enabled开启自定义下拉刷新,@refresherrefresh触发,然后去请求后端数据,首页性能优化,当已经获取到数据的时候滑动就不用每次都请求后端了,初始化定义一个变量,加载首屏的时候设为false,当切换选项卡数据的时候为true才去请求后端数据,其中选择支付的时候利用uni.requestPayment 里面有一个provider参数,该参数代表着哦支付方式 wxpay还是alipay orderInfo代表订单信息,以下是他的参数
“appid”: “wx4997c70e", // 微信开放平台 - 应用 - AppId,注意和微信小程序、公众号 AppId 可能不一致
“noncestr”: “c5sEwbaNPiXAF3iv”, // 随机字符串
“package”: “Sign=WXPay”, // 固定值
“partnerid”: "14852", // 微信支付商户号
“prepayid”: "wx202254*****************fbe90000”, // 统一下单订单号
“timestamp”: 1597935292, // 时间戳(单位:秒)
“sign”: “A842B45937F6EFF60DEC7A2EAA52D5A0” // 签名,这里用的 MD5/RSA 签名
商城购物车、地址使用的是vuex模块化,便于更好的进行管理,在vuex中定义一些商品的属性,比如id、商品名称,选没选中的状态、商品数量。在getters里面定义判断是否全选,合计,判断一下选中的商品的数组里面含不含有该id 含有的话合计应该用他的价格*数量
h5跳转理赔小程序
wx-open-launch-weapp username是小程序的原始ID path是要跳转的页面路径 利用wx.config显示这个开放标签 参数appid为要跳转的小程序的appid,还有时间戳签名加密字符串等 然后在微信开发平台设置js安全域名
小程序返回h5
可以用navgator 设置open-type = exit
小程序页面跳转h5
使用web-view标签包裹要跳转的地址,在微信公众平台里面设置要打开的域名
新华小程序资料交接小程序
主要使用的技术为socktio 断线重连监听disconnect时间 然后 回调函数如果是用户因为网络波动问题断开的话 则需要自动重连
40.vue2与vue3的区别
1.vue3
- vue3打包大小减少,初次渲染和更新更快
- 利用proxy代替defineProperty实现响应式,之前vue2中给对象中添加一个新的属性,需要利用到this.$set方法,在vue3中规避了这个问题
- setup 在setup里可以书写变量函数监听计算属性生命周期等,在beforeCreate之前执行一次 this是undefined,接收两个参数 props和context(attrs、slots、emmit)。之前vue2中使用props去接收父组件传过来的属性,在vue3中利用结构赋值在attrs里面去接收
- ref函数,定义一个响应式的数据 ref一般用于定义基本数据类型的数据 更改数据的话需要.value 当然也可以定义对象数据类型的数据 内部求助vue3的新函数 reactive函数,生成一个Proxy代理对象
- reactive函数 一般用来定义对象类型的响应式数据