01 · 前端基础(Frontend Basics)

📅 预计 70 分钟 | ⭐ = 高频考点 | 📌 中英术语见文末
✍️ 配套练习:网页练习 shengxia.dev/quiz?module=mv01


1.0 先给直觉:网页 = 房子

想象你要开一家店:HTML 是房子的骨架——墙有几面、门开在哪、房间怎么分,决定"有什么";CSS装修——墙刷什么颜色、门用什么材质、家具摆多宽,决定"长什么样";JavaScript店里的员工——有人推门就打招呼、点菜就下单、付款就找零,决定"怎么动"。

三者缺一不可:只有骨架的屋子没法住人,只装修没有员工的店不会营业,只有员工没房子就无处立足。前端开发,就是把这三件事配合好。

💡 记忆口诀:HTML 是骨头,CSS 是皮,JS 是大脑和四肢。


1.1 HTML:网页的骨架 ⭐

标签就是"积木"

HTML 用标签(tag)描述内容。一个标签通常成对出现:<标签名>内容</标签名>,前一个是开始标签,后一个是结束标签(多了个 /)。少数标签是自闭合的,比如图片 <img>

<!-- 注释:浏览器不显示,只给人看 -->
<h1>标题:页面的大标题</h1>      <!-- 一级标题 -->
<p>段落:一段普通文字</p>          <!-- paragraph 段落 -->
<a href="https://shengxia.dev">链接</a>  <!-- a = anchor 锚点,href 是目标地址 -->
<img src="logo.png" alt="网站logo">      <!-- img 图片,src 图片地址,alt 描述文字 -->

几个要点:

  • 属性(attribute)写在开始标签里,格式是 属性名="值",如 <a href="...">href
  • 元素(element)= 开始标签 + 内容 + 结束标签,是 HTML 的基本组成单位。
  • 标签可以嵌套<div> 里放 <p>,形成树状结构,称为 DOM 树

页面基本结构

一个标准网页必须有文档声明和 html/head/body 三层结构:

<!DOCTYPE html>          <!-- 告诉浏览器:这是现代 HTML 文档 -->
<html lang="zh-CN">      <!-- 根元素,lang 声明语言 -->
  <head>                 <!-- 头部:放"给浏览器看"的配置信息 -->
    <meta charset="UTF-8">  <!-- 字符编码,避免中文乱码 -->
    <title>我的第一个页面</title> <!-- 浏览器标签页上显示的文字 -->
  </head>
  <body>                 <!-- 主体:放"给用户看"的所有内容 -->
    <h1>欢迎</h1>
    <p>这是正文。</p>
  </body>
</html>

语义化:标签要"名正言顺"

不要所有内容都塞 <div>。用语义化标签(semantic tags)让结构有含义:<header> 页头、<nav> 导航、<main> 主内容、<footer> 页脚、<article> 文章。好处有两个:可读性好(人一看就懂结构),利于搜索引擎和辅助工具(屏幕阅读器能准确朗读)。这就像装修时把门牌写清楚,客人不用猜。

⚠️ 常见错误

  1. 标签忘记闭合<p>文字 少了 </p>,浏览器会自动"脑补",但嵌套会乱掉,后续样式容易出错。
  2. 乱嵌套<p><div>...</div></p>,块级元素套错,浏览器会悄悄拆开,结果和你预期不符。
  3. <img> 不写 alt:图片加载失败时显示空白,屏幕阅读器也无法描述,可访问性差。
  4. <meta charset="UTF-8"> 缺失:中文直接显示成乱码。

1.2 CSS:给网页化妆 ⭐

选择器:找到要改装的元素

CSS 规则 = 选择器(selector)+ 声明块。选择器决定"改谁",声明决定"改成什么"。

/* 选择器 { 属性: 值; } */
h1 {                  /* 标签选择器:选中所有 <h1> */
  color: #e8590c;     /* 文字颜色:十六进制橙色 */
  font-size: 28px;    /* 字号:28 像素 */
}

.title {              /* 类选择器:选中 class="title" 的元素,用 . 开头 */
  color: #2b8a3e;
}

#logo {               /* ID 选择器:选中 id="logo" 的元素,用 # 开头 */
  width: 120px;
}

