普通视图

发现新文章,点击刷新页面。
昨天 — 2026年5月5日首页

Flexbox 与 Grid 布局

作者 Rkgua
2026年5月4日 21:41

CSS 的 Flexbox(弹性盒子)和 Grid(网格)是现代前端开发中最强大的两大布局系统。它们并不是竞争关系,而是互补的搭档。

想要彻底搞懂它们,只需要抓住一个最本质的区别:一维布局 vs 二维布局

Flexbox 与 Grid 的核心区别

简单来说,Flexbox 像是在一根绳子上串珠子,而 Grid 像是在织一张纵横交错的网。

  • Flexbox(一维布局): 它一次只能处理一个方向的布局——要么是水平的一行(row),要么是垂直的一列(column)。它的核心在于“弹性”,即根据容器剩余空间,自动伸缩子元素的尺寸与排列方式。
  • Grid(二维布局): 它可以同时控制行和列。你就像在画一张 Excel 表格,可以精确地定义每个元素在第几行、第几列,以及跨越几个单元格。

为了更直观地对比,我们可以通过下表来看清它们的差异:

特性维度 Flexbox (弹性盒子) Grid (网格布局)
布局维度 一维(只能同时控制行 列) 二维(可以同时控制行 列)
核心思维 内容优先(根据内容自动伸缩) 布局优先(先定义好网格结构)
对齐能力 擅长单行/单列内的对齐与空间分配 擅长整体布局及单元格内部的对齐
间隙控制 使用 gap 属性(现代浏览器已支持) 原生支持 gaprow-gapcolumn-gap
元素重叠 较难实现,通常需要结合定位 轻松实现,通过让元素占据同一网格区域即可

Flexbox 的常见应用场景

Flexbox 非常适合处理组件级别的微观布局,或者任何只需要在一条线上排列元素的场景。

  1. 导航栏(Navbar): 这是 Flexbox 最经典的用法。你可以轻松实现 Logo 在左、菜单在右,并且让所有菜单项垂直居中。
    .navbar {
      display: flex;
      justify-content: space-between; /* 左右两端对齐 */
      align-items: center; /* 垂直居中 */
    }
    
  2. 绝对居中(Centering): 在 Flexbox 出现之前,垂直居中是前端开发的噩梦。现在只需三行代码即可完美解决(例如登录框居中)。
    .container {
      display: flex;
      justify-content: center; /* 水平居中 */
      align-items: center; /* 垂直居中 */
      height: 100vh;
    }
    
  3. 均分列布局与卡片内部: 比如一个包含头像、输入框和按钮的评论区。你可以让输入框自动占满剩余空间(flex: 1),而头像和按钮保持固定宽度。
  4. 粘性页脚(Sticky Footer): 当页面内容不足一屏时,让页脚始终固定在浏览器底部。只需将页面主体设为 flex-direction: column,并给中间的内容区设置 flex: 1 即可。

Grid 的常见应用场景

Grid 布局是处理页面级别的宏观布局,以及任何需要同时顾及行与列的复杂二维场景的终极武器。

  1. 页面整体骨架(圣杯布局): 经典的“头部 + 侧边栏 + 主内容 + 右侧栏 + 底部”布局。用 Grid 的 grid-template-areas 可以像画画一样语义化地定义出来,代码极其清晰。
    .page-layout {
      display: grid;
      grid-template-areas:
        "header header header"
        "nav    main   aside"
        "footer footer footer";
      grid-template-columns: 200px 1fr 200px; /* 左右固定,中间自适应 */
      grid-template-rows: 80px 1fr 60px;
    }
    
  2. 响应式卡片/图片画廊: Grid 拥有超强的响应式能力。仅需一行代码,就能实现卡片随屏幕宽度自动换行、自动调整列数,甚至完全不需要写媒体查询(Media Queries)。
    .gallery {
      display: grid;
      /* 自动填充列,每列最小300px,最大平分剩余空间 */
      grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
      gap: 20px;
    }
    
  3. 复杂的仪表盘(Dashboard): 仪表盘里通常有各种大小不一的组件(比如有的图表占 2x2 的格子,有的占 1x2)。Grid 可以通过 grid-column: span 2 轻松控制元素跨越多个网格,且自动对齐。
  4. 不规则的杂志式排版: 需要打破常规网格,让某些图片占据更大空间形成视觉焦点时,Grid 的二维定位能力是 Flexbox 无法比拟的。

