Web前端代码实操详解

HTML 结构 · CSS 布局与样式 · JavaScript 与 DOM 交互

一、第2章 HTML 语法基础
1.1 HTML5 基本文件结构
每个 HTML5 页面都以此结构为骨架。<!DOCTYPE html> 声明文档类型,<meta charset="UTF-8"> 设置编码,<title> 定义标题。

<!DOCTYPE html>
<meta charset="UTF-8">
<title>网页标题</title>
网页正文
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>网页标题</title>
</head>
<body>
    网页正文
</body>
</html>
▼ 点击展开完整代码

▼ 实现效果

Hello World

这是一个段落。

1.2 div 布局 vs 语义化标签
传统 div 布局使用 <div id="header/nav/content/footer"> 划分区域;HTML5 语义化标签(<header>、<nav>、<aside>、<article>、<footer>)更清晰地表达页面结构。

<div id="header">页眉
<div id="nav">导航条</div>
</div>
<div id="sidebar">边栏条
<div class="aside">边栏1</div>
<div class="aside">边栏2</div>
</div>
<div id="content">内容
<div class="article">文章1</div>
<div class="article">文章2</div>
</div>
<div id="footer">页脚</div>
</div>
<!-- div 布局 -->
<div id="container">页面全部内容的容器
<div id="header">页眉
<div id="nav">导航条</div>
</div>
<div id="sidebar">边栏条
<div class="aside">边栏1</div>
<div class="aside">边栏2</div>
</div>
<div id="content">内容
<div class="article">文章1</div>
<div class="article">文章2</div>
</div>
<div id="footer">页脚</div>
</div>
<!-- 语义化标签 -->
<div id="container">页面全部内容的容器
<header> 页眉
<nav>导航条</nav>
</header>
<div id="sidebar">边栏条
<aside>边栏1</aside>
<aside>边栏2</aside>
</div>
<div id="content">内容
<article>文章1</article>
<article>文章2</article>
</div>
<footer>页脚</footer>
</div>
▼ 点击展开完整代码

▼ 实现效果

页眉 Header
导航 Nav
导航
导航
侧边栏 Aside
文章内容 Article
页脚 Footer
二、第6章 CSS 定位与布局
2.1 文档流布局(图片列表)
font-size:0 消除 inline-block 间隙,图片在正常文档流中水平排列。来自原代码"例1 文档流定位"。

.wrap { font-size: 0; }
.wrap img {
width: 30%; margin: 1.5%;
border-radius: 3px;
}
<!DOCTYPE html>
<html>
<head>
<style>
.wrap { font-size: 0; }
.wrap img {
width: 30%; margin: 1.5%;
border-radius: 3px;
}
</style>
</head>
<body>
<div class="wrap">
<img src="images/1.jpg">
<img src="images/2.jpg">
<img src="images/3.jpg">
</div>
</body>
</html>
▼ 点击展开完整代码

▼ 实现效果

图1 图2 图3
2.2 Float 浮动布局 & Clearfix
float: left 使块级元素并排排列,常用于图片画廊/多列布局。父容器需使用 clearfix 清除浮动,避免高度塌陷。来自原代码"例2 文档流布局"。

* { box-sizing: border-box; }
.img-container {
float: left; width: 33.33%; padding: 5px;
}
.clearfix::after {
content: ""; clear: both; display: table;
}
<!DOCTYPE html>
<html>
<head>
<style>
* { box-sizing: border-box; }
.img-container {
float: left; width: 33.33%; padding: 5px;
}
.clearfix::after {
content: ""; clear: both; display: table;
}
</style>
</head>
<body>
<h1>并排的图像</h1>
<div class="clearfix">
<div class="img-container">
<img src="img/tulip.jpg" style="width:100%">
</div>
<div class="img-container">
<img src="img/tulip-2.jpg" style="width:100%">
</div>
<div class="img-container">
<img src="img/flower-4.jpg" style="width:100%">
</div>
</div>
<p>使用了 clearfix 清除浮动</p>
</body>
</html>
▼ 点击展开完整代码

▼ 实现效果

花1flower-1
花2flower-2
花3flower-3
2.3 Relative 相对定位
position: relative:元素相对于自身原位置偏移,原位置空间保留不释放(下方元素不会上移)。

