Compare commits
13 Commits
81004b437c
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2a65ba8c6a | ||
|
|
7c0cbe1320 | ||
|
|
acb1445575 | ||
|
|
3850ce7399 | ||
|
|
d0d8be443b | ||
|
|
d5ff59ac76 | ||
|
|
8b83f63235 | ||
|
|
1071f4db05 | ||
|
|
3435848495 | ||
|
|
00d3c9e4c6 | ||
|
|
3afbee1535 | ||
|
|
7be97e7ea7 | ||
|
|
f3bdaa4e88 |
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
node_modules
|
||||||
@@ -6,12 +6,27 @@
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>居中专题</title>
|
<title>居中专题</title>
|
||||||
<style>
|
<style>
|
||||||
|
html {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
background-color: rgb(255, 248, 238);
|
background-color: rgb(255, 248, 238);
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
position: fixed;
|
||||||
}
|
}
|
||||||
|
|
||||||
.stage {
|
.stage {
|
||||||
|
position: absolute;
|
||||||
|
left: 50%;
|
||||||
|
top: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
background-color: white;
|
background-color: white;
|
||||||
border: 1px solid rgba(255, 156, 7, 0.25);
|
border: 1px solid rgba(255, 156, 7, 0.25);
|
||||||
border-radius: 20px;
|
border-radius: 20px;
|
||||||
@@ -34,7 +49,7 @@
|
|||||||
|
|
||||||
<body>
|
<body>
|
||||||
<div class="stage">
|
<div class="stage">
|
||||||
<div class="box">把我放到中间</div>
|
<div class="box">把我放到中间 transform: translate(-50%, -50%); </div>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,14 @@
|
|||||||
const userName = "";
|
const userName = "小明";
|
||||||
let currentStage = "";
|
let currentStage = "学习中";
|
||||||
let completedExercises = 0;
|
let completedExercises = 0;
|
||||||
|
completedExercises = 2;
|
||||||
|
console.log('学习者:' + userName);
|
||||||
|
console.log('学习阶段:' + currentStage);
|
||||||
|
console.log('学习次数:' + completedExercises);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 任务:
|
// 任务:
|
||||||
// 1. 给上面的变量赋一个合理值
|
// 1. 给上面的变量赋一个合理值
|
||||||
|
|||||||
@@ -6,3 +6,11 @@ const hasPaid = true;
|
|||||||
// 1. 把 ageText 转成数字,保存到 ageNumber
|
// 1. 把 ageText 转成数字,保存到 ageNumber
|
||||||
// 2. 分别输出 studentName、ageText、ageNumber、hasPaid 的类型
|
// 2. 分别输出 studentName、ageText、ageNumber、hasPaid 的类型
|
||||||
// 3. 用模板字符串输出一句报名信息
|
// 3. 用模板字符串输出一句报名信息
|
||||||
|
const ageNumber = Number(ageText);
|
||||||
|
console.log(typeof studentName);
|
||||||
|
console.log(typeof ageText);
|
||||||
|
console.log(typeof ageNumber);
|
||||||
|
console.log(typeof hasPaid);
|
||||||
|
alert('姓名:${studentName},年龄:{ageNumber},报名状态:{hasPaid}')
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,31 @@ const score = 86;
|
|||||||
// 1. 用布尔值保存是否及格
|
// 1. 用布尔值保存是否及格
|
||||||
// 2. 用 if...else if...else 判断等级
|
// 2. 用 if...else if...else 判断等级
|
||||||
// 3. 输出分数、是否及格、等级
|
// 3. 输出分数、是否及格、等级
|
||||||
|
/*- 根据分数计算是否及格
|
||||||
|
- 根据分数输出等级
|
||||||
|
- 90 分及以上为 A
|
||||||
|
- 80 到 89 为 B
|
||||||
|
- 60 到 79 为 C
|
||||||
|
- 60 以下为 D*/
|
||||||
let passed = false;
|
let passed = false;
|
||||||
let grade = "";
|
let grade = "";
|
||||||
|
let point = 70;
|
||||||
|
|
||||||
|
if (point >= 90) {
|
||||||
|
grade = 'A'
|
||||||
|
} else if (point >= 80 && point <= 89) {
|
||||||
|
grade = 'B'
|
||||||
|
} else if (point >= 60 && point <= 79) {
|
||||||
|
grade = 'C'
|
||||||
|
} else if (point <= 60) {
|
||||||
|
grade = 'D'
|
||||||
|
}
|
||||||
|
|
||||||
|
if (grade != 'D') {
|
||||||
|
passed = true
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('分数:${point}');
|
||||||
|
console.log('是否及格:${passed}');
|
||||||
|
console.log('等级:${grade}');
|
||||||
|
|
||||||
|
|||||||
@@ -5,3 +5,17 @@
|
|||||||
// 4. 输出 sum
|
// 4. 输出 sum
|
||||||
|
|
||||||
let sum = 0;
|
let sum = 0;
|
||||||
|
for (let i = 1; i <= 7; i++) {
|
||||||
|
console.log(i);
|
||||||
|
if (i == 4) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let j = 1
|
||||||
|
while (j <= 5) {
|
||||||
|
sum = sum + j
|
||||||
|
j++
|
||||||
|
}
|
||||||
|
console.log(sum);
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,30 @@
|
|||||||
function getAverage(score1, score2, score3) {
|
function getAverage(score1, score2, score3) {
|
||||||
|
return (score1 + score2 + score3) / 3
|
||||||
// 返回平均分
|
// 返回平均分
|
||||||
}
|
}
|
||||||
|
|
||||||
function getLevel(average) {
|
function getLevel(average) {
|
||||||
|
if (average >= 90) {
|
||||||
|
return '优秀'
|
||||||
|
} else if (average >= 60 && average < 90) {
|
||||||
|
return '良好'
|
||||||
|
} else {
|
||||||
|
return '继续努力'
|
||||||
|
}
|
||||||
// 根据平均分返回等级描述
|
// 根据平均分返回等级描述
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const average = getAverage(75, 89, 100)
|
||||||
|
const level = getLevel(average)
|
||||||
|
console.log(average);
|
||||||
|
console.log(level);
|
||||||
|
|
||||||
|
|
||||||
// 任务:
|
// 任务:
|
||||||
// 1. 调用上面两个函数
|
// 1. 调用上面两个函数
|
||||||
// 2. 输出平均分和等级
|
// 2. 输出平均分和等级
|
||||||
|
/*- 写一个 `getAverage` 函数
|
||||||
|
- 接收 3 个分数参数
|
||||||
|
- 返回平均分
|
||||||
|
- 再写一个 `getLevel` 函数
|
||||||
|
- 根据平均分返回“优秀”“良好”“继续努力”*/
|
||||||
|
|||||||
@@ -4,3 +4,13 @@ const topics = ["HTML", "CSS", "JavaScript"];
|
|||||||
// 1. 往 topics 里新增一个主题
|
// 1. 往 topics 里新增一个主题
|
||||||
// 2. 输出 topics 的长度
|
// 2. 输出 topics 的长度
|
||||||
// 3. 用循环输出每一项
|
// 3. 用循环输出每一项
|
||||||
|
/*- 创建一个包含 3 个学习主题的数组
|
||||||
|
- 新增 1 个学习主题
|
||||||
|
- 输出数组长度
|
||||||
|
- 依次输出每个学习主题*/
|
||||||
|
topics.push('Vue')
|
||||||
|
console.log(topics.length);
|
||||||
|
for (let i = 0; i < topics.length; i++) {
|
||||||
|
console.log(topics[i]);
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@@ -9,3 +9,15 @@ const course = {
|
|||||||
// 2. 新增 teacher 属性
|
// 2. 新增 teacher 属性
|
||||||
// 3. 输出完整对象
|
// 3. 输出完整对象
|
||||||
// 4. 输出 title 和 teacher
|
// 4. 输出 title 和 teacher
|
||||||
|
/*- 创建一个课程对象
|
||||||
|
- 至少包含名称、课时、是否完结
|
||||||
|
- 修改其中一个属性
|
||||||
|
- 新增一个老师属性
|
||||||
|
- 输出完整对象和其中两个单独属性*/
|
||||||
|
course.finished = true
|
||||||
|
course.teacher = '李老师'
|
||||||
|
console.log(course);
|
||||||
|
console.log(course.title);
|
||||||
|
console.log(course.lessons);
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -6,3 +6,11 @@ const tags = ["变量", "条件", "函数"];
|
|||||||
// 2. 转成大写
|
// 2. 转成大写
|
||||||
// 3. 判断是否包含 JS
|
// 3. 判断是否包含 JS
|
||||||
// 4. 把 tags 用顿号连接成一句话
|
// 4. 把 tags 用顿号连接成一句话
|
||||||
|
/*- 把一段带空格的文本去掉首尾空格
|
||||||
|
- 把结果转成大写
|
||||||
|
- 判断里面是否包含 `JS`
|
||||||
|
- 把一个标签数组拼成一个字符串输出*/
|
||||||
|
const rawTrim = rawTitle.trim()
|
||||||
|
const rawTo = rawTitle.toUpperCase()
|
||||||
|
const result = rawTitle.includes("JS")
|
||||||
|
const tagsJoin = rawTitle.join(",")
|
||||||
@@ -2,10 +2,27 @@ function createCounter() {
|
|||||||
let count = 0;
|
let count = 0;
|
||||||
|
|
||||||
// 返回一个函数
|
// 返回一个函数
|
||||||
|
function a() {
|
||||||
|
count++
|
||||||
|
return count
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const counterA = createCounter()
|
||||||
|
const counterB = createCounter()
|
||||||
|
|
||||||
|
console.log(counterA());
|
||||||
|
console.log(counterA());
|
||||||
|
console.log(counterB());
|
||||||
|
|
||||||
// 任务:
|
// 任务:
|
||||||
// 1. 创建 counterA 和 counterB
|
// 1. 创建 counterA 和 counterB
|
||||||
// 2. 连续调用 counterA 两次
|
// 2. 连续调用 counterA 两次
|
||||||
// 3. 再调用 counterB 一次
|
// 3. 再调用 counterB 一次
|
||||||
// 4. 观察为什么两个计数器互不影响
|
// 4. 观察为什么两个计数器互不影响
|
||||||
|
/*写一个 `createCounter` 函数
|
||||||
|
- 在函数内部定义 `count`
|
||||||
|
- 返回一个内部函数
|
||||||
|
- 每次调用内部函数时,`count` 都加 1
|
||||||
|
- 创建两个不同的计数器
|
||||||
|
- 观察为什么它们各自记住了自己的 `count`*/
|
||||||
|
|||||||
@@ -7,14 +7,35 @@ const scores = [78, 85, 92];
|
|||||||
|
|
||||||
function getAverageScore(list) {
|
function getAverageScore(list) {
|
||||||
// 计算平均分
|
// 计算平均分
|
||||||
|
let sum = 0
|
||||||
|
for (let i = 0; i < list.length; i++) {
|
||||||
|
sum = sum + list[i]
|
||||||
|
}
|
||||||
|
return sum / list.length
|
||||||
}
|
}
|
||||||
|
|
||||||
function getLevel(average) {
|
function getLevel(average) {
|
||||||
// 返回等级
|
// 返回等级
|
||||||
|
if (average >= 80) {
|
||||||
|
return "可以进入下一阶段"
|
||||||
|
} else {
|
||||||
|
return "保持当前等级"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const average = getAverageScore(scores)
|
||||||
|
const level = getLevel(average)
|
||||||
|
|
||||||
|
console.log("姓名:" + student.name + "阶段:" + student.stage + "平均分:" + "average" + "等级:" + level);
|
||||||
|
|
||||||
// 任务:
|
// 任务:
|
||||||
// 1. 计算平均分
|
// 1. 计算平均分
|
||||||
// 2. 计算等级
|
// 2. 计算等级
|
||||||
// 3. 输出姓名、阶段、平均分、等级
|
// 3. 输出姓名、阶段、平均分、等级
|
||||||
// 4. 如果平均分 >= 80,输出“可以进入下一阶段”
|
// 4. 如果平均分 >= 80,输出“可以进入下一阶段”
|
||||||
|
/*一个 `student` 对象
|
||||||
|
- 一个 `scores` 数组
|
||||||
|
- 一个计算平均分的函数
|
||||||
|
- 一个判断等级的函数
|
||||||
|
- 输出姓名、平均分、等级
|
||||||
|
- 如果平均分大于等于 80,再输出“可以进入下一阶段”*/
|
||||||
@@ -13,15 +13,24 @@ function compareScope() {
|
|||||||
|
|
||||||
console.log("块内:", lessonName, chapterName, stage);
|
console.log("块内:", lessonName, chapterName, stage);
|
||||||
}
|
}
|
||||||
|
var lessonName = "变量";
|
||||||
|
let chapterName = "作用域";
|
||||||
|
const stage = "进阶";
|
||||||
|
console.log("块内:", lessonName);
|
||||||
// 任务:
|
// 任务:
|
||||||
// 1. 输出 lessonName
|
// 1. 输出 lessonName
|
||||||
// 2. 不要直接在这里输出 chapterName,否则会报错
|
// 2. 不要直接在这里输出 chapterName,否则会报错
|
||||||
// 3. 用一句注释说明为什么
|
// 3. 用一句注释说明为什么
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
compareScope();
|
compareScope();
|
||||||
|
|
||||||
// 任务:
|
// 任务:
|
||||||
// 4. 试着重新给 const 声明的值赋值
|
// 4. 试着重新给 const 声明的值赋值
|
||||||
// 5. 观察会发生什么
|
// 5. 观察会发生什么
|
||||||
|
/*观察 `var` 声明前为什么能访问到 `undefined`
|
||||||
|
- 用 `var` 声明一个函数内部变量
|
||||||
|
- 用 `let` 声明一个代码块内部变量
|
||||||
|
- 在可访问的位置输出它们
|
||||||
|
- 观察为什么 `var` 在块外还能访问,而 `let` 不行
|
||||||
|
- 再写一段代码证明 `const` 不能被重新赋值*/
|
||||||
@@ -25,3 +25,11 @@
|
|||||||
|
|
||||||
- [starter.js](/Users/lijiaqing/home/wwwroot/front-end-example/03-javascript-core/12-this-keyword/starter.js)
|
- [starter.js](/Users/lijiaqing/home/wwwroot/front-end-example/03-javascript-core/12-this-keyword/starter.js)
|
||||||
- [answer.js](/Users/lijiaqing/home/wwwroot/front-end-example/03-javascript-core/12-this-keyword/answer.js)
|
- [answer.js](/Users/lijiaqing/home/wwwroot/front-end-example/03-javascript-core/12-this-keyword/answer.js)
|
||||||
|
|
||||||
|
function a() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const b = () => {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -4,15 +4,25 @@ const student = {
|
|||||||
sayHello() {
|
sayHello() {
|
||||||
// 任务:
|
// 任务:
|
||||||
// 1. 用 this.name 输出问候语
|
// 1. 用 this.name 输出问候语
|
||||||
|
console.log(this.name + "你好!");
|
||||||
|
|
||||||
},
|
},
|
||||||
createArrowReporter() {
|
createArrowReporter() {
|
||||||
// 任务:
|
// 任务:
|
||||||
// 2. 返回一个箭头函数
|
// 2. 返回一个箭头函数
|
||||||
// 3. 在箭头函数里输出 this.name
|
// 3. 在箭头函数里输出 this.name
|
||||||
|
return () => {
|
||||||
|
console.log(this.name);
|
||||||
|
|
||||||
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// 任务:
|
// 任务:
|
||||||
// 4. 调用 student.sayHello()
|
// 4. 调用 student.sayHello()
|
||||||
|
student.sayHello()
|
||||||
// 5. 把 student.sayHello 赋值给 detachedHello 再调用
|
// 5. 把 student.sayHello 赋值给 detachedHello 再调用
|
||||||
|
const detachedHello = student.sayHello
|
||||||
|
detachedHello()
|
||||||
// 6. 调用 createArrowReporter 返回的新函数
|
// 6. 调用 createArrowReporter 返回的新函数
|
||||||
|
student.createArrowReporter()()
|
||||||
|
|||||||
@@ -5,6 +5,20 @@ const students = [
|
|||||||
{ name: "小陈", finished: false },
|
{ name: "小陈", finished: false },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const scores1 = scores.map(item => item = item + '分')
|
||||||
|
const scores2 = scores.filter(item => item > 60)
|
||||||
|
const scores3 = scores.reduce((acc, item) => { return item + acc }, 0)
|
||||||
|
const scores4 = scores.find(item => item >= 90)
|
||||||
|
const scores5 = scores.some(item => item >= 90)
|
||||||
|
const scores6 = students.every(item => item.finished === true)
|
||||||
|
|
||||||
|
console.log("分数:" + scores1);
|
||||||
|
console.log("及格分:" + scores2);
|
||||||
|
console.log("总分:" + scores3);
|
||||||
|
console.log("第一个 >= 90 的分数:" + scores4);
|
||||||
|
console.log("是否存在不及格:" + scores5);
|
||||||
|
console.log("是否都及格:" + scores6);
|
||||||
|
|
||||||
// 任务:
|
// 任务:
|
||||||
// 1. 用 map 生成 ["58分", ...]
|
// 1. 用 map 生成 ["58分", ...]
|
||||||
// 2. 用 filter 筛出及格分
|
// 2. 用 filter 筛出及格分
|
||||||
@@ -12,3 +26,9 @@ const students = [
|
|||||||
// 4. 用 find 找到第一个 >= 90 的分数
|
// 4. 用 find 找到第一个 >= 90 的分数
|
||||||
// 5. 用 some 判断是否存在不及格
|
// 5. 用 some 判断是否存在不及格
|
||||||
// 6. 用 every 判断 students 是否都 finished 为 true
|
// 6. 用 every 判断 students 是否都 finished 为 true
|
||||||
|
/* 用 `map` 生成带单位的新数组
|
||||||
|
- 用 `filter` 找出及格成绩
|
||||||
|
- 用 `reduce` 计算总分
|
||||||
|
- 用 `find` 找出第一条大于等于 90 的成绩
|
||||||
|
- 用 `some` 判断是否有人不及格
|
||||||
|
- 用 `every` 判断是否全部完成考试*/
|
||||||
@@ -19,7 +19,16 @@ function printStepTwo() {
|
|||||||
function updateUser(user) {
|
function updateUser(user) {
|
||||||
// 任务:
|
// 任务:
|
||||||
// 1. 修改 user.city
|
// 1. 修改 user.city
|
||||||
|
user.city = '北京'
|
||||||
}
|
}
|
||||||
|
scoreB = 90
|
||||||
|
console.log('scoreA' + scoreA + ',scoreB' + scoreB);
|
||||||
|
userB.city = '秦皇岛'
|
||||||
|
console.log(userA.city, userB.city);
|
||||||
|
printStepOne()
|
||||||
|
printStepTwo()
|
||||||
|
updateUser(userA)
|
||||||
|
console.log(userA);
|
||||||
|
|
||||||
// 任务:
|
// 任务:
|
||||||
// 2. 修改 scoreB,观察 scoreA 是否变化
|
// 2. 修改 scoreB,观察 scoreA 是否变化
|
||||||
|
|||||||
@@ -6,9 +6,43 @@ const finalComment = null;
|
|||||||
let statusText = "";
|
let statusText = "";
|
||||||
const finishedRecords = [];
|
const finishedRecords = [];
|
||||||
|
|
||||||
|
switch (learningStatus) {
|
||||||
|
case 'review':
|
||||||
|
console.log('已学习')
|
||||||
|
break
|
||||||
|
case 'ing':
|
||||||
|
console.log('学习中');
|
||||||
|
break
|
||||||
|
case 'prepare':
|
||||||
|
console.log('未学习');
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
console.log('状态未知');
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(optionalNote, finalComment);
|
||||||
|
|
||||||
|
for (let i = 0; i < records.length; i++) {
|
||||||
|
if (records[i] === null || records[i] === undefined) {
|
||||||
|
console.log(`第${i + 1}项为空值,停止读取`)
|
||||||
|
break
|
||||||
|
} else {
|
||||||
|
finishedRecords.push(records[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(finishedRecords)
|
||||||
|
|
||||||
|
|
||||||
// 任务:
|
// 任务:
|
||||||
// 1. 用 switch 给 learningStatus 生成说明文字
|
// 1. 用 switch 给 learningStatus 生成说明文字
|
||||||
// 2. 输出 optionalNote 和 finalComment 分别是什么
|
// 2. 输出 optionalNote 和 finalComment 分别是什么
|
||||||
// 3. 用 for 循环读取 records
|
// 3. 用 for 循环读取 records
|
||||||
// 4. 如果遇到 undefined 或 null,就 break
|
// 4. 如果遇到 undefined 或 null,就 break
|
||||||
// 5. 输出 finishedRecords
|
// 5. 输出 finishedRecords
|
||||||
|
/*用 `switch` 根据学习状态输出不同说明
|
||||||
|
- 观察 `undefined` 和 `null` 的区别
|
||||||
|
- 用循环读取学习记录
|
||||||
|
- 如果读到 `undefined` 或 `null`,立即用 `break` 停止循环
|
||||||
|
- 输出停止前已经读取到的内容*/
|
||||||
@@ -2,6 +2,7 @@ const reviewer = {
|
|||||||
name: "林晨",
|
name: "林晨",
|
||||||
stage: "final-review",
|
stage: "final-review",
|
||||||
showTitle() {
|
showTitle() {
|
||||||
|
console.log(`学习营总复盘器`);
|
||||||
// 输出总复盘标题
|
// 输出总复盘标题
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@@ -14,12 +15,47 @@ const lessons = [
|
|||||||
{ title: "综合回顾", score: 95, finished: true },
|
{ title: "综合回顾", score: 95, finished: true },
|
||||||
];
|
];
|
||||||
|
|
||||||
let mentorNote;
|
let mentorNote;//undefined
|
||||||
const reviewComment = null;
|
const reviewComment = null;//null
|
||||||
|
|
||||||
function getStageText(stage) {
|
function getStageText(stage) {
|
||||||
// 用 switch 返回阶段说明
|
// 用 switch 返回阶段说明
|
||||||
|
switch (stage) {
|
||||||
|
case 'final-review':
|
||||||
|
console.log('已学习');
|
||||||
|
break
|
||||||
|
case 'ing-review':
|
||||||
|
console.log('学习中');
|
||||||
|
break
|
||||||
|
case 'start-review':
|
||||||
|
console.log('未学习');
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
console.log('状态未知');
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
reviewer.showTitle()
|
||||||
|
|
||||||
|
console.log(mentorNote, reviewComment);
|
||||||
|
|
||||||
|
const lessons1 = []
|
||||||
|
for (let i = 0; i < lessons.length; i++) {
|
||||||
|
if (lessons[i].score != null) {
|
||||||
|
lessons1.push(lessons[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const sum = lessons.reduce((acc, item) => {
|
||||||
|
return acc + item.score
|
||||||
|
}, 0)
|
||||||
|
console.log("总分:" + sum);
|
||||||
|
console.log(`平均分:${sum / lessons.length}`);
|
||||||
|
|
||||||
|
|
||||||
|
const reviewerAlias = reviewer
|
||||||
|
reviewerAlias.stage = 'ing-review'
|
||||||
|
console.log(reviewer.stage, reviewerAlias.stage);
|
||||||
|
|
||||||
// 任务:
|
// 任务:
|
||||||
// 1. 调用 reviewer.showTitle()
|
// 1. 调用 reviewer.showTitle()
|
||||||
@@ -28,3 +64,11 @@ function getStageText(stage) {
|
|||||||
// 4. 用高阶函数统计课程标题、完成状态和平均分
|
// 4. 用高阶函数统计课程标题、完成状态和平均分
|
||||||
// 5. 创建 reviewerAlias 指向 reviewer,修改 stage,观察原对象是否变化
|
// 5. 创建 reviewerAlias 指向 reviewer,修改 stage,观察原对象是否变化
|
||||||
// 6. 输出最终结果
|
// 6. 输出最终结果
|
||||||
|
/* 一个带方法的 `reviewer` 对象
|
||||||
|
- 一个 `lessons` 数组
|
||||||
|
- 一个用 `switch` 输出阶段说明的函数
|
||||||
|
- 一个用 `for + break` 清洗有效数据的过程
|
||||||
|
- 至少两个数组高阶函数
|
||||||
|
- 对 `undefined` 和 `null` 的判断
|
||||||
|
- 一段对象引用变化的观察代码
|
||||||
|
- 最终输出标题、有效课程、平均分、完成状态*/
|
||||||
|
|||||||
28
04-dom-events-async/01-query-selectors/README.md
Normal file
28
04-dom-events-async/01-query-selectors/README.md
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
# 练习 1:获取元素
|
||||||
|
|
||||||
|
## 目标
|
||||||
|
|
||||||
|
学会用几种常见方式拿到页面元素。
|
||||||
|
|
||||||
|
## 你要练什么
|
||||||
|
|
||||||
|
- `getElementById`
|
||||||
|
- `querySelector`
|
||||||
|
- `querySelectorAll`
|
||||||
|
- 元素文本读取
|
||||||
|
|
||||||
|
## 任务
|
||||||
|
|
||||||
|
请基于页面结构完成以下操作:
|
||||||
|
|
||||||
|
- 选中主标题
|
||||||
|
- 选中“开始学习”按钮
|
||||||
|
- 选中全部学习卡片
|
||||||
|
- 在控制台输出标题文字、按钮文字和卡片数量
|
||||||
|
|
||||||
|
## 文件
|
||||||
|
|
||||||
|
- [starter.html](/Users/lijiaqing/home/wwwroot/front-end-example/04-dom-events-async/01-query-selectors/starter.html)
|
||||||
|
- [starter.js](/Users/lijiaqing/home/wwwroot/front-end-example/04-dom-events-async/01-query-selectors/starter.js)
|
||||||
|
- [answer.html](/Users/lijiaqing/home/wwwroot/front-end-example/04-dom-events-async/01-query-selectors/answer.html)
|
||||||
|
- [answer.js](/Users/lijiaqing/home/wwwroot/front-end-example/04-dom-events-async/01-query-selectors/answer.js)
|
||||||
52
04-dom-events-async/01-query-selectors/answer.html
Normal file
52
04-dom-events-async/01-query-selectors/answer.html
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>获取元素</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
padding: 32px;
|
||||||
|
font-family: "PingFang SC", "Microsoft YaHei", sans-serif;
|
||||||
|
background: #f6f8fb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel {
|
||||||
|
max-width: 760px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 24px;
|
||||||
|
border-radius: 20px;
|
||||||
|
background: #ffffff;
|
||||||
|
border: 1px solid #dbe3f0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cards {
|
||||||
|
display: grid;
|
||||||
|
gap: 12px;
|
||||||
|
margin-top: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
padding: 16px;
|
||||||
|
border-radius: 14px;
|
||||||
|
background: #f8fbff;
|
||||||
|
border: 1px solid #dce8f8;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<section class="panel">
|
||||||
|
<h1 id="page-title">DOM 获取元素练习</h1>
|
||||||
|
<button class="start-btn" type="button">开始学习</button>
|
||||||
|
|
||||||
|
<div class="cards">
|
||||||
|
<article class="card">获取标题</article>
|
||||||
|
<article class="card">获取按钮</article>
|
||||||
|
<article class="card">获取一组卡片</article>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<script src="./answer.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
7
04-dom-events-async/01-query-selectors/answer.js
Normal file
7
04-dom-events-async/01-query-selectors/answer.js
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
const title = document.getElementById("page-title");
|
||||||
|
const button = document.querySelector(".start-btn");
|
||||||
|
const cards = document.querySelectorAll(".card");
|
||||||
|
|
||||||
|
console.log("标题:", title.textContent);
|
||||||
|
console.log("按钮:", button.textContent);
|
||||||
|
console.log("卡片数量:", cards.length);
|
||||||
59
04-dom-events-async/01-query-selectors/starter.html
Normal file
59
04-dom-events-async/01-query-selectors/starter.html
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>获取元素</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
padding: 32px;
|
||||||
|
font-family: "PingFang SC", "Microsoft YaHei", sans-serif;
|
||||||
|
background: #f6f8fb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel {
|
||||||
|
max-width: 760px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 24px;
|
||||||
|
border-radius: 20px;
|
||||||
|
background: #ffffff;
|
||||||
|
border: 1px solid #dbe3f0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cards {
|
||||||
|
display: grid;
|
||||||
|
gap: 12px;
|
||||||
|
margin-top: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
padding: 16px;
|
||||||
|
border-radius: 14px;
|
||||||
|
background: #f8fbff;
|
||||||
|
border: 1px solid #dce8f8;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<section class="panel">
|
||||||
|
<h1 id="page-title">
|
||||||
|
<p>111</p> 获取元素练习
|
||||||
|
</h1>
|
||||||
|
<button class="start-btn" type="button">开始学习</button>
|
||||||
|
|
||||||
|
<div class="cards">
|
||||||
|
<article class="card">获取标题</article>
|
||||||
|
<article class="card">获取按钮</article>
|
||||||
|
<article class="card">获取一组卡片</article>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<script src="./starter.js"></script>
|
||||||
|
|
||||||
|
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
13
04-dom-events-async/01-query-selectors/starter.js
Normal file
13
04-dom-events-async/01-query-selectors/starter.js
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
// 任务:
|
||||||
|
// 1. 用 getElementById 获取标题
|
||||||
|
// 2. 用 querySelector 获取按钮
|
||||||
|
// 3. 用 querySelectorAll 获取全部卡片
|
||||||
|
// 4. 在控制台输出标题文字、按钮文字和卡片数量
|
||||||
|
const a = document.getElementById("page-title")
|
||||||
|
console.log(a.textContent);
|
||||||
|
const b = document.querySelector(".start-btn")
|
||||||
|
console.log(b.textContent);
|
||||||
|
const c = document.querySelectorAll(".card")
|
||||||
|
console.log(c.length);
|
||||||
|
|
||||||
|
|
||||||
25
04-dom-events-async/02-text-class-style/README.md
Normal file
25
04-dom-events-async/02-text-class-style/README.md
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
# 练习 2:修改文本、类名和样式
|
||||||
|
|
||||||
|
## 目标
|
||||||
|
|
||||||
|
学会改元素内容、切换类名和设置简单样式。
|
||||||
|
|
||||||
|
## 你要练什么
|
||||||
|
|
||||||
|
- `textContent`
|
||||||
|
- `classList.add`
|
||||||
|
- `classList.remove`
|
||||||
|
- `style`
|
||||||
|
|
||||||
|
## 任务
|
||||||
|
|
||||||
|
- 把标题改成“今天已完成 DOM 练习”
|
||||||
|
- 给状态标签加上完成样式
|
||||||
|
- 修改说明文字颜色
|
||||||
|
|
||||||
|
## 文件
|
||||||
|
|
||||||
|
- [starter.html](/Users/lijiaqing/home/wwwroot/front-end-example/04-dom-events-async/02-text-class-style/starter.html)
|
||||||
|
- [starter.js](/Users/lijiaqing/home/wwwroot/front-end-example/04-dom-events-async/02-text-class-style/starter.js)
|
||||||
|
- [answer.html](/Users/lijiaqing/home/wwwroot/front-end-example/04-dom-events-async/02-text-class-style/answer.html)
|
||||||
|
- [answer.js](/Users/lijiaqing/home/wwwroot/front-end-example/04-dom-events-async/02-text-class-style/answer.js)
|
||||||
47
04-dom-events-async/02-text-class-style/answer.html
Normal file
47
04-dom-events-async/02-text-class-style/answer.html
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>修改文本、类名和样式</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
padding: 32px;
|
||||||
|
font-family: "PingFang SC", "Microsoft YaHei", sans-serif;
|
||||||
|
background: #f3f6fb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
max-width: 720px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 24px;
|
||||||
|
border-radius: 18px;
|
||||||
|
background: #ffffff;
|
||||||
|
border: 1px solid #d9e3f2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 6px 12px;
|
||||||
|
border-radius: 999px;
|
||||||
|
background: #eef2f7;
|
||||||
|
color: #4b5563;
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge.done {
|
||||||
|
background: #dcfce7;
|
||||||
|
color: #166534;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<section class="card">
|
||||||
|
<h1 id="title">今天的学习状态</h1>
|
||||||
|
<p id="description">当前还没有更新进度。</p>
|
||||||
|
<span id="badge" class="badge">进行中</span>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<script src="./answer.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
9
04-dom-events-async/02-text-class-style/answer.js
Normal file
9
04-dom-events-async/02-text-class-style/answer.js
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
const title = document.getElementById("title");
|
||||||
|
const description = document.getElementById("description");
|
||||||
|
const badge = document.getElementById("badge");
|
||||||
|
|
||||||
|
title.textContent = "今天已完成 DOM 练习";
|
||||||
|
description.textContent = "已经练习了元素选择、文本修改和样式切换。";
|
||||||
|
description.style.color = "#2563eb";
|
||||||
|
badge.textContent = "已完成";
|
||||||
|
badge.classList.add("done");
|
||||||
47
04-dom-events-async/02-text-class-style/starter.html
Normal file
47
04-dom-events-async/02-text-class-style/starter.html
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>修改文本、类名和样式</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
padding: 32px;
|
||||||
|
font-family: "PingFang SC", "Microsoft YaHei", sans-serif;
|
||||||
|
background: #f3f6fb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
max-width: 720px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 24px;
|
||||||
|
border-radius: 18px;
|
||||||
|
background: #ffffff;
|
||||||
|
border: 1px solid #d9e3f2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 6px 12px;
|
||||||
|
border-radius: 999px;
|
||||||
|
background: #eef2f7;
|
||||||
|
color: #4b5563;
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge.done {
|
||||||
|
background: #dcfce7;
|
||||||
|
color: #166534;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<section class="card">
|
||||||
|
<h1 id="title">今天的学习状态</h1>
|
||||||
|
<p id="description">当前还没有更新进度。</p>
|
||||||
|
<span id="badge" class="badge">进行中</span>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<script src="./starter.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
11
04-dom-events-async/02-text-class-style/starter.js
Normal file
11
04-dom-events-async/02-text-class-style/starter.js
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
// 任务:
|
||||||
|
// 1. 选中标题、描述、状态标签
|
||||||
|
// 2. 修改标题文字
|
||||||
|
// 3. 给标签加上 done 类名
|
||||||
|
// 4. 修改描述文字颜色
|
||||||
|
const a = document.getElementById("title")
|
||||||
|
const b = document.getElementById("description")
|
||||||
|
const c = document.getElementById("badge")
|
||||||
|
a.textContent = "学习状态非常好"
|
||||||
|
a.classList.add("badge.done")
|
||||||
|
b.style.color = "red"
|
||||||
24
04-dom-events-async/03-create-and-remove/README.md
Normal file
24
04-dom-events-async/03-create-and-remove/README.md
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
# 练习 3:创建和删除节点
|
||||||
|
|
||||||
|
## 目标
|
||||||
|
|
||||||
|
学会动态新增和删除页面节点。
|
||||||
|
|
||||||
|
## 你要练什么
|
||||||
|
|
||||||
|
- `createElement`
|
||||||
|
- `appendChild`
|
||||||
|
- `remove`
|
||||||
|
- 事件绑定
|
||||||
|
|
||||||
|
## 任务
|
||||||
|
|
||||||
|
- 点击“新增任务”时往列表里加一个新项
|
||||||
|
- 点击“删除最后一项”时删除最后一个列表项
|
||||||
|
|
||||||
|
## 文件
|
||||||
|
|
||||||
|
- [starter.html](/Users/lijiaqing/home/wwwroot/front-end-example/04-dom-events-async/03-create-and-remove/starter.html)
|
||||||
|
- [starter.js](/Users/lijiaqing/home/wwwroot/front-end-example/04-dom-events-async/03-create-and-remove/starter.js)
|
||||||
|
- [answer.html](/Users/lijiaqing/home/wwwroot/front-end-example/04-dom-events-async/03-create-and-remove/answer.html)
|
||||||
|
- [answer.js](/Users/lijiaqing/home/wwwroot/front-end-example/04-dom-events-async/03-create-and-remove/answer.js)
|
||||||
47
04-dom-events-async/03-create-and-remove/answer.html
Normal file
47
04-dom-events-async/03-create-and-remove/answer.html
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>创建和删除节点</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
padding: 32px;
|
||||||
|
font-family: "PingFang SC", "Microsoft YaHei", sans-serif;
|
||||||
|
background: #f5f7fb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel {
|
||||||
|
max-width: 720px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 24px;
|
||||||
|
border-radius: 18px;
|
||||||
|
background: #ffffff;
|
||||||
|
border: 1px solid #dce4ef;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul {
|
||||||
|
padding-left: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<section class="panel">
|
||||||
|
<h1>任务列表</h1>
|
||||||
|
<button id="add-btn" type="button">新增任务</button>
|
||||||
|
<button id="remove-btn" type="button">删除最后一项</button>
|
||||||
|
|
||||||
|
<ul id="task-list">
|
||||||
|
<li>学习 querySelector</li>
|
||||||
|
<li>学习 classList</li>
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<script src="./answer.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
20
04-dom-events-async/03-create-and-remove/answer.js
Normal file
20
04-dom-events-async/03-create-and-remove/answer.js
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
const addButton = document.getElementById("add-btn");
|
||||||
|
const removeButton = document.getElementById("remove-btn");
|
||||||
|
const taskList = document.getElementById("task-list");
|
||||||
|
|
||||||
|
let taskIndex = 3;
|
||||||
|
|
||||||
|
addButton.addEventListener("click", function () {
|
||||||
|
const item = document.createElement("li");
|
||||||
|
item.textContent = `新任务 ${taskIndex}`;
|
||||||
|
taskList.appendChild(item);
|
||||||
|
taskIndex += 1;
|
||||||
|
});
|
||||||
|
|
||||||
|
removeButton.addEventListener("click", function () {
|
||||||
|
const lastItem = taskList.lastElementChild;
|
||||||
|
|
||||||
|
if (lastItem) {
|
||||||
|
lastItem.remove();
|
||||||
|
}
|
||||||
|
});
|
||||||
47
04-dom-events-async/03-create-and-remove/starter.html
Normal file
47
04-dom-events-async/03-create-and-remove/starter.html
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>创建和删除节点</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
padding: 32px;
|
||||||
|
font-family: "PingFang SC", "Microsoft YaHei", sans-serif;
|
||||||
|
background: #f5f7fb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel {
|
||||||
|
max-width: 720px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 24px;
|
||||||
|
border-radius: 18px;
|
||||||
|
background: #ffffff;
|
||||||
|
border: 1px solid #dce4ef;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul {
|
||||||
|
padding-left: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<section class="panel">
|
||||||
|
<h1>任务列表</h1>
|
||||||
|
<button id="add-btn" type="button">新增任务</button>
|
||||||
|
<button id="remove-btn" type="button">删除最后一项</button>
|
||||||
|
|
||||||
|
<ul id="task-list">
|
||||||
|
<li>学习 querySelector</li>
|
||||||
|
<li>学习 classList</li>
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<script src="./starter.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
22
04-dom-events-async/03-create-and-remove/starter.js
Normal file
22
04-dom-events-async/03-create-and-remove/starter.js
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
// 任务:
|
||||||
|
// 1. 获取新增按钮、删除按钮和列表
|
||||||
|
// 2. 点击新增按钮时创建一个新的 li 并追加到列表
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// 3. 点击删除按钮时删除最后一个 li
|
||||||
|
const add = document.getElementById("add-btn")
|
||||||
|
const remove = document.getElementById("remove-btn")
|
||||||
|
const list = document.getElementById("task-list")
|
||||||
|
add.onclick = function () {
|
||||||
|
const a = document.createElement("li")
|
||||||
|
a.textContent = "巧克力"
|
||||||
|
list.appendChild(a)
|
||||||
|
}
|
||||||
|
remove.onclick = function () {
|
||||||
|
const c = list.lastElementChild
|
||||||
|
if (c) {
|
||||||
|
c.remove()
|
||||||
|
}
|
||||||
|
}
|
||||||
25
04-dom-events-async/04-click-counter/README.md
Normal file
25
04-dom-events-async/04-click-counter/README.md
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
# 练习 4:点击计数器
|
||||||
|
|
||||||
|
## 目标
|
||||||
|
|
||||||
|
学会给按钮绑定点击事件,并更新页面数据。
|
||||||
|
|
||||||
|
## 你要练什么
|
||||||
|
|
||||||
|
- `addEventListener`
|
||||||
|
- 点击事件
|
||||||
|
- 数字状态更新
|
||||||
|
- DOM 渲染
|
||||||
|
|
||||||
|
## 任务
|
||||||
|
|
||||||
|
- 点击加一按钮时计数加 1
|
||||||
|
- 点击减一按钮时计数减 1
|
||||||
|
- 点击重置按钮时恢复为 0
|
||||||
|
|
||||||
|
## 文件
|
||||||
|
|
||||||
|
- [starter.html](/Users/lijiaqing/home/wwwroot/front-end-example/04-dom-events-async/04-click-counter/starter.html)
|
||||||
|
- [starter.js](/Users/lijiaqing/home/wwwroot/front-end-example/04-dom-events-async/04-click-counter/starter.js)
|
||||||
|
- [answer.html](/Users/lijiaqing/home/wwwroot/front-end-example/04-dom-events-async/04-click-counter/answer.html)
|
||||||
|
- [answer.js](/Users/lijiaqing/home/wwwroot/front-end-example/04-dom-events-async/04-click-counter/answer.js)
|
||||||
51
04-dom-events-async/04-click-counter/answer.html
Normal file
51
04-dom-events-async/04-click-counter/answer.html
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>点击计数器</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
min-height: 100vh;
|
||||||
|
display: grid;
|
||||||
|
place-items: center;
|
||||||
|
font-family: "PingFang SC", "Microsoft YaHei", sans-serif;
|
||||||
|
background: #f4f7fb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.counter {
|
||||||
|
width: 320px;
|
||||||
|
padding: 24px;
|
||||||
|
text-align: center;
|
||||||
|
border-radius: 20px;
|
||||||
|
background: #ffffff;
|
||||||
|
border: 1px solid #dbe3ef;
|
||||||
|
}
|
||||||
|
|
||||||
|
#value {
|
||||||
|
font-size: 48px;
|
||||||
|
font-weight: 800;
|
||||||
|
}
|
||||||
|
|
||||||
|
.actions {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<section class="counter">
|
||||||
|
<h1>点击计数器</h1>
|
||||||
|
<p id="value">0</p>
|
||||||
|
<div class="actions">
|
||||||
|
<button id="decrease-btn" type="button">-1</button>
|
||||||
|
<button id="increase-btn" type="button">+1</button>
|
||||||
|
<button id="reset-btn" type="button">重置</button>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<script src="./answer.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
25
04-dom-events-async/04-click-counter/answer.js
Normal file
25
04-dom-events-async/04-click-counter/answer.js
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
let count = 0;
|
||||||
|
|
||||||
|
const value = document.getElementById("value");
|
||||||
|
const decreaseButton = document.getElementById("decrease-btn");
|
||||||
|
const increaseButton = document.getElementById("increase-btn");
|
||||||
|
const resetButton = document.getElementById("reset-btn");
|
||||||
|
|
||||||
|
function render() {
|
||||||
|
value.textContent = count;
|
||||||
|
}
|
||||||
|
|
||||||
|
decreaseButton.addEventListener("click", function () {
|
||||||
|
count -= 1;
|
||||||
|
render();
|
||||||
|
});
|
||||||
|
|
||||||
|
increaseButton.addEventListener("click", function () {
|
||||||
|
count += 1;
|
||||||
|
render();
|
||||||
|
});
|
||||||
|
|
||||||
|
resetButton.addEventListener("click", function () {
|
||||||
|
count = 0;
|
||||||
|
render();
|
||||||
|
});
|
||||||
51
04-dom-events-async/04-click-counter/starter.html
Normal file
51
04-dom-events-async/04-click-counter/starter.html
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>点击计数器</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
min-height: 100vh;
|
||||||
|
display: grid;
|
||||||
|
place-items: center;
|
||||||
|
font-family: "PingFang SC", "Microsoft YaHei", sans-serif;
|
||||||
|
background: #f4f7fb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.counter {
|
||||||
|
width: 320px;
|
||||||
|
padding: 24px;
|
||||||
|
text-align: center;
|
||||||
|
border-radius: 20px;
|
||||||
|
background: #ffffff;
|
||||||
|
border: 1px solid #dbe3ef;
|
||||||
|
}
|
||||||
|
|
||||||
|
#value {
|
||||||
|
font-size: 48px;
|
||||||
|
font-weight: 800;
|
||||||
|
}
|
||||||
|
|
||||||
|
.actions {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<section class="counter">
|
||||||
|
<h1>点击计数器</h1>
|
||||||
|
<p id="value">0</p>
|
||||||
|
<div class="actions">
|
||||||
|
<button id="decrease-btn" type="button">-1</button>
|
||||||
|
<button id="increase-btn" type="button">+1</button>
|
||||||
|
<button id="reset-btn" type="button">重置</button>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<script src="./starter.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
29
04-dom-events-async/04-click-counter/starter.js
Normal file
29
04-dom-events-async/04-click-counter/starter.js
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
let count = 0;
|
||||||
|
|
||||||
|
// 任务:
|
||||||
|
// 1. 获取数字元素和 3 个按钮
|
||||||
|
// 2. 点击按钮时更新 count
|
||||||
|
// 3. 每次修改后,把最新 count 渲染到页面
|
||||||
|
const num = document.getElementById("value")
|
||||||
|
const del = document.getElementById("decrease-btn")
|
||||||
|
const add = document.getElementById("increase-btn")
|
||||||
|
const reset = document.getElementById("reset-btn")
|
||||||
|
|
||||||
|
function ren() {
|
||||||
|
num.textContent = count
|
||||||
|
}
|
||||||
|
|
||||||
|
add.addEventListener("click", function () {
|
||||||
|
count++
|
||||||
|
ren()
|
||||||
|
})
|
||||||
|
|
||||||
|
del.addEventListener("click", function () {
|
||||||
|
count--
|
||||||
|
ren()
|
||||||
|
})
|
||||||
|
|
||||||
|
reset.addEventListener("click", function () {
|
||||||
|
count = 0
|
||||||
|
ren()
|
||||||
|
})
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
# 练习 5:表单提交和 preventDefault
|
||||||
|
|
||||||
|
## 目标
|
||||||
|
|
||||||
|
学会拦截表单默认提交,并把输入内容渲染到页面。
|
||||||
|
|
||||||
|
## 你要练什么
|
||||||
|
|
||||||
|
- `submit` 事件
|
||||||
|
- `preventDefault()`
|
||||||
|
- 表单值读取
|
||||||
|
- 动态追加列表项
|
||||||
|
|
||||||
|
## 任务
|
||||||
|
|
||||||
|
- 提交表单时阻止页面刷新
|
||||||
|
- 读取输入框内容
|
||||||
|
- 把内容加入到待办列表
|
||||||
|
- 提交后清空输入框
|
||||||
|
|
||||||
|
## 文件
|
||||||
|
|
||||||
|
- [starter.html](/Users/lijiaqing/home/wwwroot/front-end-example/04-dom-events-async/05-form-submit-and-prevent-default/starter.html)
|
||||||
|
- [starter.js](/Users/lijiaqing/home/wwwroot/front-end-example/04-dom-events-async/05-form-submit-and-prevent-default/starter.js)
|
||||||
|
- [answer.html](/Users/lijiaqing/home/wwwroot/front-end-example/04-dom-events-async/05-form-submit-and-prevent-default/answer.html)
|
||||||
|
- [answer.js](/Users/lijiaqing/home/wwwroot/front-end-example/04-dom-events-async/05-form-submit-and-prevent-default/answer.js)
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>表单提交和 preventDefault</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
padding: 32px;
|
||||||
|
font-family: "PingFang SC", "Microsoft YaHei", sans-serif;
|
||||||
|
background: #f5f7fb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel {
|
||||||
|
max-width: 720px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 24px;
|
||||||
|
border-radius: 18px;
|
||||||
|
background: #ffffff;
|
||||||
|
border: 1px solid #dce4ef;
|
||||||
|
}
|
||||||
|
|
||||||
|
form {
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
flex: 1;
|
||||||
|
padding: 10px 12px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<section class="panel">
|
||||||
|
<h1>学习待办</h1>
|
||||||
|
|
||||||
|
<form id="todo-form">
|
||||||
|
<input id="todo-input" type="text" placeholder="输入今天要学的内容" />
|
||||||
|
<button type="submit">添加</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<ul id="todo-list">
|
||||||
|
<li>完成 DOM 选择练习</li>
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<script src="./answer.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
const form = document.getElementById("todo-form");
|
||||||
|
const input = document.getElementById("todo-input");
|
||||||
|
const list = document.getElementById("todo-list");
|
||||||
|
|
||||||
|
form.addEventListener("submit", function (event) {
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
const value = input.value.trim();
|
||||||
|
|
||||||
|
if (!value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const item = document.createElement("li");
|
||||||
|
item.textContent = value;
|
||||||
|
list.appendChild(item);
|
||||||
|
input.value = "";
|
||||||
|
});
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>表单提交和 preventDefault</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
padding: 32px;
|
||||||
|
font-family: "PingFang SC", "Microsoft YaHei", sans-serif;
|
||||||
|
background: #f5f7fb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel {
|
||||||
|
max-width: 720px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 24px;
|
||||||
|
border-radius: 18px;
|
||||||
|
background: #ffffff;
|
||||||
|
border: 1px solid #dce4ef;
|
||||||
|
}
|
||||||
|
|
||||||
|
form {
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
flex: 1;
|
||||||
|
padding: 10px 12px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<section class="panel">
|
||||||
|
<h1>学习待办</h1>
|
||||||
|
|
||||||
|
<form id="todo-form">
|
||||||
|
<input id="todo-input" type="text" placeholder="输入今天要学的内容" />
|
||||||
|
<button type="submit">添加</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<ul id="todo-list">
|
||||||
|
<li>完成 DOM 选择练习</li>
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<script src="./starter.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
// 任务:
|
||||||
|
// 1. 获取表单、输入框和列表
|
||||||
|
// 2. 监听 submit 事件
|
||||||
|
// 3. 用 preventDefault() 阻止默认提交
|
||||||
|
// 4. 读取输入框内容,创建新 li,追加到列表
|
||||||
|
// 5. 清空输入框
|
||||||
|
const form = document.getElementById("todo-form")
|
||||||
|
const input = document.getElementById("todo-input")
|
||||||
|
const list = document.getElementById("todo-list")
|
||||||
|
|
||||||
|
form.addEventListener("submit", function (e) {
|
||||||
|
e.preventDefault()
|
||||||
|
const text = input.value.trim()
|
||||||
|
if (text) {
|
||||||
|
const li = document.createElement("li")
|
||||||
|
li.textContent = text
|
||||||
|
list.appendChild(li)
|
||||||
|
input.value = ""
|
||||||
|
}
|
||||||
|
})
|
||||||
25
04-dom-events-async/06-bubbling-and-delegation/README.md
Normal file
25
04-dom-events-async/06-bubbling-and-delegation/README.md
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
# 练习 6:冒泡、委托和 stopPropagation
|
||||||
|
|
||||||
|
## 目标
|
||||||
|
|
||||||
|
理解事件会冒泡,并学会在列表里使用事件委托。
|
||||||
|
|
||||||
|
## 你要练什么
|
||||||
|
|
||||||
|
- 事件冒泡
|
||||||
|
- `event.target`
|
||||||
|
- 事件委托
|
||||||
|
- `stopPropagation()`
|
||||||
|
|
||||||
|
## 任务
|
||||||
|
|
||||||
|
- 点击外层面板时输出一条日志
|
||||||
|
- 点击列表项时,通过事件委托切换激活状态
|
||||||
|
- 点击列表项里的删除按钮时,阻止冒泡并删除当前项
|
||||||
|
|
||||||
|
## 文件
|
||||||
|
|
||||||
|
- [starter.html](/Users/lijiaqing/home/wwwroot/front-end-example/04-dom-events-async/06-bubbling-and-delegation/starter.html)
|
||||||
|
- [starter.js](/Users/lijiaqing/home/wwwroot/front-end-example/04-dom-events-async/06-bubbling-and-delegation/starter.js)
|
||||||
|
- [answer.html](/Users/lijiaqing/home/wwwroot/front-end-example/04-dom-events-async/06-bubbling-and-delegation/answer.html)
|
||||||
|
- [answer.js](/Users/lijiaqing/home/wwwroot/front-end-example/04-dom-events-async/06-bubbling-and-delegation/answer.js)
|
||||||
58
04-dom-events-async/06-bubbling-and-delegation/answer.html
Normal file
58
04-dom-events-async/06-bubbling-and-delegation/answer.html
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>冒泡、委托和 stopPropagation</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
padding: 32px;
|
||||||
|
font-family: "PingFang SC", "Microsoft YaHei", sans-serif;
|
||||||
|
background: #f5f7fb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel {
|
||||||
|
max-width: 760px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 24px;
|
||||||
|
border-radius: 20px;
|
||||||
|
background: #ffffff;
|
||||||
|
border: 1px solid #dbe2ee;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lesson-item {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 12px 14px;
|
||||||
|
border: 1px solid #dbe2ee;
|
||||||
|
border-radius: 12px;
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lesson-item.active {
|
||||||
|
background: #dbeafe;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<section id="panel" class="panel">
|
||||||
|
<h1>事件委托练习</h1>
|
||||||
|
<p>点击列表项可以切换高亮,点击删除按钮可以移除当前项。</p>
|
||||||
|
|
||||||
|
<ul id="lesson-list">
|
||||||
|
<li class="lesson-item">
|
||||||
|
<span>事件冒泡</span>
|
||||||
|
<button class="remove-btn" type="button">删除</button>
|
||||||
|
</li>
|
||||||
|
<li class="lesson-item">
|
||||||
|
<span>事件委托</span>
|
||||||
|
<button class="remove-btn" type="button">删除</button>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<script src="./answer.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
27
04-dom-events-async/06-bubbling-and-delegation/answer.js
Normal file
27
04-dom-events-async/06-bubbling-and-delegation/answer.js
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
const panel = document.getElementById("panel");
|
||||||
|
const lessonList = document.getElementById("lesson-list");
|
||||||
|
|
||||||
|
panel.addEventListener("click", function () {
|
||||||
|
console.log("点击到了外层面板");
|
||||||
|
});
|
||||||
|
|
||||||
|
lessonList.addEventListener("click", function (event) {
|
||||||
|
const removeButton = event.target.closest(".remove-btn");
|
||||||
|
|
||||||
|
if (removeButton) {
|
||||||
|
event.stopPropagation();
|
||||||
|
const currentItem = removeButton.closest(".lesson-item");
|
||||||
|
|
||||||
|
if (currentItem) {
|
||||||
|
currentItem.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentItem = event.target.closest(".lesson-item");
|
||||||
|
|
||||||
|
if (currentItem) {
|
||||||
|
currentItem.classList.toggle("active");
|
||||||
|
}
|
||||||
|
});
|
||||||
58
04-dom-events-async/06-bubbling-and-delegation/starter.html
Normal file
58
04-dom-events-async/06-bubbling-and-delegation/starter.html
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>冒泡、委托和 stopPropagation</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
padding: 32px;
|
||||||
|
font-family: "PingFang SC", "Microsoft YaHei", sans-serif;
|
||||||
|
background: #f5f7fb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel {
|
||||||
|
max-width: 760px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 24px;
|
||||||
|
border-radius: 20px;
|
||||||
|
background: #ffffff;
|
||||||
|
border: 1px solid #dbe2ee;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lesson-item {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 12px 14px;
|
||||||
|
border: 1px solid #dbe2ee;
|
||||||
|
border-radius: 12px;
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lesson-item.active {
|
||||||
|
background: #dbeafe;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<section id="panel" class="panel">
|
||||||
|
<h1>事件委托练习</h1>
|
||||||
|
<p>点击列表项可以切换高亮,点击删除按钮可以移除当前项。</p>
|
||||||
|
|
||||||
|
<ul id="lesson-list">
|
||||||
|
<li class="lesson-item">
|
||||||
|
<span>事件冒泡</span>
|
||||||
|
<button class="remove-btn" type="button">删除</button>
|
||||||
|
</li>
|
||||||
|
<li class="lesson-item">
|
||||||
|
<span>事件委托</span>
|
||||||
|
<button class="remove-btn" type="button">删除</button>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<script src="./starter.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
30
04-dom-events-async/06-bubbling-and-delegation/starter.js
Normal file
30
04-dom-events-async/06-bubbling-and-delegation/starter.js
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
// 任务:
|
||||||
|
// 1. 给 panel 绑定点击事件,输出一条日志
|
||||||
|
// 2. 给 lesson-list 绑定点击事件,使用事件委托
|
||||||
|
// 3. 点击 li 时切换 active 类名
|
||||||
|
// 4. 点击删除按钮时,阻止冒泡并删除当前 li
|
||||||
|
const panel = document.getElementById("panel")
|
||||||
|
panel.addEventListener("click", function () {
|
||||||
|
console.log("点击外部")
|
||||||
|
})
|
||||||
|
|
||||||
|
const list = document.getElementById("lesson-list")
|
||||||
|
list.addEventListener("click", function (event) {
|
||||||
|
|
||||||
|
const remove = event.target.closest(".remove-btn")
|
||||||
|
if (remove) {
|
||||||
|
const li = remove.closest(".lesson-item")
|
||||||
|
|
||||||
|
if (li) {
|
||||||
|
li.remove()
|
||||||
|
event.stopPropagation()
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const tog = event.target.closest(".lesson-item")
|
||||||
|
if (tog) {
|
||||||
|
tog.classList.add("active")
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
25
04-dom-events-async/07-timers-and-async-order/README.md
Normal file
25
04-dom-events-async/07-timers-and-async-order/README.md
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
# 练习 7:setTimeout 和异步顺序
|
||||||
|
|
||||||
|
## 目标
|
||||||
|
|
||||||
|
理解同步代码和异步回调的执行先后顺序。
|
||||||
|
|
||||||
|
## 你要练什么
|
||||||
|
|
||||||
|
- `setTimeout`
|
||||||
|
- 同步顺序
|
||||||
|
- 异步回调
|
||||||
|
- DOM 日志输出
|
||||||
|
|
||||||
|
## 任务
|
||||||
|
|
||||||
|
- 点击按钮后先输出“开始执行”
|
||||||
|
- 再立刻输出“同步代码结束”
|
||||||
|
- 然后延迟输出“异步回调完成”
|
||||||
|
|
||||||
|
## 文件
|
||||||
|
|
||||||
|
- [starter.html](/Users/lijiaqing/home/wwwroot/front-end-example/04-dom-events-async/07-timers-and-async-order/starter.html)
|
||||||
|
- [starter.js](/Users/lijiaqing/home/wwwroot/front-end-example/04-dom-events-async/07-timers-and-async-order/starter.js)
|
||||||
|
- [answer.html](/Users/lijiaqing/home/wwwroot/front-end-example/04-dom-events-async/07-timers-and-async-order/answer.html)
|
||||||
|
- [answer.js](/Users/lijiaqing/home/wwwroot/front-end-example/04-dom-events-async/07-timers-and-async-order/answer.js)
|
||||||
38
04-dom-events-async/07-timers-and-async-order/answer.html
Normal file
38
04-dom-events-async/07-timers-and-async-order/answer.html
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>setTimeout 和异步顺序</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
padding: 32px;
|
||||||
|
font-family: "PingFang SC", "Microsoft YaHei", sans-serif;
|
||||||
|
background: #f6f8fb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel {
|
||||||
|
max-width: 720px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 24px;
|
||||||
|
border-radius: 18px;
|
||||||
|
background: #ffffff;
|
||||||
|
border: 1px solid #dce4ef;
|
||||||
|
}
|
||||||
|
|
||||||
|
#log-list li {
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<section class="panel">
|
||||||
|
<h1>异步顺序练习</h1>
|
||||||
|
<button id="run-btn" type="button">开始执行</button>
|
||||||
|
<ul id="log-list"></ul>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<script src="./answer.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
20
04-dom-events-async/07-timers-and-async-order/answer.js
Normal file
20
04-dom-events-async/07-timers-and-async-order/answer.js
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
const runButton = document.getElementById("run-btn");
|
||||||
|
const logList = document.getElementById("log-list");
|
||||||
|
|
||||||
|
function appendLog(text) {
|
||||||
|
const item = document.createElement("li");
|
||||||
|
item.textContent = text;
|
||||||
|
logList.appendChild(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
runButton.addEventListener("click", function () {
|
||||||
|
logList.innerHTML = "";
|
||||||
|
|
||||||
|
appendLog("开始执行");
|
||||||
|
|
||||||
|
setTimeout(function () {
|
||||||
|
appendLog("异步回调完成");
|
||||||
|
}, 600);
|
||||||
|
|
||||||
|
appendLog("同步代码结束");
|
||||||
|
});
|
||||||
38
04-dom-events-async/07-timers-and-async-order/starter.html
Normal file
38
04-dom-events-async/07-timers-and-async-order/starter.html
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>setTimeout 和异步顺序</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
padding: 32px;
|
||||||
|
font-family: "PingFang SC", "Microsoft YaHei", sans-serif;
|
||||||
|
background: #f6f8fb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel {
|
||||||
|
max-width: 720px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 24px;
|
||||||
|
border-radius: 18px;
|
||||||
|
background: #ffffff;
|
||||||
|
border: 1px solid #dce4ef;
|
||||||
|
}
|
||||||
|
|
||||||
|
#log-list li {
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<section class="panel">
|
||||||
|
<h1>异步顺序练习</h1>
|
||||||
|
<button id="run-btn" type="button">开始执行</button>
|
||||||
|
<ul id="log-list"></ul>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<script src="./starter.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
26
04-dom-events-async/07-timers-and-async-order/starter.js
Normal file
26
04-dom-events-async/07-timers-and-async-order/starter.js
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
// 任务:
|
||||||
|
// 1. 获取按钮和日志列表
|
||||||
|
// 2. 点击按钮后清空旧日志
|
||||||
|
// 3. 先追加“开始执行”
|
||||||
|
// 4. 用 setTimeout 延迟追加“异步回调完成”
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// 5. 再立刻追加“同步代码结束”
|
||||||
|
const btn = document.getElementById("run-btn")
|
||||||
|
const list = document.getElementById("log-list")
|
||||||
|
|
||||||
|
function add1(message) {
|
||||||
|
const li = document.createElement("li")
|
||||||
|
li.textContent = message
|
||||||
|
list.appendChild(li)
|
||||||
|
}
|
||||||
|
|
||||||
|
btn.addEventListener("click", function () {
|
||||||
|
list.textContent = ""
|
||||||
|
add1("开始执行")
|
||||||
|
setTimeout(function () {
|
||||||
|
add1("异步回调完成")
|
||||||
|
}, 2000)
|
||||||
|
add1("同步代码结束")
|
||||||
|
})
|
||||||
26
04-dom-events-async/08-promise-and-render/README.md
Normal file
26
04-dom-events-async/08-promise-and-render/README.md
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
# 练习 8:Promise 和渲染
|
||||||
|
|
||||||
|
## 目标
|
||||||
|
|
||||||
|
学会在 Promise 完成后把结果渲染到页面。
|
||||||
|
|
||||||
|
## 你要练什么
|
||||||
|
|
||||||
|
- Promise
|
||||||
|
- `.then()`
|
||||||
|
- `catch()`
|
||||||
|
- loading 状态
|
||||||
|
|
||||||
|
## 任务
|
||||||
|
|
||||||
|
- 点击按钮后显示“加载中”
|
||||||
|
- 等待 Promise 返回数据
|
||||||
|
- 把课程名称渲染到列表
|
||||||
|
- 如果失败,显示错误信息
|
||||||
|
|
||||||
|
## 文件
|
||||||
|
|
||||||
|
- [starter.html](/Users/lijiaqing/home/wwwroot/front-end-example/04-dom-events-async/08-promise-and-render/starter.html)
|
||||||
|
- [starter.js](/Users/lijiaqing/home/wwwroot/front-end-example/04-dom-events-async/08-promise-and-render/starter.js)
|
||||||
|
- [answer.html](/Users/lijiaqing/home/wwwroot/front-end-example/04-dom-events-async/08-promise-and-render/answer.html)
|
||||||
|
- [answer.js](/Users/lijiaqing/home/wwwroot/front-end-example/04-dom-events-async/08-promise-and-render/answer.js)
|
||||||
35
04-dom-events-async/08-promise-and-render/answer.html
Normal file
35
04-dom-events-async/08-promise-and-render/answer.html
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>Promise 和渲染</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
padding: 32px;
|
||||||
|
font-family: "PingFang SC", "Microsoft YaHei", sans-serif;
|
||||||
|
background: #f4f7fb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel {
|
||||||
|
max-width: 760px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 24px;
|
||||||
|
border-radius: 18px;
|
||||||
|
background: #ffffff;
|
||||||
|
border: 1px solid #dce3ef;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<section class="panel">
|
||||||
|
<h1>Promise 数据渲染</h1>
|
||||||
|
<button id="load-btn" type="button">加载课程</button>
|
||||||
|
<p id="status-text">等待加载</p>
|
||||||
|
<ul id="course-list"></ul>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<script src="./answer.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
30
04-dom-events-async/08-promise-and-render/answer.js
Normal file
30
04-dom-events-async/08-promise-and-render/answer.js
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
function fakeFetchCourses() {
|
||||||
|
return new Promise(function (resolve) {
|
||||||
|
setTimeout(function () {
|
||||||
|
resolve(["DOM 获取元素", "事件监听", "异步基础"]);
|
||||||
|
}, 800);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const loadButton = document.getElementById("load-btn");
|
||||||
|
const statusText = document.getElementById("status-text");
|
||||||
|
const courseList = document.getElementById("course-list");
|
||||||
|
|
||||||
|
loadButton.addEventListener("click", function () {
|
||||||
|
statusText.textContent = "加载中...";
|
||||||
|
courseList.innerHTML = "";
|
||||||
|
|
||||||
|
fakeFetchCourses()
|
||||||
|
.then(function (courses) {
|
||||||
|
courses.forEach(function (course) {
|
||||||
|
const item = document.createElement("li");
|
||||||
|
item.textContent = course;
|
||||||
|
courseList.appendChild(item);
|
||||||
|
});
|
||||||
|
|
||||||
|
statusText.textContent = "加载完成";
|
||||||
|
})
|
||||||
|
.catch(function () {
|
||||||
|
statusText.textContent = "加载失败";
|
||||||
|
});
|
||||||
|
});
|
||||||
35
04-dom-events-async/08-promise-and-render/starter.html
Normal file
35
04-dom-events-async/08-promise-and-render/starter.html
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>Promise 和渲染</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
padding: 32px;
|
||||||
|
font-family: "PingFang SC", "Microsoft YaHei", sans-serif;
|
||||||
|
background: #f4f7fb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel {
|
||||||
|
max-width: 760px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 24px;
|
||||||
|
border-radius: 18px;
|
||||||
|
background: #ffffff;
|
||||||
|
border: 1px solid #dce3ef;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<section class="panel">
|
||||||
|
<h1>Promise 数据渲染</h1>
|
||||||
|
<button id="load-btn" type="button">加载课程</button>
|
||||||
|
<p id="status-text">等待加载</p>
|
||||||
|
<ul id="course-list"></ul>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<script src="./starter.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
34
04-dom-events-async/08-promise-and-render/starter.js
Normal file
34
04-dom-events-async/08-promise-and-render/starter.js
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
function fakeFetchCourses() {
|
||||||
|
return new Promise(function (resolve) {
|
||||||
|
setTimeout(function () {
|
||||||
|
resolve(["DOM 获取元素", "事件监听", "异步基础"]);
|
||||||
|
}, 800);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 任务:
|
||||||
|
// 1. 获取按钮、状态文字、列表
|
||||||
|
// 2. 点击按钮后显示“加载中”
|
||||||
|
// 3. 调用 fakeFetchCourses()
|
||||||
|
// 4. 用 then 渲染课程列表
|
||||||
|
// 5. 用 catch 处理错误
|
||||||
|
const btn = document.getElementById("load-btn")
|
||||||
|
const text = document.getElementById("status-text")
|
||||||
|
const list = document.getElementById("course-list")
|
||||||
|
|
||||||
|
btn.addEventListener("click", function () {
|
||||||
|
text.textContent = "加载中..."
|
||||||
|
|
||||||
|
fakeFetchCourses()
|
||||||
|
.then(function (result) {
|
||||||
|
text.textContent = "加载成功"
|
||||||
|
const a = result.forEach(item => {
|
||||||
|
const li = document.createElement("li")
|
||||||
|
li.textContent = item
|
||||||
|
list.appendChild(li)
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(function (error) {
|
||||||
|
list.textContent = "失败" + error
|
||||||
|
})
|
||||||
|
})
|
||||||
26
04-dom-events-async/09-async-await-panel/README.md
Normal file
26
04-dom-events-async/09-async-await-panel/README.md
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
# 练习 9:async / await 面板
|
||||||
|
|
||||||
|
## 目标
|
||||||
|
|
||||||
|
学会用 `async` / `await` 写一个更直观的异步流程。
|
||||||
|
|
||||||
|
## 你要练什么
|
||||||
|
|
||||||
|
- `async`
|
||||||
|
- `await`
|
||||||
|
- `try...catch`
|
||||||
|
- DOM 更新
|
||||||
|
|
||||||
|
## 任务
|
||||||
|
|
||||||
|
- 点击按钮后进入加载状态
|
||||||
|
- 等待异步函数返回用户信息
|
||||||
|
- 把结果渲染到卡片里
|
||||||
|
- 如果失败,显示错误信息
|
||||||
|
|
||||||
|
## 文件
|
||||||
|
|
||||||
|
- [starter.html](/Users/lijiaqing/home/wwwroot/front-end-example/04-dom-events-async/09-async-await-panel/starter.html)
|
||||||
|
- [starter.js](/Users/lijiaqing/home/wwwroot/front-end-example/04-dom-events-async/09-async-await-panel/starter.js)
|
||||||
|
- [answer.html](/Users/lijiaqing/home/wwwroot/front-end-example/04-dom-events-async/09-async-await-panel/answer.html)
|
||||||
|
- [answer.js](/Users/lijiaqing/home/wwwroot/front-end-example/04-dom-events-async/09-async-await-panel/answer.js)
|
||||||
35
04-dom-events-async/09-async-await-panel/answer.html
Normal file
35
04-dom-events-async/09-async-await-panel/answer.html
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>async / await 面板</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
padding: 32px;
|
||||||
|
font-family: "PingFang SC", "Microsoft YaHei", sans-serif;
|
||||||
|
background: #f6f8fb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel {
|
||||||
|
max-width: 760px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 24px;
|
||||||
|
border-radius: 18px;
|
||||||
|
background: #ffffff;
|
||||||
|
border: 1px solid #dbe4ef;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<section class="panel">
|
||||||
|
<h1>用户信息面板</h1>
|
||||||
|
<button id="load-user-btn" type="button">加载用户信息</button>
|
||||||
|
<p id="user-status">等待加载</p>
|
||||||
|
<div id="user-card"></div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<script src="./answer.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
35
04-dom-events-async/09-async-await-panel/answer.js
Normal file
35
04-dom-events-async/09-async-await-panel/answer.js
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
function fakeFetchUser() {
|
||||||
|
return new Promise(function (resolve) {
|
||||||
|
setTimeout(function () {
|
||||||
|
resolve({
|
||||||
|
name: "林晨",
|
||||||
|
role: "前端学习者",
|
||||||
|
focus: "DOM + 事件 + 异步",
|
||||||
|
});
|
||||||
|
}, 900);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const loadButton = document.getElementById("load-user-btn");
|
||||||
|
const statusText = document.getElementById("user-status");
|
||||||
|
const userCard = document.getElementById("user-card");
|
||||||
|
|
||||||
|
async function loadUser() {
|
||||||
|
statusText.textContent = "加载中...";
|
||||||
|
userCard.innerHTML = "";
|
||||||
|
|
||||||
|
try {
|
||||||
|
const user = await fakeFetchUser();
|
||||||
|
|
||||||
|
userCard.innerHTML = `
|
||||||
|
<p>姓名:${user.name}</p>
|
||||||
|
<p>身份:${user.role}</p>
|
||||||
|
<p>当前重点:${user.focus}</p>
|
||||||
|
`;
|
||||||
|
statusText.textContent = "加载完成";
|
||||||
|
} catch (error) {
|
||||||
|
statusText.textContent = "加载失败";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
loadButton.addEventListener("click", loadUser);
|
||||||
35
04-dom-events-async/09-async-await-panel/starter.html
Normal file
35
04-dom-events-async/09-async-await-panel/starter.html
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>async / await 面板</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
padding: 32px;
|
||||||
|
font-family: "PingFang SC", "Microsoft YaHei", sans-serif;
|
||||||
|
background: #f6f8fb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel {
|
||||||
|
max-width: 760px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 24px;
|
||||||
|
border-radius: 18px;
|
||||||
|
background: #ffffff;
|
||||||
|
border: 1px solid #dbe4ef;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<section class="panel">
|
||||||
|
<h1>用户信息面板</h1>
|
||||||
|
<button id="load-user-btn" type="button">加载用户信息</button>
|
||||||
|
<p id="user-status">等待加载</p>
|
||||||
|
<div id="user-card"></div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<script src="./starter.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
39
04-dom-events-async/09-async-await-panel/starter.js
Normal file
39
04-dom-events-async/09-async-await-panel/starter.js
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
function fakeFetchUser() {
|
||||||
|
return new Promise(function (resolve) {
|
||||||
|
setTimeout(function () {
|
||||||
|
resolve({
|
||||||
|
name: "林晨",
|
||||||
|
role: "前端学习者",
|
||||||
|
focus: "DOM + 事件 + 异步",
|
||||||
|
});
|
||||||
|
}, 900);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 任务:
|
||||||
|
// 1. 获取按钮、状态文字、信息面板
|
||||||
|
// 2. 写一个 async 函数
|
||||||
|
// 3. 用 await 等待 fakeFetchUser()
|
||||||
|
// 4. 渲染用户信息
|
||||||
|
// 5. 用 try...catch 处理异常
|
||||||
|
const btn = document.getElementById("load-user-btn")
|
||||||
|
const status = document.getElementById("user-status")
|
||||||
|
const card = document.getElementById("user-card")
|
||||||
|
|
||||||
|
async function a() {
|
||||||
|
status.textContent = "加载中"
|
||||||
|
card.innerHTML = ""
|
||||||
|
|
||||||
|
try {
|
||||||
|
const a = await fakeFetchUser()
|
||||||
|
status.textContent = "加载成功"
|
||||||
|
card.innerHTML = `
|
||||||
|
<p>姓名:${a.name}</p>
|
||||||
|
<p>角色:${a.role}</p>
|
||||||
|
<p>任务:${a.focus}</p>
|
||||||
|
`
|
||||||
|
} catch (error) {
|
||||||
|
status.textContent = "加载失败"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
btn.addEventListener("click", a)
|
||||||
34
04-dom-events-async/10-final-dashboard/README.md
Normal file
34
04-dom-events-async/10-final-dashboard/README.md
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
# 练习 10:综合页面
|
||||||
|
|
||||||
|
## 目标
|
||||||
|
|
||||||
|
把 DOM、事件和异步知识拼起来,做一个可以真实互动的小页面。
|
||||||
|
|
||||||
|
## 项目名称
|
||||||
|
|
||||||
|
学习面板
|
||||||
|
|
||||||
|
## 任务
|
||||||
|
|
||||||
|
请完成一个控制台之外可见的页面交互,要求至少包含:
|
||||||
|
|
||||||
|
- 一个课程列表区域
|
||||||
|
- 一个表单区域
|
||||||
|
- 一个添加课程的交互
|
||||||
|
- 一个点击课程切换完成状态的交互
|
||||||
|
- 一个异步加载提示或远程数据模拟
|
||||||
|
- 清晰的状态文案更新
|
||||||
|
|
||||||
|
## 建议顺序
|
||||||
|
|
||||||
|
1. 先看 HTML 结构
|
||||||
|
2. 先写元素获取和渲染函数
|
||||||
|
3. 再写表单提交和点击事件
|
||||||
|
4. 最后补异步加载逻辑
|
||||||
|
|
||||||
|
## 文件
|
||||||
|
|
||||||
|
- [starter.html](/Users/lijiaqing/home/wwwroot/front-end-example/04-dom-events-async/10-final-dashboard/starter.html)
|
||||||
|
- [starter.js](/Users/lijiaqing/home/wwwroot/front-end-example/04-dom-events-async/10-final-dashboard/starter.js)
|
||||||
|
- [answer.html](/Users/lijiaqing/home/wwwroot/front-end-example/04-dom-events-async/10-final-dashboard/answer.html)
|
||||||
|
- [answer.js](/Users/lijiaqing/home/wwwroot/front-end-example/04-dom-events-async/10-final-dashboard/answer.js)
|
||||||
82
04-dom-events-async/10-final-dashboard/answer.html
Normal file
82
04-dom-events-async/10-final-dashboard/answer.html
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>学习面板</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
padding: 32px;
|
||||||
|
font-family: "PingFang SC", "Microsoft YaHei", sans-serif;
|
||||||
|
background: linear-gradient(180deg, #eef4ff 0%, #f7faff 100%);
|
||||||
|
color: #0f172a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page {
|
||||||
|
width: min(900px, calc(100% - 24px));
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero,
|
||||||
|
.panel,
|
||||||
|
.form-panel {
|
||||||
|
margin-top: 18px;
|
||||||
|
padding: 24px;
|
||||||
|
border-radius: 20px;
|
||||||
|
background: #ffffff;
|
||||||
|
border: 1px solid #dbe4f0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lesson-item {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-top: 10px;
|
||||||
|
padding: 12px 14px;
|
||||||
|
border-radius: 12px;
|
||||||
|
background: #f8fbff;
|
||||||
|
border: 1px solid #dbe4f0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lesson-item.done {
|
||||||
|
background: #dcfce7;
|
||||||
|
border-color: #bbf7d0;
|
||||||
|
}
|
||||||
|
|
||||||
|
form {
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
flex: 1;
|
||||||
|
padding: 10px 12px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<main class="page">
|
||||||
|
<section class="hero">
|
||||||
|
<h1>DOM + 事件 + 异步学习面板</h1>
|
||||||
|
<p id="status-text">正在初始化页面...</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="panel">
|
||||||
|
<h2>课程列表</h2>
|
||||||
|
<button id="load-btn" type="button">模拟加载课程</button>
|
||||||
|
<ul id="lesson-list"></ul>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="form-panel">
|
||||||
|
<h2>添加课程</h2>
|
||||||
|
<form id="lesson-form">
|
||||||
|
<input id="lesson-input" type="text" placeholder="输入课程名称" />
|
||||||
|
<button type="submit">添加</button>
|
||||||
|
</form>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<script src="./answer.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
84
04-dom-events-async/10-final-dashboard/answer.js
Normal file
84
04-dom-events-async/10-final-dashboard/answer.js
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
const lessons = [
|
||||||
|
{ title: "获取元素", done: false },
|
||||||
|
{ title: "修改 DOM", done: true },
|
||||||
|
];
|
||||||
|
|
||||||
|
function fakeLoadExtraLessons() {
|
||||||
|
return new Promise(function (resolve) {
|
||||||
|
setTimeout(function () {
|
||||||
|
resolve([
|
||||||
|
{ title: "事件委托", done: false },
|
||||||
|
{ title: "异步渲染", done: false },
|
||||||
|
]);
|
||||||
|
}, 900);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const statusText = document.getElementById("status-text");
|
||||||
|
const loadButton = document.getElementById("load-btn");
|
||||||
|
const lessonList = document.getElementById("lesson-list");
|
||||||
|
const lessonForm = document.getElementById("lesson-form");
|
||||||
|
const lessonInput = document.getElementById("lesson-input");
|
||||||
|
|
||||||
|
function renderLessons() {
|
||||||
|
lessonList.innerHTML = "";
|
||||||
|
|
||||||
|
lessons.forEach(function (lesson, index) {
|
||||||
|
const item = document.createElement("li");
|
||||||
|
item.className = "lesson-item";
|
||||||
|
|
||||||
|
if (lesson.done) {
|
||||||
|
item.classList.add("done");
|
||||||
|
}
|
||||||
|
|
||||||
|
item.dataset.index = index;
|
||||||
|
item.textContent = lesson.title;
|
||||||
|
lessonList.appendChild(item);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
lessonList.addEventListener("click", function (event) {
|
||||||
|
const currentItem = event.target.closest(".lesson-item");
|
||||||
|
|
||||||
|
if (!currentItem) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const index = Number(currentItem.dataset.index);
|
||||||
|
lessons[index].done = !lessons[index].done;
|
||||||
|
renderLessons();
|
||||||
|
});
|
||||||
|
|
||||||
|
lessonForm.addEventListener("submit", function (event) {
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
const value = lessonInput.value.trim();
|
||||||
|
|
||||||
|
if (!value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
lessons.push({
|
||||||
|
title: value,
|
||||||
|
done: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
lessonInput.value = "";
|
||||||
|
statusText.textContent = "已新增一门课程";
|
||||||
|
renderLessons();
|
||||||
|
});
|
||||||
|
|
||||||
|
loadButton.addEventListener("click", async function () {
|
||||||
|
statusText.textContent = "正在异步加载课程...";
|
||||||
|
|
||||||
|
const newLessons = await fakeLoadExtraLessons();
|
||||||
|
newLessons.forEach(function (lesson) {
|
||||||
|
lessons.push(lesson);
|
||||||
|
});
|
||||||
|
|
||||||
|
statusText.textContent = "额外课程加载完成";
|
||||||
|
renderLessons();
|
||||||
|
});
|
||||||
|
|
||||||
|
statusText.textContent = "页面初始化完成";
|
||||||
|
renderLessons();
|
||||||
82
04-dom-events-async/10-final-dashboard/starter.html
Normal file
82
04-dom-events-async/10-final-dashboard/starter.html
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>学习面板</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
padding: 32px;
|
||||||
|
font-family: "PingFang SC", "Microsoft YaHei", sans-serif;
|
||||||
|
background: linear-gradient(180deg, #eef4ff 0%, #f7faff 100%);
|
||||||
|
color: #0f172a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page {
|
||||||
|
width: min(900px, calc(100% - 24px));
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero,
|
||||||
|
.panel,
|
||||||
|
.form-panel {
|
||||||
|
margin-top: 18px;
|
||||||
|
padding: 24px;
|
||||||
|
border-radius: 20px;
|
||||||
|
background: #ffffff;
|
||||||
|
border: 1px solid #dbe4f0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lesson-item {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-top: 10px;
|
||||||
|
padding: 12px 14px;
|
||||||
|
border-radius: 12px;
|
||||||
|
background: #f8fbff;
|
||||||
|
border: 1px solid #dbe4f0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lesson-item.done {
|
||||||
|
background: #dcfce7;
|
||||||
|
border-color: #bbf7d0;
|
||||||
|
}
|
||||||
|
|
||||||
|
form {
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
flex: 1;
|
||||||
|
padding: 10px 12px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<main class="page">
|
||||||
|
<section class="hero">
|
||||||
|
<h1>DOM + 事件 + 异步学习面板</h1>
|
||||||
|
<p id="status-text">正在初始化页面...</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="panel">
|
||||||
|
<h2>课程列表</h2>
|
||||||
|
<button id="load-btn" type="button">模拟加载课程</button>
|
||||||
|
<ul id="lesson-list"></ul>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="form-panel">
|
||||||
|
<h2>添加课程</h2>
|
||||||
|
<form id="lesson-form">
|
||||||
|
<input id="lesson-input" type="text" placeholder="输入课程名称" />
|
||||||
|
<button type="submit">添加</button>
|
||||||
|
</form>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<script src="./starter.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
104
04-dom-events-async/10-final-dashboard/starter.js
Normal file
104
04-dom-events-async/10-final-dashboard/starter.js
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
const lessons = [
|
||||||
|
{ title: "获取元素", done: false },
|
||||||
|
{ title: "修改 DOM", done: true },
|
||||||
|
];
|
||||||
|
|
||||||
|
function fakeLoadExtraLessons() {
|
||||||
|
return new Promise(function (resolve) {
|
||||||
|
setTimeout(function () {
|
||||||
|
resolve([
|
||||||
|
{ title: "事件委托", done: false },
|
||||||
|
{ title: "异步渲染", done: false },
|
||||||
|
]);
|
||||||
|
}, 900);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 任务:
|
||||||
|
// 1. 获取页面里的关键元素
|
||||||
|
// 2. 写一个 renderLessons 函数,把 lessons 渲染到列表
|
||||||
|
// 3. 点击列表项时切换 done 状态
|
||||||
|
// 4. 提交表单时阻止默认提交,并新增课程
|
||||||
|
// 5. 点击加载按钮时显示加载状态,并把异步返回的课程追加到列表
|
||||||
|
/* 一个课程列表区域
|
||||||
|
- 一个表单区域
|
||||||
|
- 一个添加课程的交互
|
||||||
|
- 一个点击课程切换完成状态的交互
|
||||||
|
- 一个异步加载提示或远程数据模拟
|
||||||
|
- 清晰的状态文案更新*/
|
||||||
|
const page = document.querySelector(".page")
|
||||||
|
const hero = document.querySelector("hero")
|
||||||
|
const text = document.getElementById("status-text")
|
||||||
|
const panel = document.querySelector(".panel")
|
||||||
|
const btn = document.getElementById("load-btn")
|
||||||
|
const list = document.getElementById("lesson-list")
|
||||||
|
const formPanel = document.querySelector(".form-panel")
|
||||||
|
const lessonForm = document.getElementById("lesson-form")
|
||||||
|
const lessonInput = document.getElementById("lesson-input")
|
||||||
|
|
||||||
|
function renderLessons() {
|
||||||
|
lessons.forEach(item => {
|
||||||
|
const li = document.createElement("li")
|
||||||
|
li.classList.add("li")
|
||||||
|
li.setAttribute("title", item.title)
|
||||||
|
li.setAttribute("done", item.done)
|
||||||
|
li.textContent = `
|
||||||
|
标题:${item.title}
|
||||||
|
状态:${item.done}`
|
||||||
|
|
||||||
|
list.appendChild(li)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
renderLessons()
|
||||||
|
|
||||||
|
//event.target,closest,
|
||||||
|
list.addEventListener("click", function (event) {
|
||||||
|
const a = event.target.closest(".li")
|
||||||
|
if (a) {
|
||||||
|
a.textContent = `
|
||||||
|
标题:${a.title}
|
||||||
|
状态:${!a.done}`
|
||||||
|
|
||||||
|
a.done = !a.done
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
lessonForm.addEventListener("submit", function (event) {
|
||||||
|
event.preventDefault()
|
||||||
|
const c = document.createElement("li")
|
||||||
|
const d = lessonInput.value.trim()
|
||||||
|
c.textContent = `
|
||||||
|
标题:${d}
|
||||||
|
状态:true`
|
||||||
|
c.setAttribute("title", d)
|
||||||
|
c.setAttribute("done", true)
|
||||||
|
c.classList.add("li")
|
||||||
|
lessonInput.value = ""
|
||||||
|
list.appendChild(c)
|
||||||
|
})
|
||||||
|
|
||||||
|
async function load() {
|
||||||
|
text.textContent = "加载中"
|
||||||
|
text.innerHTML = ""
|
||||||
|
try {
|
||||||
|
|
||||||
|
const s = await fakeLoadExtraLessons()
|
||||||
|
text.textContent = "加载完成"
|
||||||
|
s.forEach(item => {
|
||||||
|
const li = document.createElement("li")
|
||||||
|
li.classList.add("li")
|
||||||
|
li.setAttribute("title", item.title)
|
||||||
|
li.setAttribute("done", item.done)
|
||||||
|
li.textContent = `
|
||||||
|
标题:${item.title}
|
||||||
|
状态:${item.done}`
|
||||||
|
|
||||||
|
list.appendChild(li)
|
||||||
|
})
|
||||||
|
} catch (error) {
|
||||||
|
text.textContent = "加载失败"
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
btn.addEventListener("click", load)
|
||||||
25
04-dom-events-async/11-input-live-preview/README.md
Normal file
25
04-dom-events-async/11-input-live-preview/README.md
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
# 练习 11:input 实时预览
|
||||||
|
|
||||||
|
## 目标
|
||||||
|
|
||||||
|
学会处理输入类事件,让页面随着用户输入实时变化。
|
||||||
|
|
||||||
|
## 你要练什么
|
||||||
|
|
||||||
|
- `input` 事件
|
||||||
|
- `change` 事件
|
||||||
|
- 表单值读取
|
||||||
|
- 实时 DOM 更新
|
||||||
|
|
||||||
|
## 任务
|
||||||
|
|
||||||
|
- 在输入框输入昵称时,实时更新预览标题
|
||||||
|
- 在文本域输入学习目标时,实时更新预览内容
|
||||||
|
- 切换学习阶段下拉框时,更新阶段标签
|
||||||
|
|
||||||
|
## 文件
|
||||||
|
|
||||||
|
- [starter.html](/Users/lijiaqing/home/wwwroot/front-end-example/04-dom-events-async/11-input-live-preview/starter.html)
|
||||||
|
- [starter.js](/Users/lijiaqing/home/wwwroot/front-end-example/04-dom-events-async/11-input-live-preview/starter.js)
|
||||||
|
- [answer.html](/Users/lijiaqing/home/wwwroot/front-end-example/04-dom-events-async/11-input-live-preview/answer.html)
|
||||||
|
- [answer.js](/Users/lijiaqing/home/wwwroot/front-end-example/04-dom-events-async/11-input-live-preview/answer.js)
|
||||||
86
04-dom-events-async/11-input-live-preview/answer.html
Normal file
86
04-dom-events-async/11-input-live-preview/answer.html
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>input 实时预览</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
padding: 32px;
|
||||||
|
font-family: "PingFang SC", "Microsoft YaHei", sans-serif;
|
||||||
|
background: #f6f8fb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
gap: 18px;
|
||||||
|
max-width: 960px;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel {
|
||||||
|
padding: 24px;
|
||||||
|
border-radius: 18px;
|
||||||
|
background: #ffffff;
|
||||||
|
border: 1px solid #dce4ef;
|
||||||
|
}
|
||||||
|
|
||||||
|
label {
|
||||||
|
display: grid;
|
||||||
|
gap: 8px;
|
||||||
|
margin-top: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
input,
|
||||||
|
textarea,
|
||||||
|
select {
|
||||||
|
padding: 10px 12px;
|
||||||
|
font: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 6px 12px;
|
||||||
|
border-radius: 999px;
|
||||||
|
background: #dbeafe;
|
||||||
|
color: #1d4ed8;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<main class="page">
|
||||||
|
<section class="panel">
|
||||||
|
<h1>编辑资料</h1>
|
||||||
|
|
||||||
|
<label for="nickname-input">
|
||||||
|
昵称
|
||||||
|
<input id="nickname-input" type="text" placeholder="输入你的昵称" />
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label for="goal-input">
|
||||||
|
学习目标
|
||||||
|
<textarea id="goal-input" rows="4" placeholder="输入今天的学习目标"></textarea>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label for="stage-select">
|
||||||
|
学习阶段
|
||||||
|
<select id="stage-select">
|
||||||
|
<option value="入门阶段">入门阶段</option>
|
||||||
|
<option value="DOM 阶段">DOM 阶段</option>
|
||||||
|
<option value="异步阶段">异步阶段</option>
|
||||||
|
</select>
|
||||||
|
</label>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="panel">
|
||||||
|
<p class="badge" id="preview-stage">入门阶段</p>
|
||||||
|
<h2 id="preview-name">未填写昵称</h2>
|
||||||
|
<p id="preview-goal">这里会显示你的学习目标。</p>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<script src="./answer.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
21
04-dom-events-async/11-input-live-preview/answer.js
Normal file
21
04-dom-events-async/11-input-live-preview/answer.js
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
const nicknameInput = document.getElementById("nickname-input");
|
||||||
|
const goalInput = document.getElementById("goal-input");
|
||||||
|
const stageSelect = document.getElementById("stage-select");
|
||||||
|
|
||||||
|
const previewStage = document.getElementById("preview-stage");
|
||||||
|
const previewName = document.getElementById("preview-name");
|
||||||
|
const previewGoal = document.getElementById("preview-goal");
|
||||||
|
|
||||||
|
nicknameInput.addEventListener("input", function () {
|
||||||
|
const value = nicknameInput.value.trim();
|
||||||
|
previewName.textContent = value || "未填写昵称";
|
||||||
|
});
|
||||||
|
|
||||||
|
goalInput.addEventListener("input", function () {
|
||||||
|
const value = goalInput.value.trim();
|
||||||
|
previewGoal.textContent = value || "这里会显示你的学习目标。";
|
||||||
|
});
|
||||||
|
|
||||||
|
stageSelect.addEventListener("change", function () {
|
||||||
|
previewStage.textContent = stageSelect.value;
|
||||||
|
});
|
||||||
86
04-dom-events-async/11-input-live-preview/starter.html
Normal file
86
04-dom-events-async/11-input-live-preview/starter.html
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>input 实时预览</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
padding: 32px;
|
||||||
|
font-family: "PingFang SC", "Microsoft YaHei", sans-serif;
|
||||||
|
background: #f6f8fb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
gap: 18px;
|
||||||
|
max-width: 960px;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel {
|
||||||
|
padding: 24px;
|
||||||
|
border-radius: 18px;
|
||||||
|
background: #ffffff;
|
||||||
|
border: 1px solid #dce4ef;
|
||||||
|
}
|
||||||
|
|
||||||
|
label {
|
||||||
|
display: grid;
|
||||||
|
gap: 8px;
|
||||||
|
margin-top: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
input,
|
||||||
|
textarea,
|
||||||
|
select {
|
||||||
|
padding: 10px 12px;
|
||||||
|
font: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 6px 12px;
|
||||||
|
border-radius: 999px;
|
||||||
|
background: #dbeafe;
|
||||||
|
color: #1d4ed8;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<main class="page">
|
||||||
|
<section class="panel">
|
||||||
|
<h1>编辑资料</h1>
|
||||||
|
|
||||||
|
<label for="nickname-input">
|
||||||
|
昵称
|
||||||
|
<input id="nickname-input" type="text" placeholder="输入你的昵称" />
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label for="goal-input">
|
||||||
|
学习目标
|
||||||
|
<textarea id="goal-input" rows="4" placeholder="输入今天的学习目标"></textarea>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label for="stage-select">
|
||||||
|
学习阶段
|
||||||
|
<select id="stage-select">
|
||||||
|
<option value="入门阶段">入门阶段</option>
|
||||||
|
<option value="DOM 阶段">DOM 阶段</option>
|
||||||
|
<option value="异步阶段">异步阶段</option>
|
||||||
|
</select>
|
||||||
|
</label>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="panel">
|
||||||
|
<p class="badge" id="preview-stage">入门阶段</p>
|
||||||
|
<h2 id="preview-name">未填写昵称</h2>
|
||||||
|
<p id="preview-goal">这里会显示你的学习目标。</p>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<script src="./starter.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
29
04-dom-events-async/11-input-live-preview/starter.js
Normal file
29
04-dom-events-async/11-input-live-preview/starter.js
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
// 任务:
|
||||||
|
// 1. 获取昵称输入框、目标文本域、阶段下拉框
|
||||||
|
// 2. 监听昵称和目标的 input 事件
|
||||||
|
// 3. 把输入内容实时渲染到右侧预览
|
||||||
|
// 4. 监听阶段下拉框的 change 事件
|
||||||
|
// 5. 更新阶段标签文字
|
||||||
|
const nickname = document.getElementById("nickname-input")
|
||||||
|
const goal = document.getElementById("goal-input")
|
||||||
|
const stage = document.getElementById("stage-select")
|
||||||
|
|
||||||
|
nickname.addEventListener("input", function () {
|
||||||
|
const previewName = document.getElementById("preview-name")
|
||||||
|
previewName.textContent = nickname.value
|
||||||
|
if (!nickname.value.trim()) {
|
||||||
|
previewName.textContent = "未填写昵称"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
goal.addEventListener("input", function () {
|
||||||
|
const previewGoal = document.getElementById("preview-goal")
|
||||||
|
previewGoal.textContent = goal.value
|
||||||
|
if (!goal.value.trim()) {
|
||||||
|
previewGoal.textContent = "这里会显示你的学习目标。"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
stage.addEventListener("change", function () {
|
||||||
|
const previewStage = document.getElementById("preview-stage")
|
||||||
|
previewStage.textContent = stage.value
|
||||||
|
})
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
# 练习 12:prepend、classList.remove 和链接默认行为
|
||||||
|
|
||||||
|
## 目标
|
||||||
|
|
||||||
|
补齐几个常见但容易漏掉的 DOM 细节操作。
|
||||||
|
|
||||||
|
## 你要练什么
|
||||||
|
|
||||||
|
- `prepend()`
|
||||||
|
- `classList.remove()`
|
||||||
|
- 链接点击事件
|
||||||
|
- `preventDefault()`
|
||||||
|
|
||||||
|
## 任务
|
||||||
|
|
||||||
|
- 点击“插入到最前面”时,把一条新消息插入列表顶部
|
||||||
|
- 点击“清除高亮”时,移除全部高亮类名
|
||||||
|
- 点击帮助链接时,阻止默认跳转,并在页面显示提示信息
|
||||||
|
|
||||||
|
## 文件
|
||||||
|
|
||||||
|
- [starter.html](/Users/lijiaqing/home/wwwroot/front-end-example/04-dom-events-async/12-prepend-remove-and-link-default/starter.html)
|
||||||
|
- [starter.js](/Users/lijiaqing/home/wwwroot/front-end-example/04-dom-events-async/12-prepend-remove-and-link-default/starter.js)
|
||||||
|
- [answer.html](/Users/lijiaqing/home/wwwroot/front-end-example/04-dom-events-async/12-prepend-remove-and-link-default/answer.html)
|
||||||
|
- [answer.js](/Users/lijiaqing/home/wwwroot/front-end-example/04-dom-events-async/12-prepend-remove-and-link-default/answer.js)
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>prepend、classList.remove 和链接默认行为</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
padding: 32px;
|
||||||
|
font-family: "PingFang SC", "Microsoft YaHei", sans-serif;
|
||||||
|
background: #f5f7fb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel {
|
||||||
|
max-width: 760px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 24px;
|
||||||
|
border-radius: 18px;
|
||||||
|
background: #ffffff;
|
||||||
|
border: 1px solid #dce4ef;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item {
|
||||||
|
margin-top: 10px;
|
||||||
|
padding: 12px 14px;
|
||||||
|
border-radius: 12px;
|
||||||
|
border: 1px solid #dbe4f0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item.active {
|
||||||
|
background: #dbeafe;
|
||||||
|
}
|
||||||
|
|
||||||
|
.actions {
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<section class="panel">
|
||||||
|
<h1>补漏练习</h1>
|
||||||
|
<div class="actions">
|
||||||
|
<button id="prepend-btn" type="button">插入到最前面</button>
|
||||||
|
<button id="clear-active-btn" type="button">清除高亮</button>
|
||||||
|
<a id="help-link" href="https://example.com/help">查看帮助</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p id="hint-text">这里会显示操作提示。</p>
|
||||||
|
|
||||||
|
<ul id="message-list">
|
||||||
|
<li class="item active">先学事件监听</li>
|
||||||
|
<li class="item active">再学异步顺序</li>
|
||||||
|
<li class="item">最后做综合页面</li>
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<script src="./answer.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
const prependButton = document.getElementById("prepend-btn");
|
||||||
|
const clearActiveButton = document.getElementById("clear-active-btn");
|
||||||
|
const helpLink = document.getElementById("help-link");
|
||||||
|
const hintText = document.getElementById("hint-text");
|
||||||
|
const messageList = document.getElementById("message-list");
|
||||||
|
|
||||||
|
let messageIndex = 1;
|
||||||
|
|
||||||
|
prependButton.addEventListener("click", function () {
|
||||||
|
const item = document.createElement("li");
|
||||||
|
item.className = "item active";
|
||||||
|
item.textContent = `新插入的提醒 ${messageIndex}`;
|
||||||
|
messageList.prepend(item);
|
||||||
|
hintText.textContent = "已把一条消息插入到最前面";
|
||||||
|
messageIndex += 1;
|
||||||
|
});
|
||||||
|
|
||||||
|
clearActiveButton.addEventListener("click", function () {
|
||||||
|
const items = document.querySelectorAll(".item");
|
||||||
|
|
||||||
|
items.forEach(function (item) {
|
||||||
|
item.classList.remove("active");
|
||||||
|
});
|
||||||
|
|
||||||
|
hintText.textContent = "已移除全部高亮状态";
|
||||||
|
});
|
||||||
|
|
||||||
|
helpLink.addEventListener("click", function (event) {
|
||||||
|
event.preventDefault();
|
||||||
|
hintText.textContent = "已阻止默认跳转";
|
||||||
|
});
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>prepend、classList.remove 和链接默认行为</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
padding: 32px;
|
||||||
|
font-family: "PingFang SC", "Microsoft YaHei", sans-serif;
|
||||||
|
background: #f5f7fb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel {
|
||||||
|
max-width: 760px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 24px;
|
||||||
|
border-radius: 18px;
|
||||||
|
background: #ffffff;
|
||||||
|
border: 1px solid #dce4ef;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item {
|
||||||
|
margin-top: 10px;
|
||||||
|
padding: 12px 14px;
|
||||||
|
border-radius: 12px;
|
||||||
|
border: 1px solid #dbe4f0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item.active {
|
||||||
|
background: #dbeafe;
|
||||||
|
}
|
||||||
|
|
||||||
|
.actions {
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<section class="panel">
|
||||||
|
<h1>补漏练习</h1>
|
||||||
|
<div class="actions">
|
||||||
|
<button id="prepend-btn" type="button">插入到最前面</button>
|
||||||
|
<button id="clear-active-btn" type="button">清除高亮</button>
|
||||||
|
<a id="help-link" href="https://example.com/help">查看帮助</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p id="hint-text">这里会显示操作提示。</p>
|
||||||
|
|
||||||
|
<ul id="message-list">
|
||||||
|
<li class="item active">先学事件监听</li>
|
||||||
|
<li class="item active">再学异步顺序</li>
|
||||||
|
<li class="item">最后做综合页面</li>
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<script src="./starter.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
// 任务:
|
||||||
|
// 1. 获取两个按钮、帮助链接、提示文字和列表
|
||||||
|
// 2. 点击 prepend-btn 时创建新 li,并插入到列表最前面
|
||||||
|
// 3. 点击 clear-active-btn 时移除所有 item 的 active 类名
|
||||||
|
// 4. 点击帮助链接时,用 preventDefault() 阻止跳转
|
||||||
|
// 5. 在提示文字里输出“已阻止默认跳转”
|
||||||
|
const prependBtn = document.getElementById("prepend-btn")
|
||||||
|
const clear = document.getElementById("clear-active-btn")
|
||||||
|
const helpLink = document.getElementById("help-link")
|
||||||
|
const hintText = document.getElementById("hint-text")
|
||||||
|
const messageList = document.getElementById("message-list")
|
||||||
|
|
||||||
|
prependBtn.addEventListener("click", function () {
|
||||||
|
const li = document.createElement("li")
|
||||||
|
li.classList.add("item")
|
||||||
|
messageList.prepend(li)
|
||||||
|
})
|
||||||
|
|
||||||
|
clear.addEventListener("click", function () {
|
||||||
|
const a = document.querySelectorAll("#message-list li")
|
||||||
|
a.forEach(item => {
|
||||||
|
item.classList.remove("active")
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
helpLink.addEventListener("click", function (event) {
|
||||||
|
event.preventDefault()
|
||||||
|
hintText.textContent = "已阻止默认跳转"
|
||||||
|
})
|
||||||
176
04-dom-events-async/README.md
Normal file
176
04-dom-events-async/README.md
Normal file
@@ -0,0 +1,176 @@
|
|||||||
|
# DOM + 事件 + 异步
|
||||||
|
|
||||||
|
这部分只解决一个问题:你能不能让页面里的元素被 JavaScript 真正控制起来,并对用户操作和异步结果做出响应。
|
||||||
|
|
||||||
|
## 学完后你应该掌握
|
||||||
|
|
||||||
|
- 如何获取页面元素
|
||||||
|
- 如何修改文本、样式和类名
|
||||||
|
- 如何创建、插入和删除节点
|
||||||
|
- 如何监听点击、输入、提交等事件
|
||||||
|
- `preventDefault()` 和 `stopPropagation()` 的常见场景
|
||||||
|
- 事件委托的基本写法
|
||||||
|
- `prepend()`、`classList.remove()` 的基础使用
|
||||||
|
- `setTimeout` 的异步顺序
|
||||||
|
- Promise 的基础用法
|
||||||
|
- `async` / `await` 的基础写法
|
||||||
|
- 如何把 DOM、事件、异步组合成一个小页面
|
||||||
|
|
||||||
|
## 这一章在解决什么
|
||||||
|
|
||||||
|
前面三章分别解决了:
|
||||||
|
|
||||||
|
- 页面有什么结构
|
||||||
|
- 页面长什么样
|
||||||
|
- 代码逻辑怎么写
|
||||||
|
|
||||||
|
这一章开始,JavaScript 不再只是打印到控制台,而是要真正操作页面。
|
||||||
|
|
||||||
|
它回答的是:
|
||||||
|
|
||||||
|
- 我怎么拿到某个按钮或输入框
|
||||||
|
- 用户点击后页面怎么变
|
||||||
|
- 表单提交后怎么处理
|
||||||
|
- 数据晚一点回来时页面怎么更新
|
||||||
|
|
||||||
|
## 必须建立的 5 个核心意识
|
||||||
|
|
||||||
|
### 1. 先选中元素,再操作元素
|
||||||
|
|
||||||
|
DOM 操作第一步不是“改”,而是“找到”。
|
||||||
|
|
||||||
|
常见方式:
|
||||||
|
|
||||||
|
- `getElementById`
|
||||||
|
- `querySelector`
|
||||||
|
- `querySelectorAll`
|
||||||
|
|
||||||
|
### 2. 事件是页面和用户的连接点
|
||||||
|
|
||||||
|
页面本身不会“自动响应”。
|
||||||
|
|
||||||
|
是你通过事件监听告诉浏览器:
|
||||||
|
|
||||||
|
- 点了按钮要做什么
|
||||||
|
- 输入框变化后要做什么
|
||||||
|
- 提交表单要做什么
|
||||||
|
|
||||||
|
### 3. 改页面就是改 DOM
|
||||||
|
|
||||||
|
常见 DOM 改动包括:
|
||||||
|
|
||||||
|
- 改文字:`textContent`
|
||||||
|
- 改类名:`classList`
|
||||||
|
- 改样式:`style`
|
||||||
|
- 增删节点:`appendChild`、`remove`
|
||||||
|
|
||||||
|
### 4. 异步不是“慢一点执行”,而是“先不阻塞主流程”
|
||||||
|
|
||||||
|
比如:
|
||||||
|
|
||||||
|
- `setTimeout`
|
||||||
|
- Promise
|
||||||
|
- `async` / `await`
|
||||||
|
|
||||||
|
这些都意味着:当前代码先继续往下走,结果稍后回来再处理。
|
||||||
|
|
||||||
|
### 5. 一个完整交互通常是“事件 + DOM + 状态 + 异步”
|
||||||
|
|
||||||
|
例如点击“加载数据”按钮时:
|
||||||
|
|
||||||
|
1. 监听点击事件
|
||||||
|
2. 更新 loading 状态
|
||||||
|
3. 等待异步结果
|
||||||
|
4. 把结果渲染到页面
|
||||||
|
|
||||||
|
## 高频 API 速记
|
||||||
|
|
||||||
|
### 获取元素
|
||||||
|
|
||||||
|
- `document.getElementById()`
|
||||||
|
- `document.querySelector()`
|
||||||
|
- `document.querySelectorAll()`
|
||||||
|
|
||||||
|
### 修改元素
|
||||||
|
|
||||||
|
- `textContent`
|
||||||
|
- `innerHTML`
|
||||||
|
- `style`
|
||||||
|
- `classList.add()`
|
||||||
|
- `classList.remove()`
|
||||||
|
- `classList.toggle()`
|
||||||
|
|
||||||
|
### 节点操作
|
||||||
|
|
||||||
|
- `document.createElement()`
|
||||||
|
- `appendChild()`
|
||||||
|
- `prepend()`
|
||||||
|
- `remove()`
|
||||||
|
|
||||||
|
### 事件
|
||||||
|
|
||||||
|
- `addEventListener()`
|
||||||
|
- `event.target`
|
||||||
|
- `preventDefault()`
|
||||||
|
- `stopPropagation()`
|
||||||
|
|
||||||
|
### 异步
|
||||||
|
|
||||||
|
- `setTimeout()`
|
||||||
|
- `Promise`
|
||||||
|
- `.then()`
|
||||||
|
- `async`
|
||||||
|
- `await`
|
||||||
|
|
||||||
|
## 学习顺序
|
||||||
|
|
||||||
|
1. 获取元素
|
||||||
|
2. 修改文本、类名、样式
|
||||||
|
3. 创建和删除节点
|
||||||
|
4. 点击事件
|
||||||
|
5. 表单提交和 `preventDefault`
|
||||||
|
6. 冒泡、委托和 `stopPropagation`
|
||||||
|
7. `setTimeout` 和异步顺序
|
||||||
|
8. Promise 渲染
|
||||||
|
9. `async` / `await`
|
||||||
|
10. 综合小页面
|
||||||
|
11. `input` / `change` 事件
|
||||||
|
12. `prepend`、`classList.remove` 和链接默认行为
|
||||||
|
|
||||||
|
## 练习目录
|
||||||
|
|
||||||
|
- [01-query-selectors/README.md](/Users/lijiaqing/home/wwwroot/front-end-example/04-dom-events-async/01-query-selectors/README.md)
|
||||||
|
- [02-text-class-style/README.md](/Users/lijiaqing/home/wwwroot/front-end-example/04-dom-events-async/02-text-class-style/README.md)
|
||||||
|
- [03-create-and-remove/README.md](/Users/lijiaqing/home/wwwroot/front-end-example/04-dom-events-async/03-create-and-remove/README.md)
|
||||||
|
- [04-click-counter/README.md](/Users/lijiaqing/home/wwwroot/front-end-example/04-dom-events-async/04-click-counter/README.md)
|
||||||
|
- [05-form-submit-and-prevent-default/README.md](/Users/lijiaqing/home/wwwroot/front-end-example/04-dom-events-async/05-form-submit-and-prevent-default/README.md)
|
||||||
|
- [06-bubbling-and-delegation/README.md](/Users/lijiaqing/home/wwwroot/front-end-example/04-dom-events-async/06-bubbling-and-delegation/README.md)
|
||||||
|
- [07-timers-and-async-order/README.md](/Users/lijiaqing/home/wwwroot/front-end-example/04-dom-events-async/07-timers-and-async-order/README.md)
|
||||||
|
- [08-promise-and-render/README.md](/Users/lijiaqing/home/wwwroot/front-end-example/04-dom-events-async/08-promise-and-render/README.md)
|
||||||
|
- [09-async-await-panel/README.md](/Users/lijiaqing/home/wwwroot/front-end-example/04-dom-events-async/09-async-await-panel/README.md)
|
||||||
|
- [10-final-dashboard/README.md](/Users/lijiaqing/home/wwwroot/front-end-example/04-dom-events-async/10-final-dashboard/README.md)
|
||||||
|
- [11-input-live-preview/README.md](/Users/lijiaqing/home/wwwroot/front-end-example/04-dom-events-async/11-input-live-preview/README.md)
|
||||||
|
- [12-prepend-remove-and-link-default/README.md](/Users/lijiaqing/home/wwwroot/front-end-example/04-dom-events-async/12-prepend-remove-and-link-default/README.md)
|
||||||
|
|
||||||
|
## 过关标准
|
||||||
|
|
||||||
|
如果你能独立做到下面这些,就说明这一章已经基本过关:
|
||||||
|
|
||||||
|
- 能正确选中页面里的元素
|
||||||
|
- 能改文字、类名和内联样式
|
||||||
|
- 能动态创建和删除列表项
|
||||||
|
- 能给按钮、表单绑定事件
|
||||||
|
- 能理解事件冒泡和事件委托
|
||||||
|
- 能在需要时使用 `preventDefault()` 和 `stopPropagation()`
|
||||||
|
- 能处理 `input` / `change` 这类常见表单事件
|
||||||
|
- 能使用 `prepend()`、`classList.remove()` 完成简单 DOM 调整
|
||||||
|
- 能理解 `setTimeout` 的异步顺序
|
||||||
|
- 能用 Promise 和 `async` / `await` 处理一个简单异步流程
|
||||||
|
- 能做出一个有真实交互的小页面
|
||||||
|
|
||||||
|
## 学习建议
|
||||||
|
|
||||||
|
- 每个练习都用浏览器打开 `starter.html`
|
||||||
|
- 打开开发者工具,边看页面边看控制台
|
||||||
|
- 一个交互没反应时,先确认元素有没有选中
|
||||||
|
- 一个异步结果不对时,先打印中间状态
|
||||||
24
05-es6-plus/01-template-and-destructuring/README.md
Normal file
24
05-es6-plus/01-template-and-destructuring/README.md
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
# 练习 1:模板字符串和解构
|
||||||
|
|
||||||
|
## 目标
|
||||||
|
|
||||||
|
学会用模板字符串拼接信息,并用解构快速读取对象和数组数据。
|
||||||
|
|
||||||
|
## 你要练什么
|
||||||
|
|
||||||
|
- 模板字符串
|
||||||
|
- 对象解构
|
||||||
|
- 数组解构
|
||||||
|
|
||||||
|
## 任务
|
||||||
|
|
||||||
|
- 从 `student` 对象里解构出姓名和阶段
|
||||||
|
- 从 `scores` 数组里解构出前两个分数
|
||||||
|
- 用模板字符串把这些信息渲染到页面
|
||||||
|
|
||||||
|
## 文件
|
||||||
|
|
||||||
|
- [starter.html](/Users/lijiaqing/home/wwwroot/front-end-example/05-es6-plus/01-template-and-destructuring/starter.html)
|
||||||
|
- [starter.js](/Users/lijiaqing/home/wwwroot/front-end-example/05-es6-plus/01-template-and-destructuring/starter.js)
|
||||||
|
- [answer.html](/Users/lijiaqing/home/wwwroot/front-end-example/05-es6-plus/01-template-and-destructuring/answer.html)
|
||||||
|
- [answer.js](/Users/lijiaqing/home/wwwroot/front-end-example/05-es6-plus/01-template-and-destructuring/answer.js)
|
||||||
16
05-es6-plus/01-template-and-destructuring/answer.html
Normal file
16
05-es6-plus/01-template-and-destructuring/answer.html
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>模板字符串和解构</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<section>
|
||||||
|
<h1>ES6+ 练习 1</h1>
|
||||||
|
<p id="output">等待渲染</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<script src="./answer.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
11
05-es6-plus/01-template-and-destructuring/answer.js
Normal file
11
05-es6-plus/01-template-and-destructuring/answer.js
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
const student = {
|
||||||
|
name: "林晨",
|
||||||
|
stage: "ES6+",
|
||||||
|
};
|
||||||
|
|
||||||
|
const scores = [88, 92, 95];
|
||||||
|
|
||||||
|
const { name, stage } = student;
|
||||||
|
const [firstScore, secondScore] = scores;
|
||||||
|
|
||||||
|
document.getElementById("output").textContent = `${name} 正在学习 ${stage},前两次练习分数分别是 ${firstScore} 和 ${secondScore}。`;
|
||||||
16
05-es6-plus/01-template-and-destructuring/starter.html
Normal file
16
05-es6-plus/01-template-and-destructuring/starter.html
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>模板字符串和解构</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<section>
|
||||||
|
<h1>ES6+ 练习 1</h1>
|
||||||
|
<p id="output">等待渲染</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<script src="./starter.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
18
05-es6-plus/01-template-and-destructuring/starter.js
Normal file
18
05-es6-plus/01-template-and-destructuring/starter.js
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
const student = {
|
||||||
|
name: "林晨",
|
||||||
|
stage: "ES6+",
|
||||||
|
};
|
||||||
|
|
||||||
|
const scores = [88, 92, 95];
|
||||||
|
|
||||||
|
// 任务:
|
||||||
|
// 1. 解构出 name、stage
|
||||||
|
// 2. 解构出前两个分数
|
||||||
|
// 3. 用模板字符串把信息写入 #output
|
||||||
|
const { name, stage } = student
|
||||||
|
const [a, b] = scores
|
||||||
|
const output = document.getElementById("output")
|
||||||
|
output.innerHTML = `
|
||||||
|
a = ${a}
|
||||||
|
b = ${b}
|
||||||
|
`
|
||||||
24
05-es6-plus/02-spread-and-rest/README.md
Normal file
24
05-es6-plus/02-spread-and-rest/README.md
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
# 练习 2:展开运算符和剩余参数
|
||||||
|
|
||||||
|
## 目标
|
||||||
|
|
||||||
|
学会复制数组、合并对象,以及用剩余参数接收不定数量的参数。
|
||||||
|
|
||||||
|
## 你要练什么
|
||||||
|
|
||||||
|
- 数组展开
|
||||||
|
- 对象展开
|
||||||
|
- 剩余参数
|
||||||
|
|
||||||
|
## 任务
|
||||||
|
|
||||||
|
- 复制一份课程数组并新增一项
|
||||||
|
- 基于用户对象生成一个更新后的对象
|
||||||
|
- 写一个 `sumScores` 函数,用剩余参数计算总分
|
||||||
|
|
||||||
|
## 文件
|
||||||
|
|
||||||
|
- [starter.html](/Users/lijiaqing/home/wwwroot/front-end-example/05-es6-plus/02-spread-and-rest/starter.html)
|
||||||
|
- [starter.js](/Users/lijiaqing/home/wwwroot/front-end-example/05-es6-plus/02-spread-and-rest/starter.js)
|
||||||
|
- [answer.html](/Users/lijiaqing/home/wwwroot/front-end-example/05-es6-plus/02-spread-and-rest/answer.html)
|
||||||
|
- [answer.js](/Users/lijiaqing/home/wwwroot/front-end-example/05-es6-plus/02-spread-and-rest/answer.js)
|
||||||
12
05-es6-plus/02-spread-and-rest/answer.html
Normal file
12
05-es6-plus/02-spread-and-rest/answer.html
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>展开运算符和剩余参数</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<pre id="output"></pre>
|
||||||
|
<script src="./answer.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
24
05-es6-plus/02-spread-and-rest/answer.js
Normal file
24
05-es6-plus/02-spread-and-rest/answer.js
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
const tracks = ["HTML", "CSS", "JavaScript"];
|
||||||
|
|
||||||
|
const user = {
|
||||||
|
name: "林晨",
|
||||||
|
stage: "基础阶段",
|
||||||
|
};
|
||||||
|
|
||||||
|
function sumScores(...scores) {
|
||||||
|
return scores.reduce((total, score) => total + score, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
const newTracks = [...tracks, "ES6+"];
|
||||||
|
const nextUser = { ...user, stage: "现代 JS" };
|
||||||
|
const totalScore = sumScores(88, 91, 95);
|
||||||
|
|
||||||
|
document.getElementById("output").textContent = JSON.stringify(
|
||||||
|
{
|
||||||
|
newTracks,
|
||||||
|
nextUser,
|
||||||
|
totalScore,
|
||||||
|
},
|
||||||
|
null,
|
||||||
|
2
|
||||||
|
);
|
||||||
12
05-es6-plus/02-spread-and-rest/starter.html
Normal file
12
05-es6-plus/02-spread-and-rest/starter.html
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>展开运算符和剩余参数</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<pre id="output"></pre>
|
||||||
|
<script src="./starter.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
32
05-es6-plus/02-spread-and-rest/starter.js
Normal file
32
05-es6-plus/02-spread-and-rest/starter.js
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
const tracks = ["HTML", "CSS", "JavaScript"];
|
||||||
|
|
||||||
|
const user = {
|
||||||
|
name: "林晨",
|
||||||
|
stage: "基础阶段",
|
||||||
|
};
|
||||||
|
|
||||||
|
function sumScores(...scores) {
|
||||||
|
// 返回总分
|
||||||
|
/*let total = 0
|
||||||
|
scores.forEach(item => {
|
||||||
|
total = total+item
|
||||||
|
})
|
||||||
|
return total*/
|
||||||
|
return scores.reduce((acc, item) => {
|
||||||
|
return acc + item
|
||||||
|
}, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 任务:
|
||||||
|
// 1. 复制 tracks 并新增 "ES6+"
|
||||||
|
// 2. 基于 user 生成一个 stage 为 "现代 JS" 的新对象
|
||||||
|
// 3. 调用 sumScores
|
||||||
|
// 4. 输出结果到 #output
|
||||||
|
const tracks1 = [...tracks, "ES6+"]
|
||||||
|
const user1 = {
|
||||||
|
...user,
|
||||||
|
stage: "现代 JS"
|
||||||
|
}
|
||||||
|
const sum = sumScores(1, 2, 3, 4)
|
||||||
|
const output = document.getElementById("output")
|
||||||
|
output.textContent = sum
|
||||||
23
05-es6-plus/03-arrow-functions/README.md
Normal file
23
05-es6-plus/03-arrow-functions/README.md
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
# 练习 3:箭头函数
|
||||||
|
|
||||||
|
## 目标
|
||||||
|
|
||||||
|
学会把简单函数改写成箭头函数。
|
||||||
|
|
||||||
|
## 你要练什么
|
||||||
|
|
||||||
|
- 箭头函数
|
||||||
|
- 简写返回值
|
||||||
|
- 数组映射
|
||||||
|
|
||||||
|
## 任务
|
||||||
|
|
||||||
|
- 把两个普通函数改成箭头函数
|
||||||
|
- 用 `map` 和箭头函数生成课程标签
|
||||||
|
|
||||||
|
## 文件
|
||||||
|
|
||||||
|
- [starter.html](/Users/lijiaqing/home/wwwroot/front-end-example/05-es6-plus/03-arrow-functions/starter.html)
|
||||||
|
- [starter.js](/Users/lijiaqing/home/wwwroot/front-end-example/05-es6-plus/03-arrow-functions/starter.js)
|
||||||
|
- [answer.html](/Users/lijiaqing/home/wwwroot/front-end-example/05-es6-plus/03-arrow-functions/answer.html)
|
||||||
|
- [answer.js](/Users/lijiaqing/home/wwwroot/front-end-example/05-es6-plus/03-arrow-functions/answer.js)
|
||||||
12
05-es6-plus/03-arrow-functions/answer.html
Normal file
12
05-es6-plus/03-arrow-functions/answer.html
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>箭头函数</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<pre id="output"></pre>
|
||||||
|
<script src="./answer.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
15
05-es6-plus/03-arrow-functions/answer.js
Normal file
15
05-es6-plus/03-arrow-functions/answer.js
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
const getLevel = (score) => (score >= 80 ? "达标" : "继续练习");
|
||||||
|
const add = (a, b) => a + b;
|
||||||
|
|
||||||
|
const tracks = ["DOM", "异步", "模块化"];
|
||||||
|
const labels = tracks.map((track) => `[${track}]`);
|
||||||
|
|
||||||
|
document.getElementById("output").textContent = JSON.stringify(
|
||||||
|
{
|
||||||
|
level: getLevel(86),
|
||||||
|
sum: add(12, 8),
|
||||||
|
labels,
|
||||||
|
},
|
||||||
|
null,
|
||||||
|
2
|
||||||
|
);
|
||||||
12
05-es6-plus/03-arrow-functions/starter.html
Normal file
12
05-es6-plus/03-arrow-functions/starter.html
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>箭头函数</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<pre id="output"></pre>
|
||||||
|
<script src="./starter.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
18
05-es6-plus/03-arrow-functions/starter.js
Normal file
18
05-es6-plus/03-arrow-functions/starter.js
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
function getLevel(score) {
|
||||||
|
return score >= 80 ? "达标" : "继续练习";
|
||||||
|
}
|
||||||
|
|
||||||
|
function add(a, b) {
|
||||||
|
return a + b;
|
||||||
|
}
|
||||||
|
|
||||||
|
const tracks = ["DOM", "异步", "模块化"];
|
||||||
|
|
||||||
|
// 任务:
|
||||||
|
// 1. 把 getLevel 改成箭头函数
|
||||||
|
// 2. 把 add 改成箭头函数
|
||||||
|
// 3. 用 map + 箭头函数生成 ["[DOM]", ...]
|
||||||
|
const getLevel1 = score => score >= 80
|
||||||
|
const add1 = (a, b) => a + b
|
||||||
|
const tracks1 = tracks.map(item => `[${item}]`)
|
||||||
|
console.log(tracks1);
|
||||||
24
05-es6-plus/04-modules-basic/README.md
Normal file
24
05-es6-plus/04-modules-basic/README.md
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
#
|
||||||
|
练习 4:模块基础
|
||||||
|
|
||||||
|
## 目标
|
||||||
|
|
||||||
|
学会用 `export` 和 `import` 把不同文件连起来。
|
||||||
|
|
||||||
|
## 你要练什么
|
||||||
|
|
||||||
|
- `export`
|
||||||
|
- `import`
|
||||||
|
- `type="module"`
|
||||||
|
## 任务
|
||||||
|
|
||||||
|
- 从模块文件里导入课程数据和格式化函数
|
||||||
|
- 把结果渲染到页面
|
||||||
|
|
||||||
|
## 文件
|
||||||
|
|
||||||
|
- [starter.html](/Users/lijiaqing/home/wwwroot/front-end-example/05-es6-plus/04-modules-basic/starter.html)
|
||||||
|
- [starter.js](/Users/lijiaqing/home/wwwroot/front-end-example/05-es6-plus/04-modules-basic/starter.js)
|
||||||
|
- [course-data.js](/Users/lijiaqing/home/wwwroot/front-end-example/05-es6-plus/04-modules-basic/course-data.js)
|
||||||
|
- [answer.html](/Users/lijiaqing/home/wwwroot/front-end-example/05-es6-plus/04-modules-basic/answer.html)
|
||||||
|
- [answer.js](/Users/lijiaqing/home/wwwroot/front-end-example/05-es6-plus/04-modules-basic/answer.js)
|
||||||
12
05-es6-plus/04-modules-basic/answer.html
Normal file
12
05-es6-plus/04-modules-basic/answer.html
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>模块基础</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<pre id="output"></pre>
|
||||||
|
<script type="module" src="./answer.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
4
05-es6-plus/04-modules-basic/answer.js
Normal file
4
05-es6-plus/04-modules-basic/answer.js
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
import { courses, formatCourse } from "./course-data.js";
|
||||||
|
|
||||||
|
const lines = courses.map((course) => formatCourse(course));
|
||||||
|
document.getElementById("output").textContent = lines.join("\n");
|
||||||
3
05-es6-plus/04-modules-basic/course-data.js
Normal file
3
05-es6-plus/04-modules-basic/course-data.js
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
export const courses = ["解构", "展开运算符", "Promise"];
|
||||||
|
|
||||||
|
export const formatCourse = (course) => `正在学习:${course}`;
|
||||||
12
05-es6-plus/04-modules-basic/starter.html
Normal file
12
05-es6-plus/04-modules-basic/starter.html
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>模块基础</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<pre id="output"></pre>
|
||||||
|
<script type="module" src="./starter.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user