总结与最佳实践:混合双打

在实际的项目开发中,我们通常不会二选一,而是**“混合双打”**:

  • 外层用 Grid:负责搭建整个页面的大框架(如 Header, Sidebar, Main, Footer 的位置)。
  • 内层用 Flexbox:负责具体组件内部的元素排列(如导航栏里的菜单项、卡片里的图文对齐、按钮组等)。

一句话决策指南: 如果你在排一行(或一列),用 Flexbox;如果你在排一张表(有行又有列),用 Grid

CSS动画效果

作者 Rkgua
2026年5月4日 21:40

CSS 动画的实现主要依赖于两大核心体系:Transition(过渡)Animation(关键帧动画)

简单来说,Transition 适合处理简单的“状态切换”(比如鼠标悬停时颜色平滑变化),而 Animation 则能实现复杂的、多步骤的自动动画(比如加载时的旋转图标、弹跳的小球)。

下面为你详细拆解它们的实现方式:

1. 基础过渡:Transition(过渡)

Transition 只能定义开始结束两个状态,当元素的属性发生变化时(比如通过 :hover 触发),浏览器会自动补全中间的过渡过程。

它通常需要配合 4 个子属性使用:

  • transition-property:要过渡的 CSS 属性(如 width, background-color,或 all 表示所有属性)。
  • transition-duration:过渡持续的时间(如 0.5s)。
  • transition-timing-function:过渡的速度曲线(如 ease, linear)。
  • transition-delay:延迟多久后开始过渡。

实现示例(鼠标悬停盒子变宽):

.box {
  width: 100px;
  height: 100px;
  background-color: red;
  /* 当宽度发生变化时,在0.5秒内平滑过渡 */
  transition: width 0.5s ease;
}

.box:hover {
  width: 300px; /* 鼠标放上去,宽度平滑变为300px */
}

2. 核心动画:@keyframes + Animation(关键帧动画)

这是 CSS 动画最强大的部分。它由两部分组成:

  1. @keyframes:相当于动画的“剧本”,定义动画从 0% 到 100% 各个阶段的状态。
  2. animation 属性:将“剧本”应用到元素上,并控制播放时长、次数、方向等。

实现步骤:

第一步:定义关键帧(剧本) 使用 from (0%) 和 to (100%),或者具体的百分比来定义中间状态。

@keyframes moveAndChange {
  0% {
    transform: translateX(0);
    background-color: red;
  }
  50% {
    transform: translateX(200px);
    background-color: blue;
  }
  100% {
    transform: translateX(0);
    background-color: red;
  }
}

第二步:将动画绑定到元素 animation 是一个简写属性,它包含了控制动画的 8 个核心子属性:

属性名 作用 常见取值
animation-name 绑定的关键帧名称 对应 @keyframes 后的名字
animation-duration 动画完成一次所需时间 1s, 500ms
animation-timing-function 速度曲线(节奏感) ease(默认), linear(匀速), ease-in-out
animation-delay 延迟多久开始 0.5s
animation-iteration-count 播放次数 1(默认), infinite(无限循环)
animation-direction 播放方向 normal(正向), alternate(来回交替)
animation-fill-mode 动画结束后的状态 forwards(保持最后一帧), backwards
animation-play-state 播放/暂停 running(默认), paused(暂停)

应用示例:

.box {
  width: 100px;
  height: 100px;
  /* 简写格式:名称 时长 速度曲线 延迟 次数 方向 填充模式 */
  animation: moveAndChange 2s ease-in-out infinite alternate;
}

3. 性能优化与最佳实践

在实现 CSS 动画时,为了保证页面流畅不卡顿,有几点需要特别注意:

  1. 优先使用 transformopacity: 改变元素的 width, height, margin, top/left 等属性会触发浏览器的重排(Reflow/Layout),非常消耗性能。而 transform(位移、旋转、缩放)和 opacity(透明度)通常只会触发合成(Compositing),可以交给 GPU 硬件加速,性能极高。
  2. 善用 will-change: 如果你预知某个元素马上要开始动画,可以给它加上 will-change: transform;。这会提前告诉浏览器:“这个元素要变了,请提前为它创建独立的渲染层”,从而让动画更丝滑。
  3. 避免过度复杂的动画: 动画的目的是提升用户体验,过多的动画反而会分散用户注意力。
昨天以前首页

ESModule和Commonjs模块的区别

