前端面试-vue系列(Vue原理)

102 阅读5分钟

vue原理

1、如何理解MVVM

组件化、数据驱动视图,view-viewModel-model

2、vue响应式

核心api:Object.defineProperty

利用get和set劫持数据进行数据的跟新

监听对象改变:首先会去判断是否是一个对象,如果是就去递归解析,知道全部值解析出来,然后进行赋值;注意,在赋值前也需要递归一次,因为有可能是变更的值是一个对象,然后赋值进行视图更新。这儿的话有个缺点就是对对象属性的操作监听不到,比如新增或者删除属性这种,vue提供了专门的api针对这种情况。
监听数组改变:Object.defineProperty不能监听数组,首先监听数组原型,创建一个新的对象,然后在新对象上对数组的方法进行重写,然后监听数组值进行更新,然后再执行数据的原生方法进行数组的更改。
vue3:proxy兼容性不好:无法poryfill

3、 虚拟DOM

虚拟DOM:用js模拟数据结构
{
	tag: 'div',
	props: {
		className: 'div1',
		id: 'div2'
	},
	children: [
		{
			tag: 'p',
			children: 'text'
		}.
		{
			tag: 'ul',
			props: {
				style: 'font-size: 14px',
			},
			children: [
				{
					tag: 'li'
				}
				...
			]
		}
	]
}
为什么要用vdom,因为js的执行速度很快,vdom就是模拟dom结构,计算出最小的变更,最后去操作DOM

4、diff算法

-- 只比较同一层级,不跨级比较

-- tag不相同,直接删除重建,不再深度比较

-- tag和key都相同,则认为是相同节点,不再深度比较

此处vnode都统一表示新的node,oldvnode表示旧的node

h函数接受一个树形结构对象,经过处理后,返回一个包含$e、data、children,text,element等我们需要的vnode对象。得到新旧vnode后,在patch函数中去进行比较,在patch里面执行pre hook,判断第一个函数不是vode类型的话就去创建一个空的vnode关联到这个vnode元素,如何进行的绑定,是因为vode对象里面会有element传下来;

然后进行vnode的比较,如果是sel和key都相同的话,就判断为相同的vnode,然后执行patchnode进行vnode的对比,首先执行一个pre hook(一个生命周期的钩子),设置vnode element(将旧的element赋值给新的进行相应的对比),判断vnode.text是否是undefined,如果是说明新的node的children一般有值,(1)如果新旧都有children: (2)如果新children有,旧children无,旧的text有值就设置为空,然后添加新的children(3)旧children有,新children无,就直接移除children(4)旧的text有值,新的无,直接移除;如果text有值,判断新旧的text是否相同,不相同的话移除旧的children,设置新的text;

如果新旧节点都有children的话执行updataChildren函数:

传入新旧节点进行对比,对比顺序都以前面旧节点后面新节点进行对比,是开始和开始,结束和结束,开始和结束,结束和开始,判断是否相等就是samenode方法就是比较key和sel是否相等,然后根据patchvnode进行处理;如果都没命中,就拿新节点的key和所有的旧节点的key进行比较是否相同,都不相同的话,插入建立新的节点,对应上的话,拿上对应的key节点,判断sel是否相等,不想等的话插入建立新节点,sel和key都想等的话就patchvnode;然后指针累加相遇结束

不相同的话就直接删除重建;

这个就是为什么循环要加key,减少比对过程和销毁重建过程。

5、模版编译

vue的template会通过vue-template-compiler转换成一段js代码就是render函数,执行rendr函数会返回vnode,基于vonde然后再去执行patch和diff,然后去做渲染。(如果用webpack的话,vue-loader会在开发环境进行编译)

vue组件中也可以直接写render函数去代替template

双向绑定原理:

input上会挂载一个input事件,执行这个事件的时候,会把当前input的值给this下的name,value显示的时候显示的是name的这个变量,变量更新后再重新prop进来变量name放在input的value上,然后实现双向数据绑定。

6、组件渲染

初次渲染过程

-- 解析模版为render函数

-- 触发响应式,监听data的setter和getter

-- 执行render函数,生成vnode,然后去path(ole, node)

更新过程

-- 修改data,触发setter(此前在getter中已被监听),如果只是定义了但是没有用到就只触发getter

-- 重新执行render函数,生成newvnode

-- patch(anode, newVnode)

异步渲染

-- 汇总data的修改,一次性更新视图

-- 减少DOM的操作,提高性能

7、 vue-router

-- 稍微复杂点儿的spa,都需要前端路由

hash:

-- hash变化会触发网页跳转,即浏览器的前进与后退

-- hash变化不会刷新网页,

-- hash永远不会提交到server端

主要是通过监听onHashChange事件,来得到新旧路径来进行的页面的渲染

H5 history:

-- 用url规范的路由,但跳转时不刷新页面

-- 主要通过hsitory.pushState和window.onpopstate来实现

页面首次进来刷新页面获取pathName,然后进行路由跳转的时候使用pushState通过定义的页面路径进行跳转,然后通过window.onpopState来监听页面的前进和后退

需要服务端支持,无论切换到哪个页面都是进入index.html(根页面),然后再由这个页面进行路由的切换(由前端控制),否则就会找不到

下一篇:vue面试真题:juejin.cn/spost/72410…