#box-relative {
position: relative;  /*相对原位置偏移,原位置保留*/
top: 20px; left: 20px;
width: 200px; height: 150px;
background-color: #cef;
}
#box-static {
width: 200px; height: 100px;
background-color: #cde;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>relative 定位</title>
<style>
#box-relative {
position: relative;  /*相对原位置偏移,原位置保留*/
top: 20px; left: 20px;
width: 200px; height: 150px;
background-color: #cef;
}
#box-static {
width: 200px; height: 100px;
background-color: #cde;
}
</style>
</head>
<body>
<div id="box-relative">relative</div>
<div id="box-static">static</div>
</body>
</html>
▼ 点击展开完整代码

▼ 实现效果

relative 偏移 12px
static(原位,不上移)
2.4 Absolute 绝对定位
position: absolute:元素脱离文档流,相对于最近的非 static 祖先定位。原空间被释放(下方元素会上移填补)。

#box-absolute {
position: absolute; /*脱离文档流,相对于body定位*/
top: 20px; left: 20px;
width: 200px; height: 150px;
background-color: #cef;
}
#box-static {
width: 200px; height: 100px;
background-color: #cde;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>absolute 定位</title>
<style>
#box-absolute {
position: absolute; /*脱离文档流,相对于body定位*/
top: 20px; left: 20px;
width: 200px; height: 150px;
background-color: #cef;
}
#box-static {
width: 200px; height: 100px;
background-color: #cde;
}
</style>
</head>
<body>
<div id="box-absolute">absolute</div>
<div id="box-static">static(填补原位置)</div>
</body>
</html>
▼ 点击展开完整代码

▼ 实现效果

absolute 脱离文档流
static 上移填补空位
2.5 Fixed 固定定位
position: fixed:元素相对于视口固定,滚动页面时位置不变。常用于返回顶部、侧边悬浮等。

* { margin: 0; padding: 0; }
height: 1200px; background-color: #ccc;
}
.fix {
position: fixed; /*固定在窗口右侧*/
top: 50px; right: 10px;
width: 10%; height: 300px;
background-color: #ccc;
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>fix 定位</title>
<style>
* { margin: 0; padding: 0; }
#container {
margin: 0 auto; width: 70%;
height: 1200px; background-color: #ccc;
}
.fix {
position: fixed; /*固定在窗口右侧*/
top: 50px; right: 10px;
width: 10%; height: 300px;
background-color: #ccc;
}
</style>
</head>
<body>
<div id="container">
<p>1</p><p>2</p>
<p>3</p><p>4</p>
<p>5</p><p>6</p>
</div>
<div class="fix">fixed</div>
</body>
</html>
▼ 点击展开完整代码

▼ 实现效果(模拟,右侧固定不随滚动移动)

滚动查看固定效果 ↓
固定元素(滚动时可见停留)
下方内容区…继续滚动可见上方固定元素停留
2.6 Sticky 粘性定位
position: sticky:元素滚动到指定阈值(如 top:0)前为 relative,到达后变为 fixed 固定住。

* { padding: 0; margin: 0; }
}
header {
position: -webkit-sticky;
position: sticky; /*滚动到顶部时固定*/
top: 0;
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>粘性定位</title>
<style>
* { padding: 0; margin: 0; }
#container {
width: 1000px; margin: 0 auto;
padding: 10px; margin-top: 40px;
}
main {
height: 1000px; margin-top: 10px;
margin-bottom: 10px; background: #eee;
}
header, footer {
height: 100px;
background-color: #ddd;
border: 1px solid;
}
header {
position: -webkit-sticky;
position: sticky; /*滚动到顶部时固定*/
top: 0;
}
</style>
</head>
<body>
<div id="container">
<header>页眉(粘性)</header>
<main>内容区</main>
<footer>页脚</footer>
</div>
</body>
</html>
▼ 点击展开完整代码

▼ 实现效果(模拟)

粘性导航条(滚动可见停留)
滚动内容区域
往下滚动可见导航条固定在顶部
2.7 Relative + Absolute 组合(文字覆盖图片)
典型应用:父 relative + 子 absolute,实现文字/标签覆盖在图片上的效果(如图片标题、折扣标签)。来自原代码"例4 relative abs"。

.pic { position: relative; display: inline-block; }
.pic p {
position: absolute; bottom: 0; left: 0;
width: 100%; text-align: center;
background: rgba(0,0,0,.5); color: #fff;
padding: 6px 0; margin: 0;
}
<!DOCTYPE html>
<html>
<head>
<style>
.pic { position: relative; display: inline-block; }
.pic p {
position: absolute; bottom: 0; left: 0;
width: 100%; text-align: center;
background: rgba(0,0,0,.5); color: #fff;
padding: 6px 0; margin: 0;
}
</style>
</head>
<body>
<div class="pic">
<img src="images/coffee.jpg">
<p>咖啡·图片标题</p>
</div>
</body>
</html>
▼ 点击展开完整代码

