1月7日 每日五题
谈谈你对spa的理解
Spa就是单页面应用,整个项目只有一个核心的html,初次加载后,后续内容都由js来动态更新,靠路由来匹配不同组件展示,首次加载后,后续页面切换不需要重新加载整个页面,从而提升用户体验
优点:
- 前后端分离,组件化开发,易于维护
- 无过多html页面的请求,减轻服务器压力
- 初次加载后,页面切换快,体验好
缺点:
初次加载慢
不利于SEO(可以使用 SSR)
computed(计算属性)和 watch(侦听器)的区别及使用场景?
计算属性是基于其依赖进行缓存的,只有当相关的数据发生变化时,才会重新计算。这使得我们可以在模板中使用它们来展示经过处理的数据。
而侦听器则是用来观察数据的变化,并在变化时执行一些操作,比如发起异步请求或进行复杂的逻辑处理。
一般来说,当我们需要计算一个值并在视图中使用时,应该选择计算属性;而当我们需要在数据变化时执行副作用或者耗时任务时,使用侦听器更合适。
- computed(计算属性):
- 计算属性是基于它们的依赖进行缓存的,只有在相关依赖发生变化时才会重新计算。
- 适用于需要基于已有数据进行计算或处理后再展示的场景。
- 有返回值的,不支持异步.初始化默认会触发
- watch(侦听器):
- 侦听器是用来观察 Vue 响应式数据变化,并在数据变化时执行指定的操作。
- 适用于需要在数据变化时执行特定操作(如 API 调用、路由跳转等)的场景
- 没有返回值,支持异步,默认不会触发,需要手动设置 immediate
什么是插槽,类型有哪些?
插槽主要是用于在组件中插入内容,允许父组件像子组件传递内容,实现灵活的组件组合,它有三种类型
默认插槽.没有显式名称,隐式名称是
default,可以省略template允许父组件可以在子组件标签内随便写内容,会传递到子组件的slot位置具名插槽: 需要使用
template+v-slot或者#号声明具体名称的插槽作用域插槽,在具名插槽的基础上可以拿到子组件传递出来的数据
Vue响应式原理?
先明确核心目标:当数据发生变化时,页面中使用该数据的地方自动更新。
整个响应式系统的核心可以总结为 3 个步骤(Vue 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 ),去执行更新。"