小问题需要注意

1. useEffect和uselayoutEffect区别

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

使用场景建议

useEffect 适合:

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

useLayoutEffect 适合:

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

✅ 记住口诀

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

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

基本规则

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
复制编辑
[执行栈为空] →
  执行微任务队列全部任务 →
    执行一个宏任务 →
      执行微任务队列全部任务 →
        再取一个宏任务 →
          循环...
相关推荐
2501_933670792 小时前
2027校招销售运营面试:大数据管理与应用专业如何拆解漏斗分析
大数据·人工智能·面试
丑陋小蚊子9 小时前
邮件投简历,正文和附件各写什么?
面试·求职招聘·大学生·简历·简历下载
架构技术专栏10 小时前
学习率:一次参数更新,到底应该改多少
面试
架构技术专栏10 小时前
AI Agent 框架怎么选:从一次制度查询拆出技术边界
后端·面试
花间相见14 小时前
【后端开发|Redis进阶01】—— Redis分布式锁全解:从SETNX到Redisson看门狗,再到RedLock
后端·面试
ShineWinsu18 小时前
对于Redis:AOF持久化的解析
linux·数据库·redis·缓存·面试·持久化·aof
考研保研资料分享20 小时前
金融专硕保研经验:清华五道口预推免、北大汇丰夏令营与面试复盘
面试·金融
事圆则缓20 小时前
Kotlin 入门与面试:从空安全、扩展函数到协程
安全·面试·kotlin
ShineWinsu1 天前
对于Redis:RDB持久化的解析
linux·数据库·redis·缓存·面试·持久化·rdb
丑陋小蚊子1 天前
项目数据不能公开,就写清交付物
面试·求职招聘·大学生·简历·简历下载