小问题需要注意

1. useEffect和uselayoutEffect区别

Hook 触发时机 是否阻塞渲染
useEffect 浏览器完成渲染(绘制)之后 才执行,属于 异步 调用,不会阻塞页面的绘制。 ❌ 不阻塞
useLayoutEffect DOM 更新后、浏览器绘制前 执行,属于 同步 调用,会在页面绘制前完成执行,因此可能阻塞渲染。 ✅ 阻塞

使用场景建议

useEffect 适合:

  • 数据请求
  • 事件监听/解绑
  • 日志记录
  • 不影响页面首屏渲染的逻辑

useLayoutEffect 适合:

  • 需要立即 测量 DOM 尺寸/位置(如 getBoundingClientRect
  • 需要阻止页面闪烁的布局调整
  • 同步修改 DOM 样式(如动画的初始位置)

记住口诀

useEffect:绘制后执行 → 异步 → 不影响渲染
useLayoutEffect:绘制前执行 → 同步 → 会阻塞渲染

2.useEffectreturn (清理函数)和 依赖数组 的执行时机梳理成一个精确的时序表

基本规则

scss 复制代码
ts
复制编辑
useEffect(() => {
  // 副作用逻辑

  return () => {
    // 清理逻辑
  };
}, [dep1, dep2]);

执行顺序

  1. 组件首次渲染 → 执行副作用函数(// 副作用逻辑)。
  2. 依赖变化 → 先执行上一次的 return 清理逻辑,再执行新的副作用逻辑。
  3. 组件卸载 → 执行最后一次的 return 清理逻辑。

3.taiwindcss如何选择组件内的子元素

1. space-* / divide-* 处理直接子元素间距或边框

这种方式最适合「兄弟元素」场景,不需要自己写选择器。

css 复制代码
html
复制编辑
<div class="space-y-4">
  <p>第一段</p>
  <p>第二段</p>
  <p>第三段</p>
</div>
  • space-y-4 → 给所有 直接子元素 添加垂直间距
  • space-x-4 → 给所有 直接子元素 添加水平间距
  • divide-y / divide-x → 给直接子元素之间添加分隔线

2. group + group-* 选择子元素

group 是 Tailwind 内置的父级状态类,可以配合伪类选择子元素(常用在 hover、focus 场景)。

ini 复制代码
html
复制编辑
<div class="group p-4 border">
  <p class="group-hover:text-red-500">鼠标移到父元素时变红</p>
</div>
  • 父元素加 .group
  • 子元素用 group-hover:group-focus: 等前缀响应父元素状态

3. @layer 写自定义选择器

如果需要像普通 CSS 那样 .parent > .child,可以借助 Tailwind 的 @layer 功能扩展样式:

scss 复制代码
css
复制编辑
@layer components {
  .card > .title {
    @apply text-lg font-bold text-blue-500;
  }
}

HTML:

ini 复制代码
html
复制编辑
<div class="card">
  <div class="title">标题</div>
</div>
  • 这样 Tailwind 编译时会保留 .card > .title 规则
  • 适合复用性强的子元素样式

4. 使用 & 嵌套选择器(在 Tailwind 的 SCSS/Sass/ PostCSS 中)

如果项目用了 Sass 或 PostCSS Nesting,可以直接写嵌套语法:

scss 复制代码
css
复制编辑
@layer components {
  .parent {
    @apply p-4 bg-gray-100;
    & > .child {
      @apply text-red-500;
    }
  }
}

编译后会生成:

css 复制代码
css
复制编辑
.parent { padding: 1rem; background-color: #f7fafc; }
.parent > .child { color: #ef4444; }

5.实现一个es6的proxy

js 复制代码
function MyProxy(target, handler) {
  const proxy = {};

  Object.keys(target).forEach(key => {
    Object.defineProperty(proxy, key, {
      get() {
        if (handler.get) {
          return handler.get(target, key, proxy);
        }
        return target[key];
      },
      set(value) {
        if (handler.set) {
          const res = handler.set(target, key, value, proxy);
          if (res) target[key] = value;
          return res;
        }
        target[key] = value;
        return true;
      }
    });
  });

  return proxy;
}

// 测试
const obj = { a: 1, b: 2 };

const p = MyProxy(obj, {
  get(target, prop) {
    console.log(`get ${prop}`);
    return target[prop];
  },
  set(target, prop, value) {
    console.log(`set ${prop} = ${value}`);
    target[prop] = value;
    return true;
  }
});

console.log(p.a); // get a -> 1
p.b = 10;         // set b = 10

6.JavaScript 事件循环(Event Loop)主线程(Main Thread)消息队列(Message Queue / Task Queue)调用栈(Call Stack) 的运作过程

2. 执行流程

假设代码:

javascript 复制代码
js
复制编辑
console.log("A");

setTimeout(() => console.log("B"), 0);

Promise.resolve().then(() => console.log("C"));

console.log("D");

执行过程:

  1. 主线程执行同步代码console.log("A") 输出 → 压栈/弹栈
  2. 遇到 setTimeout → 定时器到点后回调放入 宏任务队列
  3. 遇到 Promise.then → 回调放入 微任务队列
  4. 继续执行 console.log("D")
  5. 执行所有微任务队列 (输出 C
  6. 执行一个宏任务队列的任务(输出 B

最终输出:

css 复制代码
css
复制编辑
A
D
C
B

可视化顺序图

javascript 复制代码
javascript
复制编辑
┌───────────────────┐
│   Call Stack       │
└───────┬───────────┘
        │
        ▼
同步任务先执行(A、D)
        │
        ▼
微任务队列(Promise.then)
        │
        ▼
宏任务队列(setTimeout)

事件循环流程:

css 复制代码
css
复制编辑
[执行栈为空] →
  执行微任务队列全部任务 →
    执行一个宏任务 →
      执行微任务队列全部任务 →
        再取一个宏任务 →
          循环...
相关推荐
前端小巷子4 小时前
JS实现丝滑文字滚动
前端·javascript·面试
保卫大狮兄5 小时前
连锁零售企业如何能更有效地管理门店考勤?
面试·职场和发展
薄荷糖__5 小时前
(二)模块化:ES Module使用原理,包管理工具npm
前端·面试
大模型真好玩5 小时前
大模型工程面试经典(五)—大模型专业领域微调数据集如何构建?
人工智能·python·面试
UrbanJazzerati5 小时前
Python正则表达式匹配和替换详细指南
python·面试
绝无仅有7 小时前
从拉取代码到前端运行访问:Vue 前端项目的常规启动流程
后端·面试·github
青鱼入云7 小时前
java面试中经常会问到的zookeeper问题有哪些(基础版)
java·面试·java-zookeeper
DarkLONGLOVE1 天前
JS魔法中介:Proxy和Reflect为何形影不离?
前端·javascript·面试
yinke小琪1 天前
分库分表后,主键 ID 如何优雅生成?
java·后端·面试
Q741_1471 天前
C++ 面试高频考点 力扣 153. 寻找旋转排序数组中的最小值 二分查找 题解 每日一题
c++·算法·leetcode·面试·二分查找