vue 常见面试题
- v-show和v-if 的区别
- 为何v-for中要用到key
- 描述Vue组件生命周期(有父子组件的情况)
- Vue组件如何通讯
- 描述组件渲染和更新的过程
- 双向数据绑定v-model的实现原理
基础
Vue基本使用
1、指令、插值
指令:
- v-text
- v-html
- v-show
- v-if
- v-else
- v-else-if
- v-for
- v-on
- v-bind
- v-model
- v-slot
- v-pre
- v-cloak
- v-once
a、插值、表达式
b、指令、动态属性
c、v-html:会有xss风险、会覆盖子组件
2、computed和watch
computed有缓存,data不变则不会重新计算
watch 如何深度监听
info:{
handler(oldVal,val){
},
deep:true
}
watch监听引用类型,拿不到oldVal
3、class和style
- 使用动态属性
- 使用驼峰式写法
4、条件渲染
- v-if v-else的用法,可使用变量,也可以使用===表达式
- v-if 和v-show的区别
- v-if和v-show的使用场景
5、事件
【观察】事件被绑定到哪里
- event是原生的
- 事件被挂在到当前元素
组件
Vue组件使用
1. props和$emit
2. 组件间通讯-自定义事件
- event.$emit('add',this.add)
- event.$on('add',this.addHandler)
3、组件生命周期
- 挂载阶段
- 更新阶段
- 销毁阶段
高级
Vue高级特性
- a、自定义v-model
- b、$nextTick
- c、slot
- d、动态、异步组件
- e、keep-alive
- 频繁切换,不需要重复渲染
- f、mixin
- 变量来源不明确,不利于阅读
- 多mixin可能会造成命名冲突
- mixin和组件可能出现多对多的关系,复杂度较高
Vue 是异步渲染
data 改变之后,DOM不会立刻渲染 $nextTick会在DOM渲染之后被触发,以获取最新DOM节点
- 异步组件:图表
- import() 函数
- 第三ui库按需加载
vuex 使用
- dispatch
- commit
- mapstate
- mapGetters
- mapActions
- mapMutations
vue-router
- 动态路由
- to和push
- hash和history
- 懒加载(配合动态组件)
vue 原理
- 面试为何会考察原理
- 面试中如何考察?以何种方式
- 考察重点,而不是考察细节。掌握好2/8原则
- 和使用相关联的原理,例如vdom,模板渲染
- 整体流程是否全面?热门技术是否有深度
Vue原理包括那些?
- 组件化
- 响应式
- vdom和diff
- 模板编译
- 组件渲染过程
- 前端路由
组件化基础
“很久以前”就有组件化
asp jsp php 已经有组件化
node.js
数据驱动视图(MVVM、setState)
传统组件,只是静态渲染,更新还要依赖于操作DOM
数据驱动视图 - Vue MVVM
数据驱动视图 - React setState
Vue 响应式
组件data的数据一旦变化,立刻触发视图的更新
实现数据驱动视图的第一步
核心API - Object.defineProperty
Vue3.0 Proxy
- Proxy 有兼容性问题
- Proxy 兼容性不好,且无法polyfill
Object.defineProperty基本使用
Object.defineProperty 实现响应式
- 监听对象,监听数组
- 复杂对象,深度监听
- 几个缺点
- 深度监听,需要递归到底,一次性计算量大
- 无法监听到新增属性/删除属性 (Vue.set Vue.delete)
- 无法原生监听数组,需要特殊处理
// 触发更新视图
function updateView() { console.log('视图更新') }
// 重新定义数组原型
const oldArrayProperty = Array.prototype
// 创建新对象,原型指向 oldArrayProperty ,再扩展新的方法不会影响原型
const arrProto = Object.create(oldArrayProperty);
['push', 'pop', 'shift', 'unshift', 'splice'].forEach(methodName => {
arrProto[methodName] = function () {
updateView() // 触发视图更新
oldArrayProperty[methodName].call(this, ...arguments)
// Array.prototype.push.call(this, ...arguments)
}
})
// 重新定义属性,监听起来
function defineReactive(target, key, value) {
// 深度监听
observer(value)
// 核心 API
Object.defineProperty(target, key, {
get() {
return value
},
set(newValue) {
if (newValue !== value) {
// 深度监听
observer(newValue)
// 设置新值
// 注意,value 一直在闭包中,此处设置完之后,再 get 时也是会获取最新的值
value = newValue
// 触发更新视图
updateView()
}
}
})
}
// 监听对象属性
function observer(target) {
if (typeof target !== 'object' || target === null) {
// 不是对象或数组
return target
}
// 污染全局的 Array 原型
// Array.prototype.push = function () {
// updateView()
// ...
// }
if (Array.isArray(target)) {
target.__proto__ = arrProto
}
// 重新定义各个属性(for in 也可以遍历数组)
for (let key in target) {
defineReactive(target, key, target[key])
}
}
// 准备数据
const data = {
name: 'zhangsan',
age: 20,
info: {
address: '北京' // 需要深度监听
},
nums: [10, 20, 30]
}
// 监听数据 observer(data)
// 测试
// data.name = 'lisi'
// data.age = 21
// // console.log('age', data.age)
// data.x = '100' // 新增属性,监听不到 —— 所以有 Vue.set
// delete data.name // 删除属性,监听不到 —— 所有已 Vue.delete
// data.info.address = '上海' // 深度监听
data.nums.push(4) // 监听数组
虚拟DOM(Virtual DOM) 和diff
- vdom实现vue和React的重要基石
- diff 算法是vdom 中最核心、最关键的部分
- vdom 是一个热门话题,也是面试中的热门问题
DOM操作非常消耗性能
- 以前用jq,可以自行控制DOM 操作的时机,手动调整
- Vue和React是数据驱动视图,如何有效控制DOM 操作?
解决方案 - vdom
- 有了一定复杂度,想减少计算次数比较难
- 能不能把计算,更多的转移为js计算?因为js执行速度很快
- vdom-用js模拟dom结构,计算出最小的变更,操作dom
通过snabbdom学习vdom
- 简洁强大的vdom库,易学易用
- Vue参考它实现的vdom和diff
- diff 算法
- diff算法是vdom中最核心,最关键的部分
- diff算法能在日常使用vue React 中体现出来(如key)
- diff算法是前端热门话题
- diff 算法总结
- patchVnode
- addVnodes removeVnodes
- updateChildren(key 的重要性)
- vdom 和diff 总结
细节不重要,updateChildren vdom核心概念很主要:h、vnode、patch、diff、key等 vdom 存在的价值更加重要:数据驱动视图,控制DOM操作
模板编译
模板是vue开发最常见的部分,即与使用相关联的原理 它不是html,有指令,插值,js表达式,到底是什么? 面试不会直接问题,但会通过“组件渲染和更新过程”考察
vue template complier 将模板编译为render 函数 执行render 函数生成vnode
编译模板
模板编译为render函数,执行render函数返回vnode 基于vnode再执行patch和diff 使用webpack vue-loader,会在开发环境下编译模板(重要)
组件 渲染/更新 过程
一个组件渲染到页面,修改data触发更新 (数据驱动视图) 其背后原理是什么,需要更新掌握哪些要点 考察对流程了解的全面程度
过程:
初次渲染过程
解析模板为render函数(或在开发环境已完成,vue-loader)
触发响应式,监听data属性getter setter
执行render函数,生成vnode,patch(elem,vnode)
更新过程
修改data,触发setter (此前在getter中已被监听)
重新执行render函数,生成newVnode
patch(vnode,newVnode)
渲染异步
回顾:
- 响应式:监听data 属性 getter setter (包括数组)
- 模板编译:模板到render函数,再到vnode
- vdom:patch(elem,vnode) 和 patch(vnode,newVnode)
总结:
-
渲染和响应式的关系
-
渲染和模板编译的关系
-
渲染和vdom的关系
-
如何理解MVVM模型
-
数据驱动视图
-
Model view viewModel
监听data变化的核心
前端路由原理
稍微复杂一点SPA,都需要路由
vue-router 也是vue全家桶的标配之一
属于“和日常使用相关联的原理”,面试参考
回顾vue-router 的路由模式
hash
H5 history
hash
hash 特点:
hash 变化会触发网页跳转,即浏览器的前进、后退
hash 变化不会刷新页面,SPA 必需的特点
hash永远不会提交到server端(前端自生自灭)
H5 history
用url规范的路由,但跳转时不刷新新页面
history.pushState
window.onpopstate
两者选择
to B 的系统推荐用hash,简单易用,对url规范不敏感
to c的系统,可以考虑选择H5 history,但需要服务端支持
Vue面试真题演练
v-show 和 v-if的区别
v-show 通过CSS display 控制显示和隐藏
v-if组件真正的渲染和销毁,而不是显示和隐藏
频繁切换显示状态用v-show,否则用v-if
为何在v-for中用key
必须用key,且不能是index 和random
diff 算法中通过tag和key 来判断,是否是sameNode
减少渲染次数,提升渲染性能
描述Vue组件生命周期(父子组件)
单组件生命周期图
父子组件生命周期关系
Vue组件如何通讯
父子组件props和this.$emit
自定义事件 event.$on event.$off event.$emit
vuex
双向数据绑定v-model的实现原理
input 元素的value = this.name
绑定input 事件 this.name = $event.target.value
data 更新触发re-render
对MVVM的理解
model view viewModel
computed 有何特点
缓存,data 不变不会重新计算
提高性能
为何组件data必须是一个函数
每个vue文件是class 实例, 当data是一个函数的时候,每一个实例的data属性都是独立的,不会相互影响了
ajax 请求应该放在那个生命周期
mounted
JS 是单线程,ajax异步获取数据
放在mounted之前没有用,只会让逻辑更加混乱
如何将组件所有props 传递给子组件
$props
<User v-bind="$props" />
细节知识点优先级不高
如何自己实现v-model
多个组件有相同的逻辑,如何抽离
mixin
以及mixin的一些缺点
变量来源不明确,不利于阅读
多mixin可能会造成命名冲突
mixin和组件可能出现多对多的关系,复杂度较高
何时要使用异步组件
加载大组件
路由异步加载
何时需要使用keep-alive
缓存组件,不需要重复渲染
如多个静态tab页的切换
优化性能
何时需要使用beforeDestory
解绑自定义事件 event.$off
清除定时器
解绑自定义的DOM事件,如window scroll等
Vuex中acttions 和 mutation 有何区别
action 中处理异步,mutation 不可以
mutation 做原子操作
action 可以整合多个mutation
Vue-router 常见的路由模式
hash 默认
H5 history
两者比较
如何配置Vue-router 异步加载
请用vnode 描述一个DOM 结构
监听data 变化的核心API 是什么
object.defineProperty
以及深度监听,监听数组
有何缺点
Vue 如何监听数组变化
Object.defineProperty 不能监听数组变化
重新定义原型,重写push pop等方法,实现监听
Proxy 可以原生支持监听数组变化
请描述响应式原理
监听data 变化
组件渲染和更新的流程
Vue为何是异步渲染,$nextTick 何用
异步渲染(以及合并data修改),以提高渲染性能
$nextTick 在DOM 更新完之后,触发回调
Vue 常见性能优化方式
合理使用 v-show 和 v-if
合理使用computed
v-for 时加key,以及避免和v-if 同时使用
自定义事件、DOM事件时销毁
合理使用异步组件
合理使用keep-alive
data 层级不要太深
使用v-loader 在开发环境做模板编译(预编译)
前端通用的性能优化,如图片懒加载
使用SSR
vue3.0
vue3.0 重写了vdom的代码,优化了了性能