关于vue的面试考点总结🤯

页面渲染优化

  1. html 不要嵌套过深 (减轻回流的压力)
  2. css 尽量使用精确的选择器 (减少回流的压力)
  3. 代码压缩 (减轻请求的压力)
  4. js 角度(js引擎线程和浏览器的渲染线程不会同时工作) 在script标签里面放 (async 异步加载 + 直接执行) 和 (defer 异步加载 + 延迟执行) 关键字
  5. 图片(懒加载,预加载,骨架屏,压缩,精灵图)
  6. 缓存

谈谈你对 vue 的理解

  1. 渐进式的单页应用框架 (根据项目的需求逐渐引入功能 use install 函数)
  2. MVVM 数据驱动页面更新 (model views views-model)
  3. 组件化 (可复用,方便调试)
  4. 指令
  5. 虚拟dom (跨端开发,减少dom操作,读取代码,生成虚拟dom树,给浏览器渲染)
  6. 生态完善

谈谈你对spa的理解

spa(单页面应用),整个项目只有一个页面,页面中的内容是动态的,以组件的形式展示,靠路由来映射匹配组件。

优点:

  1. 组件化开发,易于维护
  2. 页面切换快,体验好
  3. 前后端分离,提升开发效率

缺点:首屏加载时间长,不利于 SEO

可以通过服务端渲染 ssr 解决首屏加载时间长,不利于SEO的问题:

ssr服务端渲染原理:

  1. 创建 node 服务
  2. 读取 vue 组件
  3. 借助 vue 自带编译器函数编译 vue 组件,得到 AST
  4. 借助 vue 自带渲染器函数渲染 AST 得到 html
  5. 拼接 html 模板
  6. 发送响应

vue项目里面再启动一个node服务,读取需要第一个被展示出来的组件,将该组件由vue自带的编译器和渲染器,处理成代码块,最后拼接到一个html模板当中,响应给浏览器。

SPA 首屏加载优化

首屏加载慢的原因:

  1. 单页应用需要把所有页面的代码都执行完,首屏才加载
  2. 加载js脚本
  3. 网络延时

优化策略:

  1. 路由懒加载
  2. ssr 服务端渲染
  3. 骨架屏
  4. UI 框架按需加载

说说你对 vue 生命周期的理解

生命周期就是一个vue组件从创建到销毁的过程,其中官方打造了一系列的钩子函数。

  1. setup = beforeCreate + created

  2. onBeforeMount = beforeMount

  3. onMounted = mounted

  4. onBeforeUpdated = beforeUpdated

  5. onUpdated = updated

  6. onBeforeUnmount = beforeUnmount

  7. onUnmounted = unmounted

  8. onActived() 命中缓存会调用

  9. onDeactivated()

  10. 捕获子组件错误时触发 onErrorCaptured

  11. 收集依赖时触发 onRenderTracked

  12. 触发依赖时触发 onRenderTriggered 响应式值变更,调试用的

当被keep-alive标签包裹后,里面的内容就被缓存,没有执行卸载操作

说说你对双向绑定的理解

vue中的双向绑定就是v-model指令,修改数据,页面会同步更新,页面内容修改,数据也会同步更新。

原理:双向绑定由三个重要部分构成(MVVM):Model(模板层),View(视图层,浏览器的可视区域),ViewModel(vue框架的核心,将数据与视图关联起来)。

ViewModel:

  1. Observer(监听器):数据的代理
  2. Compiler(解析器):解析模板的指令

当vue组件被读取到时,将数据变成响应式以及解析模板指令,解析完指令会初始化视图,当数据源发生变化的时候就需要更新视图,通过Dep机制通知变更,通知watcher观察者,然后观察者去触发更新视图的函数。Dep充当数据与视图之间的中介,它知道哪些视图(Watcher)依赖于特定的数据,当数据变化时,能够通知到所有依赖该数据的视图。为了避免不必要的试图更新。

双向绑定的原理:

  1. 变量被处理成响应式的过程中会为变量做依赖收集,当变量的值变更时,触发setter,并执行依赖,导致试图更新。
  2. 视图更新相当于用户触发了 input 事件,修改响应式变量,进而又导致setter触发。

vue 组件通讯

list是一个数组。

父向子传值

  1. 父组件用 v-bind : 传递给子组件,子组件用 defineProps 接收数据。
js 复制代码
// parent.vue
<child :data="list"></child>

// child.vue
const props = defineProps({
  data: {
    type: String,
    default: ''
  }
})

console.log(props.data);
  1. 父组件 provide 数据,子组件 inject 注入 (全部子组件都能接收到,数据流向不明确,只能从上往下注入,在最外层的App.vue里面使用provide可以类似仓库效果)
js 复制代码
// parent.vue
import { provide } from 'vue'
provide('list', list.value)  // 向下提供数据 提供的是引用地址(子组件可以改)
provide('list', readonly(list.value))  // readonly接收一个对象,返回只读代理(不能改)

