第一部分:事件传播机制
1.1 什么是事件传播
⭐ 老师强调 :事件传播发生在嵌套父子元素 绑定了相同事件类型时,触发其中一个会连带触发其他嵌套元素上的相同事件。就像洋葱层层包裹,碰外皮内层也感知到震动。
触发条件:
- 元素间存在嵌套关系(父子、祖孙)
- 这些元素绑定了相同事件类型 (如都是
click)
事件传播方向:
捕获阶段(从外到内):
body → container → father → child(触点元素)
↓
冒泡阶段(从内到外):
触点元素 child → father → container → body
1.2 事件传播的两个阶段
| 阶段 | 方向 | 说明 |
|---|---|---|
| 捕获阶段 | 从祖先到触点 | 从body→container→father→child |
| 冒泡阶段 | 从触点到祖先 | 从child→father→container→body(默认) |
⭐ 老师强调 :
onclick默认走冒泡阶段 。要观察捕获阶段,需用addEventListener并设置第三个参数为true。
代码示例:
window.onload = function() {
var body = document.querySelector("body");
var container = document.querySelector(".container");
var father = document.querySelector(".father");
var child = document.querySelector(".child");
// 方式1:onclick(默认冒泡阶段)
body.onclick = function() {
console.log("我是body");
};
container.onclick = function(e) {
e.stopPropagation(); // 阻止事件传播
console.log("我是container");
};
father.onclick = function() {
console.log("我是father");
};
child.onclick = function() {
console.log("我是child");
};
// 方式2:addEventListener(可指定阶段)
// 第三个参数:false=冒泡(默认),true=捕获
body.addEventListener("click", function() {
console.log("我是body");
}, true); // 捕获阶段
container.addEventListener("click", function(e) {
e.stopPropagation(); // 在捕获阶段拦截
console.log("我是container");
}, true);
father.addEventListener("click", function() {
console.log("我是father");
}, true);
child.addEventListener("click", function() {
console.log("我是child");
}, true);
};
1.3 阻止事件传播:stopPropagation()
// 在任意阶段调用,阻止事件继续传播
container.onclick = function(e) {
e.stopPropagation(); // 事件到此停止,不再向上/向下传播
console.log("我是container");
};
执行顺序示例(捕获阶段):
点击child时(捕获阶段,第三个参数为true):
执行顺序:body → container → father → child
若在container中调用e.stopPropagation():
执行顺序:body → container(停止,father和child不执行)
1.4 addEventListener 参数说明
element.addEventListener(事件类型, 事件函数, 传播阶段);
// └─字符串 └─函数 └─true=捕获 / false=冒泡(默认)
| 参数位置 | 说明 | 示例 |
|---|---|---|
| 第1个 | 事件类型(不带on) | "click"、"mouseenter" |
| 第2个 | 触发时执行的函数 | function(){...} |
| 第3个 | 传播阶段(可选) | true(捕获)/ false(冒泡,默认) |
第二部分:CSS关键帧动画
2.1 过渡动画 vs 真动画
⭐ 老师强调 :
transition只是过渡动画,只有开始和结束 两个状态。真动画(关键帧动画)可定义多个中间状态,像动画片由多帧组成。
| 对比项 | 过渡动画(transition) | 真动画(@keyframes) |
|---|---|---|
| 状态数量 | 仅起止两态 | 可定义多个中间状态 |
| 控制方式 | 自动计算中间值 | 手动设置关键帧 |
| 复杂度 | 简单 | 可复杂 |
| 适用场景 | 悬停效果、简单变化 | 循环动画、复杂特效 |
2.2 定义关键帧动画:@keyframes
/* 第一步:定义动画(关键帧) */
@keyframes change {
0% { /* 起始状态(可省略) */
width: 200px;
height: 150px;
background: yellow;
}
30% {
width: 300px;
height: 300px;
background: purple;
}
60% {
width: 400px;
height: 400px;
border-radius: 200px; /* 变成圆形 */
background: yellowgreen;
}
100% { /* 结束状态 */
background: blue;
width: 500px;
height: 500px;
}
}
⭐ 老师强调 :
from表示初始状态,to表示结束状态,等价于0%和100%。各关键帧独立设样式,按百分比进度平滑过渡。
2.3 使用动画:animation 复合属性
.demo {
/* 简写:一次设置所有属性 */
animation: change 4s ease 2s infinite alternate;
/* └名 └时长 └函数 └延迟 └次数 └方向 */
/* 分步写法 */
animation-name: change; /* 动画名称 */
animation-duration: 7s; /* 持续时间 */
animation-timing-function: ease; /* 速度曲线 */
animation-delay: 2s; /* 延迟时间 */
animation-iteration-count: infinite; /* 执行次数:无限 */
animation-direction: alternate; /* 方向:交替执行 */
}
animation 子属性说明:
| 属性 | 说明 | 示例值 |
|---|---|---|
animation-name |
指定动画名称 | change |
animation-duration |
持续时间 | 3s、1.2s |
animation-timing-function |
速度曲线 | ease、linear |
animation-delay |
延迟时间 | 0.5s、2s |
animation-iteration-count |
执行次数 | 1(默认)、infinite |
animation-direction |
执行方向 | alternate(交替)、normal |
2.4 动画方向:alternate(交替执行)
⭐ 老师强调 :默认动画是"结束→跳回开始"再执行,有断层。
alternate让动画从结束状态平滑倒放回开始,再正向执行,形成连续往返。
/* 普通:结束瞬间跳回开始 */
.demo {
animation: change 4s ease infinite;
}
/* 交替:结束平滑倒放回开始 */
.demo {
animation: change 4s ease infinite alternate;
}
2.5 逐字延迟动画示例(I LOVE YOU)
<div class="text">
<span>I</span>
<span>L</span>
<span>O</span>
<span>V</span>
<span>E</span>
<span>Y</span>
<span>O</span>
<span>U</span>
</div>
.text span {
animation: change 1.2s ease infinite alternate;
}
/* 每个字符错开延迟,形成依次变化效果 */
.text span:nth-child(2) { animation-delay: .2s; }
.text span:nth-child(3) { animation-delay: .4s; }
.text span:nth-child(4) { animation-delay: .5s; }
.text span:nth-child(5) { animation-delay: .7s; }
.text span:nth-child(6) { animation-delay: .9s; }
.text span:nth-child(7) { animation-delay: 1s; }
.text span:nth-child(8) { animation-delay: 1.2s; }
@keyframes change {
50% { color: #81ecec; }
100% {
color: #55efc4;
text-shadow: 77px 0px 35px #a29bfe;
font-size: 200px;
}
}
⭐ 老师强调 :动画必须加在
span标签上才能分别设延迟,不能加在父容器。第一个不延迟,其余每个递增延迟,形成"推波助澜"的递进效果------像多米诺骨牌,靠时间差形成连贯动画。
2.6 文字描边:-webkit-text-stroke
.text span {
/* 文字描边(WebKit内核) */
-webkit-text-stroke: 7px #fab1a0;
}
⭐ 老师强调 :描边相当于给每一个笔画 单独描边框,而非整体勾外轮廓。像字母
a中间镂空处,系统没法像人手那样"拐掉掏空",描出来不完美,这是自带处理的局限。
第三部分:服务器字体
3.1 本地字体的问题
⭐ 老师强调 :用
font-family直接指定字体(如宋体)依赖访问者电脑本地安装的字体。别人电脑没安装,就会走默认字体(如微软雅黑),导致显示不一致。
/* ❌ 依赖本地字体:别人电脑没宋体就失效 */
div {
font-family: "宋体";
}
3.2 @font-face 定义服务器字体
⭐ 老师强调 :把字体当作资源随服务器部署,访问时加载该资源,不依赖用户本地字体 。分两步:先用
@font-face定义,再用font-family引用。
/* 第一步:定义服务器字体 */
@font-face {
font-family: "demo"; /* 自定义字体名(随意) */
src: url("font/HuXiaoBoSaoBaoTi-2.otf"); /* 字体文件路径 */
/* format: .otf → "opentype" .ttf → "truetype" */
}
/* 第二步:使用字体 */
div {
font-family: "demo"; /* 引用上面定义的名字 */
font-size: 80px;
color: aqua;
}
多字体示例:
@font-face {
font-family: "demo";
src: url("font/HuXiaoBoSaoBaoTi-2.otf");
}
@font-face {
font-family: "text";
src: url("font/TravelightpersonaluseBold-z8o5D.ttf");
}
@font-face {
font-family: "run";
src: url("font/QianTuXiaoTuTi-2.ttf");
}
div { font-family: "demo"; font-size: 80px; color: aqua; }
p { font-family: "text"; font-size: 80px; color: gold; }
span { font-family: "run"; font-size: 80px; color: plum; }
3.3 字体文件格式
| 后缀 | format值 | 说明 |
|---|---|---|
.otf |
opentype |
OpenType字体 |
.ttf |
truetype |
TrueType字体 |
⭐ 老师强调 :字体文件只能是
.otf或.ttf。format写错会导致浏览器识别不了,要么不写让浏览器自己识别,要么写对。
3.4 字体兼容性注意
⭐ 老师强调 :自定义字体可能不支持中文,写中文会没效果,需实测确认。有的字体只认中文、有的只认英文、有的都认。下载后需自己打开测试。
<!-- 测试效果 -->
<div>你好</div> <!-- 可能无效 -->
<div>hello</div> <!-- 可能有效 -->
<p>hello你好</p> <!-- 混合测试 -->
第四部分:jQuery 核心语法
4.1 什么是jQuery
⭐ 老师强调 :jQuery是一个JavaScript库,对原生JS进行封装,简化了DOM操作、事件处理和Ajax请求。它不改变原生语法规则,只是把常用功能包成方法供调用。
原生JS vs jQuery:
| 对比项 | 原生JS | jQuery |
|---|---|---|
| 查找元素 | document.querySelectorAll() |
$() |
| 遍历绑定 | 手动for循环 |
内置循环,自动处理 |
| 隐藏元素 | element.style.display = "none" |
.hide() |
| 获取元素 | DOM元素 | jQuery对象(JDom) |
4.2 引入jQuery
<!-- 方式1:在线引入 -->
<script src="https://cdn.jsdelivr.net/npm/jquery@3.6.0/dist/jquery.min.js"></script>
<!-- 方式2:本地引入 -->
<script src="js/jquery.js"></script>
⭐ 老师强调 :jQuery本质就是个
.js文件,引入方式和普通JS完全一样。官网展示的是源码,复制即下载。
4.3 文档就绪函数
// 方式1:完整写法
$(document).ready(function() {
// DOM加载完成后执行
});
// 方式2:简写(推荐)
$(function() {
// DOM加载完成后执行
});
⭐ 老师强调 :
$(document).ready()等价于原生JS的window.onload,都是等HTML加载完再执行,避免找不到元素。简写为$(function(){...})。
4.4 jQuery核心语法:$()
// $() 是jQuery的语法标识,用于选择元素
$(selector).action()
// └─选择器 └─操作
// 示例
$(".btn").click(function() { ... }); // 选择class为btn的元素绑定点击
$("#id1").hide(); // 选择id为id1的元素隐藏
$("p").css("color", "red"); // 选择所有p标签改颜色
4.5 jQuery对象 vs DOM对象
⭐ 老师强调 :
$()获取的是jQuery对象(JDom) ,原生document.querySelector()获取的是DOM元素 。两者的方法不互通:JDom只能调jQuery方法,DOM只能调原生方法。
| 获取方式 | 返回类型 | 可调方法 |
|---|---|---|
$(".btn") |
jQuery对象(JDom) | .hide()、.css()、.click()等 |
document.querySelector(".btn") |
DOM元素 | style.display、addEventListener()等 |
相互转换:
// JDom → DOM(用下标)
var jdom = $(".btn");
var dom = jdom[0]; // 或 jdom.get(0)
dom.style.background = "red"; // 调原生方法
// DOM → JDom(用$()包裹)
var dom = document.querySelector(".btn");
var jdom = $(dom);
jdom.css("background", "red"); // 调jQuery方法
⭐ 老师强调 :中括号取值会脱离jQuery封装 ,变成原生DOM,之后只能用原生方法。反过来用
$()包裹原生DOM就能用jQuery方法。
// ❌ 常见错误:混用方法
$(".test")[0].css("color", "red"); // 报错![0]后是DOM,无css方法
// ✅ 正确用法
$(".test").css("color", "red"); // JDom调jQuery方法
$(".test")[0].style.color = "red"; // DOM调原生方法
第五部分:jQuery DOM操作
5.1 内容操作
| 方法 | 说明 | 对应原生 |
|---|---|---|
.text() |
获取/设置纯文本 | innerText |
.html() |
获取/设置HTML内容 | innerHTML |
.val() |
获取/设置表单值 | value |
.attr() |
获取/设置属性 | getAttribute/setAttribute |
规则: 括号内传参=设置 ,不传参=获取
// 获取
var text = $(".demo").text();
var html = $(".demo").html();
var value = $(".info").val();
var attr = $(".demo").attr("index");
// 设置
$(".demo").text("新文本");
$(".demo").html("<h1>新标题</h1>");
$(".info").val("新值");
$(".demo").attr("index", "5");
5.2 样式操作:.css()
// 获取样式(传一个参数)
var bg = $(".demo").css("background-color");
// 设置样式(传两个参数)
$(".demo").css("background", "yellow");
$(".demo").css("color", "#888");
// 批量设置(传对象)
$(".demo").css({
"color": "#888",
"text-decoration": "line-through"
});
5.3 类操作
| 方法 | 说明 |
|---|---|
.addClass("类名") |
添加类 |
.removeClass("类名") |
移除类 |
.toggleClass("类名") |
切换类 |
.hasClass("类名") |
判断是否有某类 |
5.4 添加元素
| 方法 | 说明 | 位置 |
|---|---|---|
.append(内容) |
在内部末尾添加 | 子元素最后 |
.prepend(内容) |
在内部开头添加 | 子元素最前 |
.after(内容) |
在元素后面添加 | 兄弟元素 |
.before(内容) |
在元素前面添加 | 兄弟元素 |
// 示例
$(".demo").append("<p>追加内容</p>"); // 内部末尾
$(".demo").prepend("<p>开头内容</p>"); // 内部开头
$("p").after("<p>后面的兄弟</p>"); // 后面
$("p").before("<p>前面的兄弟</p>"); // 前面
// jQuery方式添加表格行
$("tbody").append(
'<tr>' +
'<td index="' + idCard + '">' + $(".info").val() + '</td>' +
'<td>' +
'<input type="button" class="finish" value="完成">' +
'<input type="button" class="update" value="修改">' +
'<input type="button" class="delete" value="删除">' +
'</td>' +
'</tr>'
);
⭐ 老师强调 :jQuery添加节点不用
createElement,直接传HTML字符串即可,比原生简洁很多。注意引号嵌套------外单内双或外双内单。
5.5 删除元素
| 方法 | 说明 |
|---|---|
.remove() |
删除元素本身(连壳带肉) |
.empty() |
清空内部内容(留壳) |
$(".demo").remove(); // 删除整个元素
$(".demo").empty(); // 清空内部,元素保留
5.6 关系查找
| 方法 | 说明 |
|---|---|
.parent() |
直接父元素 |
.parents() |
所有祖先元素 |
.prev() |
前一个兄弟元素 |
.next() |
后一个兄弟元素 |
.children() |
所有子元素 |
.find(选择器) |
后代中查找 |
// 示例
$(this).parent().remove(); // 删除父元素
$(this).parent().prev().css("color", "red"); // 父级的前一个兄弟
$(this).parents("ul").css("border", "1px solid red"); // 祖先ul
5.7 eq() 方法:按索引取元素
⭐ 老师强调 :jQuery对象不能用
[0]下标(会转成DOM),要用.eq(索引)取指定位置的JDom元素。
// ❌ 错误:用下标会变成DOM,失去jQuery方法
$("td")[0].css("color", "red"); // 报错!
// ✅ 正确:用eq()保持JDom
$("td").eq(0).css("color", "red"); // 第一个td变红
第六部分:jQuery事件绑定
6.1 事件绑定方式
// 方式1:事件函数绑定(去掉on前缀)
$(".btn").click(function() {
alert("点击了");
});
// 常用事件:click, mouseenter, mouseleave, focus, blur
// 注意:原生onclick → jQuery click(去on)
6.2 hover 特殊事件
⭐ 老师强调 :
hover是jQuery自行封装的,原生JS没有。它把鼠标进入和离开合并为一个方法。
// hover:鼠标进入触发第一个函数,离开触发第二个
$(".menu > li").hover(
function() {
// 鼠标放上去:展开
$(this).find(".model").css("height", "200px");
},
function() {
// 鼠标离开:收起
$(this).find(".model").css("height", "0");
}
);
6.3 on() 事件绑定
// 方式1:普通绑定(事件类型 + 函数)
$(".btn").on("click", function() {
alert("点击了");
});
// 方式2:委托绑定(事件类型 + 目标元素 + 函数)
// ⭐ 用于绑定动态生成的未来元素
$("tbody").on("click", ".delete", function() {
$(this).parent().parent().remove();
});
⭐ 老师强调 :委托绑定中,代理容器必须是原本就存在的祖先元素 (如
tbody、table、body),不能是后来动态生成的。on会循环批量给所有匹配元素绑事件,不论未来新增几个都能生效。
普通绑定 vs 委托绑定:
| 对比项 | 普通绑定 | 委托绑定 |
|---|---|---|
| 参数 | (事件, 函数) |
(事件, 目标元素, 函数) |
| 适用元素 | 已存在的元素 | 动态生成的未来元素 |
| 容器要求 | 目标元素本身 | 必须是静态祖先 |
6.4 动态事件绑定
// 方式1:直接事件函数(动态元素不适用)
$(".delete").click(function() {
// 只对初始存在的.delete生效
});
// 方式2:on委托(动态元素适用)⭐推荐
$("tbody").on("click", ".delete", function() {
$(this).parent().parent().remove();
});
// 方式3:每次添加后重新绑定(繁琐,不推荐)
function bindEvents() {
$(".delete").click(function() { ... });
}
第七部分:jQuery To-Do List 完整实现
$(function() {
var idCard = 0; // 唯一标识计数器
var targetIdCard; // 要修改的目标行标识
// 1. 添加 / 修改(共用同一按钮)
$(".btn").click(function() {
var text = $(".info").val().trim();
if (text) {
if ($(".btn").val() == "添加") {
// 添加
$("tbody").append(
'<tr>' +
'<td index="' + idCard + '">' + text + '</td>' +
'<td>' +
'<input type="button" class="finish" value="完成">' +
'<input type="button" class="update" value="修改">' +
'<input type="button" class="delete" value="删除">' +
'</td>' +
'</tr>'
);
idCard++;
$(".info").val("");
} else {
// 修改
var list = $("table tr td:nth-child(1)");
for (var i = 0; i < list.length; i++) {
if (list.eq(i).attr("index") == targetIdCard) {
list.eq(i).text(text);
$(".info").val("");
$(".btn").val("添加");
$(".btn").css("background", "#feca57");
}
}
}
}
});
// 2. 删除(委托绑定未来元素)
$("tbody").on("click", ".delete", function() {
$(this).parent().parent().remove();
});
// 3. 完成(委托绑定未来元素)
$("tbody").on("click", ".finish", function() {
$(this).parent().prev().css("color", "#888");
$(this).parent().prev().css("text-decoration", "line-through");
$(this).css("background", "#aaa");
});
// 4. 修改回显(委托绑定未来元素)
$("tbody").on("click", ".update", function() {
var td = $(this).parent().prev();
$(".info").val(td.text());
$(".btn").val("修改");
$(".btn").css("background", "#48dbfb");
targetIdCard = td.attr("index");
});
});
附录一:事件传播代码示例(事件传播.html)
<!DOCTYPE html>
<html>
<head>
<style>
.container { width: 600px; height: 600px; background: gold; }
.father { width: 400px; height: 400px; background: pink; }
.child { width: 200px; height: 200px; background: plum; }
</style>
<script>
window.onload = function() {
var body = document.querySelector("body");
var container = document.querySelector(".container");
var father = document.querySelector(".father");
var child = document.querySelector(".child");
// 捕获阶段演示
body.addEventListener("click", function() {
console.log("我是body");
}, true);
container.addEventListener("click", function(e) {
e.stopPropagation(); // 在此拦截
console.log("我是container");
}, true);
father.addEventListener("click", function() {
console.log("我是father");
}, true);
child.addEventListener("click", function() {
console.log("我是child");
}, true);
}
</script>
</head>
<body>
<div class="container">
<div class="father">
<div class="child"></div>
</div>
</div>
</body>
</html>
附录二:jQuery方法速查表
选择器
| 写法 | 说明 |
|---|---|
$("p") |
所有p标签 |
$("#id1") |
id为id1的元素 |
$(".demo") |
class为demo的元素 |
内容操作
| 方法 | 说明 |
|---|---|
.text() |
获取/设置纯文本 |
.html() |
获取/设置HTML |
.val() |
获取/设置表单值 |
.attr() |
获取/设置属性 |
样式操作
| 方法 | 说明 |
|---|---|
.css() |
获取/设置CSS样式 |
.addClass() |
添加类 |
.removeClass() |
移除类 |
.toggleClass() |
切换类 |
DOM操作
| 方法 | 说明 |
|---|---|
.append() |
内部末尾添加 |
.prepend() |
内部开头添加 |
.after() |
后面添加 |
.before() |
前面添加 |
.remove() |
删除自身 |
.empty() |
清空内部 |
关系查找
| 方法 | 说明 |
|---|---|
.parent() |
直接父级 |
.parents() |
所有祖先 |
.prev() |
前一个兄弟 |
.next() |
后一个兄弟 |
.eq(索引) |
按索引取元素 |
事件绑定
| 方法 | 说明 |
|---|---|
.click(fn) |
点击事件 |
.hover(fn1, fn2) |
悬停事件 |
.on(event, fn) |
普通绑定 |
.on(event, selector, fn) |
委托绑定 |