常用选择器:标签选择器 div类选择器 .box(最常用,可复用)、ID 选择器 #header(唯一)、后代选择器 .nav a(.nav 里的 a)。优先级大致是 ID > 类 > 标签,记不住就用类选择器,最不容易踩坑。

盒模型:每个元素都是个盒子

每个元素都是一个盒子,从内到外四层:content(内容)→ padding(内边距)→ border(边框)→ margin(外边距)。

.card {
  width: 300px;
  padding: 20px;      /* 内容与边框之间的空隙 */
  border: 1px solid #ddd; /* 1 像素实线边框 */
  margin: 10px auto;  /* 上下 10px,左右自动居中 */
}

Flex 布局:一行摆平

想让一排元素横着排列、垂直居中,用 flex 最省事:

.nav {
  display: flex;            /* 开启弹性布局 */
  justify-content: space-between; /* 主轴:两端对齐 */
  align-items: center;      /* 交叉轴:垂直居中 */
}

display: flex 开启后,子元素自动变成一行排列,justify-content 管水平分布,align-items 管垂直对齐。这是现代前端最常用的布局手段。

⚠️ 常见错误

  1. 类选择器忘记写 .:写 title { ... },浏览器会当成"找 <title> 标签",样式不生效。
  2. 盒模型算错尺寸width: 300px + padding: 20px 实际占 340px,因为默认 box-sizing 是 content-box。想要"宽就是宽",加 box-sizing: border-box
  3. 忘记写分号color: red 后面没 ;,同一条规则后续的其他声明可能失效。
  4. ID 当类用id 页面中必须唯一,给多个元素用同一个 id 会导致选择器错乱,复用请用 class

1.3 JavaScript:让页面动起来 ⭐

变量与函数

JS 是网页的编程语言。变量用 let 声明,函数用 function 定义:

let count = 0;               // 声明一个可变的变量
const max = 10;              // 声明常量,不能重新赋值

function addOne() {          // 定义一个函数
  count = count + 1;         // 修改外部变量
  console.log(count);        // 在控制台打印,便于调试
}
addOne();                    // 调用函数,count 变成 1

数组与对象

数组是有序列表,对象是"名值对"集合,两者是前端数据的主力:

const todos = ['买牛奶', '交房租'];   // 数组,用 [] 
const user = { name: '小张', age: 20 }; // 对象,用 {}

todos.push('写作业');          // 向数组末尾追加
console.log(user.name);        // 读取对象属性,输出: 小张
user.age = 21;                 // 修改对象属性

DOM:HTML 在 JS 眼中的样子

浏览器把 HTML 解析成一棵 DOM 树(Document Object Model),JS 通过操作这棵树来改变页面。最常用的两个"找人"方法:

const btn = document.querySelector('#submit'); // 按 CSS 选择器找第一个匹配元素
const list = document.querySelectorAll('li');   // 找到所有 <li>,返回列表

btn.textContent = '提交中...';    // 修改元素文本
btn.classList.add('disabled');     // 添加一个 CSS 类

在 JS 里修改了,页面立即变化——这是后面理解"数据驱动视图"的直觉起点:JS 是唯一能真正改变页面的角色。

⚠️ 常见错误

  1. 没等页面加载完就操作 DOM<script> 放在 <head> 里时元素还不存在,querySelector 返回 null 然后报错。解决办法:把 <script> 放到 </body> 前,或用 DOMContentLoaded 事件。
  2. letconst 混用:该用 const 的用 let,代码意图不清晰;反过来用 const 声明了又要改,直接报错。
  3. 字符串拼接混乱"我的名字" + name 容易漏空格,模板字符串更稳:\我的名字是 ${name}``。
  4. ===== 混淆== 会做类型转换(1 == "1" 为 true),=== 要求类型也相同,写代码一律用 ===

1.4 事件:让页面"听见"用户 ⭐

addEventListener:给元素"装耳朵"

事件(event)是用户与页面的交互信号:点击、输入、鼠标移动……用 addEventListener 给元素绑定处理函数:

<button id="btn">点我</button>
<p id="msg"></p>
const btn = document.querySelector('#btn');
const msg = document.querySelector('#msg');

