diff --git a/docs/technical-development/React.md b/docs/technical-development/React.md new file mode 100644 index 0000000..af0974d --- /dev/null +++ b/docs/technical-development/React.md @@ -0,0 +1,12 @@ +--- +title: React 学习资料 +status: unread +direction: technical-development +--- + +# React 学习资料 + +## 课程讲义 + +- [React(第一次)](assets/react-session-1.pdf) +- [React(第二次)](assets/react-session-2.pdf) diff --git a/docs/technical-development/assets/CSS.pdf b/docs/technical-development/assets/CSS.pdf new file mode 100644 index 0000000..23f77b3 Binary files /dev/null and b/docs/technical-development/assets/CSS.pdf differ diff --git a/docs/technical-development/assets/HTML.pdf b/docs/technical-development/assets/HTML.pdf new file mode 100644 index 0000000..e82e0bd Binary files /dev/null and b/docs/technical-development/assets/HTML.pdf differ diff --git a/docs/technical-development/assets/react-session-1.pdf b/docs/technical-development/assets/react-session-1.pdf new file mode 100644 index 0000000..b162a9d Binary files /dev/null and b/docs/technical-development/assets/react-session-1.pdf differ diff --git a/docs/technical-development/assets/react-session-2.pdf b/docs/technical-development/assets/react-session-2.pdf new file mode 100644 index 0000000..83cd948 Binary files /dev/null and b/docs/technical-development/assets/react-session-2.pdf differ diff --git a/docs/technical-development/backend-database-mysql-prisma.md b/docs/technical-development/backend-database-mysql-prisma.md index 5ff7d83..966518f 100644 --- a/docs/technical-development/backend-database-mysql-prisma.md +++ b/docs/technical-development/backend-database-mysql-prisma.md @@ -6,11 +6,42 @@ direction: technical-development # 数据库、MySQL 与 Prisma -## 关系型数据库 +> 本文整合自“产研后端第二次内训-数据库入门”讲义(作者:仙人掌),并补充了可直接练习的 SQL 和 Prisma 示例。 -数据库保存结构化数据,表由行和列组成。主键唯一标识一行,外键表达表之间的关系。常见关系包括一对一、一对多和多对多。 +## 数据库是什么 + +数据库是用来保存和管理数据的软件系统。它帮助程序有条理地存储、查询和修改数据,而不必把所有内容都塞进普通文本文件中。 + +### 常见的数据存储方式 + +- **关系型数据库(重点掌握)**:数据按表组织,表由行和列组成。表可以通过主键和外键建立关系。常见系统有 SQLite、MySQL、SQL Server 和 PostgreSQL。结构清晰,适合数据之间有明确关系的业务。 +- **文档数据库(延伸了解)**:常以 JSON 文档保存数据。不同文档可以有不同字段,结构较灵活,适合字段会随业务变化的场景。 +- **键值存储(了解)**:按 `key -> value` 保存和读取数据。Redis 是常见例子。原讲义此处另有示例文字 `Redl/sql-tutorial.html`,看起来不是有效链接,因此只保留为原文备注。 + +本篇重点学习关系型数据库、MySQL、SQL 和 Prisma。 + +## 关系型数据库基础 + +表可以理解为一组结构相同的记录。每一行是一条记录,每一列描述一种属性。以待办事项为例: + +| id | title | completed | +| --- | --- | --- | +| 1 | 阅读文档 | false | +| 2 | 完成练习 | true | + +- **主键**(Primary Key)唯一标识一行,例如 `id`。 +- **外键**(Foreign Key)引用另一张表的主键,用来表示表之间的关系。 +- 常见关系有一对一、一对多和多对多。例如,一个用户可以有多条待办事项,就是一对多关系。 + +列需要选择合适的数据类型,例如整数 `INT`、字符串 `VARCHAR`、布尔值 `BOOLEAN` 和时间 `TIMESTAMP`。约束用于限制数据,例如 `NOT NULL` 表示不能为空,`DEFAULT` 指定默认值。 + +## SQL 入门 + +SQL 是操作关系型数据库的常用语言。基本流程包括创建数据库和表、写入数据、查询数据、修改数据和删除数据。常见命令有 `CREATE`、`SELECT`、`INSERT`、`UPDATE` 和 `DELETE`,合称 CRUD(创建、读取、更新、删除)。 ```sql +CREATE DATABASE training; + CREATE TABLE todo ( id INT PRIMARY KEY AUTO_INCREMENT, title VARCHAR(200) NOT NULL, @@ -18,14 +49,57 @@ CREATE TABLE todo ( created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ); -SELECT id, title FROM todo WHERE completed = FALSE ORDER BY created_at DESC; +INSERT INTO todo (title) VALUES ('阅读数据库文档'); + +SELECT id, title +FROM todo +WHERE completed = FALSE +ORDER BY created_at DESC; + +UPDATE todo +SET completed = TRUE +WHERE id = 1; + +DELETE FROM todo +WHERE id = 1; +``` + +`WHERE` 用来筛选目标记录。执行 `UPDATE` 或 `DELETE` 前要确认筛选条件;漏掉 `WHERE` 可能会修改或删除整张表的数据。程序写入数据时使用参数化查询,不要把用户输入直接拼接进 SQL,以避免 SQL 注入。索引应服务于实际查询;索引太多会增加写入和维护成本。 + +SQL 数据类型、主键和外键约束、`SELECT ... WHERE`、`INSERT INTO`、`UPDATE` 和 `DELETE` 都是后端开发的基础内容。讲义推荐的 SQL 入门资料: + +- [MySQL 创建数据库教程](https://www.runoob.com/mysql/mysql-create-database.html) +- 原讲义还列有一个 SQL 教程地址:`https://www.runoob.com/sqzju课程:数据库系统`。该地址格式异常,按原文记录,未转换成可点击链接。 +- 深入学习关系型数据库可查阅《数据库系统概念》。原讲义中的第三方镜像地址为 `https://zh.singlelogin.re/book/5668770/6f85ac/%E6%95%B0%E6%8D%AE%E5%BA%93%E7%B3%BB%E7%BB%9F%E6%A6%82%E5%BF%B5-%E5%8E%9F%E4%B9%A6%E7%AC%AC6%E7%89%88.html`;按原文保留为文字,不设为可点击入口。 + +## MySQL:服务端与连接 + +MySQL 通常以后台服务的形式运行,负责接收请求并读写数据。Workbench 是图形化客户端;命令行工具也是客户端。客户端连接 MySQL 服务后,发送 SQL,由服务端执行并返回结果。Windows 上安装 MySQL 时,可以分别理解为后台服务和用于连接它的工具。 + +连接数据库时需要指定协议、用户名、密码、主机、端口和数据库名称。常见连接字符串形式如下: + +```text +mysql://USER:PASSWORD@HOST:PORT/DATABASE +``` + +例如: + +```text +mysql://janedoe:mypassword@localhost:5432/mydb?connection_limit=5 ``` -写入数据时使用参数化查询,避免把用户输入拼接进 SQL。索引应服务于真实查询,过多索引会增加写入成本。 +其中 `USER` 和 `PASSWORD` 是登录凭据,`HOST` 和 `PORT` 指向数据库服务,`DATABASE` 是要使用的数据库,问号后的部分是连接参数。上例中的用户名和密码只是示例。不要把包含真实密码的连接字符串提交到 Git 仓库。 + +讲义列出的 MySQL 安装参考文章如下,具体步骤可能因系统和版本而异: + +- [MySQL 安装参考(CSDN)](https://blog.csdn.net/bobo553443/article/details/81383194) +- [MySQL 安装参考(博客园)](https://www.cnblogs.com/oukele/p/10642061.html) -## Prisma +## ORM 与 Prisma -Prisma 用 schema 描述数据模型,并生成类型安全的客户端: +ORM 是 Object-Relational Mapping(对象关系映射)。它把关系型数据库中的表映射为程序中的类或模型,把表中的行映射为对象,让程序能通过代码读写数据,而不必在每处都手写 SQL。TypeORM 是一种 ORM 工具,感兴趣时可阅读[相关文档](https://typeorm.bootcss.com/)。 + +Prisma 是数据库工具集,包含 ORM 能力,并根据 schema 生成类型安全的客户端。开发者在 Prisma schema 中描述模型,再通过客户端查询和修改数据: ```prisma model Todo { @@ -36,9 +110,42 @@ model Todo { } ``` -典型流程:配置 `DATABASE_URL` → 编写 schema → 创建迁移 → 生成客户端 → 在服务层调用客户端。迁移文件应提交到 Git,生产环境不要随意重置数据库。 +典型流程是:配置 `DATABASE_URL` → 编写 schema → 创建数据库迁移 → 生成客户端 → 在服务层调用客户端。迁移(migration)用于记录并应用数据库结构的变化,例如创建表或修改列。迁移文件应提交到 Git;不要在生产数据库上随意重置或删除数据。 + +讲义列出的 Prisma 参考资料: + +- [Prisma 中文文档站](https://prisma.nodejs.cn/) +- [MySQL 数据库配置](https://prisma.nodejs.cn/orm/overview/databases/mysql) +- [从头开始:TypeScript 与 MySQL](https://prisma.nodejs.cn/getting-started/setup-prisma/start-from-scratch/relational-databases-typescript-mysql) +- [Prisma Client 增删改查(CRUD)](https://prisma.nodejs.cn/orm/prisma-client/queries/crud) + +## 综合练习:题目管理系统 + +实现一个题目管理系统。程序可以从命令行接收命令,也可以从文件读取命令;为了方便观察执行结果,可以在处理每条命令后暂停约一秒。命令的具体输入格式可以自行设计,但功能需要完整。 + +基础功能: + +1. **添加单选题**:输入题干、选项数量、各选项和正确选项;创建成功后输出题目 ID。 +2. **添加多选题**:输入题干、选项数量、各选项、正确答案数量和正确选项;创建成功后输出题目 ID。 +3. **删除题目**:根据题目 ID 删除一题。 +4. **查询题目**:根据题目 ID 展示题干和选项。 +5. **回答题目**:输入题目 ID 和答案,输出 `Right Answer` 或 `Wrong Answer`。 + +基础质量要求: + +- 能完成上述操作。 +- 代码结构清楚、命名易懂,并写必要且有用的注释。 + +进阶要求(选做): + +- 修改题目:根据题目 ID 修改题干、选项或答案。 +- 使用日志框架,并将日志输出到文件。 +- 支持 `insert question filename.json` 一类的命令,从 JSON 文件读取并添加一道题。 +- 支持 `execute filename.txt`,从文本文件批量读取并执行多条管理命令。也可以扩展为读取文件中的数据并一次性批量导入。 + +开始实现前,先设计题目和选项的数据结构,再决定表之间的关系。一个题目有多个选项,通常可拆成题目表和选项表;查询或回答时通过题目 ID 找到相应选项和正确答案。 -## 练习 +## 其他练习 - [ ] 为“用户—待办”设计表结构,并说明主键和外键。 - [ ] 写出查询未完成待办、创建待办和更新状态的 SQL。 diff --git a/docs/technical-development/backend-oop-typescript.md b/docs/technical-development/backend-oop-typescript.md index 58d2a8e..253c209 100644 --- a/docs/technical-development/backend-oop-typescript.md +++ b/docs/technical-development/backend-oop-typescript.md @@ -6,55 +6,330 @@ direction: technical-development # 后端面向对象与 TypeScript -面向对象把问题中的实体抽象为对象:对象拥有状态(属性)和行为(方法),相同结构的对象由类描述。 +> 本文整合自“产研后端第一次内训-面向对象程序设计”讲义(作者:仙人掌),并补充了 TypeScript 示例。讲义中的 Flutter/Dart 代码截图用于说明代码规范;本文用 TypeScript 重写相关示例。 -## 类、封装与继承 +## 写代码时先注意这些 + +### 命名与注释 + +- 变量和函数使用 `camelCase`,例如 `playerName`、`getPlayer()`。 +- 类、接口和类型使用 `PascalCase`,例如 `Player`、`Animal`。 +- 常量通常使用全大写加下划线,例如 `MAX_HP`。 +- 注释用来解释意图和复杂逻辑,不要逐行复述代码。普通行内说明使用 `//`,较长说明可以使用 `/* ... */` 或文档注释。 +- 用 `TODO` 标出尚未完成的功能,用 `FIXME` 标出已知问题,并写清具体事项;不要让它们代替真正的修复。 + +```ts +// TODO: 支持玩家切换武器 +// FIXME: 离开房间后需要重置当前房间状态 +``` + +### 结构、日志与测试 + +- 尽量减少多层嵌套。多个明确的分支可以用 `switch` 表达;把长函数拆成职责清楚的小函数。 +- 一行不要塞入太多逻辑,但也不必为了短行把一个表达式拆成许多行;优先保证容易阅读。 +- 调试时不要到处留下 `console.log`。项目中应选用日志框架,在关键流程按需要记录 `debug`、`info`、`warn` 或错误信息,并输出到合适的位置。 +- 功能完成后,在有余力时为关键逻辑补充单元测试,检查实际结果是否符合预期。 + +### npm 包管理器 + +JavaScript 和 TypeScript 项目常用 npm 管理依赖和运行脚本。讲义提供了两篇入门参考:[npm 包管理器文章(CSDN)](https://blog.csdn.net/2301_79985178/article/details/140573837)和[知乎专栏](https://zhuanlan.zhihu.com/p/686389408)。 + +## 面向过程与面向对象 + +面向过程(Procedure Oriented)关注解决问题的步骤:先把任务拆成函数,再按顺序调用这些函数。它开销小、执行直接,适合流程清楚、性能要求高的场景。 + +面向对象(Object Oriented)把问题中的实体抽象成对象,由对象保存状态并提供行为。它适合围绕业务实体组织较大的程序,便于分工和扩展。使用哪种方式要看问题本身;面向对象并不会自动让程序更快或更简单。 + +设计面向对象程序时,通常先找出需要操作的对象,再明确对象的属性、行为,以及对象之间的关系(也叫数据建模)。复杂业务中也可以先用 UML 图梳理角色和关系。 + +## 类、对象与实例 + +类描述一类对象共有的属性和方法;根据类创建出的具体对象叫实例。下面用汽车举例: + +```ts +class Car { + engine: string + + constructor(engine: string) { + this.engine = engine + } + + display(): void { + console.log(`发动机为:${this.engine}`) + } +} + +const car = new Car('Engine 1') +car.display() +``` + +`engine` 是属性,`display` 是方法,`new Car(...)` 创建了一个 `Car` 实例。 + +## 继承与方法重写 + +继承表示一个类在已有类的基础上扩展能力。已有类叫父类或基类,新类叫子类或派生类。TypeScript 使用 `extends` 声明继承;子类可以调用 `super` 访问父类构造函数或方法,也可以重写方法: + +```ts +class Printer { + print(): void { + console.log('父类的 print 方法') + } +} + +class StringPrinter extends Printer { + override print(): void { + super.print() + console.log('子类的 print 方法') + } +} + +const printer: Printer = new StringPrinter() +printer.print() +``` + +继承适合表达明确的“是一种”关系。若只是想共享少量能力,接口或组合通常更灵活。 + +## 封装与访问控制 + +封装把对象的状态和操作集中在类中,并限制外部随意改动内部状态。外部通过公开方法与对象交互,类可以在这些方法中检查输入并维持自身状态的有效性。 + +TypeScript 常用以下访问控制修饰符: + +- `public`:公开访问;默认访问级别。 +- `protected`:类自身和子类可以访问。 +- `private`:只允许定义它的类访问。 ```ts class Student { private grade = 0 - constructor(public readonly name: string, private readonly studentId: string) {} + constructor(public readonly name: string) {} setGrade(value: number): void { - if (value < 0 || value > 100) throw new Error('成绩必须在 0 到 100 之间') + if (value < 0 || value > 100) { + throw new Error('成绩必须在 0 到 100 之间') + } this.grade = value } - getGrade(): number { return this.grade } + getGrade(): number { + return this.grade + } } + +const student = new Student('小明') +student.setGrade(90) +console.log(student.getGrade()) +// student.grade = 101 // 编译错误:grade 是 private ``` -`private` 隐藏实现细节,公共方法提供受控接口。继承用 `extends` 表达“是一个”关系,子类通过 `super` 调用父类构造函数;如果只是共享能力,优先考虑接口和组合。 +`readonly` 属性只能在声明时或构造函数中赋值,之后不能重新赋值。接口中也可以声明只读属性和可选属性,见下文。 -## 接口与多态 +## 多态 + +多态指不同对象可以响应同一个操作,但各自给出不同实现。调用方使用共同的接口,不必知道对象内部的具体类型: ```ts -interface Notifier { send(message: string): void } +interface Notifier { + send(message: string): void +} class ConsoleNotifier implements Notifier { - send(message: string): void { console.log(message) } + send(message: string): void { + console.log(message) + } } + +function notify(notifier: Notifier, message: string): void { + notifier.send(message) +} + +notify(new ConsoleNotifier(), '任务完成') ``` -调用方只依赖 `Notifier`,因此可以替换具体实现。接口还能描述请求体、数据库记录等数据结构。 +同一个 `send` 调用可以由不同通知方式实现,例如控制台、邮件或其他服务。 + +## TypeScript 接口 + +TypeScript 的 `interface` 描述对象应具有的属性、方法及其类型。它能检查对象形状是否符合约定,让错误更早出现在编译阶段。接口本身不会生成运行时对象。 + +### 描述对象结构 + +```ts +interface User { + id: number + name: string + email: string +} + +const user: User = { + id: 1, + name: 'Alice', + email: 'alice@example.com', +} +``` + +`User` 规定对象要包含 `id`、`name` 和 `email`,并且类型要相符。 + +### 约束类的实现 + +类使用 `implements` 表示自己遵守某个接口。编译器会检查类是否提供了接口要求的属性和方法: + +```ts +interface Animal { + name: string + makeSound(): void +} + +class Dog implements Animal { + constructor(public name: string) {} + + makeSound(): void { + console.log('Woof!') + } +} + +const dog = new Dog('Buddy') +dog.makeSound() +``` + +### 描述函数类型 + +接口也可以约定函数的参数和返回值: + +```ts +interface Greet { + (name: string): string +} + +const sayHello: Greet = (name) => `Hello, ${name}` +console.log(sayHello('Alice')) +``` + +### 结构类型与鸭子类型 + +TypeScript 主要按结构判断类型:对象只要具有所需的属性和方法,就可以传给相应函数,不要求它必须继承某个特定类。这种方式也称为鸭子类型。 + +```ts +interface Point { + x: number + y: number +} + +function addPoints(p1: Point, p2: Point): Point { + return { x: p1.x + p2.x, y: p1.y + p2.y } +} + +const result = addPoints({ x: 3, y: 4 }, { x: 5, y: 1 }) +// addPoints({ x: 1 }, { x: 4, y: 3 }) // 编译错误:缺少 y +``` + +### 可选属性与只读属性 + +在属性名后加 `?` 表示该属性可以省略;加 `readonly` 表示初始化后不能重新赋值: + +```ts +interface Vehicle { + readonly make: string + model: string + year?: number +} + +const vehicle: Vehicle = { make: 'Toyota', model: 'Corolla' } +vehicle.model = 'Camry' // 可以修改 +// vehicle.make = 'Honda' // 编译错误:make 是只读属性 +``` + +### 接口继承 + +接口可以通过 `extends` 组合。子接口会包含父接口的要求,并能添加自己的属性: + +```ts +interface Person { + name: string +} + +interface Employee extends Person { + employeeId: number +} + +const employee: Employee = { name: 'Alice', employeeId: 12345 } +``` + +### 为第三方 JavaScript 库补充类型 + +有些 JavaScript 库没有内置 TypeScript 类型。可以通过类型声明描述库提供的对象和方法,让 TypeScript 代码获得类型检查。讲义将其列为扩展了解内容;实际使用时优先查找该库维护者提供的类型声明。 + +## 面向对象的主要特性 + +- **封装(Encapsulation)**:把数据和操作集中在对象中,通过明确的接口访问状态,避免外部代码随意改动内部实现。 +- **继承(Inheritance)**:让子类沿用并扩展父类的能力,适用于明确的类型层级。 +- **多态(Polymorphism)**:不同实现通过同一接口提供相同操作,调用方不必依赖具体实现。 + +## 面向对象设计原则:SOLID + +这些原则帮助代码保持职责清楚、便于扩展。它们是设计时的参考,不是每段代码都必须强行套用的规则。 + +- **单一职责原则(SRP, Single Responsibility Principle)**:一个类或模块聚焦一项职责,避免一个类包办许多互不相关的功能。 +- **开闭原则(OCP, Open-Closed Principle)**:对扩展开放、对修改关闭。新增客户端能力时,尽量通过抽象扩展,而不是反复改动稳定的服务端实现。 +- **里氏替换原则(LSP, Liskov Substitution Principle)**:子类应能替换父类使用,并遵守父类对行为的约定。例如,若所有员工都能参加年会抽奖,新员工也应遵守同一规则。 +- **依赖倒置原则(DIP, Dependency Inversion Principle)**:高层业务依赖抽象,具体实现依赖同一抽象;不要让核心逻辑直接绑定某个底层实现。 +- **接口隔离原则(ISP, Interface Segregation Principle)**:调用方不应依赖用不到的接口。把大而全的接口拆成调用方真正需要的小接口。 + +## 综合练习 + +下面两个作业来自讲义。重点是练习对象建模、接口、继承和设计原则;命令和输出可以自行调整。 + +### T1:龙与魔法(基础) + +用 TypeScript 实现一个简单的战斗规则。讲义认为此题的设计空间较大,建议有余力的同学挑战 T2。 + +角色与规则: + +- 玩家可以是战士(`Fighter`)、法师(`Mage`)或龙骑士(`Dragoon`)。 +- 怪物可以是兽人(`Orc`)、精灵(`Elf`)或龙(`Dragon`);怪物有血量。 +- 战士受到兽人攻击时,伤害减半。 +- 精灵受到法师攻击时,伤害减半。 +- 主程序创建若干玩家和怪物,让双方可以互相攻击,并能观察攻击后的血量等结果。 + +基础要求:代码风格清楚、注释有用,并能查看攻击后的结果。 + +选做扩展: + +- 给玩家增加护甲,不同类型的护甲提供不同效果。 +- 增加武器,例如剑(`Sword`)和法杖(`Staff`);玩家可装备或切换武器。武器有攻击力和伤害类型,例如物理或火焰,也可以设计更细的类型。 +- 增加规则:兽人受到物理攻击时伤害减半;精灵受到冰属性攻击时伤害减半;龙免疫物理和魔法攻击,但龙骑士攻击龙时可以造成双倍伤害。 +- 使用日志框架记录战斗过程并写入文件。 + +### T2:Adventure 命令行游戏(进阶) + +实现一个命令行冒险游戏。玩家要探索城堡中的房间,找到被关押的公主,并带她离开城堡。可以有多个楼层和多个房间;每种房间有自己的出口。 + +游戏规则: + +- 玩家从大厅开始。程序显示当前房间名称、出口数量和出口名称,例如: + + ```text + Welcome to the lobby. There are 3 exits: east, west and up. + Enter your command: + ``` -## SOLID 与代码规范 +- 玩家通过 `go east` 一类的命令选择出口,进入相邻房间后,程序继续显示该房间的信息。 +- 城堡中有多个房间,其中一间有怪物,怪物的具体位置未知。玩家进入怪物所在房间时,游戏结束。 +- 公主在一间秘密房间里。玩家找到她后会看到对话,并与她一起离开。 +- 离开城堡的唯一出口是大厅;找到公主后,玩家还需要找到返回大厅的路线。 +- 输入和输出都使用英文。 -- 单一职责:一个模块只有一个主要变化原因。 -- 开闭原则:增加行为时优先扩展,不随意修改稳定代码。 -- 里氏替换:子类应遵守父类的行为约定。 -- 接口隔离:小接口比一个包揽所有能力的大接口更易维护。 -- 依赖倒置:业务逻辑依赖抽象,基础设施实现抽象。 +基础要求:代码风格清楚、注释有用;至少有 3 种不同房间,房间总数至少为 5;公主和怪物的位置每次随机决定。 -变量和函数使用 `camelCase`,类、接口和类型使用 `PascalCase`。关键逻辑写注释,调试信息使用项目的日志工具。 +选做扩展:房间总数由用户输入或配置文件决定;使用日志框架并输出到文件;支持多层城堡。 -## 练习 +## 原讲义参考链接 -- [ ] 为命令行冒险游戏设计 `Room`、`Player` 和 `Monster` 类。 -- [ ] 用接口抽象存储层,让内存存储和数据库存储可以互换。 -- [ ] 写一个测试,验证成绩校验和异常信息。 +- [npm 包管理器文章(CSDN)](https://blog.csdn.net/2301_79985178/article/details/140573837) +- [npm 包管理器文章(知乎)](https://zhuanlan.zhihu.com/p/686389408) +- [面向对象设计原则(CSDN)](https://blog.csdn.net/qq_34760445/article/details/82931002) ## 学习衔接 -在[TypeScript 基础](environment-typescript.md)之后练习业务建模,再学习[HTTP、API 与爬虫](backend-http-api.md);需求关系可参考[UML 建模](../product-operations/uml.md)。 +先学习[TypeScript 基础](environment-typescript.md),再用这些概念练习业务建模,然后学习[HTTP、API 与爬虫](backend-http-api.md);需求和对象关系可参考[UML 建模](../product-operations/uml.md)。 diff --git a/docs/technical-development/frontend-html-css.md b/docs/technical-development/frontend-html-css.md index c8558db..5cdaa8d 100644 --- a/docs/technical-development/frontend-html-css.md +++ b/docs/technical-development/frontend-html-css.md @@ -6,23 +6,38 @@ direction: technical-development # HTML 与 CSS +HTML 负责页面内容和结构,CSS 负责外观和布局。浏览器读取两者后显示网页。做页面时,先用 HTML 把内容和层级写清楚,再用 CSS 调整样式。 + ## HTML:页面结构 -HTML 是标记语言,用元素表达页面结构。一个元素通常由开始标签、内容和结束标签组成;属性用于补充元素信息。 +HTML 是标记语言,用元素表达页面结构。大多数元素由开始标签、内容和结束标签组成,属性用于补充信息。新建页面时,可以从下面的基本结构开始: ```html -
-

训练进度

-

已完成 2 个节点

- 查看详情 -
+ + + + + + 训练进度 + + + +
+

训练进度

+

已完成 2 个节点

+ 查看详情 +
+ + ``` -语义化元素(如 `main`、`nav`、`article`、`button`)能帮助无障碍工具和后续维护。表单控件要有明确的 `label`,图片应提供有意义的 `alt` 文本。 +`class` 通常用于给一组元素添加样式,`id` 用于标记页面中一个特定元素。优先选择表达含义的元素,例如 `main`、`nav`、`article` 和 `button`,不要只用 `div` 包住所有内容。表单控件要有对应的 `label`,图片应提供说明内容的 `alt`。 + +配套资料:[HTML 讲义(PDF)](assets/HTML.pdf)。 ## CSS:页面样式 -CSS 通过选择器选择元素,并设置属性: +CSS 通过选择器找到 HTML 元素,再为它设置样式。下面的 `.card` 会选中 `class="card"` 的元素: ```css .card { @@ -36,22 +51,30 @@ CSS 通过选择器选择元素,并设置属性: .card h1 { color: #1769aa; } ``` -样式可以写在元素的 `style` 属性、页面的 `