Skip to content

1月7日 每日五题

谈谈你对spa的理解

Spa就是单页面应用,整个项目只有一个核心的html,初次加载后,后续内容都由js来动态更新,靠路由来匹配不同组件展示,首次加载后,后续页面切换不需要重新加载整个页面,从而提升用户体验

优点:

  1. 前后端分离,组件化开发,易于维护
  2. 无过多html页面的请求,减轻服务器压力
  3. 初次加载后,页面切换快,体验好

缺点:

  1. 初次加载慢

  2. 不利于SEO(可以使用 SSR)

computed(计算属性)和 watch(侦听器)的区别及使用场景?

计算属性是基于其依赖进行缓存的,只有当相关的数据发生变化时,才会重新计算。这使得我们可以在模板中使用它们来展示经过处理的数据。

而侦听器则是用来观察数据的变化,并在变化时执行一些操作,比如发起异步请求或进行复杂的逻辑处理。

一般来说,当我们需要计算一个值并在视图中使用时,应该选择计算属性;而当我们需要在数据变化时执行副作用或者耗时任务时,使用侦听器更合适。

  • computed(计算属性):
    • 计算属性是基于它们的依赖进行缓存的,只有在相关依赖发生变化时才会重新计算。
    • 适用于需要基于已有数据进行计算或处理后再展示的场景。
    • 有返回值的,不支持异步.初始化默认会触发
  • watch(侦听器):
    • 侦听器是用来观察 Vue 响应式数据变化,并在数据变化时执行指定的操作。
    • 适用于需要在数据变化时执行特定操作(如 API 调用、路由跳转等)的场景
    • 没有返回值,支持异步,默认不会触发,需要手动设置 immediate

什么是插槽,类型有哪些?

插槽主要是用于在组件中插入内容,允许父组件像子组件传递内容,实现灵活的组件组合,它有三种类型

  1. 默认插槽.没有显式名称,隐式名称是 default,可以省略 template 允许父组件可以在子组件标签内随便写内容,会传递到子组件的slot位置

  2. 具名插槽: 需要使用 template+v-slot 或者#号声明具体名称的插槽

  3. 作用域插槽,在具名插槽的基础上可以拿到子组件传递出来的数据

Vue响应式原理?

先明确核心目标:当数据发生变化时,页面中使用该数据的地方自动更新

整个响应式系统的核心可以总结为 3 个步骤(Vue 2/3 都遵循这个核心逻辑,只是实现细节不同):

  1. 数据劫持 / 代理:监听数据的读取和修改操作;
  2. 依赖收集:记录哪些地方(如模板、计算属性)用到了这个数据;
  3. 触发更新:当数据修改时,通知所有依赖该数据的地方重新执行(更新视图)。

Vue 2 基于 Object.defineProperty() 实现响应式,以下是核心逻辑和局限:

  • 无法监听数组:Object.defineProperty() 不能劫持数组的下标和长度,Vue 2 只能通过重写 push/pop/shift/unshift/splice/sort/reverse 7 个方法实现数组响应式,直接修改下标(如 arr[0] = 1)不会触发更新;
  • 无法监听对象新增 / 删除属性:只能劫持已存在的属性,新增属性(obj.newKey = 1)或删除属性(delete obj.key)需要手动调用 Vue.set()/Vue.delete();
  • 深度监听需递归:初始化时要递归遍历所有属性,数据量大时会影响性能;
  • 只能劫持属性:无法直接监听整个对象,必须逐个属性处理。

Vue 3 基于 ES6 的 Proxy + Reflect 重构了响应式系统,解决了 Vue 2 的所有局限,

Vue 3 还提供了 ref 来解决基本数据类型(字符串 / 数字 / 布尔) 的响应式问题(因为 Proxy 只能代理对象,无法代理基本类型):

Vue 响应式原理的核心就是 Observer 、 Dep 、 Watcher

Observer 中进行响应式的绑定

在数据被读的时候,触发 get 方法,执行 Dep 来收集依赖,也就是收集 Watcher 。

在数据被改的时候,触发 set 方法,通过对应的所有依赖( Watcher ),去执行更新。"

什么是vue生命周期?生命周期有哪些?