diff --git a/docs/.vitepress/theme/components/appendix/web-basics/CssBoxModel.vue b/docs/.vitepress/theme/components/appendix/web-basics/CssBoxModel.vue index 3093fba..b04b877 100644 --- a/docs/.vitepress/theme/components/appendix/web-basics/CssBoxModel.vue +++ b/docs/.vitepress/theme/components/appendix/web-basics/CssBoxModel.vue @@ -1,39 +1,65 @@ @@ -73,41 +116,66 @@ diff --git a/docs/.vitepress/theme/components/appendix/web-basics/CssFlexbox.vue b/docs/.vitepress/theme/components/appendix/web-basics/CssFlexbox.vue index f8d92f1..d1b51ed 100644 --- a/docs/.vitepress/theme/components/appendix/web-basics/CssFlexbox.vue +++ b/docs/.vitepress/theme/components/appendix/web-basics/CssFlexbox.vue @@ -1,15 +1,41 @@ @@ -72,95 +116,188 @@ import { computed, ref } from 'vue' const directions = [ - { id: 'row', label: '水平' }, - { id: 'column', label: '垂直' } + { id: 'row', label: 'row(水平)' }, + { id: 'column', label: 'column(垂直)' } ] const justifies = [ - { id: 'flex-start', label: '靠左' }, - { id: 'center', label: '居中' }, - { id: 'space-between', label: '两端' } + { id: 'flex-start', label: 'flex-start' }, + { id: 'center', label: 'center' }, + { id: 'flex-end', label: 'flex-end' }, + { id: 'space-between', label: 'space-between' }, + { id: 'space-around', label: 'space-around' } +] +const aligns = [ + { id: 'stretch', label: 'stretch' }, + { id: 'flex-start', label: 'flex-start' }, + { id: 'center', label: 'center' }, + { id: 'flex-end', label: 'flex-end' } ] const wraps = [ - { id: 'nowrap', label: '不换行' }, - { id: 'wrap', label: '换行' } + { id: 'nowrap', label: 'nowrap' }, + { id: 'wrap', label: 'wrap' } ] const dir = ref('row') const justify = ref('flex-start') +const align = ref('stretch') const wrap = ref('nowrap') const boxStyle = computed(() => ({ display: 'flex', flexDirection: dir.value, justifyContent: justify.value, + alignItems: align.value, flexWrap: wrap.value, gap: '8px', - minHeight: dir.value === 'column' ? '140px' : '60px', - padding: '12px' + minHeight: dir.value === 'column' ? '240px' : '100px' })) + +const cssCode = computed(() => { + const parts = ['display: flex'] + if (dir.value !== 'row') parts.push(`flex-direction: ${dir.value}`) + if (justify.value !== 'flex-start') parts.push(`justify-content: ${justify.value}`) + if (align.value !== 'stretch') parts.push(`align-items: ${align.value}`) + if (wrap.value !== 'nowrap') parts.push(`flex-wrap: ${wrap.value}`) + return parts.join('; ') + ';' +}) diff --git a/docs/.vitepress/theme/components/appendix/web-basics/DomManipulator.vue b/docs/.vitepress/theme/components/appendix/web-basics/DomManipulator.vue index 7c5a77f..8eaeb83 100644 --- a/docs/.vitepress/theme/components/appendix/web-basics/DomManipulator.vue +++ b/docs/.vitepress/theme/components/appendix/web-basics/DomManipulator.vue @@ -1,48 +1,121 @@ @@ -50,178 +123,307 @@ diff --git a/docs/.vitepress/theme/components/appendix/web-basics/WebTechTriad.vue b/docs/.vitepress/theme/components/appendix/web-basics/WebTechTriad.vue index 3294923..aa5855e 100644 --- a/docs/.vitepress/theme/components/appendix/web-basics/WebTechTriad.vue +++ b/docs/.vitepress/theme/components/appendix/web-basics/WebTechTriad.vue @@ -1,9 +1,8 @@ @@ -62,9 +61,9 @@ import { computed, ref } from 'vue' const modes = [ - { id: 'html', label: 'HTML' }, - { id: 'css', label: 'CSS' }, - { id: 'js', label: 'JS' } + { id: 'html', label: 'HTML', icon: '结构' }, + { id: 'css', label: 'CSS', icon: '样式' }, + { id: 'js', label: 'JavaScript', icon: '行为' } ] const current = ref('html') @@ -72,9 +71,9 @@ const clicks = ref(0) const selectedPart = ref('h1') const codeTitle = computed(() => { - if (current.value === 'html') return 'HTML:定义结构' - if (current.value === 'css') return 'CSS:定义样式' - return 'JS:定义行为' + if (current.value === 'html') return 'HTML 代码' + if (current.value === 'css') return 'CSS 代码' + return 'JavaScript 代码' }) const codeLines = computed(() => { @@ -87,12 +86,15 @@ const codeLines = computed(() => { } if (current.value === 'css') { return [ - { key: 'h1', text: '.hero { color: #0ea5e9; font-size: 20px; }' }, - { key: 'p', text: '.desc { color: #666; }' }, - { key: 'btn', text: '.cta { background: #0ea5e9; color: #fff; }' } + { key: 'h1', text: '.hero {' }, + { key: 'h1', text: ' color: #0ea5e9;' }, + { key: 'h1', text: ' font-size: 20px;' }, + { key: 'h1', text: '}' }, + { key: 'btn', text: '.cta { background: #0ea5e9; }' } ] } return [ + { key: 'btn', text: "const btn = document.querySelector('.cta')" }, { key: 'btn', text: "btn.addEventListener('click', () => {" }, { key: 'btn', text: ' count++' }, { key: 'btn', text: " btn.textContent = '点我 (' + count + ')'" }, @@ -102,12 +104,24 @@ const codeLines = computed(() => { const steps = computed(() => { if (current.value === 'html') { - return ['浏览器读取标签,知道"这是标题、这是按钮"', '按默认样式显示(所以看起来朴素)'] + return [ + '浏览器解析标签,识别内容类型', + 'h1 是标题,p 是段落,button 是按钮', + '按默认样式渲染(此时看起来很朴素)' + ] } if (current.value === 'css') { - return ['读取选择器,找到对应元素', '应用颜色、字号、间距等样式'] + return [ + '解析选择器,找到对应元素', + '应用颜色、字号、间距等样式规则', + '页面外观发生变化' + ] } - return ['给按钮绑定点击事件', '点击时更新计数和文字'] + return [ + '通过选择器获取按钮元素', + '注册 click 事件监听器', + '点击时执行回调函数,更新计数' + ] }) const handleBtnClick = () => { @@ -119,28 +133,35 @@ const handleBtnClick = () => { diff --git a/docs/zh-cn/appendix/web-basics.md b/docs/zh-cn/appendix/web-basics.md index 2f8e005..a271b77 100644 --- a/docs/zh-cn/appendix/web-basics.md +++ b/docs/zh-cn/appendix/web-basics.md @@ -1,16 +1,16 @@ # HTML/CSS/JavaScript 基础 (Web Basics) ::: tip 🎯 核心问题 -**网页是怎么做出来的?为什么有的网页只有文字,有的却像应用一样可以交互?** 这个问题会引出 Web 开发的三大基石,让你理解每一个网页背后的结构。 +**网页是怎么做出来的?为什么有的网页只有文字,有的却像应用一样可以交互?** 这个问题会引出 Web 开发的三大基石,让你理解每一个网页背后的结构。 ::: --- -## 1. 为什么要理解网页的"三剑客"? +## 1. HTML、CSS、JavaScript 分别是什么? -### 1.1 从"电子海报"到"Web 应用" +### 1.1 从静态网页到动态应用 -想象一下你在街上看到的**海报**。你只能看,不能互动——海报不会因为你看了就改变内容,也不会因为你点了某个地方就弹出更多信息。 +想象一下你在街上看到的**海报**。你只能看,不能互动——海报不会因为你看了就改变内容,也不会因为你点了某个地方就弹出更多信息。 早期的网页就是这样的"电子海报":只能看、不能改、内容固定。 @@ -18,13 +18,11 @@ - 你可以点击、拖拽、输入、上传 - 页面会根据你的操作实时变化 -- 可以像软件一样完成复杂任务(比如在线视频剪辑) +- 可以像软件一样完成复杂任务(比如在线视频剪辑) -**这种转变的核心原因,就是网页技术的三大基石:HTML + CSS + JavaScript**。 +**这种转变的核心原因,就是网页技术的三大基石:HTML + CSS + JavaScript**。 -### 1.2 一个生活的比喻:盖房子 - -为了让你快速理解这三者的关系,我们用"盖房子"来比喻: +### 1.2 一个比喻:盖房子 | 技术 | 🏠 房子比喻 | 实际作用 | 具体例子 | | -------------- | ------------------------ | -------------------- | ------------------------------------ | @@ -32,443 +30,403 @@ | **CSS** | 房子的**装修和外观** | 控制网页的样式和布局 | 墙刷成蓝色、窗户放在东边、地板铺瓷砖 | | **JavaScript** | 房子的**电器和智能系统** | 让网页具备交互和逻辑 | 按开关灯亮了、开门窗帘自动拉开 | -::: tip 💡 从表格中你能看到什么? +::: tip 💡 三者的关系 -**HTML → CSS**: 先有房子,才能装修。HTML 是基础,CSS 是美化。没有 HTML,CSS 就没有东西可以装饰。 +**HTML → CSS**:先有房子,才能装修。HTML 是基础,CSS 是美化。 -**HTML + CSS → JavaScript**: 先有房子和装修,才能装智能系统。JavaScript 会让"死"的页面变"活"。 +**HTML + CSS → JavaScript**:先有房子和装修,才能装智能系统。JavaScript 会让"死"的页面变"活"。 -**核心思想**: 三者各司其职,但缺一不可。只有 HTML 的页面很丑,只有 HTML+CSS 的页面不能互动,三者齐全才能做出像微信网页版、淘宝这样的"Web 应用"。 +**核心思想**:三者各司其职,缺一不可。只有 HTML 的页面很丑,只有 HTML+CSS 的页面不能互动,三者齐全才能做出像微信网页版、淘宝这样的"Web 应用"。 +::: -🎯 动手试试看: +### 1.3 动手试试看 -下面这个演示展示了 HTML/CSS/JavaScript 三者如何协作。你可以切换三种模式,点击页面上的元素会高亮对应的代码: +👇 下面这个演示展示了 HTML/CSS/JavaScript 三者如何协作: -::: - --- -## 2. HTML: 网页的"骨架" +## 2. HTML:网页的骨架 -### 2.1 为什么不能只用纯文本? +### 2.1 为什么需要 HTML? -在 HTML 出现之前,互联网上的内容只是**纯文本**。就像你现在看的这段文字,没有任何格式、没有层级、没有链接。 +在 HTML 出现之前,互联网上的内容只是**纯文本**。就像你现在看的这段文字,没有任何格式、没有层级、没有链接。 -纯文本的问题是什么? +纯文本的问题是什么? -- ❌ **无法表达层级**: 分不清哪是标题、哪是正文、哪是注释 -- ❌ **机器看不懂**: 搜索引擎、屏幕阅读器(盲人用)无法理解内容 -- ❌ **无法交互**: 没有链接、没有按钮、没有输入框 +- ❌ **无法表达层级**:分不清哪是标题、哪是正文、哪是注释 +- ❌ **机器看不懂**:搜索引擎、屏幕阅读器(盲人用)无法理解内容 +- ❌ **无法交互**:没有链接、没有按钮、没有输入框 -**HTML (HyperText Markup Language)** 就是为了解决这个问题诞生的。它用"标签"(tag)来标记内容的含义,让浏览器知道"这是什么"。 +**HTML (HyperText Markup Language)** 就是为了解决这个问题诞生的。它用"标签"(tag)来标记内容的含义,让浏览器知道"这是什么"。 -### 2.2 HTML 的核心概念:标签与元素 +### 2.2 HTML 代码长什么样? -HTML 的基本单位是"标签"(tag)。标签用尖括号 `< >` 包裹,成对出现: +HTML 的基本单位是"标签"(tag)。标签用尖括号 `< >` 包裹,成对出现: ```html -

这是标题

- - -<标签名>内容 +

这是段落

+这是链接 ``` -**关键概念**: +**关键概念**: -- **标签 (Tag)**: `

`、`

` 这种标记,告诉浏览器"这是什么" -- **元素 (Element)**: 标签 + 内容,比如 `

标题

` 整体 -- **属性 (Attribute)**: 标签上的附加信息,比如 `` 中的 `src` -- **嵌套 (Nesting)**: 标签里可以再放标签,形成父子关系 +| 概念 | 解释 | 例子 | +|------|------|------| +| **标签** | 用尖括号包裹的标记 | `

`、`

` | +| **元素** | 标签 + 内容的整体 | `

标题

` | +| **属性** | 标签上的附加信息 | `href="url"`、`class="card"` | +| **嵌套** | 标签里再放标签 | `

文字

` | -::: details 💡 点击查看:HTML 标签的"家族树" +### 2.3 如何看懂 HTML 代码? -HTML 标签之间的嵌套关系,就像一个家族树: +::: tip 🎯 零基础必读:看代码的方法 + +很多新手看到一堆 `` 就晕了。其实看 HTML 代码有**固定套路**: + +**第一步:找"最外层"** + +```html +
← 这是容器,里面装着内容 +

标题

+

描述文字

+
+``` + +**第二步:看标签名猜含义** + +| 标签名 | 一眼记住 | 里面放什么 | +|--------|----------|------------| +| `
` | 大盒子 | 任何内容,用来分组 | +| `` | 小盒子 | 文字片段,用来标记 | +| `

` | 段落 | 一段文字 | +| `

`-`

` | 标题 | 标题文字,数字越小越重要 | +| `` | 锚点/链接 | 可点击跳转的内容 | +| `` | 图片 | 不放内容,用 src 指向图片 | +| ` ``` -**语义化标签** (HTML5 新增,让页面含义更明确): +**语义化标签**(HTML5 新增,让页面含义更明确): ```html -
这是页面头部
- -
这是主要内容区
-
这是一篇文章
- -
这是页脚
+
页面头部
+ +
主要内容区
+
一篇文章
+ +
页脚
``` -::: tip 💡 为什么要用语义化标签? +::: tip 💡 为什么要用语义化标签? -`
` 和 `
` 看起来效果一样,为什么要用后者? +`
` 和 `
` 看起来效果一样,为什么要用后者? -1. **SEO 友好**: 搜索引擎能更好理解页面结构 -2. **可访问性**: 屏幕阅读器能快速定位"导航""主要内容"等区域 -3. **代码可读性**: 看到 `
` 一眼就知道是头部,不用猜 `class="header"` 的意图 - ::: +1. **SEO 友好**:搜索引擎能更好理解页面结构 +2. **可访问性**:屏幕阅读器能快速定位"导航""主要内容"等区域 +3. **代码可读性**:看到 `
` 一眼就知道是头部 + +**什么时候用 div?** 当没有合适的语义标签时。比如一个纯装饰性的容器。 +::: --- -## 3. CSS: 网页的"皮肤" +## 3. CSS:网页的皮肤 -### 3.1 只有 HTML 会怎样? +### 3.1 为什么需要 CSS? -想象你住进了一个**毛坯房**: 有墙、有窗、有门,能住人,但是: +想象你住进了一个**毛坯房**:有墙、有窗、有门,能住人,但是: -- 墙是灰色的水泥,不好看 -- 插座和开关随便装,不美观 -- 没有家具,生活不方便 +- 墙是灰色的水泥,不好看 +- 插座和开关随便装,不美观 +- 没有家具,生活不方便 -只有 HTML 的网页就是这样:有内容、有结构,但**丑**、**乱**、**不友好**。 +只有 HTML 的网页就是这样:有内容、有结构,但**丑**、**乱**、**不友好**。 -CSS (Cascading Style Sheets) 就是网页的"装修队"。它不改变 HTML 的结构(不拆墙、不改门),只负责: +CSS (Cascading Style Sheets) 就是网页的"装修队"。它不改变 HTML 的结构(不拆墙、不改门),只负责: -- 🎨 **刷墙**: 改变颜色、背景 -- 🖼️ **挂画**: 添加边框、阴影、圆角 -- 🪑 **摆家具**: 调整布局、间距、对齐 +- 🎨 **刷墙**:改变颜色、背景 +- 🖼️ **挂画**:添加边框、阴影、圆角 +- 🪑 **摆家具**:调整布局、间距、对齐 -### 3.2 CSS 的三种写法 +### 3.2 CSS 代码长什么样? -CSS 有三种"安装"方式,就像装修也有三种方式: +CSS 代码有固定格式: -**方式一: 行内样式** (临时贴个装饰) - -```html -
这段文字是红色的,背景是黄色的
+```css +选择器 { + 属性名: 属性值; + 属性名: 属性值; +} ``` -**适用场景**: 临时测试、快速原型。不推荐在生产代码中使用。 - -**方式二: 内部样式** (写在户型图背面) +**三种写法**: ```html - - - - -
这段文字是红色
- -``` + +
红色文字
-**适用场景**: 单页应用、组件的专属样式。 + + -**方式三: 外部样式** (请专业装修公司) ⭐ - -```html - + ``` +### 3.3 如何看懂 CSS 代码? + +::: tip 🎯 零基础必读:看 CSS 的方法 + +**第一步:看选择器——"给谁装修?"** + +| 选择器 | 写法 | 含义 | +|--------|------|------| +| 标签选择器 | `p { }` | 所有 `

` 标签 | +| 类选择器 | `.card { }` | 所有 `class="card"` 的元素 | +| ID 选择器 | `#header { }` | 唯一的 `id="header"` 元素 | +| 后代选择器 | `.card h2 { }` | `.card` 里面的所有 `

` | +| 组合选择器 | `.card, .box { }` | `.card` 或 `.box` 都选中 | + +**第二步:看属性——"装修什么?"** + +| 属性分类 | 常见属性 | 作用 | +|----------|----------|------| +| 文字 | `color`, `font-size`, `font-weight` | 颜色、大小、粗细 | +| 背景 | `background`, `background-color` | 背景色、背景图 | +| 边框 | `border`, `border-radius` | 边框线、圆角 | +| 间距 | `margin`, `padding` | 外边距、内边距 | +| 布局 | `display`, `flex`, `grid` | 排列方式 | + +**第三步:看值——"装修成什么样?"** + ```css -/* styles.css 文件 */ -.red-text { - color: red; +.card { + width: 300px; /* 固定宽度 */ + padding: 16px; /* 内边距 16 像素 */ + border-radius: 8px; /* 圆角 8 像素 */ + background: #fff; /* 白色背景 */ } ``` -**适用场景**: 所有正规项目。优点是可以复用、易于维护、浏览器会缓存。 - -### 3.3 CSS 如何找到 HTML?选择器的工作原理 - -新手最容易晕的地方是:"CSS 写的 `.card`、`#btn`、`p` 到底是怎么跟 HTML 对应上的?" - -这就像老师在班级里点名,有三种点法: - -**1. 喊"所有人"(标签选择器)** - -```css -p { - color: red; -} -``` - -喊"所有同学",全班同学都要站起来。这里所有 `

` 标签的元素都会变成红色。 - -**2. 喊"小组名"(类选择器 class)** - -```css -.highlight { - background: yellow; -} -``` - -喊"英语课代表",可能有几个同学都是。所有 `class="highlight"` 的元素背景都会变黄。 - -**3. 喊"学号"(ID 选择器)** - -```css -#submit-btn { - background: blue; -} -``` - -喊"2024001",全班只有一个。只有 `id="submit-btn"` 的元素会变蓝。 - -::: tip 💡 优先级:谁听谁的? - -如果一个元素同时被多个选择器选中,怎么办? - -```html -

这段文字是什么颜色?

-``` - -```css -p { - color: red; -} /* 优先级: 1 */ -.highlight { - color: yellow; -} /* 优先级: 10 */ -#special-para { - color: blue; -} /* 优先级: 100 */ -``` - -**答案**: 蓝色。ID 选择器优先级最高,类选择器次之,标签选择器最低。 - -**内联样式**(写在 style 属性里)优先级是 1000,最高! +**常见单位**: +- `px`:像素,固定大小 +- `%`:百分比,相对于父元素 +- `rem`:相对于根元素字体大小 +- `vw/vh`:相对于视口宽度/高度 ::: -### 3.4 CSS 的"三明治":盒模型 +### 3.4 选择器优先级 -每个 HTML 元素在 CSS 中都被看作一个"盒子",由四层组成: +如果一个元素同时被多个选择器选中,谁说了算? +```html +

这段文字是什么颜色?

``` -┌──────────────────────────────────┐ -│ margin (外边距) │ ← 盒子之间的距离 -│ ┌─────────────────────────┐ │ -│ │ border (边框) │ │ ← 盒子的外壳 -│ │ ┌───────────────────┐ │ │ -│ │ │ padding (内边距) │ │ │ ← 内容到边框的距离 -│ │ │ ┌─────────────┐ │ │ │ -│ │ │ │ content │ │ │ │ ← 实际内容(文字/图片) -│ │ │ └─────────────┘ │ │ │ -│ │ └───────────────────┘ │ │ -│ └─────────────────────────┘ │ -└──────────────────────────────────┘ -``` - -**总宽度计算**: ```css -width: 200px; -padding: 10px; /* 左右各 10px */ -border: 5px; /* 左右各 5px */ -margin: 20px; /* 左右各 20px */ +p { color: red; } /* 优先级:1 */ +.highlight { color: yellow; } /* 优先级:10 */ +#special { color: blue; } /* 优先级:100 */ ``` -**元素实际占据的宽度** = 20 + 5 + 10 + 200 + 10 + 5 + 20 = **270px** +**答案**:蓝色。ID 选择器优先级最高,类选择器次之,标签选择器最低。 -::: warning ⚠️ 常见错误:宽度对不上 +**内联样式**(写在 style 属性里)优先级是 1000,最高! -新手常问:"我设置了 `width: 200px`,为什么测量出来是 270px?" +### 3.5 盒模型:为什么宽度对不上? -因为你没有算上 padding、border、margin! +::: tip 🎯 真实场景 -**解决方案**: +你做一个网页,要求三个卡片并排显示,每个卡片宽度 300px,容器总宽度 900px。你写了: + +```css +.card { width: 300px; } +``` + +结果:**第三个卡片掉到下一行了!** + +**为什么?** 因为 `width: 300px` 只是内容宽度,你忘了算 padding 和 border。如果卡片有 `padding: 20px` 和 `border: 1px`,实际宽度是 342px,三个卡片就是 1026px,超出了容器! +::: + +每个 HTML 元素在 CSS 中都被看作一个"盒子",由四层组成。想象你在**打包快递**:内容是商品,padding 是气泡膜,border 是纸箱,margin 是箱子之间的间隔。 + +👇 **动手试试看**:拖动滑块调节各层大小,观察盒模型的变化: + + + +**解决方案**: ```css .box { - box-sizing: border-box; /* 让 width 包含 padding 和 border */ + box-sizing: border-box; /* 让 width 包含 padding 和 border */ width: 200px; padding: 10px; border: 5px; } ``` -这样,`width: 200px` 就是最终宽度,padding 和 border 会"挤"在里面。 -::: +这样,`width: 200px` 就是最终宽度,padding 和 border 会"挤"在里面。 -🎯 动手试试看: +### 3.6 Flexbox:怎么让元素自动对齐? -下面这个演示让你调节 padding、border 和 margin,实时看到盒模型的变化和总宽度计算: +Flexbox 是现代 CSS 最常用的布局方式。它让元素自动排列对齐,就像书架上的书会自动对齐一样。 - - -### 3.5 怎么知道有哪些 CSS 属性? - -::: tip 🎯 AI 时代的学习方式 - -**以前**: 背 CSS 属性手册 - -**现在**: 告诉 AI 你要什么效果 - -例子: - -- 你说"我要一个带阴影的蓝色圆角按钮" -- AI 会给出: `background: blue; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1)` - -**为什么这是首选?** 因为 AI 不仅告诉你"属性名",还帮你把"值"都调好了。 -::: - -不过,你仍然需要了解一些**最常用的 CSS 属性分类**: - -**文字相关**: - -```css -color: red; /* 文字颜色 */ -font-size: 16px; /* 字体大小 */ -font-weight: bold; /* 字体粗细 */ -text-align: center; /* 对齐方式 */ -line-height: 1.5; /* 行高 */ -``` - -**背景与边框**: - -```css -background: blue; /* 简写,可设置颜色、图片等 */ -border: 1px solid black; /* 1px 实线黑色边框 */ -border-radius: 8px; /* 圆角 */ -box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); /* 阴影 */ -``` - -**布局相关**: - -```css -display: flex; /* 弹性布局 */ -justify-content: center; /* 主轴对齐 */ -align-items: center; /* 交叉轴对齐 */ -gap: 10px; /* 元素之间的间距 */ -``` - -🎯 动手试试看: - -下面这个演示展示了 Flexbox 布局的效果。你可以切换方向、对齐方式和换行,观察盒子如何排列: +👇 **动手试试看**:切换方向、对齐方式,观察盒子如何排列: -**尺寸与间距**: +**Flex 核心概念**: + +| 属性 | 作用 | 常用值 | +|------|------|--------| +| `display: flex` | 开启 Flex 布局 | - | +| `flex-direction` | 主轴方向 | `row`(水平)、`column`(垂直) | +| `justify-content` | 主轴对齐 | `flex-start`、`center`、`space-between` | +| `align-items` | 交叉轴对齐 | `stretch`、`center`、`flex-start` | +| `flex-wrap` | 是否换行 | `nowrap`、`wrap` | +| `gap` | 元素间距 | `10px`、`1rem` | + +### 3.7 SCSS:CSS 的"升级版" + +::: tip 🎯 真实场景 + +你写了一个项目,CSS 文件有 2000 行。后来要改主题色,你发现: + +- 主色调 `#3b82f6` 出现了 50 次 +- 改一个颜色要全局搜索替换 +- 还要担心漏改了某个地方 + +**SCSS 解决的问题**:变量、嵌套、混入、模块化 +::: + +**SCSS 示例**: + +```scss +// 1. 变量:定义主题色 +$primary-color: #3b82f6; + +// 2. 嵌套:父子关系一目了然 +.card { + background: white; + + h2 { + color: $primary-color; + } + + &:hover { + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); + } +} +``` + +**编译后变成普通 CSS**: ```css -width: 100px; -height: 100px; -padding: 10px; /* 内边距 */ -margin: 20px; /* 外边距 */ +.card { + background: white; +} +.card h2 { + color: #3b82f6; +} +.card:hover { + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); +} ``` -### 3.6 现代 CSS 开发:Tailwind CSS 简介 +**SCSS vs Less vs 原生 CSS**: -::: tip 💡 这部分可选,了解即可 +| 特性 | 原生 CSS | SCSS | Less | +|------|----------|------|------| +| 变量 | ✅ `--var` | ✅ `$var` | ✅ `@var` | +| 嵌套 | ❌ | ✅ | ✅ | +| 混入 | ❌ | ✅ `@mixin` | ✅ `.mixin()` | +| 学习曲线 | 简单 | 中等 | 中等 | -Tailwind 是一种"原子化 CSS"框架,最近几年非常流行。它的核心思想是:**不要写 CSS,直接在 HTML 里写"样式代号"**。 +::: tip 💡 新手建议 -**传统写法**: - -```html - - - - - -``` - -**Tailwind 写法**: - -```html - -``` - -**为什么这么火?** - -1. **不用起名**: 最头疼的"这个类叫什么"环节没了 -2. **不切文件**: 不用在 HTML 和 CSS 之间来回切换 -3. **不怕删**: 删掉 HTML,样式自动就没了,不会留下堆积如山的无用 CSS +1. **先学好原生 CSS**:预处理器只是"语法糖",本质还是 CSS +2. **项目大了再用 SCSS**:小项目直接写 CSS 更简单 +3. **现代 CSS 已经支持变量**:`--primary-color: #3b82f6;` 原生就能用 +::: --- -## 4. JavaScript: 网页的"大脑" +## 4. JavaScript:网页的大脑 -### 4.1 没有 JavaScript 会怎样? +### 4.1 为什么需要 JavaScript? -只有 HTML + CSS 的网页,就像**商店橱窗里的模特**: +只有 HTML + CSS 的网页,就像**商店橱窗里的模特**: -- ✅ 看起来很漂亮(CSS) -- ✅ 结构很清晰(HTML) -- ❌ 但你跟它说话,它不会回应 -- ❌ 你按了按钮,什么也不会发生 +- ✅ 看起来很漂亮(CSS) +- ✅ 结构很清晰(HTML) +- ❌ 但你跟它说话,它不会回应 +- ❌ 你按了按钮,什么也不会发生 -**JavaScript** 让网页从"橱窗模特"变成"真人": +**JavaScript** 让网页从"橱窗模特"变成"真人": -- ✅ 点击按钮,会弹出提示 -- ✅ 输入文字,会实时检查格式 -- ✅ 滚动页面,会加载更多内容 -- ✅ 提交表单,会显示"正在提交..." +- ✅ 点击按钮,会弹出提示 +- ✅ 输入文字,会实时检查格式 +- ✅ 滚动页面,会加载更多内容 +- ✅ 提交表单,会显示"正在提交..." -### 4.2 JavaScript 的核心能力 +### 4.2 JavaScript 代码长什么样? -JavaScript 是一种**编程语言**,它让网页具备"逻辑"和"记忆"。 - -**能力一: 记住数据**(变量) +**能力一:记住数据**(变量) ```javascript let userName = '张三' @@ -476,378 +434,611 @@ let isLoggedIn = true let cartCount = 5 ``` -**能力二: 重复做事**(函数) +**能力二:重复做事**(函数) ```javascript -// 定义一个函数 function sayHello(name) { - return '你好, ' + name + '!' + return '你好,' + name + '!' } -// 调用函数 -console.log(sayHello('张三')) // 输出: 你好, 张三! +console.log(sayHello('张三')) // 输出:你好,张三! ``` -**能力三: 响应事件**(事件监听) +**能力三:响应事件**(事件监听) ```javascript -// 当按钮被点击时 -button.addEventListener('click', function () { - alert('按钮被点击了!') +button.addEventListener('click', function() { + alert('按钮被点击了!') }) ``` -**能力四: 修改页面**(DOM 操作) +**能力四:修改页面**(DOM 操作) ```javascript -// 修改页面内容 document.getElementById('title').textContent = '新标题' - -// 修改样式 document.getElementById('box').style.background = 'red' ``` -### 4.3 ECMAScript 是什么?JavaScript 的版本 +### 4.3 如何看懂 JavaScript 代码? -你可能听说过 **ECMAScript** 这个词。它和 JavaScript 是什么关系? +::: tip 🎯 零基础必读:看 JS 代码的方法 -**简单来说: ECMAScript 是标准,JavaScript 是实现**。 - -打个比方: - -- **ECMAScript** = "普通话标准规范",定义了语法规则 -- **JavaScript** = "实际说的普通话",是浏览器真正运行的语言 - -**为什么会有两个名字?** - -- 1995 年,网景公司创造了 JavaScript -- 1996 年,微软推出了 JScript(和 JavaScript 类似但不完全一样) -- 为了避免各浏览器"方言"不统一,1997 年 ECMA 国际组织制定了标准,命名为 ECMAScript - -**版本演进**: - -JavaScript 这门语言在不断"升级"。每年都会发布新版本: - -| 版本 | 发布年份 | 重要特性 | -| -------------- | -------- | ------------------------------------------------------ | -| **ES5** | 2009 | 严格模式、JSON、Array.map/filter/reduce | -| **ES6/ES2015** | 2015 | `let/const`、箭头函数、`class`、**ES 模块**、`Promise` | -| **ES2020** | 2020 | 可选链 `?.`、空值合并 `??`、`BigInt` | -| **ES2024** | 2024 | `Object.groupBy()`、`Promise.withResolvers()` | - -::: tip 💡 实用建议 - -现代浏览器已经支持大部分 ES6+ 特性。如果你需要兼容老浏览器(如 IE),可以用 Babel 等工具把新语法"翻译"成老语法。 - -不过,现在很多项目已经不再支持 IE,所以你可以放心使用新语法。 -::: - -### 4.4 TypeScript:加上了"类型"的 JavaScript - -你可能还听说过 **TypeScript (TS)**,它和 JavaScript 又是什么关系? - -**一句话概括: TypeScript = JavaScript + 类型系统**。 - -| 对比项 | JavaScript | TypeScript | -| ------------ | -------------------------- | ------------------------------ | -| **类型系统** | 动态类型(运行时才知道类型) | 静态类型(写代码时就知道类型) | -| **编译** | 不需要编译,浏览器直接运行 | 需要编译成 JavaScript 才能运行 | -| **错误检查** | 运行时才发现错误 | 写代码时就能发现错误 | -| **学习曲线** | 入门简单 | 需要学习类型语法 | -| **适用场景** | 小型项目、快速原型 | 大型项目、团队协作 | - -**代码对比**: +**第一步:找变量——"记住了什么?"** ```javascript -// JavaScript - 动态类型,变量可以随便变 -let name = '张三' -name = 123 // 不报错,但可能出问题 +const API_URL = 'https://api.example.com' // 常量,不会变 +let count = 0 // 变量,会变 +const user = { name: '张三', age: 25 } // 对象,多个数据 +const items = ['苹果', '香蕉', '橙子'] // 数组,列表数据 ``` -```typescript -// TypeScript - 静态类型,类型写死了 -let name: string = '张三' -name = 123 // 编译时报错: 不能把数字赋给字符串 +**第二步:找函数——"能做什么?"** + +```javascript +// 函数名通常能猜出用途 +function handleClick() { } // 处理点击 +function fetchData() { } // 获取数据 +function validateForm() { } // 验证表单 ``` -::: tip 💡 为什么大型项目偏爱 TypeScript? +**第三步:找事件——"什么时候触发?"** -想象你在团队里开发一个复杂系统,代码几万行。JavaScript 的灵活性在这里变成了"灾难"——你不知道这个函数期望接收什么类型的参数,也不知道它返回什么。 +```javascript +button.addEventListener('click', handleClick) // 点击时 +input.addEventListener('input', validateForm) // 输入时 +window.addEventListener('scroll', loadMore) // 滚动时 +``` -TypeScript 强制你写清楚类型,就像给代码加了"说明书",IDE 也能给你更好的提示。 +**第四步:找 DOM 操作——"改了什么?"** + +```javascript +element.textContent = '新内容' // 改文字 +element.classList.add('active') // 加样式类 +element.style.display = 'none' // 隐藏元素 +parent.appendChild(child) // 添加元素 +``` ::: ---- +### 4.4 DOM:JavaScript 如何操作页面? -## 5. 深入理解 DOM: 网页的"族谱" - -你可能经常听到 **DOM (Document Object Model)** 这个词。别被这个专业术语吓到,它其实就是一张**网页的"族谱"**。 - -### 5.1 什么是 DOM 树? - -浏览器读取 HTML 代码后,不会把它们当成一堆字符串,而是在内存里把它们画成一棵"树"。 +浏览器读取 HTML 代码后,不会把它们当成一堆字符串,而是在内存里把它们画成一棵"树": ``` Document (文档) ↓ - - ├─ + + ├─ │ └─我的网页 - └─ + └─ ├─

欢迎

- └─
+ └─
├─ └─

一段文字

``` 这棵树就叫 **DOM 树**。每个 HTML 标签都是这棵树上的一个"节点"。 -### 5.2 为什么叫"对象模型"(Object Model)? - -因为在 JavaScript 眼里,HTML 标签不仅仅是标签,而是**对象 (Object)**。它们有**属性**(可以读/写的数据)和**方法**(可以执行的动作)。 - -**属性 (Property)**: 节点的"数据" - -```javascript -imgElement.src = 'photo.jpg' // 修改图片地址 -divElement.className = 'box' // 修改类名 -inputElement.value = '123' // 修改输入框的值 -``` - -**方法 (Method)**: 节点的"动作" - -```javascript -buttonElement.click() // 模拟点击 -divElement.remove() // 删除元素 -bodyElement.appendChild(newDiv) // 添加子元素 -``` - -### 5.3 怎么找节点?(DOM 查询) - -就像在族谱里找人一样,JavaScript 提供了很多方法: - -**按"身份证"找**(ID): +**怎么找到节点?** ```javascript +// 按 ID 找(最快,唯一) const element = document.getElementById('header') -// 全局唯一,速度最快 + +// 按选择器找(最常用) +const element = document.querySelector('.card h2') // 找第一个 +const elements = document.querySelectorAll('button') // 找所有 + +// 按关系找 +element.parentNode // 找父节点 +element.children // 找子节点 +element.nextElementSibling // 找下一个兄弟 ``` -**按"特征"找**(选择器): +**性能警告**:操作 DOM 是很**贵**的。每次修改 DOM,浏览器都要重新计算布局、重新绘制。 ```javascript -// 找到第一个匹配的元素 -const element = document.querySelector('.card h2') - -// 找到所有匹配的元素 -const elements = document.querySelectorAll('button') -``` - -**按"关系"找**: - -```javascript -element.parentNode // 找爸爸 -element.children // 找孩子 -element.nextElementSibling // 找下一个兄弟 -``` - -### 5.4 性能警告:不要频繁"拆家" - -操作 DOM 是很**贵**的。每次你修改 DOM(比如改大小、改位置),浏览器都要: - -1. **重新计算排版** (Reflow) -2. **重新绘制** (Repaint) - -这两个操作都很耗时。 - -::: warning ⚠️ 低效操作 - -```javascript -// ❌ 低效:循环 1000 次,每次都操作 DOM +// ❌ 低效:循环 1000 次,每次都操作 DOM for (let i = 0; i < 1000; i++) { document.body.appendChild(createDiv()) } -``` -**为什么会慢?** 每次appendChild,浏览器都要重新计算整页布局,1000 次就是 1000 次重排! - -::: - -::: tip ✅ 高效操作 - -```javascript -// ✅ 高效:先拼好,一次性插入 +// ✅ 高效:先拼好,一次性插入 const fragment = document.createDocumentFragment() for (let i = 0; i < 1000; i++) { fragment.appendChild(createDiv()) } -document.body.appendChild(fragment) // 只触发一次重排 +document.body.appendChild(fragment) ``` -这也正是 **Vue / React** 等现代框架诞生的原因: 它们在内存里玩"虚拟 DOM",计算好最小修改量,最后才去动真正的 DOM,从而保护了性能。 -::: +这也正是 **Vue / React** 等现代框架诞生的原因:它们在内存里玩"虚拟 DOM",计算好最小修改量,最后才去动真正的 DOM。 -🎯 动手试试看: - -下面这个演示展示了 DOM 操作的基本方法。你可以修改标题文字、切换高亮样式,并看到对应的 JavaScript 代码: +👇 **动手试试看**:DOM 操作的基本方法: +### 4.5 ECMAScript:JavaScript 的版本演进 + +**ECMAScript** 是 JavaScript 的"标准说明书"。浏览器厂商按照这个标准来实现 JavaScript 引擎。 + +#### 为什么要有版本号? + +JavaScript 不是一成不变的。每年都会新增功能、修复问题。版本号告诉你"这个浏览器支持哪些功能"。 + +#### 重要版本一览 + +| 版本 | 年份 | 核心特性 | 解决了什么问题 | +|------|------|----------|----------------| +| **ES5** | 2009 | 严格模式、`forEach`/`map`/`filter` | 规范化语言,增加数组方法 | +| **ES6/ES2015** | 2015 | `let/const`、箭头函数、`class`、`Promise`、模块化 | 最大的更新,现代 JS 的起点 | +| **ES2016** | 2016 | `includes()`、`**` 幂运算 | 小更新 | +| **ES2017** | 2017 | `async/await`、`Object.entries()` | 异步代码更易读 | +| **ES2018** | 2018 | `...` 扩展运算符、`Promise.finally()` | 对象和异步增强 | +| **ES2020** | 2020 | 可选链 `?.`、空值合并 `??`、`BigInt` | 安全访问嵌套属性 | +| **ES2021** | 2021 | `replaceAll()`、逻辑赋值 `??=` | 字符串和赋值增强 | +| **ES2022** | 2022 | 顶层 `await`、`.at()` 索引 | 模块异步加载更方便 | + +#### ES6+ 最常用的新语法 + +**1. `let` 和 `const` 替代 `var`** + +```javascript +// ❌ 旧写法:var 有变量提升,容易出 bug +var name = '张三' +if (true) { + var name = '李四' // 覆盖了外面的 name +} +console.log(name) // '李四',不是预期的结果 + +// ✅ 新写法:let 有块级作用域 +let name = '张三' +if (true) { + let name = '李四' // 只在这个 if 里有效 +} +console.log(name) // '张三',符合预期 + +// ✅ const:声明后不能重新赋值 +const PI = 3.14159 +PI = 3 // 报错!防止意外修改 +``` + +**2. 箭头函数:更简洁的函数写法** + +```javascript +// ❌ 旧写法 +const add = function(a, b) { + return a + b +} + +// ✅ 新写法 +const add = (a, b) => a + b + +// 箭头函数的 this 绑定外层作用域 +const obj = { + name: '张三', + // ❌ 普通函数:this 指向调用者 + oldWay: function() { + setTimeout(function() { + console.log(this.name) // undefined + }, 100) + }, + // ✅ 箭头函数:this 继承自 obj + newWay: function() { + setTimeout(() => { + console.log(this.name) // '张三' + }, 100) + } +} +``` + +**3. 解构赋值:从对象/数组中提取数据** + +```javascript +// 对象解构 +const user = { name: '张三', age: 25, city: '北京' } +const { name, age } = user // 直接提取 +console.log(name) // '张三' + +// 数组解构 +const colors = ['red', 'green', 'blue'] +const [first, second] = colors +console.log(first) // 'red' + +// 函数参数解构 +function greet({ name, age }) { + console.log(`${name} 今年 ${age} 岁`) +} +greet(user) // '张三 今年 25 岁' +``` + +**4. 模板字符串:字符串拼接不再痛苦** + +```javascript +// ❌ 旧写法:一堆引号和加号 +const msg = '用户 ' + name + ' 的年龄是 ' + age + ' 岁' + +// ✅ 新写法:反引号 + ${} +const msg = `用户 ${name} 的年龄是 ${age} 岁` + +// 还支持多行 +const html = ` +
+

${name}

+

年龄:${age}

+
+` +``` + +**5. `async/await`:异步代码像同步一样写** + +```javascript +// ❌ 回调地狱 +fetchUser(function(user) { + fetchOrders(user.id, function(orders) { + fetchDetails(orders[0].id, function(details) { + console.log(details) + }) + }) +}) + +// ✅ async/await +async function getUserData() { + const user = await fetchUser() + const orders = await fetchOrders(user.id) + const details = await fetchDetails(orders[0].id) + console.log(details) +} +``` + +**6. 可选链 `?.` 和空值合并 `??`** + +```javascript +const user = { + name: '张三', + address: { + city: '北京' + } +} + +// ❌ 旧写法:层层判断 +const street = user && user.address && user.address.street +const streetName = street !== undefined ? street : '未知' + +// ✅ 新写法:可选链 + 空值合并 +const streetName = user?.address?.street ?? '未知' +``` + +::: tip 💡 如何知道浏览器支持哪些特性? + +1. **查兼容表**:[caniuse.com](https://caniuse.com/) 输入特性名 +2. **用构建工具**:Babel 可以把新语法转成旧浏览器支持的代码 +3. **看目标用户**:如果只支持现代浏览器,大部分 ES6+ 特性都能直接用 +::: + +### 4.6 TypeScript:给 JavaScript 加上类型约束 + +#### 为什么需要 TypeScript? + +**场景一:函数参数类型不确定** + +```javascript +// JavaScript +function calculateTotal(price, quantity) { + return price * quantity +} + +calculateTotal(100, 5) // 500 ✅ +calculateTotal('100', 5) // '1005' ❌ 字符串拼接,不是乘法 +calculateTotal(100, '5') // 500 ✅ 但这是运气好 +``` + +JavaScript 不会告诉你参数类型错了,直到运行时才发现问题。 + +**场景二:对象属性拼写错误** + +```javascript +// JavaScript +const user = { + name: '张三', + age: 25 +} + +console.log(user.nmae) // undefined,拼写错误但不报错 +``` + +**TypeScript 解决这些问题**: + +```typescript +// TypeScript +interface User { + name: string + age: number +} + +function greet(user: User) { + console.log(`你好,${user.name}`) + console.log(user.nmae) // ❌ 编译时报错:属性 'nmae' 不存在 +} + +greet({ name: '张三', age: 25 }) // ✅ +greet({ name: '张三', age: '25' }) // ❌ 编译时报错:age 应该是 number +greet({ name: '张三' }) // ❌ 编译时报错:缺少 age +``` + +#### TypeScript 的核心概念 + +**1. 基本类型** + +```typescript +let name: string = '张三' +let age: number = 25 +let isActive: boolean = true +let anyValue: any = '可以是任何类型' // 不推荐,失去类型检查的意义 +``` + +**2. 接口(Interface):定义对象结构** + +```typescript +interface Product { + id: number + name: string + price: number + discount?: number // 可选属性 + readonly createdAt: Date // 只读属性 +} + +const product: Product = { + id: 1, + name: 'iPhone 15', + price: 6999, + createdAt: new Date() +} +``` + +**3. 类型别名(Type)** + +```typescript +type ID = string | number // 联合类型 +type Status = 'pending' | 'approved' | 'rejected' // 字面量类型 + +function updateStatus(id: ID, status: Status) { + // ... +} + +updateStatus(1, 'approved') // ✅ +updateStatus('abc', 'pending') // ✅ +updateStatus(1, 'processing') // ❌ 'processing' 不是有效的 Status +``` + +**4. 泛型:可复用的类型** + +```typescript +// 不用泛型:每个类型写一遍 +function getFirstNumber(arr: number[]): number { + return arr[0] +} +function getFirstString(arr: string[]): string { + return arr[0] +} + +// 用泛型:一个函数搞定 +function getFirst(arr: T[]): T { + return arr[0] +} + +getFirst([1, 2, 3]) // 返回 number +getFirst(['a', 'b', 'c']) // 返回 string +``` + +#### TypeScript vs JavaScript 对比 + +| 特性 | JavaScript | TypeScript | +|------|------------|------------| +| 类型检查 | 运行时才发现错误 | 编译时就发现错误 | +| IDE 支持 | 基础提示 | 智能补全、重构、跳转定义 | +| 学习曲线 | 简单 | 需要学习类型系统 | +| 适用场景 | 小项目、原型 | 大型项目、团队协作 | +| 运行方式 | 浏览器直接运行 | 需要编译成 JavaScript | + +#### 实际开发中的 TypeScript + +```typescript +// API 响应类型定义 +interface ApiResponse { + code: number + message: string + data: T +} + +interface User { + id: number + name: string + email: string +} + +// 带类型的 API 请求 +async function fetchUser(id: number): Promise> { + const response = await fetch(`/api/users/${id}`) + return response.json() +} + +// 使用时 IDE 会提示所有属性 +fetchUser(1).then(res => { + console.log(res.data.name) // ✅ IDE 自动补全 + console.log(res.data.nmae) // ❌ 编译时报错 +}) +``` + +::: tip 💡 新手建议 + +1. **先学好 JavaScript**:TypeScript 是 JS 的超集,不懂 JS 学 TS 会很痛苦 +2. **小项目不用强上 TS**:类型定义会增加代码量,简单项目反而变复杂 +3. **从 JSDoc 开始过渡**:在 JS 文件里写 `/** @type {User} */` 注释,体验类型提示 +4. **用 `any` 是妥协,不是解决方案**:遇到类型问题先尝试解决,不要直接 `any` +::: + +### 4.7 现代 JavaScript 开发工具链 + +::: tip 🎯 为什么需要工具链? + +浏览器只认识 HTML/CSS/JS。但现代开发中,我们会用: + +- **TypeScript**:浏览器不认识,需要编译成 JS +- **SCSS/Less**:浏览器不认识,需要编译成 CSS +- **模块化**:`import/export` 需要打包成一个文件 +- **新语法**:ES6+ 需要转译成旧浏览器支持的代码 + +工具链就是把这些"开发时用的代码"转换成"浏览器能运行的代码"。 +::: + +**核心工具**: + +| 工具 | 作用 | 类比 | +|------|------|------| +| **Node.js** | JavaScript 运行环境 | 让 JS 可以脱离浏览器运行 | +| **npm/yarn/pnpm** | 包管理器 | 下载别人写好的代码库 | +| **Vite/Webpack** | 构建工具 | 把源代码打包成浏览器能运行的代码 | +| **Babel** | 编译器 | 把新语法转成旧语法 | +| **ESLint** | 代码检查 | 发现代码问题和风格不一致 | + +**一个典型的开发流程**: + +```bash +# 1. 初始化项目 +npm create vite@latest my-app -- --template vue-ts + +# 2. 安装依赖 +cd my-app +npm install + +# 3. 开发模式(热更新) +npm run dev + +# 4. 构建生产版本 +npm run build +``` + --- -## 6. 三剑客如何协作? +## 5. 三者的协作关系 -### 6.1 分工对比表 +### 5.1 分工对比 -| 角色 | 负责什么 | 不做什么 | 典型示例 | -| -------------- | ---------------- | --------------- | ---------------------------------- | -| **HTML** | 定义结构与语义 | 不负责样式/交互 | `

标题

` | -| **CSS** | 定义表现与布局 | 不存放业务逻辑 | `.card { border-radius: 8px; }` | -| **JavaScript** | 定义行为与数据流 | 不承担视觉表现 | `button.onclick = changeTitle` | +| 角色 | 负责什么 | 不做什么 | 典型示例 | +|------|----------|----------|----------| +| **HTML** | 定义结构与语义 | 不负责样式/交互 | `

标题

` | +| **CSS** | 控制外观与布局 | 不负责逻辑/数据 | `.card { background: white; }` | +| **JavaScript** | 处理交互与逻辑 | 不负责结构定义 | `button.onclick = () => alert()` | -### 6.2 一个完整的例子:点击改变标题 +### 5.2 一个完整的协作示例 ```html - - - + + + +
+

点击按钮

+ +
- .btn { - background: var(--vp-c-brand); - color: white; - border: none; - padding: 10px 20px; - border-radius: 4px; - cursor: pointer; - } - - .btn:hover { - opacity: 0.9; - } - - - - -
-

欢迎

-

点击按钮改变标题!

- -
- - - - + + ``` -**这个例子展示了三者的协作**: +--- -1. **HTML** 定义了页面结构: 卡片、标题、按钮 -2. **CSS** 让页面变好看: 边框、圆角、颜色 -3. **JavaScript** 让页面变活: 点击后改变标题 +## 6. 遇到不认识的代码怎么办? + +### 6.1 问 AI + +> "HTML 中的 `