vue面试经验总结
vue基本使用
- props
- e m i t 自 定 义 事 件 e v e n t . emit 自定义事件event. emit自定义事件event.on()兄弟传值 注意销毁 event.$off()
- 生命周期 创建或update从外到内 渲染从内到外
- vue 高阶特性
- 自定义v-model
<template>
<div class="hello">
<p>{{ msg }}</p>
子:<input
type="text"
:value="msg"
@input="$emit('change', $event.target.value)"
/>
</div>
</template>
<script>
export default {
name: "HelloWorld",
model: {
prop: "msg",
event: "change",
},
props: {
msg: String,
},
};
</script>
-
n e x t T i c k v u e 是 异 步 渲 染 d a t a 改 变 之 后 , d o m 不 会 立 刻 渲 染 , nextTick vue是异步渲染 data改变之后,dom不会立刻渲染, nextTickvue是异步渲染data改变之后,dom不会立刻渲染,nexTick 会在dom渲染之后触发,以获取最新的dom节点。浏览器宏任务微任务。
-
slot
基本使用
作用域插槽:父子组件接受到子组件的属性 v-slot
具名插槽: v-slot:name -
动态异步组件
动态组件::is=“component name”
比如一个新闻页面不确定各个图片或者文字组件的顺序 。
异步组件:import()函数 demo:()=>import(’ ') -
keep-alive: 缓存组件 频繁切换 单不需要重复渲染
-
mixin
优先级:
1、组件data,methods等里的数据会覆盖mixin里
2、生命周期函数先执行mixin,再执行组件里
3、通过this.$options获取自定义属性 同样组件中的优先
4、通过app.config.optionMergeStrategies.[属性]修改优先级
多个组件有相同的逻辑抽出来
有些问题待解决,vue3 composition api 旨在解决这些问题
变量来源不明确,不利于阅读
多个mixin可能会造成命名冲突
mixin和组件可能会出现多对多的关系复杂度较高
- vuex
- 基本特性:state mutation action getters
- 用于vue组件:dispatch commit mapstate mapGetters
mapActions mapMutations
- vue-router 动态路由,嵌套路由 ,懒加载
vue原理
-
考察重点而非细节。掌握好2/8原则
-
掌握好和使用相关联的原理,如vdom ,模板渲染
-
流程是否全面,热门技术是否有深度 ?
-
组件化
很久以前就有组件化:asp,jsp,php已经有组件化了,node里也有类似的组件 化,后端模板渲染jade ext等。但是vue/react 和后端组件化有一个本质的区别,那就是数据驱动视图。
传统组只是静态渲染,更新还依赖于操作dom
动态数据驱动视图(mvvm,setState)不再去操作dom,更加关注数据,更加关注业务,而不是背诵怎么操作dom,浏览器兼容等,富客户端业务出现,页面功能非常复杂。
model view viewmodel -
响应式
核心API Object.defineProperty
get、set 来做监听简单对象
监听数组:重新定义数组原型、使用Object.create(Array.prototype) 避免污染全局原型、 重写方法比如push pop shift 等 首先触发更新视图 再使用call 来继承原始的方法
监听复杂对象:深度监听递归调用 observe(value) 设置新值是也要调用一次
几个缺点:
深度监听需要递归到底,一次性计算量大 后面解决
新增删除属性时不会触发更新 需使用Vue.set Vue.delete
无法原生监听数组需要特殊处理
proxy 有兼容性问题ie11不支持,无法用polyfill 所以vue2.x还会存在一段时间所以都得学。 -
vdom diff
vdom是实现vue和react的重要基石
diff算法是vdom中最核心最关键的部分
vdom是热门话题,面试中的热门问题
vue和react如何有效控制dom操作?
把dom操作转化为js计算,用js来模拟dom结构,计算出最小的变更再操作dom
通过snappdom学习vdom
vdom库 vue 参考它实现vdom和diff
vue3.0 重写了vdom的代码优化了性能,但vdom的基本理念不变,面试考点也不变。reactvdom和vue具体实现不同但是理念相同。
diff 算法:是vdom中最核心最关键的部分
能在日常应用中体现出来,例如:key
diff即对比,是一个广泛的概念 如linux diff 、git diff
树diff 的事件复杂度 O(n^3) 太复杂不可用
优化时间复杂度到O(n)
* 只比较同一层级不跨级比较
* tag不相同则直接删掉重建不再深度比较
* tab和key都相同则认为是相同节点不再进行深度比较
* vnode h函数 patch函数
* 都不传key 那么undifined===undefined 通过tag和select比较
* h vnode patch diff key 等
* updatechildren 函数 比较子节点时使用 newStartVnode oldStartVnode
oldEndVnode newEndVnode 对比 sameVnode 函数
开始和开始、结束和结束、开始和结束、结束和开始 index累加累减直到合并
如果都没有命中拿新节点的key对比旧节点,如果没有对应上则重建
如果对应上则看select是否相等 如果相等 patchvnode -
模板编译
- js with语法:
with要慎用 打破了作用域规则易读性变差 - vue template compiler 工具将模板编译为render函数:
- 执行render 函数生成vnode:
- js with语法:
-
渲染过程
初次渲染:
1、解析模板为render函数(或在开发环境已完成vue-loader)2、触发响应式,监听data属性的getter,和setter。
3、执行render函数生成vnode,patch,会触发getter,生成依赖变量观察起来。
更新过程:1、修改data,触发setter。2、重新执行render函数生成newVnode
3、patch(vnode,newVnode) patch的diff算法会自动获取变动最小值。
异步渲染
汇总data的修改,一次性更新视图
减少dom操作次数,提高性能 -
前端路由
hash变化会触发网页跳转,前进后退,不会刷新页面,不会与后端产生交互。
重点api://location.href 手动修改hash window.onHashChange((e)=>{ //e.oldUrl e.newUrl })
H5 history:用url规范的路由,但跳转时不刷新页面。
history.pushState 切换路由
window.onpopstate 监听浏览器前进后退
需要server配合
两者选择:
to B 系统推荐用hash,简单易用,对url规范不敏感
to C 系统可以考虑用history,但需要服务端支持,如果不需要seo
能简单就简单,不要用复杂的。考虑成本和收益 -
vue 性能优化
合理使用v-if v-show
合理使用 computed 缓存
key 避免和v-if 同时使用
自定义事件dom事件及时销毁
合理使用异步组件 keep-alive
data层级不要太深
webpack层面优化
前端通用的优化,图片懒加载
使用ssr
vue3:
- 升级内容:
- 全部用ts重写
- 性能提升减少代码量
- 调整部分api
- vue2.x还有大量项目需要维护升级
- proxy存在兼容性问题,不能polyfill
- proxy:
proxy对象用于定义基本操作的自定义行为,与defineproperty功能几乎一样但是用法不同
区别:
第一个区别在于defineproperty只能监听某个属性不能全对象监听
proxy不用设置具体属性
defineproperty监听需要知道那个对象的那个属性,而proxy只需要知道那个对象就可以了。也就是会省去for in 循环提高了效率
第二个区别在于proxy不需要借助外部value,也有单独相配的对象即Reflect,
eg:var ob={a:1,b:2}
在proxy的get里面有target,key,receiver三个值,其中target是对象ob,key是ob.a,receiver是,set里面除了这三个额外多加了一个value,value是传出来的新值。所以在get里return的就是target[key],set里面return的是target[key]=value或者用proxy里的Reflect.set(target,key,value)这样写优雅一点
第三个区别在于不会污染原对象(关键区别)
proxy去代理了ob,他会返回一个新的代理对象不会对原对象ob进行改动,而defineproperty是去修改元对象,修改元对象的属性,而proxy只是对元对象进行代理并给出一个新的代理对象