btn.addEventListener('click', function () {   // 监听 click 点击事件
  msg.textContent = '按钮被点击了!';
});

事件对象与常用事件

处理函数会收到一个事件对象 event,里面有触发元素、坐标等信息:

btn.addEventListener('click', (event) => {
  console.log(event.target);   // 被点击的元素
  console.log(event.type);     // 事件类型,这里是 "click"
});

// 输入事件:input 事件在用户每次输入时触发
const input = document.querySelector('#name');
input.addEventListener('input', (event) => {
  console.log(event.target.value);  // 当前输入框里的内容
});

常用事件:click(点击)、input(输入)、change(失去焦点且值变化)、submit(表单提交)、keydown(按键)。箭头函数 (event) => {...} 是普通函数的简写形式,现在的主流写法。

表单提交:拦截默认行为

点提交按钮页面会刷新,用 preventDefault() 拦下来做自己的处理:

const form = document.querySelector('#form');
form.addEventListener('submit', (event) => {
  event.preventDefault();        // 阻止默认的页面刷新
  console.log('表单提交,但页面没刷新');
});

⚠️ 常见错误

  1. addEventListener 写错在 HTML 里onclick="fn()" 这种写法能跑但耦合度高、难维护,推荐统一用 addEventListener
  2. 回调函数名带括号btn.addEventListener('click', fn()) 括号导致立即执行而非点击时执行,传 fn 不带括号。
  3. 忘记 preventDefault():表单提交后页面刷新,调试半天才发现状态全没了。
  4. 事件绑定在动态添加的元素上失效:后来才插入 DOM 的元素,不会自动拥有之前绑定的监听,需要绑定在它自己身上。

1.5 综合小案例:一个待办输入框

把前三节串起来,做一个"输入 → 点击 → 追加到列表"的小功能:

<input id="input" placeholder="输入内容">
<button id="btn">添加</button>
<ul id="list"></ul>
const input = document.querySelector('#input');
const btn = document.querySelector('#btn');
const list = document.querySelector('#list');

btn.addEventListener('click', () => {
  const text = input.value.trim();      // 读取输入并去掉首尾空格
  if (!text) return;                    // 空内容直接返回,不添加

  const li = document.createElement('li'); // 创建一个 li 元素
  li.textContent = text;                // 填入文本
  list.appendChild(li);                 // 挂到 <ul> 下
  input.value = '';                     // 清空输入框
});

这个案例的流程:找元素 → 绑定事件 → 读数据 → 改页面。注意一个关键动作——createElement 创建节点、appendChild 插入节点,这就是"用 JS 手动操作 DOM"的典型姿势。后面学 MVVM 时,你会发现框架帮你把这一步自动化了。

⚠️ 常见错误

  1. input.value 的时机不对:在点击事件里读,拿到的是最新值;在输入框外读,可能是空字符串。
  2. trim() 漏掉:用户只敲空格也算有内容,列表会多一条空白项。
  3. 没有清空输入框:添加完用户还得手动删,体验差,代码也不够"闭环"。

1.6 CSS 布局进阶:让元素"站对位置"

水平居中

让块级元素在容器里水平居中,最常用的是 margin: 0 auto——左右外边距自动平分剩余空间:

.box {
  width: 300px;
  margin: 0 auto;   /* 左右自动居中,前提是元素有确定宽度 */
}

文字居中则用 text-align: center;注意它管的是文字和行内元素,管不了块级元素本身。

垂直居中:flex 一招通吃

过去垂直居中要写不少"奇技淫巧",现在用 flex 最省心——父容器开启 flex,子元素自动居中:

.parent {
  display: flex;
  justify-content: center;  /* 水平居中 */
  align-items: center;      /* 垂直居中 */
  height: 200px;            /* 父容器要有高度,才能算出"居中" */
}

只要记住这一组:父容器 display: flex + 两条对齐属性,几乎所有居中需求都能解决。

网格布局 Grid:二维"切豆腐"

flex 擅长一维(一行或一列)排列;grid 擅长二维(行列同时控制),像切豆腐一样把容器切成格子:

.grid {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;  /* 三列,每列等宽 */
  gap: 12px;                            /* 格子间距 */
}