作者 Rkgua
2026年5月3日 22:12

ES Module(ESM)和 CommonJS(CJS)是 JavaScript 中两种主流的模块化规范。ESM 是 ES6 推出的官方标准,而 CommonJS 则是 Node.js 早期采用的模块化方案。

以下从几个核心角度为你详细拆解:

1. 核心差异速览表

对比角度 CommonJS (CJS) ES Module (ESM)
基本语法 require() 导入,module.exports 导出 import 导入,export 导出
加载时机 运行时加载(动态) 编译时加载(静态)
加载方式 同步加载 异步加载(浏览器端)
导出本质 值的拷贝(浅拷贝) 值的引用(Live Binding)
代码优化 不支持 Tree Shaking 支持 Tree Shaking
顶层 this 指向 module.exports undefined(严格模式)

2. 深度解析各个角度

语法与规范来源

  • CommonJS:是社区提出的规范,主要用于 Node.js 服务端环境。它的语法非常直观,使用 require() 来引入模块,使用 module.exportsexports 来向外暴露功能。
  • ES Module:是 ECMAScript 2015 (ES6) 的官方语言标准,旨在统一浏览器和服务端的模块化。它使用 importexport 关键字,语法更加语义化,支持命名导出和默认导出。

加载时机与方式(最核心的区别)

  • CommonJS 是“运行时同步加载”:当你代码执行到 require() 这一行时,才会去加载并执行对应的模块文件。这种方式在服务端(读取本地硬盘文件)非常高效,但在浏览器端会因为网络请求阻塞页面渲染,所以浏览器不原生支持。
  • ES Module 是“编译时静态加载”:JS 引擎在解析代码的阶段(编译时),就会通过分析 importexport 语句,提前确定好模块之间的依赖关系。在浏览器中,ESM 默认是异步加载的,不会阻塞 HTML 的解析。

导出的本质:值拷贝 vs 值的引用 这是两者在实际开发中最容易产生 Bug 的差异点:

  • CommonJS(值拷贝):导出的是模块内部变量的一个副本。如果模块内部修改了这个变量,外部引入的地方是感知不到的。
    // CommonJS 示例
    // counter.js
    let count = 0;
    module.exports = { count };
    setTimeout(() => { count = 1; }, 1000); // 内部修改
    
    // main.js
    const { count } = require('./counter.js');
    console.log(count); // 0
    setTimeout(() => { console.log(count); }, 1100); // 依然是 0,因为是拷贝的旧值
    
  • ES Module(值的引用 / Live Binding):导出的是对模块内部变量的动态引用。当模块内部修改了变量,所有引入该变量的地方都会同步更新。
    // ESM 示例
    // counter.js
    export let count = 0;
    setTimeout(() => { count = 1; }, 1000); // 内部修改
    
    // main.js
    import { count } from './counter.js';
    console.log(count); // 0
    setTimeout(() => { console.log(count); }, 1100); // 1,实时同步了最新值
    

代码优化(Tree Shaking)

  • ES Module:由于它是静态的,打包工具(如 Webpack、Rollup、Vite)可以在打包阶段就分析出哪些代码被使用了,哪些没有。未被使用的代码(Dead Code)会被直接剔除,这个过程叫 Tree Shaking(摇树优化),能显著减小打包体积。
  • CommonJS:由于 require() 可以在代码运行时动态执行(比如写在 if 判断里),打包工具很难在编译阶段确定到底引用了哪些模块,因此无法有效支持 Tree Shaking。

运行环境与兼容性

  • CommonJS:Node.js 的默认模块规范,生态极其成熟。在浏览器中无法直接使用,必须通过 Webpack、Browserify 等工具打包转换。
  • ES Module:现代浏览器原生支持(通过 <script type="module">),也是现代前端框架(Vue3, React)和构建工具(Vite)的首选。Node.js 从 v12 版本后也开始支持 ESM,但需要在 package.json 中配置 "type": "module" 或使用 .mjs 后缀。

总结建议: 在现代前端开发和新的 Node.js 项目中,优先推荐使用 ES Module,因为它更标准、性能更好且支持代码优化。但在维护一些老旧的 Node.js 项目或依赖某些仅支持 CJS 的第三方库时,你依然会频繁接触到 CommonJS。

事件流模型是什么和DOM事件模型等关系

作者 Rkgua
2026年5月2日 21:03

