1、Vue 如何处理组件性能优化?(如 watchEffect、memo、Suspense)
答:Vue组件性能优化手段包括依赖精确追踪(watchEffect)、跳过不必要渲染(v-memo, v-once)、组件缓存(keep-alive)、异步占位(Suspense) 以及传统的 虚拟列表、懒加载等。核心思路是减少无关渲染,优化首屏与大数据场景。
Vue组件性能瓶颈常见于:重复渲染(父组件更新导致子组件无关渲染)、大数据列表渲染过多、异步数据加载阻塞页面、复杂计算/副作用频繁触发watchEffect与依赖追踪- 用于收集依赖的副作用逻辑,只有相关依赖变化时才重新执行。
- 避免冗余的计算或副作用调用。
v-memo (Vue 3.2+)- 用于跳过组件或节点的渲染,当绑定的依赖不变时,直接复用之前的渲染结果。
<div v-memo="[id]">
<span>{{ id }}</span>
<span>{{ name }}</span>
</div>
<!-- 只有`id`变化才会重新渲染,`name`变化时会被忽略。-->
<!-- 类似`React`的`memo`,适合大列表、局部渲染优化。 -->
<Suspense>异步组件加载优化Vue内置的 异步组件占位机制,在异步数据/组件加载时展示fallback,避免白屏。
<Suspense>
<template #default>
<AsyncComponent />
</template>
<template #fallback>
<LoadingSpinner />
</template>
</Suspense>
- 其它优化手段
v-once:一次性渲染,永不更新keep-alive:缓存动态组件,避免重复创建/销毁- 计算属性缓存:复杂计算逻辑放入
computed,避免重复执行 - 事件绑定优化:使用事件委托,避免在大列表中每个元素单独绑定事件
- 异步组件 & 懒加载:路由级别拆分,减少首屏压力
2、vuex 和 pinia 有何不同?pinia 是如何实现状态持久化的?
Vuex:Vue2时代的官方状态管理库,采用mutations + actions,语法偏重。Pinia:Vue3官方推荐的状态管理库,API更简洁,支持组合式写法,无mutations,更贴近原生Vue响应式。- 持久化:
Pinia自身不带持久化,需要通过 插件机制(如pinia-plugin-persistedstate)将store自动存储到localStorage / sessionStorage,并在初始化时恢复。 Vuex特点- 单一状态树(
Single Source of Truth) - 强制
mutations同步修改state(方便devtools追踪) actions处理异步逻辑,最后提交到mutations- 结构清晰但模板代码多
- 单一状态树(
Pinia特点- 直接使用函数
defineStore定义store - 不再强制区分
mutations / actions,直接写方法修改state - 支持
TypeScript完整类型推导 - 与
Vue组合式API更自然结合
- 直接使用函数
3、解释一下 z-index 的作用及层叠上下文的形成规则
答:z-index用来控制元素在z轴上的显示顺序,但只在同一个层叠上下文中比较。层叠上下文可以由根元素、设置了定位且z-index非auto的元素、或一些特殊属性(如opacity < 1、transform、filter)创建。不同层叠上下文之间互相独立,内部元素不会跨上下文去比较z-index,这就是为什么有时z-index设置很大也无法“置顶”的原因。
z-index的作用
- 作用:在同一个层叠上下文(stacking context)中,决定元素在**z 轴方向(前后顺序)**的绘制顺序。
- 前提:只有定位元素(position 不是 static)或某些特殊属性的元素,才会创建层叠上下文,
z-index才有实际意义。
层叠上下文(Stacking Context):层叠上下文是浏览器绘制时的一个分组/局部坐标系,内部元素的层叠顺序受控于这个上下文,而不会与外部元素直接比较。
形成层叠上下文触发条件:
- 根元素 (
<html>) 天然是一个层叠上下文。 - 定位元素 +
z-index非auto:position: relative | absolute | fixed | sticky; z-index: 0 | 正数 | 负数; - 特定
CSS属性(即使没有z-index):opacity < 1、transform、perspective、filter、will-change、mix-blend-mode、isolation: isolate、contain: paint、clip-path等
层叠顺序规则:在同一层叠上下文中,元素的绘制顺序遵循以下规则(从低到高,后面的会覆盖前面的):
- 背景与边框(block background/border)
- 负
z-index的子元素 - 普通文档流中的
block/inline元素(z-index: auto的内容) - 浮动元素
- 正常的
inline/inline-block(z-index: auto) z-index ≥ 0的定位子元素(按z-index数值排序)
不同
stacking context的元素不会打乱内部顺序,而是整个上下文作为一个单元,参与外层的比较。
常见坑:
z-index无效- 父元素未形成层叠上下文时,子元素的
z-index可能表现异常。 - 解决:给父元素设置
position + z-index或其他会创建上下文的属性。
- 父元素未形成层叠上下文时,子元素的
z-index冲突解释错误- 很多人以为
z-index: 9999就能绝对置顶,但其实要看它所在的stacking context。
- 很多人以为
- 层叠上下文隔离
- 内层元素无法“逃脱”父层叠上下文,即使
z-index设置再大,也盖不住外层兄弟。
- 内层元素无法“逃脱”父层叠上下文,即使
4、CSS 选择器优先级规则是怎样的?
答:CSS选择器优先级规则是:行内样式最高,其次是ID选择器,然后是类/属性/伪类,最后是元素/伪元素。同级比较数量,从高到低逐层比。!important可以提升声明优先级,但不会改变选择器本身的权重。
行内 > ID > 类/属性/伪类 > 元素/伪元素。同级比较数量,层级逐级比较。
!important能碾压一切(除非对方也有)。
特殊规则:
通配符 *、关系选择器 > + ~、否定伪类 :not():不会增加优先级。(比如div :not(.a),优先级只算.a)!important:会将当前声明提升到最高优先级,但不会改变选择器权重。如果两个规则都有!important,就再比较选择器优先级。继承的样式:优先级最低,只有在没有更具体的规则时才生效。