最后
正值招聘旺季,很多小伙伴都询问我有没有前端方面的面试题!
开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】
我们知道,Vue 不可以直接操作 DOM 结构,而是通过数据驱动、指令等机制来间接操作 DOM 结构。当我们修改模版中的数据时,Vue 会触发重新渲染过程,调用render
函数,它会返回一个 虚拟 DOM 树,它描述了整个组件模版的结构。
举个栗子🌰:
<template>
<ul class="list">
<li v-for="item in list" :key="item.index" class="item">{{ item }}</li>
</ul>
</template>
<script setup>
import { ref } from 'vue';
const list = ref(['html', 'css', 'js'])
</script>
Vue 在渲染这个列表时,就会调用render
函数,它会返回一个类似下面这个虚拟 DOM 树。
let VDom = {
tagName: 'ul',
props: {
class: 'list'
},
chilren: [
{
tagName: 'li',
props: {
class: 'item'
},
chilren: ['html']
},
{
tagName: 'li',
props: {
class: 'item'
},
chilren: ['css']
},
{
tagName: 'li',
props: {
class: 'item'
},
chilren: ['js']
}
]
}
虚拟 DOM 的每个节点对应于真实 DOM 树中的一个节点。
当我们修改数据时,Vue 又会触发重新渲染的过程。
const list = ref(['html', 'css', 'vue']) //修改列表第三项'js'->'vue'
Vue 又会生成一个新的虚拟DOM树:
let VDom = {
tagName: 'ul',
props: {
class: 'list'
},
chilren: [
{
tagName: 'li',
props: {
class: 'item'
},
chilren: ['html']
},
{
tagName: 'li',
props: {
class: 'item'
},
chilren: ['css']
},
{
tagName: 'li',
props: {
class: 'item'
},
chilren: ['vue']
}
]
}
注意观察,这里最后一个节点的子节点为'vue'
,发生了数据变化,Vue内部又会返回一个新的虚拟 DOM。那么 Vue 是如何将这个变化响应给页面的呢?
摆在面前的有两条路
要么重新渲染这个新的虚拟 DOM ,要么只新旧虚拟 DOM 之间改变的地方。
显而易见,只渲染修改了的地方是不是会更节省性能。
巧了,尤雨溪也是这样想的,于是便有了“ Diff 算法 ”。
Diff 算法
Vue 将新生成的新虚拟 DOM 与上一次渲染时生成的旧虚拟 DOM 进行比较,对比出是哪个虚拟节点更改了,找出这个虚拟节点,并只更新这个虚拟节点所对应的真实节点,而不用更新其他数据没发生改变的节点。
我自己总结了一下Diff算法的过程,由于代码过多,就不在此展示了:
- 新旧虚拟DOM对比的时候,Diff 算法比较只会在同层级进行,不会跨层级比较。
- 首先比较两个节点的类型,如果类型不同,则废弃旧节点并用新节点替代。
- 对于相同类型的节点,进一步比较它们的属性。记录属性差异,以便生成相应的补丁。
- 如果两个节点相同,继续递归比较它们的子节点,直到遍历完整个树。
- 如果节点有唯一标识,可以通过这些标识来快速定位相同标识的节点。
- 如果节点的相同,只是顺序变化,不会执行不必要的操作。
面试官:为什么不用 index 做 key?
平常v-for
循环渲染的时候,为什么不建议用 index
作为循环项的 key
呢?
最后
总的来说,面试官要是考察思路就会从你实际做过的项目入手,考察你实际编码能力,就会让你在电脑敲代码,看你用什么编辑器、插件、编码习惯等。所以我们在回答面试官问题时,有一个清晰的逻辑思路,清楚知道自己在和面试官说项目说技术时的话就好了
开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】
15627276480)]
[外链图片转存中…(img-5C9hv7JC-1715627276480)]