目录
3 描述 vue 组件生命周期(以及有父子组件,两者的生命周期)
18 vuex 的 action 和 mutation 有何区别?
1 v-if 和 v-show 的区别
- v-show 通过CSS display 控制显示与隐藏
- v-if 是组件真正的渲染和销毁,而不是显示与隐藏
- 频繁切换用 v-show,否则用v-if
2 为何 v-for 中要用 key
- 必须是key,不能是index和random
- diff算法中通过key和tag来判断,是否是sameNode
- 减少渲染次数,提高渲染性能
3 描述 vue 组件生命周期(以及有父子组件,两者的生命周期)
单个组件生命周期:
- 挂载过程
- 更新过程
- 销毁过程
父子组件生命周期:(index父组件,list子组件)
- 创建阶段
index beforeCreate
index created
index beforeMount
list beforeCreate
list created
list beforeMount
list mounted
index mounted
- 更新阶段
index before update
list before update
list updated
index updated
- 销毁阶段
index before destroy
list before destroy
list destroyed
index destroyed
4 组件间如何通讯(常见)
- 父子组件 props 和 this.$emit
- 自定义事件 event.$on event.$off event.$emit
- vuex
5 组件渲染和更新的过程
(图示)
vue原理的三大模块:响应式、模版编译、虚拟dom
- 初次渲染
- 对 data 进行响应式处理,监听 get set
- 解析模板为 render 函数(这一步可能在开发环境打包时就已经完成,重要!!!)
- 执行 render 函数,生成 vnode (1 这一步会触发 data getter ,收集依赖,重要!!!2 将该数据 “观察”起来 3 注意,不一定所有的 data 都会被观察,得看模板中是否用到了,如下图。)
- 将 vnode 渲染到页面上
- 页面更新
- 修改“被观察的”数据,触发 data setter
- 重新执行 render 函数,生成 newVnode
- patch(vnode, newVnode)双向数据绑定 vmodel 的原理
6 双向数据绑定 v-model 的实现原理
- input 元素的 value = this.name
- 绑定 input 事件 this.name = $event.target.value
- data 更新出发re-render
7 说一下对 MVVM 的理解
(图示)
Vue 中的 MVVM 模式是指 Model、View 和 ViewModel 的分离与协作。Model 管理数据和业务逻辑,View 负责用户界面,ViewModel 通过 Vue 的响应式系统连接 Model 和 View,自动实现数据双向绑定和视图更新。开发者只需关注数据逻辑,Vue 会处理 DOM 操作,使开发更高效,代码更简洁。
8 computed 有何特点?
- 缓存,data不变不会重新计算
- 提高性能
9 为何组件 data 必须是一个函数?
在 Vue 中,组件的 data
必须是一个函数,这是为了确保每个组件实例都有独立的数据作用域。函数形式的 data
会返回一个新的数据对象,当多个组件实例化时,每个实例都可以拥有自己的独立数据副本,避免数据相互污染。如果 data
是一个对象,则所有实例会共享同一个数据对象,导致状态被意外修改。这个设计主要是为了保证组件的复用性和稳定性。
首先组件data必须是一个函数,最根本的原因在于我们定义的vue组件是一个class(类),每个地方去使用这个组件的时候,相当于这个类的一个实例化,确保每个组件实例都有独立的数据作用域,避免相互污染。
10 ajax 请求应该放在哪个生命周期?
- mounted
- js是单线程的,ajax异步获取数据
- 放在mounted之前没有什么用,只会让逻辑更加混乱
11 如何将父组件的所有 props 传递给子组件?
- $props
- <User v-bind = "$props" />
- 细节知识点,优先级不高
12 如何自己实现一个 vmodel ?
13 多组件有相同的逻辑,如何抽离?
- mixin(缺点)
14 何时需要使用异步组件?
- 加载大组件
- 路由异步加载
15 何时需要使用 keepalive
- 缓存组件,不需要重复渲染
- 如多个静态 tab 页的切换
- 优化性能
16 何时需要使用 beforeDestroy ?
- 解绑自定义事件 event.$off
- 清除定时器
- 解绑自定义的DOM事件,如 window scroll等
17 什么是作用域插槽?为何需要它
18 vuex 的 action 和 mutation 有何区别?
- action中处理异步,mutation不可以
- mutation做原子操作
- action可以整合多个mutation
19 vue-router 路由模式有几种?
- hash(默认)
- h5 history(需要服务端支持)
20 如何配置 vue-router 异步加载?
21 场景题:用虚拟 DOM 描述一个 html 结构
<div id="div1" class="container">
<p>vdom</p>
<ul style="font-size: 20px">
<li>a</li>
</ul>
</div>
{
tag: 'div',
props: {
className: 'container',
id: 'div1'
}
children: [
{
tag: 'p',
children: 'vdom'
},
{
tag: 'ul',
props: { style: 'font-size: 20px' }
children: [
{
tag: 'li',
children: 'a'
}
// ....
]
}
]
}
22 监听data变化的核心API
- Object.defineProperty
- 缺点
- 深度监听,需要递归到底
- 无法监听新增属性/删除属性(Vue.set Vue.delete)
- 无法监听数组,需要特殊处理
23 vue 如何监听 data 变化?
// Object.defineProperty 的基本用法
const data = {}
const name = 'zhangsan'
Object.defineProperty(data, "name", {
get: function () {
console.log('get')
return name
},
set: function (newVal) {
console.log('set')
name = newVal
}
});// 测试
console.log(data.name) // get zhangsan
data.name = 'lisi' // set
24 vue 如何监听数组变化?
- Object.defineProperty 不能监听数组变化
- 重新定义原型,重写push pop等方法,实现监听
- Proxy可以原生支持监听数组的变化
// 触发更新视图
function updateView() {
console.log('视图更新')
}
// 数组方法处理,这里稍微复杂一点
const oldArrayPrototype = Array.prototype
const arrProto = Object.create(oldArrayPrototype); // 创建新对象,原型指向 oldArrayPrototype ,再扩展属性不会影响 oldArrayPrototype
['push', 'pop', 'shift', 'unshift', 'splice'].forEach(method => {
// 重新定义这些新方法,监听数组变化
arrProto[method] = function () {
updateView() // 触发更新视图
oldArrayPrototype[method].call(this, ...arguments) // 调用原有方法
}
})
25 描述响应式原理
- 监听data变化
- 组件渲染和更新的流程
26 diff 算法时间复杂度是多少
- O(n)
- 是在O(n^3)基础上做了一些调整
27 简述 diff 算法过程
- patch(elem,vnode) 和 patch(vnode,newVnode)
- patchVnode 和 addVnodes 和 removeVnodes
- updateChildren(key的重要性)
Vue 的 diff 算法以 patch
为入口,首次渲染通过 patch(elem, vnode)
将虚拟 DOM 转化为真实 DOM;更新时通过 patch(vnode, newVnode)
比较新旧虚拟 DOM。节点相同时,调用 patchVnode
递归更新节点内容;对于子节点列表,调用 updateChildren
比较新旧子节点,利用 key
快速定位变化,避免不必要的操作;新增子节点由 addVnodes
创建并插入,移除多余子节点则通过 removeVnodes
完成。整体过程通过最小化 DOM 操作实现高效更新。
28 vue 为何是异步渲染?$nextTick有何用?
- 异步渲染(以及合并data修改),以提高渲染性能
- $nextTick 在DOM更新完之后,触发回调
29 vue-router 如何实现路由变化?
-
URL 变化监听:
- Hash 模式:通过监听
window.onhashchange
事件来检测#
后的部分变化。 - History 模式:通过监听
popstate
事件来检测浏览器地址栏路径的变化。
- Hash 模式:通过监听
-
匹配路由规则:
路由变化后,Vue Router 会根据当前 URL,利用定义的路由配置表匹配对应的路由规则,找到对应的组件。 -
更新视图:
匹配到的组件会通过 Vue 的动态组件机制(<router-view>
)进行渲染,依托于 Vue 的响应式系统,确保路由变化时视图能够自动更新。 -
路由钩子:
在路由切换过程中,Vue Router 会执行相应的导航守卫(如全局守卫、路由独享守卫、组件内守卫等),对路由切换进行控制,比如权限校验或数据加载。
30 vue 性能优化
- 合理使用 v-show 和 v-if
- 合理使用 computed
- v-for 时加key,以及避免和v-if 同时使用
- 自定义事件、DOM事件要及时销毁
- 合理使用异步组件
- 合理使用 keep-alive
- data层级不要太深
- 使用vue-loader在开发环境做模版编译(预编译)
- webpack(······)
- 前端通用的性能优化,如懒加载
- 使用SSR