(对事件流和DOM,BOM误解,所发出的疑惑) 问题涉及 JavaScript 事件机制的核心概念。我们来系统梳理:

“事件流模型”是什么?它和‘浏览器事件模型’、‘文档事件模型’有什么关系或区别?”

实际上,“浏览器事件模型”和“文档事件模型”并不是标准术语,它们很可能是对以下两个概念的模糊表述:

  • DOM 事件模型(Document Object Model Event Model):即 W3C 标准定义的事件处理规范。
  • 浏览器对事件流的具体实现:所有现代浏览器都遵循 W3C DOM 事件模型。

因此,更准确地说,我们应该讨论的是:


一、什么是 事件流模型(Event Flow Model)

事件流描述的是:当一个事件(如点击)发生时,浏览器如何在 DOM 树中传播这个事件的顺序

✅ W3C 标准定义的事件流包含 三个阶段

  1. 捕获阶段(Capturing Phase)

    • 事件从 windowdocumenthtmlbody → ... → 目标元素的父级
    • 目的:允许祖先元素“提前拦截”事件
  2. 目标阶段(Target Phase)

    • 事件到达实际触发的元素(即 e.target
    • 此时既可视为捕获结束,也可视为冒泡开始
  3. 冒泡阶段(Bubbling Phase)

    • 事件从目标元素 → 父元素 → ... → bodyhtmldocumentwindow
    • 这是最常用的阶段,事件委托就依赖它

🌰 举例:点击一个 <button>,事件会先“下潜”到 button(捕获),然后在 button 上触发(目标),再“上浮”回页面顶部(冒泡)。


二、什么是 DOM 事件模型(Event Model)

“事件模型”指的是 如何为元素绑定事件监听器的机制,历史上有三种主要模型:

模型 名称 特点 是否支持事件流
DOM0 级 原始模型 element.onclick = fn只能绑定一个处理函数简单、兼容性好 ❌ 不支持捕获✅ 部分浏览器以冒泡方式实现
IE 事件模型 IE 特有(已淘汰) attachEvent()只支持冒泡 ✅ 仅冒泡
DOM2 级 现代标准 addEventListener(type, handler, useCapture)可绑定多个监听器支持捕获/冒泡 ✅ 完整支持三阶段事件流

🔍 关键点

  • 事件流 是“事件如何传播”的过程
  • 事件模型 是“如何注册监听器”的接口规范
  • DOM2 级事件模型 实现了 完整的事件流

三、“浏览器事件模型” vs “文档事件模型”?——澄清误解

这两个说法并非官方术语,但可以这样理解:

说法 实际指代 说明
浏览器事件模型 浏览器对 W3C DOM 事件标准的实现 所有现代浏览器(Chrome、Firefox、Safari 等)都遵循 W3C DOM Level 2/3 Events 规范
文档事件模型 DOM(文档对象模型)中的事件处理机制 即 W3C 定义的 EventTarget.addEventListener 等 API

结论

它们本质上是同一套东西 —— 浏览器实现了 W3C 定义的 DOM 事件模型,而该模型规定了 事件流 的行为。


四、如何控制事件流?

虽然不能“关闭”事件流,但可以干预:

1. 在捕获 or 冒泡阶段监听

// 捕获阶段
parent.addEventListener("click", handler, true);

// 冒泡阶段(默认)
child.addEventListener("click", handler, false); // 或省略第三个参数

2. 阻止传播

e.stopPropagation(); // 阻止继续冒泡或捕获
e.stopImmediatePropagation(); // 还阻止同元素其他监听器执行

3. 判断当前处于哪个阶段

e.eventPhase === Event.CAPTURING_PHASE; // 1
e.eventPhase === Event.AT_TARGET; // 2
e.eventPhase === Event.BUBBLING_PHASE; // 3

五、总结:核心关系图

W3C DOM 事件标准
│
├── 定义了「事件模型」→ 如何绑定监听器(addEventListener)
│
└── 定义了「事件流」→ 事件传播的三阶段(捕获 → 目标 → 冒泡)
     │
     └── 浏览器(Chrome/Firefox等)实现了这一标准
          → 所谓“浏览器事件模型”就是 DOM 事件模型的实现

💡 记住

  • e.target 始终是最初触发事件的元素
  • e.currentTarget当前执行回调的监听器所绑定的元素
  • 默认监听的是冒泡阶段,这是事件委托的基础

掌握这些,你就真正理解了 JS 事件的底层逻辑!

❌
❌