▼ 实现效果

咖啡

咖啡 · 图片标题覆盖

2.8 Border 技巧:分隔线 & CSS 箭头
border-top 在空 div 上实现分隔线。CSS 箭头原理:宽高为0,四边不同颜色,显示一边即得箭头。

.divider {
width: 500px; border-top: 1px solid blue;
}
.arrow-down {
width: 0; height: 0;
border: 15px solid;
border-color: black transparent transparent transparent;
}
<!DOCTYPE html>
<html>
<head>
<style>
.divider {
width: 500px; border-top: 1px solid blue;
}
.arrow-down {
width: 0; height: 0;
border: 15px solid;
border-color: black transparent transparent transparent;
}
.arrow-up {
width: 0; height: 0;
border: 15px solid;
border-color: transparent transparent black transparent;
}
.arrow-left {
width: 0; height: 0;
border: 15px solid;
border-color: transparent black transparent transparent;
}
.arrow-right {
width: 0; height: 0;
border: 15px solid;
border-color: transparent transparent transparent black;
}
</style>
</head>
<body>
<div class="divider"></div>
<div class="arrow-down"></div>
</body>
</html>
▼ 点击展开完整代码

▼ 实现效果

↑↓←→ 四个箭头
2.9 Overflow 溢出处理
overflow: hidden 隐藏溢出内容;overflow: scroll 显示滚动条;overflow: auto 自动判断。常用于固定高度容器中的内容裁剪或滚动。