// child.vue
import { inject } from 'vue'
const list = inject('list')  // 注入数据

子向父传值

  1. 子组件通过 defineEmits 定义发布一个事件,父组件通过 v-on 订阅这个事件。
js 复制代码
// parent.vue
<Child @add="handle" />

const handle = (val) => {
  console.log(val)    // hello
}

// child.vue
const emit = defineEmits(['add'])   // 定义一个事件
const handle = () => {
  emit('add', 'hello world')   // 发布事件
}
  1. 子组件通过 defineExpose 暴露数据,父组件通过 ref 引用子组件中的数据
js 复制代码
// parent.vue
<Child ref="childRef" />

const childRef = ref(null)
console.log(childRef.value);  // 输出list的值

// childRef?.list 如果 childRef 有值执行 list,否则不执行
// :key 作用是Vue会根据该值来判断哪些元素是新的,哪些元素需要被重用,从而提高渲染效率
<li v-for="(item, index) in childRef?.list" :key="index">{{ item }}</li>


// child.vue
defineExpose({
  list
})
  1. 父组件通过 v-model 绑定数据给子组件,子组件通过 defineProps接收,然后定义 'update:xxx' 事件,并直接修改父组件给过来的数据,但是一定要发布 'update:xxx' 事件
js 复制代码
// parent.vue
<Child v-model:list="arr" />

const arr = ref(['html', 'css', 'js'])

// child.vue
const props = defineProps(['list'])   // 接收父组件传过来的值
const emits = defineEmits(['update:abc'])   // 定义 update: 事件

const add = () => {
  const arr = props.list
  arr.push('vue')
  emits('update:abc', arr)   // 发布 update: 事件
}

兄弟组件通讯

  1. 在外部的 js 文件中定义响应式变量,同时引入到两个组件中,因为是响应式的,所以两个组件都可以修改这个变量,从而实现通讯。
js 复制代码
// bus.js
export const list = ['html', 'css']

// child.vue
import { list } from './bus.js'

const add = () => {
  list.push('child')
}

// parent.vue
import { list } from './bus.js'

const add = () => {
  list.push('parent')
}
  1. pinia 状态管理库

v-if 和 v-show 的区别

  1. v-if是动态地向 DOM 树内添加或删除 DOM 元素,v-show 是通过 css 控制元素的 display属性
  2. v-if 控制的组件会触发生命周期,v-show 不会
  3. v-if 有更高的切换开销, v-show 会导致两次回流

v-if 和 v-for 可以一起使用吗?

  1. 在vue3中,v-if的优先级比v-for高
  2. 在vue2中,v-for的优先级比v-if高

data 为什么是一个函数,不能是一个对象?

如果 data 是一个对象,那么当该组件被多处使用时,会导致数据共享,会出现数据污染的问题,为了确保每个组件实例都有其独立的数据副本,避免数据污染,data 必须是一个函数,返回一个对象,每个组件实例都有自己的 data 对象

说说你对 vue 中 nextTick 的理解

nextTick 是一个异步函数,它的作用是在 DOM 更新后执行回调函数,延迟回调。

实现原理如下:

js 复制代码
<script>
  // 1. 什么时候执行 cb 回调函数
  // 2. 执行resolve函数
  function nextTick(cb) {
    return new Promise(resolve => {
      function fn() {
        return () => {
          cb()
          resolve()
        }
      }
      // 当 DOM 结构渲染完成后,再执行回调
      if (typeof MutationObserver !== 'undefined') {
        const observer = new MutationObserver(fn())  // 浏览器监听DOM的api
        observer.observe(document.body, {   // 监听dom结构更新
          childList: true,
          subtree: true
        })
      } else {//如果浏览器不支持`MutationObserver`,则使用`setTimeout`将回调函数延迟到下一个事件循环执行
        setTimeout(fn(), 0)
      }
    })
  }

  const app = document.getElementById('app')

  nextTick(() => {
    console.log(app.innerHTML);
  }).then(() => {
    console.log(app.innerHTML, 'then');
  })

  app.addEventListener('click', () => {
    app.innerHTML = 'hello world'
  })
</script>

所以:

  • 在拥有 MutationObserver 的浏览器中,通过 MutationObserver 来监听 DOM 的变化,触发会回调
  • 在不支持 MutationObserver 的环境中,使用 setTimeout 来模拟 MutationObserver,当 DOM 变化时,触发回调

说说你对 slot 的理解

slot vue中的插槽功能,是组件中的一个占位符,用于接收该组件标签中的内容

  1. 匿名 slot
  2. 具名 slot
  3. 作用域 slot
  4. 条件 slot
js 复制代码
// 匿名 slot
// layout.vue
<template>
  <div class="head">
    <slot>
       xxxxxx
    </slot>
  </div>
  <div class="body">
    <div class="left"></div>
    <div class="right"></div>
  </div>
