1.css布局整体布局从大到小用那种方式,系统性布局的方式了解吗?
核心思想:从大到小,由外而内
推荐采用由外向内的顺序。这种方式能确保页面的骨架稳定,避免局部细节撑破容器。
- 全局骨架: 确定大块区域。 通常使用 CSS Grid,因为它是二维布局,最擅长定义"框架"。
Grid 优势: 你只需在一个父级容器上定义
grid-template-columns和grid-template-rows。 这就像给页面打了一个硬性的"钢筋地基",无论子元素怎么变,格子(Cell)的大小是预设好的。
- 区域模块(Component Layout): 在大框架内划分功能区。通常使用 Flexbox,因为它是一维布局,处理对齐和分配剩余空间最灵活。
既然 Grid 负责了"外墙和承重墙"的稳定性,那么 Flexbox 就是"室内装修"和"家具摆放"的神器。
- 为什么组件级布局首选 Flexbox? 在大框架(Grid)中,每个格子的大小通常是相对固定的(比如 30% 或 1fr)。 但组件内部的内容(如导航链接、头像、标签、按钮)往往是不可预测的。 内容驱动(Content-Driven): Flexbox 默认是"内向外"的。 它会询问子元素:"你有多大?"然后根据剩余空间决定如何伸缩。
一维控制的简单性: 组件通常只有水平或垂直一个方向。用 Flexbox 处理这种局部排列,代码量更少,语义更清晰。 3. 原子组件(Atomic Elements): 处理具体内容(文本、图标、按钮)。使用 inline-flex、margin/padding 或 gap。 之前的大多数原子组件(按钮、标签、输入框)本质上是**行内块(inline-block)**元素。
- 痛点: 传统的 inline-block 会受到 HTML 源代码中空格/换行符的影响,产生神秘的 4px 间隙;且垂直对齐极其困难。
解决方案: 使用 display: inline-flex;。
容器化对齐: 它让组件内部的图标和文字能够通过 align-items: center; 完美垂直居中。
尺寸自适应: 它既能像 inline 元素一样随行流动,又具备 Flex 容器对内部元素的精密控制力。
一维布局和二维布局了解多少? flex呢?
一维布局 (Flexbox)
- 定义: 一次只能处理一个轴线(主轴 main axis 或交叉轴 cross axis)。虽然 Flex 可以折行(flex-wrap),但每一行都是相互独立的。
底层逻辑: 内容驱动。它会根据子元素的尺寸和设定的伸缩比例(flex-grow/shrink)来动态分配空间。
适用场景: 组件内部元素对齐、导航栏、侧边栏文字与图标排列、等高卡片等。
txt
Flexbox 的"自生自灭"模式 (一维)
当第一行排满 3 个标签,剩下的 2 个标签掉到第二行时,第二行完全不看第一行是怎么排的。
第一行: 有 3 个标签,它们平分了空间,左右撑满。
第二行: 只有 2 个标签。因为 space-between 的作用,这两个标签会一个死磕左边,一个死磕右边。
结果: 第二行的第二个标签,无法和第一行的第二个标签垂直对齐。中间会空出一大块"迷之空白"。
Flexbox 的每一行都是一个'独立王国'。它只管分配自己那一行的剩余空间,管不到楼上或楼下。
二维布局 (Grid)
- 定义: 同时处理行(Row)和列(Column)。
底层逻辑: 布局驱动。它先在父级定义好一个"网格模板",然后将子元素放入指定的"格点"或"区域"中。
适用场景: 复杂的页面大骨架、非对称布局(如报刊杂志排版)、需要元素跨行且跨列重叠的场景。
txt
Grid 的"严丝合缝"模式 (二维)
如果我们用 display: grid; 并定义 grid-template-columns: repeat(3, 1fr);(分成三列)。
第一行: 占满 3 个格子。
第二行: 虽然只有 2 个标签,但它们必须乖乖待在第一列和第二列的格子里。
结果: 第二行的标签会和第一行的标签垂直对齐。第三列的格子会空出来,但布局不会乱。
Grid 的核心逻辑是'先定结构,后填内容'。它建立了一个全局的垂直坐标系(Track),强制子元素跨行共享同一套列约束,从而确保了布局在纵向维度上的绝对严整。
总结
"如果我的设计要求内容自然流动,不在乎上下对齐(比如搜索关键词标签),我用 Flexbox。"
想象一下手机淘宝或美团的搜索历史记录,或者社交媒体上的话题标签。 "如果我的设计要求整齐的列感(比如标准的商品列表页),即使内容不够多,我也要保证它垂直对齐,那我一定用 Grid。"
这个"对不齐"的痛点,就是理解 一维Flex与二维Grid最直观的钥匙。
flex布局了解多少? 解决了什么问题?
Flexbox 的本质意义在于,它将布局从'静态的像素计算'转变为'动态的空间协商'。 它让容器具备了分配空间和对齐子元素的能力,从而真正实现了响应式设计中的'流动性'。
-
A. 垂直居中(The Vertical Center Problem) 以前: 需要用到 display: table-cell、计算 line-height 或者使用复杂的 position: absolute 加 transform 偏移。
-
Flex: 只需 align-items: center。这是最直观、最优雅的工业级解决方案。
-
B. 空间的等分与自动填充(Flexibility) 以前: 为了让三个按钮平分容器,必须写死 width: 33.33%。如果增加一个按钮,所有 CSS 都要重写。
-
Flex: 使用 flex: 1。无论容器里有几个元素,它们都会自动缩放并完美平分剩余空间。
-
C. 响应式的顺序与流向(Order & Direction) 以前: HTML 结构决定了显示顺序。如果移动端想把侧边栏放到顶部,必须改动 DOM 结构。
Flex: 拥有 order 属性和 flex-direction: column-reverse。你可以在不改变 HTML 的情况下,通过 CSS 彻底翻转页面的视觉逻辑。
- D. 等高布局(Equal Height Columns) 以前: 如果一排卡片中,某个卡片文字多、某个文字少,它们的底部是参差不齐的。
Flex: 默认行为就是 align-items: stretch,所有子元素会自动拉伸到与最高的那一个对齐。
但是Flex还是有缺点的 在极度复杂的超长页面中,深层嵌套的 Flex 可能会引起浏览器多次重排(Reflow),导致滚动卡顿。 如果是网格对齐的话 会使用 CSS Grid,因为无法感知到列的概念 与旧版不兼容。
你觉得typescript解决了什么问题?你觉得它用什么方式解决的?
解决了什么问题
- 痛点1: 很多错误(比如 Cannot read property 'xxx' of undefined)只有在程序运行到那一行时才会报错。
TS 的价值: 将这类错误从运行阶段提前到了编译阶段。你还没运行代码,编辑器就红线报错了。
- 痛点2: 在 JS 中重构一个核心函数的参数名,你得全局搜索字符串,战战兢兢地改,生怕漏掉一个地方导致全线崩溃。
TS 的价值: 有了类型系统,重构变得极其简单。修改一处类型,编译器会自动指出所有受影响的代码,实现了"所见即所得"的安全重构。
用什么方式解决的?
- 静态类型检查器 (Static Type Checker) 这是 TS 的核心引擎。它在代码执行前进行控制流分析。它不仅检查变量类型,还能推断出你代码逻辑中的死角。 "类型推导(Type Inference)"。TS 不要求你到处写类型,它能根据上下文聪明地猜出类型,在保持开发效率的同时提供保护。
- 结构化类型系统 (Structural Typing / Duck Typing) JS 的本质是灵活的,TS 并没有强行引入 Java 那种严格的名义类型。
方式: TS 使用"鸭子类型"。只要一个对象的结构符合要求,它就是合法的。
编译器不关心你的对象是从哪个类 new 出来的,它只关心你的对象里有没有我需要的属性。
在 Java 中(名义类型/Nominal Typing): 你必须显式地写 class Person implements Named。如果你传一个普通的 Object 进去,即便它有 name 属性,Java 也会报错,因为它没"名分"。
在 TS 中(结构化类型): 我直接传一个字面量 { name: "Gemini", age: 1 } 进去。TS 检查发现:嗯,你有 name 且是 string,通过!至于你有没有多余的 age,或者你是不是某个类的实例,它不在乎。
意义: 这完美适配了 JS 的动态特性,让 TS 既严谨又不会像 Java 那样死板。
"Java 的类型系统是基于'血缘'的,必须有明确的继承关系才能兼容; TypeScript 的类型系统是基于'形状'的。只要两个对象的'形状'(Shape)一致,它们就是兼容的。
这种设计是因为 JS 本质上是处理数据的脚本语言,结构化类型系统(Structural Typing)让 TS 在不破坏 JS 灵活性前提下,实现了工程级的类型安全。它关注的是数据契约,而不是身份标签。"
"如果我传的对象比接口要求的属性多,会报错吗?"
你可以专业地回答: 如果是变量赋值: 允许。只要"满足最小值"即可(协变性)。 如果是直接传对象字面量: TS 会触发 "额外属性检查"(Excess Property Checks) 报错,防止你拼写错误(比如把 name 写成 nane)。
泛型解决了什么问题?你觉得它具体用了哪种思想?
泛型解决了什么问题
一句话总结 :解决了"代码复用"和"类型安全"打架的问题。不用再写一堆重复的代码,也不用担心 any 导致程序报错。
-
假设你要写一个简单的工具函数:"给我什么,我就还给你什么"(Identity Function)。
-
场景 A:为了"类型安全",放弃"复用" 你为数字写一个,为字符串写一个:
TypeScript
function getNumber(item: number): number { return item; }
function getString(item: string): string { return item; }
结果: 非常安全,绝不会出错。
代价: 如果有 100 种类型,你要写 100 遍。代码复用性极差。
场景 B:为了"复用",放弃"安全"(使用 any) 你写一个万能函数,接受 any,返回 any:
TypeScript
function getAnything(item: any): any { return item; }
const result = getAnything("Hello");
// 此时 result 的类型是 any,你甚至可以把它当数字去调用 .toFixed()
result.toFixed(); // ❌ 运行报错!但 TS 编译时不报错
结果: 复用性无敌,一行代码搞定所有需求。
代价: 你失去了 TS 的保护。any 就像是个"黑洞",它吞噬了所有类型信息。编译器不知道返回值是什么,只能祈祷运行时别崩溃。
运用了什么思想
- 思想一:参数化
以前我们只把"数值"当参数传给函数。 现在,我们把**"类型"也当成一种参数传给函数。
"泛型就是给'类型'开了一个后门,让我们可以像传递变量一样传递类型。"
- 思想二:抽象与契约
我不确定你传什么,但我可以要求你必须符合某种规则。 比如:我不限制你往盒子里装什么,但你装的东西必须得有体积(以便我计算运费)。
在代码里就是:<T extends { length: number }>。
"泛型不是无限制的自由,而是一种'带约束的抽象'。"
总结
泛型就是 延迟确定的思想。写代码的时候先"占个位",等真正用的时候再填入具体的类型。
介绍一下你对函数式编程的认识
函数式编程是一种声明式的编程范式。
-
命令式编程(Imperative): 关注过程。就像做菜说明书:先开火,再倒油,炒 5 分钟。
-
函数式编程(FP): 关注映射。它认为程序就是一系列数学函数的组合。给定输入 <math xmlns="http://www.w3.org/1998/Math/MathML"> A A </math>A,永远得到输出 <math xmlns="http://www.w3.org/1998/Math/MathML"> B B </math>B。
"函数式编程的本质是将计算过程抽象为一系列嵌套的函数调用,它把'状态变化'视为避之不及的副作用,追求逻辑的纯粹与可预测性。"