div { width: 200px; height: 50px; margin: 5px; float: left; }
.hidden { overflow: hidden; background: #eee; }
.scroll { overflow: scroll; background: #f5f5f5; }
.auto { overflow: auto; background: #fafafa; }
<!DOCTYPE html>
<html>
<head>
<style>
div { width: 200px; height: 50px; margin: 5px; float: left; }
.hidden { overflow: hidden; background: #eee; }
.scroll { overflow: scroll; background: #f5f5f5; }
.auto { overflow: auto; background: #fafafa; }
</style>
</head>
<body>
<div class="hidden">
内容超出容器高度会被裁剪隐藏
</div>
<div class="scroll">
始终显示滚动条方便查看全部内容
</div>
<div class="auto">
自动判断是否需要滚动条
</div>
</body>
</html>
▼ 点击展开完整代码

▼ 实现效果

overflow:hidden
这是一段超出容器高度的文本,overflow:hidden 会裁剪掉多余部分,不会显示滚动条。
overflow:auto
这是一段超出容器高度的文本,overflow:auto 会出现滚动条,方便查看全部内容。
三、第9章 CSS3 特效
3.1 2D 变换:旋转 / 平移 / 缩放 / 倾斜
transform 支持 rotate(deg)、translate(px,px)、scale(x,y)、skewX/Y(deg)。多个变换用空格组合。

body { margin: 100px; }
.transform-box {
transform: skewX(10deg);
}
<!DOCTYPE html>
<html>
<head>
<style>
body { margin: 100px; }
div { width: 100px; height: 100px;
background: orange; border: 1px solid; }
.transform-box {
/* transform: translate(20px, 50px); */
/* transform: rotate(30deg); */
/* transform: scale(0.5, 2); */
transform: skewX(10deg);
/* transform: skew(10deg, 30deg); */
/* 多个变换用空格隔开 */
/* transform: translate(200px, 200px) skew(30deg); */
/* transform: rotate(30deg) scale(0.5, 2); */
}
</style>
</head>
<body>
<div>1</div>
<div class="transform-box">2</div>
<div>3</div>
</body>
</html>
▼ 点击展开完整代码

▼ 实现效果(鼠标悬停查看)

旋转
平移
缩放
倾斜
3.2 3D 变换:透视 + rotateY
在父级设置 perspective: 400px,子级使用 rotateY(deg) 产生 3D 纵深旋转效果。来自原代码"例3 扑克牌3d翻转"。

.stage { perspective: 150px; }
.stage img {
transform: rotateY(45deg);
transition: transform 0.6s;
}
.stage img:hover {
transform: rotateY(0deg);
}
<!DOCTYPE html>
<html>
<head>
<style>
.stage { perspective: 150px; }
.stage img {
transform: rotateY(45deg);
transition: transform 0.6s;
}
.stage img:hover {
transform: rotateY(0deg);
}
</style>
</head>
<body>
<div class="stage">
<img src="king.png" width="80">
</div>
</body>
</html>
▼ 点击展开完整代码

▼ 实现效果(鼠标悬停旋转)

3.3 圆角边框 & 盒子阴影 & 文字阴影
border-radius 可分别控制每个角(椭圆角用两个值)。box-shadow:h v blur color,可选 inset。text-shadow 为文字添加阴影。

div {
height: 100px; width: 150px;
border: 1px solid blue;
border-top-left-radius: 40px 20px;
}
.shadow {
box-shadow: 10px 10px 5px rgba(0,0,0,.5);
}
h1 {
color: white;
text-shadow: 2px 2px 4px #000;
}
<!DOCTYPE html>
<html>
<head>
<style>
/* 圆角边框 */
div {
height: 100px; width: 150px;
border: 1px solid blue;
border-top-left-radius: 40px 20px;
}
/* 盒子阴影 */
.shadow {
box-shadow: 10px 10px 5px rgba(0,0,0,.5);
}
h1 {
color: white;
text-shadow: 2px 2px 4px #000;
}
</style>
</head>
<body>
<div></div>
<h1>Web Design</h1>
</body>
</html>
▼ 点击展开完整代码

▼ 实现效果

阴影文字
3.4 多层阴影
同一元素可以叠加多个 box-shadow(逗号分隔),模拟立体分层效果。hover 切换为 inset 产生"按下"效果。来自原代码"例1 多层阴影"。

.imgbox {
width: 170px; height: 190px;
margin: 50px auto;
background-color: #fff;
border-radius: 5px;
box-shadow: 0 1px 1px rgba(0,0,0,.12),
0 2px 2px rgba(0,0,0,.12),
0 4px 4px rgba(0,0,0,.12),
0 8px 8px rgba(0,0,0,.12),
0 16px 16px rgba(0,0,0,.12);
}
<!DOCTYPE html>
<html>
<head>
<style>
.imgbox {
width: 170px; height: 190px;
margin: 50px auto;
background-color: #fff;
border-radius: 5px;
box-shadow: 0 1px 1px rgba(0,0,0,.12),
0 2px 2px rgba(0,0,0,.12),
0 4px 4px rgba(0,0,0,.12),
0 8px 8px rgba(0,0,0,.12),
0 16px 16px rgba(0,0,0,.12);
}
img { width: 150px; margin: 10px; }
.imgbox:hover {
box-shadow: inset 0 0 5px orange;
}
</style>
</head>
<body>
<div class="imgbox">
<a href="#"><img src="coffee.jpg"></a>
</div>
</body>
</html>
▼ 点击展开完整代码

▼ 实现效果(悬停切换阴影样式)

咖啡
3.5 Transition 过渡 & 按钮切换
transition: property duration easing 让样式变化平滑过渡。典型应用:hover 改变背景色/位置。

#btn {
position: relative; width: 48px; height: 20px;
border: 1px solid #ccc; border-radius: 20px;
background-color: white;
transition: all 1s ease;
}
#btn i {
display: inline-block; position: absolute;
top: 0; right: 28px;
height: 18px; width: 18px;
border-radius: 9px; border: 1px solid #ddd;
}
#btn:hover { background-color: #4cb946; }
#btn:hover i { right: 0; background-color: white; }
<!DOCTYPE html>
<html>
<head>
<style>
#btn {
position: relative; width: 48px; height: 20px;
border: 1px solid #ccc; border-radius: 20px;
background-color: white;
transition: all 1s ease;
}
#btn i {
display: inline-block; position: absolute;
top: 0; right: 28px;
height: 18px; width: 18px;
border-radius: 9px; border: 1px solid #ddd;
background-color: #4cb946;
transition: all 0.6s ease;
}
#btn:hover { background-color: #4cb946; }
#btn:hover i { right: 0; background-color: white; }
</style>
</head>
<body>
<div id="btn"><i id="btn_circle"></i></div>
</body>
</html>
▼ 点击展开完整代码

▼ 实现效果(悬停查看切换)

悬停开/关
3.6 @keyframes 动画 & 加载条效果
使用 @keyframes 定义动画过程,animation 属性设置时长/缓动/循环。animation-delay 错开各元素的动画起点。

}
@keyframes bump {
0%, 100% { transform: scaleY(0.3); }
50% { transform: scaleY(1.0); }
<!DOCTYPE html>
<html>
<head>
<style>
.loading {
margin: 100px auto;
width: 50px; height: 40px;
}
.loading div {
background-color: lightblue;
height: 100%; width: 6px;
display: inline-block;
animation: bump 1s infinite ease-in-out;
}
.loading .line1 { animation-delay: -0.5s; }
.loading .line2 { animation-delay: -0.6s; }
.loading .line3 { animation-delay: -0.7s; }
@keyframes bump {
0%, 100% { transform: scaleY(0.3); }
50% { transform: scaleY(1.0); }
}
</style>
</head>
<body>
<div class="loading">
<div class="line1"></div>
<div class="line2"></div>
<div class="line3"></div>
</div>
</body>
</html>
▼ 点击展开完整代码

▼ 实现效果

加载中...
3.7 文字滑入效果
父容器 overflow: hidden + 子 position: absolute + transition。默认文字滑出可视区(top: 100%),hover 时滑入(top: 0)。来自原代码"例5 文字滑入效果"。

#container { width: 510px; margin: 0 auto; }
.wrap {
width: 170px; height: 190px;
float: left; position: relative;
overflow: hidden;
}
.wrap .text {
width: 170px; height: 190px;
position: absolute; left: 0; top: 190px;
background-color: rgba(0,0,0,.3);
font-size: 12px; color: #fff;
transition: top 0.6s ease-in-out;
}
.wrap:hover .text { top: 0; }
<!DOCTYPE html>
<html>
<head>
<style>
#container { width: 510px; margin: 0 auto; }
.wrap {
width: 170px; height: 190px;
float: left; position: relative;
overflow: hidden;
}
.wrap img { width: 170px; height: 190px; }
.wrap .text {
width: 170px; height: 190px;
position: absolute; left: 0; top: 190px;
background-color: rgba(0,0,0,.3);
font-size: 12px; color: #fff;
transition: top 0.6s ease-in-out;
}
.wrap:hover .text { top: 0; }
</style>
</head>
<body>
<div id="container">
<div class="wrap">
<img src="1.jpg">
<div class="text">
<h1>Cappuccino</h1>
<p>手工热奶与细腻奶泡...</p>
</div>
</div>
</div>
</body>
</html>
▼ 点击展开完整代码

▼ 实现效果(悬停显示滑入文字)

图片1
说明文字 1
图片2
说明文字 2
图片3
说明文字 3
3.8 综合项目:咖啡店菜单页面
来自原代码"咖啡店"项目,综合运用了 CSS 定位、float 布局、过渡、变换、阴影等全部 CSS3 技术。左侧固定图片、导航栏、两栏布局、极坐标图片画廊、悬停放大效果。

<img src="images/cooker.jpg">
</div>
</div>
<nav>
<ul>
<li>首页</li>
<li>菜单</li>
</ul>
</nav>
<aside>侧边栏</aside>
<div id="content">
<div class="gallery">
<img src="images/Mocha.jpg">
<img src="images/Latte.jpg">
<img src="images/Espresso.jpg">
</div>
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<!-- 左侧固定图片 -->
<div id="l-fix">
<img src="images/cooker.jpg">
</div>
<!-- 横幅 -->
<div id="banner">
<img src="images/banner.gif">
</div>
<!-- 导航栏 -->
<nav>
<ul>
<li>首页</li>
<li>菜单</li>
</ul>
</nav>
<!-- 两栏内容 -->
<aside>侧边栏</aside>
<div id="content">
<div class="gallery">
<img src="images/Mocha.jpg">
<img src="images/Latte.jpg">
<img src="images/Espresso.jpg">
</div>
</div>
<footer>版权信息</footer>
</body>
</html>
▼ 点击展开完整代码

▼ 模拟效果

☕ 咖啡店菜单
美式咖啡
拿铁
摩卡
悬停图片放大
四、第10章 JavaScript 基本语法
4.1 输出方式
console.log() 调试输出;alert() 弹窗;document.write() 覆盖整个页面(谨慎使用);innerHTML 定点更新指定元素。

document.getElementById("show")
.innerHTML = "Hello World";
console.log("Hello World");
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>JS 输出</title>
</head>
<body>
<h1>say hello</h1>
<p id="show"></p>
<script>
// 找到id为show的元素,修改文本
document.getElementById("show")
.innerHTML = "Hello World";
console.log("Hello World");
// alert("Hello World");
</script>
</body>
</html>
▼ 点击展开完整代码

▼ 实现效果

点击按钮更新此内容
4.2 == 与 === 的区别
== 会进行类型转换后比较值(10 == "10" 为 true);=== 比较值且类型必须相同(10 === "10" 为 false)。推荐始终使用 ===。

var i = 10; var j = "10";
// == 先转换类型再比较值
document.write("10 == '10': " + (i == j) + "<br>");
// === 类型和值都必须相同
document.write("10 === '10': " + (i === j) + "<br>");
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>== vs ===</title>
</head>
<body>
<script>
var i = 10; var j = "10";
// == 先转换类型再比较值
document.write("10 == '10': " + (i == j) + "<br>");
// === 类型和值都必须相同
document.write("10 === '10': " + (i === j) + "<br>");
document.write("0 == false: " + (0 == false) + "<br>");
document.write("0 === false: " + (0 === false) + "<br>");
document.write("null == undefined: " + (null == undefined) + "<br>");
document.write("null === undefined: " + (null === undefined) + "<br>");
</script>
</body>
</html>
▼ 点击展开完整代码

▼ 实现效果

10 == "10"true(类型转换后值相等)

10 === "10"false(类型不同)

0 == falsetrue

0 === falsefalse

★ 始终使用 === 避免隐式转换陷阱

4.3 选择语句 & 循环语句
if/else if/else 条件分支;switch 多值匹配;for/while/do...while 循环。注意 break 退出整个循环,continue 跳过本次迭代。

let score = 70;
if (score < 60) { alert("不及格"); }
else if (score < 70) { alert("及格"); }
else if (score < 90) { alert("良"); }
else { alert("优秀"); }
}
for (let i = 0; i < arr.length; i++) {
htmlText += "<li>" + arr[i] + "</li>";
document.getElementById("stu").innerHTML = htmlText;
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>选择与循环</title>
</head>
<body>
<script>
//////////// if 语句 /////////////
let score = 70;
if (score < 60) { alert("不及格"); }
else if (score < 70) { alert("及格"); }
else if (score < 90) { alert("良"); }
else { alert("优秀"); }
//////////// switch 语句 /////////////
let stuType = "postGraduate";
switch (stuType) {
case "underGraduate": alert("本科生"); break;
case "postGraduate":
case "ph.D": alert("研究生"); break;
default: alert("不合理取值");
}
//////////// for 循环 /////////////
let arr = ["underGraduate","postGraduate","ph.D"];
let htmlText = "";
for (let i = 0; i < arr.length; i++) {
htmlText += "<li>" + arr[i] + "</li>";
}
document.getElementById("stu").innerHTML = htmlText;
</script>
</body>
</html>
▼ 点击展开完整代码

▼ 实现效果

    五、第13章 DOM 操作
    5.1 获取元素的方法
    通过 getElementById()(单个)、getElementsByClassName()(集合)、querySelector() / querySelectorAll()(CSS 选择器)获取 DOM 元素。推荐使用 querySelector 系列。
    
    let wrap = document.getElementById("wrapper");
    let ps = document.getElementsByTagName("p");
    let firstP = document.querySelector("p");
    let allP = document.querySelectorAll("p");
    
    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="UTF-8">
    <title>DOM 获取元素</title>
    </head>
    <body>
    <div id="wrapper"></div>
    <p>段落1</p><p>段落2</p>
    <script>
    // 通过 id
    let wrap = document.getElementById("wrapper");
    // 通过标签名
    let ps = document.getElementsByTagName("p");
    // 通过类名
    let items = document.getElementsByClassName("item");
    // 通过CSS选择器
    let firstP = document.querySelector("p");
    let allP = document.querySelectorAll("p");
    console.log("id:", wrap);
    console.log("tagName:", ps.length);
    console.log("querySelector:", firstP.textContent);
    </script>
    </body>
    </html>
    
    ▼ 点击展开完整代码

    ▼ 实现效果

    项目 1

    项目 2

    项目 3

    5.2 创建 & 添加 & 克隆 & 删除节点
    createElement() 创建新元素;appendChild() 添加到父节点;cloneNode(true) 深拷贝;removeChild()parentNode.removeChild() 删除。
    
    // 创建并添加
    let newNode = document.createElement("input");
    newNode.type = "text";
    newNode.name = "username";
    document.getElementById("myForm").appendChild(newNode);
    // 深克隆
    let list = document.getElementById("list");
    let clone = list.cloneNode(true);
    clone.id = "newList";
    document.body.appendChild(clone);
    // 删除
    let item = document.querySelector("li");
    item.parentNode.removeChild(item);
    
    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="UTF-8">
    <title>DOM CRUD</title>
    </head>
    <body>
    <form id="myForm"></form>
    <ul id="list">
    <li>项目1</li>
    <li>项目2</li>
    </ul>
    <script>
    // 创建并添加
    let newNode = document.createElement("input");
    newNode.type = "text";
    newNode.name = "username";
    document.getElementById("myForm").appendChild(newNode);
    // 深克隆
    let list = document.getElementById("list");
    let clone = list.cloneNode(true);
    clone.id = "newList";
    document.body.appendChild(clone);
    // 删除
    let item = document.querySelector("li");
    item.parentNode.removeChild(item);
    </script>
    </body>
    </html>
    
    ▼ 点击展开完整代码

    ▼ 实现效果

    已创建的元素将出现在这里
    5.3 行内样式 vs 计算后样式
    element.style.xxx 仅能读取/设置行内样式。window.getComputedStyle(element) 可读取最终生效样式(包含样式表和继承值)。
    
    let wrap = document.getElementById("wrap");
    let cs = window.getComputedStyle(wrap);
    
    <!DOCTYPE html>
    <html>
    <head>
    <style>
    #wrap { background-color: red; height: 300px; }
    </style>
    </head>
    <body>
    <div id="wrap" style="font-size:18px; width:200px;"></div>
    <script>
    let wrap = document.getElementById("wrap");
    console.log("style.width:", wrap.style.width);       // "200px"
    console.log("style.height:", wrap.style.height);      // null
    console.log("style.fontSize:", wrap.style.fontSize);  // "18px"
    console.log("style.backgroundColor:", wrap.style.backgroundColor); // null
    let cs = window.getComputedStyle(wrap);
    console.log("computed.width:", cs.width);             // "200px"
    console.log("computed.height:", cs.height);           // "300px"
    console.log("computed.backgroundColor:", cs.backgroundColor); // rgb(255,0,0)
    </script>
    </body>
    </html>
    
    ▼ 点击展开完整代码

    ▼ 实现效果

    行内宽200px
    5.4 事件注册:onclick vs addEventListener
    传统方式 onclick 只能绑定一个处理函数。现代方式 addEventListener() 可绑定多个,且支持捕获/冒泡控制(第三个参数),推荐使用。
    
    function handler1() { console.log("事件1触发"); }
    function handler2() { console.log("事件2触发"); }
    let btn = document.getElementById("btn");
    btn.addEventListener("click", handler1, false);
    btn.addEventListener("click", handler2, false);
    
    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="UTF-8">
    <title>事件注册</title>
    </head>
    <body>
    <button id="btn">点击我</button>
    <script>
    // 方式1: addEventListener(推荐)
    function handler1() { console.log("事件1触发"); }
    function handler2() { console.log("事件2触发"); }
    let btn = document.getElementById("btn");
    btn.addEventListener("click", handler1, false);
    btn.addEventListener("click", handler2, false);
    // btn.removeEventListener("click", handler1, false);
    // 方式2: onclick 属性(只能一个)
    // btn.onclick = function() { console.log("onclick"); };
    </script>
    </body>
    </html>
    
    ▼ 点击展开完整代码

    ▼ 实现效果

    5.5 事件冒泡与 event.target
    事件默认在冒泡阶段处理(从目标元素向上传播到父元素)。event.target 是触发事件的原始元素,event.currentTarget 是绑定处理器的元素。stopPropagation() 阻止冒泡。
    
    document.getElementById("a").addEventListener("click",
    function(e) { console.log("A 冒泡收到", e.target.id); }, false);
    document.getElementById("b").addEventListener("click",
    function(e) { console.log("B 冒泡收到", e.target.id); }, false);
    document.getElementById("c").addEventListener("click",
    function(e) { console.log("C 点击"); }, false);
    
    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="UTF-8">
    <title>事件冒泡</title>
    <style>
    #a { padding: 20px; background: #f00; }
    #b { padding: 20px; background: #0f0; }
    #c { padding: 20px; background: #00f; }
    </style>
    </head>
    <body>
    <div id="a">A
    <div id="b">B
    <div id="c">C</div>
    </div>
    </div>
    <script>
    // 冒泡阶段(默认false):c → b → a
    document.getElementById("a").addEventListener("click",
    function(e) { console.log("A 冒泡收到", e.target.id); }, false);
    document.getElementById("b").addEventListener("click",
    function(e) { console.log("B 冒泡收到", e.target.id); }, false);
    document.getElementById("c").addEventListener("click",
    function(e) { console.log("C 点击"); }, false);
    </script>
    </body>
    </html>
    
    ▼ 点击展开完整代码

    ▼ 实现效果(点击查看冒泡)

    外层 div(点击冒泡到这里)
    内层 div(点击触发,然后冒泡到外层)

    5.6 事件委托
    在父元素上绑定一个事件处理函数,通过 event.target 判断具体点击的子元素。避免为每个子元素单独注册事件,提升性能。
    
    document.getElementById("list-wrap").onclick = function(event) {
    let target = event.target;
    if (target.hasAttribute("data-action")) {
    let dataId = target.parentNode.getAttribute("data-id");
    switch (target.getAttribute("data-action")) {
    case "favorite":
    favoriteList.add(dataId);
    break;
    case "like":
    likeList.add(dataId);
    break;
    }
    }
    };
    
    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="UTF-8">
    <title>事件委托</title>
    </head>
    <body>
    <ul id="list-wrap">
    <li data-id="10001">
    <span data-action="showCont">标题</span>
    <button data-action="favorite">收藏</button>
    <button data-action="like">点赞</button>
    </li>
    </ul>
    <script>
    let favoriteList = new Set();
    let likeList = new Set();
    // 事件委托:一个处理器管理所有子元素
    document.getElementById("list-wrap").onclick = function(event) {
    let target = event.target;
    if (target.hasAttribute("data-action")) {
    let dataId = target.parentNode.getAttribute("data-id");
    switch (target.getAttribute("data-action")) {
    case "favorite":
    favoriteList.add(dataId);
    break;
    case "like":
    likeList.add(dataId);
    break;
    }
    }
    };
    </script>
    </body>
    </html>
    
    ▼ 点击展开完整代码

    ▼ 实现效果

    • 项目 A ⭐ 收藏
    • 项目 B ❤ 喜欢
    • 项目 C ✕ 删除

    点击列表项查看委托效果

    5.7 Tab 切换(综合应用)
    核心逻辑:点击标签时,清除所有标签的 active 类 → 当前标签设为 active → 隐藏所有内容面板 → 显示与点击标签 index 对应的面板。结合 data-* 自定义属性和 for 循环。
    
    .tab_title { display: flex; }
    }
    let lis = document.querySelectorAll(".tab_title li");
    let items = document.querySelectorAll(".item");
    items[0].style.display = "block"; // 默认显示第一项
    for (let i = 0; i < lis.length; i++) {
    lis[i].setAttribute("index", i);
    lis[i].onmouseover = function() {
    for (let j = 0; j < lis.length; j++) lis[j].className = "";
    this.className = "active";
    let idx = this.getAttribute("index");
    for (let j = 0; j < items.length; j++) items[j].style.display = "none";
    items[idx].style.display = "block";
    };
    
    <!DOCTYPE html>
    <html>
    <head>
    <style>
    .tab_title { display: flex; }
    .tab_title li {
    list-style: none; height: 50px;
    line-height: 50px; flex: 1;
    }
    .tab_title .active {
    background: orange;
    border-radius: 10px 10px 0 0;
    }
    .tab_cont { height: 150px; border: 1px orange solid; }
    .item { display: none; }
    </style>
    </head>
    <body>
    <div class="tab">
    <ul class="tab_title">
    <li class="active">HTML</li>
    <li>CSS</li>
    <li>JavaScript</li>
    </ul>
    <div class="tab_cont">
    <div class="item">HTML-结构</div>
    <div class="item">CSS-样式</div>
    <div class="item">JS-行为</div>
    </div>
    </div>
    <script>
    let lis = document.querySelectorAll(".tab_title li");
    let items = document.querySelectorAll(".item");
    items[0].style.display = "block"; // 默认显示第一项
    for (let i = 0; i < lis.length; i++) {
    lis[i].setAttribute("index", i);
    lis[i].onmouseover = function() {
    for (let j = 0; j < lis.length; j++) lis[j].className = "";
    this.className = "active";
    let idx = this.getAttribute("index");
    for (let j = 0; j < items.length; j++) items[j].style.display = "none";
    items[idx].style.display = "block";
    };
    }
    </script>
    </body>
    </html>
    
    ▼ 点击展开完整代码

    ▼ 实现效果

    HTML
    CSS
    JavaScript
    超文本标记语言,负责网页的结构和内容。
    层叠样式表,负责网页的样式和布局。
    编程语言,负责网页的交互和动态效果。