三列卡片、照片墙这类需求,grid 一行声明就搞定,子元素自动落进格子。

响应式:不同屏幕给不同样式

用**媒体查询(media query)**在屏幕宽度变化时切换样式,这是"响应式设计"的起点:

/* 默认样式:两列 */
.grid { grid-template-columns: 1fr 1fr; }

/* 屏幕宽度小于 600px 时:改成一列,更适合手机 */
@media (max-width: 600px) {
  .grid { grid-template-columns: 1fr; }
}

先写默认样式,再用 @media 覆盖小屏幕的样式,手机和电脑都能获得合理布局。

⚠️ 常见错误

  1. 垂直居中忘给父容器高度:父元素没有高度时"居中"无从谈起,子元素还是从顶部开始。
  2. text-align: center 想居中块级元素:它只对文字/行内元素生效,块级元素要用 margin: 0 auto 或 flex。
  3. 媒体查询写错断点:宽度条件写反、或覆盖顺序放错,小屏样式没生效,检查 max-width / min-width 的方向。
  4. grid 和 flex 混用想当然:先问"这是一维还是二维布局",一维用 flex,二维用 grid。

1.7 开发者工具:前端调试的"三板斧"

浏览器控制台

按 F12 打开开发者工具,**Console(控制台)**是你最好的伙伴:

  • console.log() 打印变量,确认数据是什么。
  • 看到红色报错先读第一行,它指向出错的文件与行号。
  • 报错信息里 xxx is not defined = 变量名拼错或没声明,Cannot read properties of null = 元素没找到。
console.log('当前值:', count);   // 打印,观察运行过程

元素面板与 Styles

**Elements(元素)**面板可以选中页面元素,右侧直接看到它的 HTML 和所有 CSS 规则。想试一个样式效果,不用改代码——在面板里临时改,满意了再写进文件。这是排查"样式为什么不生效"的最快路径。

网络面板

**Network(网络)**面板列出页面所有请求。页面资源加载失败、接口报错时,看这里:红色项就是请求失败,点进去能看状态码(404 找不到、500 服务器错误)。它帮你区分"是前端写错,还是服务器那边的问题"。

⚠️ 常见错误

  1. 报错只截图最后一行:完整报错的第一行才指向问题位置,贴全报错更好排查。
  2. 样式不生效就瞎猜:用 Elements 面板看规则有没有被其他样式覆盖,或选择器有没有匹配上。
  3. 不看 Network 就说是前端 bug:资源 404、接口 500 都可能来自服务器或路径,先看请求结果再下结论。

📌 记忆口诀

  • HTML / CSS / JS:骨头、皮、大脑,三件套各司其职。
  • 盒模型:从里到外——内容、内边距、边框、外边距,四兄弟围成一圈。
  • 选择器优先级:ID 最狠,类次之,标签最弱;写代码多用类。
  • 改页面三连querySelector 找人,addEventListener 装耳朵,改属性就变。

📌 双语术语表(本讲)

中文 English 记忆点
标签 / 元素 tag / element 标签成对出现
属性 attribute 写在开始标签里
选择器 selector 找到要改的元素
盒模型 box model 内容/内边距/边框/外边距
弹性布局 flexbox display: flex
文档对象模型 DOM HTML 的树形结构
变量 / 常量 variable / constant let / const
数组 / 对象 array / object [] / {}
事件 event 用户与页面的交互信号
事件对象 event object event.target
节点 node DOM 树上的一个元素

⭐ 本讲考点清单

  1. HTML 基本结构:<!DOCTYPE html><html>/<head>/<body>
  2. 常见标签与属性:a/hrefimg/src/altph1~h6
  3. 语义化标签的意义与常见用法
  4. 选择器:标签、类、ID、后代,优先级 ID > 类 > 标签
  5. 盒模型四层结构与 box-sizing: border-box
  6. flex 布局:display: flex + justify-content + align-items
  7. JS 变量 let/const、函数、数组、对象基本语法
  8. DOM 操作:querySelectorcreateElementappendChildtextContent
  9. 事件:addEventListenerevent.preventDefault()、常用事件类型
  10. 综合流程:找元素 → 绑事件 → 读数据 → 改页面