</template>

// App.vue
<template>
  <layout>
    <template v-slot>
      <div>hello world</div>
      <p>vue</p>
    </template>
  </layout>
</template>
js 复制代码
// 具名 slot
// layout.vue
<template>
  <div class="head">
    <slot name="head">

    </slot>
  </div>
  <div class="body">
    <div class="left"></div>
    <div class="right">
      <slot name="right">

      </slot>
    </div>
  </div>
</template>

// App.vue
<template>
  <layout>
    <template v-slot:head>
      <div>hello world</div>
    </template>
    <template v-slot:right>
      <p>vue</p>
    </template>
  </layout>
</template>
js 复制代码
// 作用域 slot
// layout.vue
<template>
  <div class="head">
    <slot name="head" :user="{ name: '张三' }">

    </slot>
  </div>
</template>

// App.vue
<template>
  <layout>
    <template v-slot:head="props">
      <div>{{ props.user.name }}</div> 
    </template>
  </layout>
</template>
js 复制代码
// 条件 slot
// layout.vue
<template>
  // 如果有head就显示
  <div class="head" v-if="$slots.head">  
    <slot name="head"></slot>
    <slot name="left"></slot>
  </div>
</template>

// App.vue
// 不显示
<template>
  <layout>
    <template v-slot:left>你好</template>   
  </layout>
</template>

应用场景:layout布局组件。

为什么要使用 key? index 做 key 有什么问题?

  • key 大大提高了 diff 的效率,减少了不必要的渲染
  • index 做 key 等同于没有 key,会导致性能问题

什么是虚拟 DOM?

用 js 对象作为树,使用对象的属性来描述节点的状态,用这个对象来描述真实的 DOM 树,这个对象就是虚拟 DOM。最少包含 tag,props,children 三个属性。

  • 减少了真实 DOM 的操作带来页面渲染的性能开销 传给了 v8 引擎
  • 抽象了原本的渲染过程,实现了跨平台开发的能力

diff 算法

diff 算法是一种对象的比较算法,效率很高,在拥有虚拟 DOM 的框架中被使用。

在vue中,拥有虚拟dom这个过程,所以,vue要先将模板代码编译成虚拟dom对象后,再拿虚拟dom对象生成真实的dom交给浏览器渲染,当响应式变量值发生改变时,会重新生成新的虚拟dom对象,为了考虑到降低渲染开销,需要用diff算法来比较,找出新的虚拟dom对象和老的dom对象的区别,把区别单独拎出来后去更新真实的dom结构。

原理:

  1. 比较旧 DOM 虚拟对象的根节点,如果根节点不同,直接替换整个 DOM 树
  2. 如果根节点相同,比较根节点的属性,如果不同,修改根节点的属性
  3. 如果根节点的属性相同,比较根节点的子节点,同层级的子节点进行比较,如果不同,替换该子节点以下的 DOM 树。
  4. 判断是不是文本节点,如果是文本节点,直接修改文本节点的内容
  5. 采用深度优先遍历对比子节点(对比的过程中,有旧没新,删除旧节点,反之增加新节点)

同层级的子节点比较:(双端队列)

  1. 设置新旧 Vnode 的头尾指针、
  2. 新旧头尾指针进行比较,向中间靠拢,这个过程包含 4 种情况,分别是:头头比,尾尾比,头尾比,尾头比

了解过 vue2 吗?vue3 和 vue2 的区别是什么?

  1. 速度更快
  • 重写了虚拟 DOM 的实现,使用 proxy 代替了 Object.defineProperty
  • 编译模板的优化,采用了静态提升策略,将静态节点缓存起来,减少了编译的时间
  1. 体积更小 (组合式api,实现按需分配的能力)
  2. 更易维护 (完全兼容 vue2 的语法,还可以搭配 vue3 模板使用)
  3. 更接近原生
  4. 更友好的 ts 支持
相关推荐
郑祎亦9 分钟前
CSS 实现 文本垂直居中
前端·css
zhongshizhi9112 分钟前
CSS元素层叠顺序规则
前端·css
申朝先生1 小时前
用CSS画一条0.5px的线
前端·javascript·css
雪碧聊技术2 小时前
element-plus中Autocomplete自动补全输入框组件的使用
前端·javascript·vue.js·自动补全输入框·autocomplete
浪遏2 小时前
当你向面试官朗诵单例模式时 ,ta说talk is cheep , show me the code🤡
前端·设计模式·面试
zczlsy113 小时前
webpack介绍
前端·webpack·node.js
浪遏4 小时前
今晚揭开单例模式的面纱~
前端·设计模式·面试
千里码aicood4 小时前
【2025】基于springboot+vue的汽车销售试驾平台(源码、万字文档、图文修改、调试答疑)
vue.js·spring boot·汽车
驯龙高手_追风4 小时前
谷歌Chrome或微软Edge浏览器修改网页任意内容
前端·chrome·edge