目录
背景介绍
作为前端开发的主力语言,
JavaScript相关的开源项目是每一个前端开发者都应该多多关注的。我们可以通过这一年新增 star 的数量来判断一个开源项目的流行趋势。本题请实现一个展示 2022 年
JavaScript明星开源项目数据的网页。
准备步骤
开始答题前,需要先打开本题的项目代码文件夹,目录结构如下:
├── css │ └── style.css ├── effect.gif ├── images ├── index.html └── js ├── all-data.json ├── index.js ├── jquery-3.6.0.min.js └── translation.json其中:
css/style.css是样式文件。index.html是主页面。images是图片文件夹。js/all-data.json是项目数据文件。js/index.js是需要补充代码的js文件。js/jquery-3.6.0.min.js是 jQuery 库文件。js/translation.json是页面所用到的翻译数据。effect.gif是页面最终的效果图。注意:打开环境后发现缺少项目代码,请复制下述命令至命令行进行下载:
cd /home/project wget https://labfile.oss.aliyuncs.com/courses/18213/2022-JavaScript.zip unzip 2022-JavaScript.zip && rm 2022-JavaScript.zip在浏览器中预览
index.html页面效果如下:
目标效果
请在
js/index.js文件中补全代码,具体需求如下:1. 在页面初始化时使用
AJAX请求地址为./js/all-data.json和./js/translation.json文件中的数据(必须使用给定的路径请求,否则可能会请求不到数据),并将后者中的数据保存至translation变量中。其中all-data.json文件中以数组的形式存储了明星项目的数据,translation.json文件中包含了网站中英文转换所需的数据。
all-data.json数据参数说明:
参数 说明 类型 name项目名称 string icon项目 icon 路径 string stars项目新增 star 数量 number descriptionCN项目中文描述 string descriptionEN项目英文描述 string tags项目标签列表 array 2. 页面初始化时利用
createProjectItem函数创建前 15 个项目数据(即all-data.json数组中的前 15 项)的列表元素并加载到页面中。当用户点击 加载更多 按钮时,则按顺序再显示 15 个项目数据。直到所有项目数据都展示完毕(共 60 个)。所有项目展示完毕后需要隐藏 加载更多 按钮。项目展示效果如图所示:
3. 当用户点击页面右上方的中英文切换按钮时,根据用户的选择改变项目描述使用的语言(不改变原有项目展示数量)。当用户选择英语模式时的项目展示效果如图所示:
最终效果可参考文件夹下面的 gif 图,图片名称为 effect.gif(提示:可以通过 VS Code 或者浏览器预览 gif 图片)。
要求规定
- 请严格按照考试步骤操作,切勿修改考试默认提供项目中的文件名称、文件夹路径、class 名、id 名、图片名等,以免造成无法判题通过。
判分标准
- 完成目标 1,得 5 分。
- 完成目标 2,得 10 分。
- 完成目标 3,得 5 分。
通关代码️
let data = []
// 保存翻译文件数据的变量
let translation = {};
// 记录当前语言
let currLang = "zh-cn";
var page = 0
// TODO: 请在此补充代码实现项目数据文件和翻译数据文件的请求功能
window.onload= async()=>{
const res1 = await fetch("./js/all-data.json ")
data = await res1.json()
const res2 = await fetch("./js/translation.json")
translation = await res2.json()
data.slice(0,15).forEach((item)=>{
$(".list > ul").append(createProjectItem({...item,description:(currLang=="zh-cn"?item.descriptionCN:item.descriptionEN)}));
})
document.querySelector(".load-more").addEventListener("click",function(){
data.slice((page+1)*15,(page+2)*15).forEach((item)=>{
$(".list > ul").append(createProjectItem({...item,description:(currLang=="zh-cn"?item.descriptionCN:item.descriptionEN)}));
});
page++
if(page == Math.ceil(data.length/15) - 1){
this.style.display ="none"
}
})
}
// 用户点击切换语言的回调
$(".lang").click(() => {
// 切换页面文字的中英文
if (currLang === "en") {
$(".lang").text("English");
currLang = "zh-cn";
} else {
$(".lang").text("中文");
currLang = "en";
}
$("body")
.find("*")
.each(function () {
const text = $(this).text().trim();
if (translation[text]) {
$(this).text(translation[text]);
}
});
// TODO: 请在此补充代码实现项目描述的语言切换
document.querySelectorAll("body > div.container > div.list > ul > li > div.desc > p").forEach((item)=>{
item.textContent=
currLang == "zh-cn"
?data.find(i=>i.descriptionEN==item.textContent).descriptionCN
:data.find(i=>i.descriptionCN==item.textContent).descriptionEN
})
});
// 生成列表DOM元素的函数,将该元素的返回值append至列表中即可生成一行项目数据
/**
* @param {string} name - 项目名称
* @param {string} description - 项目描述
* @param {string[]} tags - 项目标签
* @param {number} stars - 项目star数量
* @param {string} icon - 项目icon路径
*/
function createProjectItem({ name, description, tags, stars, icon }) {
return `
<li class="item">
<img src="images/${icon}" >
<div class="desc">
<h3>${name}</h3>
<p>${description}</p>
<ul class="labels">
${tags.map((tag) => `<li>${tag}</li>`).join("")}
</ul>
</div>
<div class="stars">
+${stars}
</div>
</li>
`;
}
代码解析
一、HTML 部分
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>年度明星项目</title> <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" /> <script src="js/jquery-3.6.0.min.js" type="text/javascript" charset="utf-8" ></script> <link rel="stylesheet" type="text/css" href="css/style.css" /> </head> <body> <div class="container"> <div class="head"> <header> <h1>JavaScript明星项目</h1> <div class="lang">English</div> </header> </div> <div class="banner">2022 年 JavaScript 明星项目</div> <div class="intro"> <p>欢迎来到2022 JavaScript明星项目网站!</p> <p> 在这里,我们将对过去 12 个月里 JavaScript 生态中的趋势性项目做一个总结。今年的冠军是一个带有微笑标志的美味面包,用微笑开启新的一年是不错的开始! </p> <hr /> <p class="small"> 下面的列表中展示了各个项目在 GitHub 上于过去 12 个月新增的 star 数量。分析的数据来源为 Best of JS 网站 ,一个 web 领域优秀项目的精选网站。 </p> </div> <div class="list"> <h2>最受欢迎项目</h2> <ul></ul> <div class="load-more">加载更多</div> </div> </div> <script src="js/index.js"></script> </body> </html>
<!DOCTYPE html>声明文档类型为 HTML5。<html>是整个 HTML 文档的根元素。<head>部分:
<meta charset="UTF-8">设置文档的字符编码为 UTF-8。<title>设置页面标题为 “年度明星项目”。<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no">用于设置页面在移动端的显示效果,使其适应设备宽度,禁止用户缩放。- 引入了 jQuery 库文件
js/jquery-3.6.0.min.js,以便在 JavaScript 中使用 jQuery 提供的功能。- 引入了外部 CSS 样式表
css/style.css,用于定义页面的样式。<body>部分:
<div class="container">是页面的主要容器。
<div class="head">包含页面的头部信息,其中<header>内有页面标题<h1>JavaScript明星项目</h1>和语言切换按钮<div class="lang">English</div>。<div class="banner">显示 “2022 年 JavaScript 明星项目” 的横幅信息。<div class="intro">包含页面的介绍文本,描述了网站的功能和数据来源等信息。<div class="list">包含项目列表部分,<h2>最受欢迎项目</h2>是列表标题,<ul></ul>用于显示项目列表项,<div class="load-more">加载更多</div>是加载更多数据的按钮。- 最后引入了自定义的 JavaScript 脚本文件
js/index.js,用于实现页面的交互功能。
二、CSS 部分
:root { --orange: #cc4700; } body { margin: 0; padding: 0; background-color: rgb(239, 239, 236); color: #541600; } .head { display: flex; width: 100vw; justify-content: center; background-color: white; } header { color: #cc4700; display: flex; width: 100%; max-width: 1200px; justify-content: space-between; padding: 0 1rem; align-items: center; box-sizing: border-box; } header h1 { margin: 1rem; } .lang { font-family: "Times New Roman", Times, serif; cursor: pointer; font-size: 110%; } .lang:hover { color: rgba(204, 71, 0, 0.8); } .banner { background-color: #e65100; color: white; font-size: 300%; text-align: center; font-family: Space Mono, monospace; height: 300px; display: grid; align-items: center; margin-bottom: 2rem; } .intro { padding: 2rem; border: 1px solid #788080; max-width: 650px; margin: auto; margin-bottom: 2rem; font-size: 20px; } .small { font-size: 16px; } .list { max-width: 1200px; margin: auto; } .list h2 { font-size: 1.3rem; border: 1px solid #788080; margin-bottom: 40px; text-align: center; padding: 2rem; } .list ul { list-style: none; width: 650px; margin: auto; } .list .item { display: flex; align-items: center; justify-content: space-evenly; gap: 1rem; border-top: #bbb dashed 1px; } .list .item:last-child { border-bottom: #bbb dashed 1px; } .list img { width: 60px; } .list .desc { font-family: "Times New Roman", Times, serif; width: 400px; padding: 1rem 0; } .list .desc h3 { color: #e65100; font-weight: 400; font-family: "Courier New", Courier, monospace; margin: 0; } .list .desc p { margin: 0.5rem 0; } .list .desc .labels { display: flex; gap: 1rem; padding: 0; } .list .desc .labels li { padding: 0.5rem; color: rgba(84, 22, 0, 0.6); border: 1px solid rgba(84, 22, 0, 0.2); border-radius: 5px; font-family: sans-serif; font-size: 0.8rem; } .list .stars { font-family: monospace; font-size: 1.1rem; } .load-more { font-size: 1.3rem; border: 1px solid #788080; margin: 40px 0; text-align: center; padding: 2rem; color: #e65100; cursor: pointer; } .load-more:hover { background-color: white; }
:root选择器定义了一个全局变量--orange,值为#cc4700,用于统一管理颜色。body选择器设置页面的边距、内边距、背景颜色和文本颜色。.head类设置头部容器的显示方式为 flex 布局,宽度为视口宽度,背景颜色为白色,并居中内容。header类设置头部内容的颜色、显示方式为 flex 布局,最大宽度为 1200px,水平方向上两端对齐,垂直方向上居中内容。.lang类设置语言切换按钮的字体、鼠标样式和字体大小,:hover伪类设置鼠标悬停时的颜色变化。.banner类设置横幅的背景颜色、文本颜色、字体大小、文本对齐方式、字体类型、高度和显示方式为 grid 布局,并设置底部外边距。.intro类设置介绍部分的内边距、边框、最大宽度、居中显示和字体大小。.small类设置特定段落的字体大小。.list类设置项目列表容器的最大宽度并居中显示。.list h2类设置列表标题的字体大小、边框、底部外边距、文本对齐方式和内边距。.list ul类设置列表的样式,去除默认的列表符号,并设置宽度和居中显示。.list .item类设置项目列表项的显示方式为 flex 布局,垂直方向上居中内容,水平方向上均匀分布元素,设置元素间的间距和顶部边框。.list .item:last-child类设置最后一个项目列表项的底部边框。.list img类设置项目图标图片的宽度。.list .desc类设置项目描述部分的字体、宽度和内边距。.list .desc h3类设置项目描述标题的颜色、字体权重、字体类型和边距。.list .desc p类设置项目描述段落的底部外边距。.list .desc .labels类设置项目标签列表的显示方式为 flex 布局和元素间的间距。.list .desc .labels li类设置项目标签的内边距、颜色、边框、边框半径、字体和字体大小。.list .stars类设置项目星星数量的字体和字体大小。.load-more类设置加载更多按钮的字体大小、边框、外边距、文本对齐方式、内边距、颜色和鼠标样式,:hover伪类设置鼠标悬停时的背景颜色变化。
三、JavaScript 部分
let data = []; // 保存翻译文件数据的变量 let translation = {}; // 记录当前语言 let currLang = "zh-cn"; var page = 0;
- 定义了四个变量:
data用于存储从all-data.json文件中获取的项目数据,初始化为空数组。translation用于存储从translation.json文件中获取的翻译数据,初始化为空对象。currLang用于记录当前页面显示的语言,初始值为"zh-cn",即中文。page用于记录当前加载数据的页码,初始值为0。window.onload = async () => { const res1 = await fetch("./js/all-data.json "); data = await res1.json(); const res2 = await fetch("./js/translation.json"); translation = await res2.json(); data.slice(0, 15).forEach((item) => { $(".list > ul").append(createProjectItem({...item, description: (currLang == "zh-cn"? item.descriptionCN : item.descriptionEN) })); }); document.querySelector(".load-more").addEventListener("click", function () { data.slice((page + 1) * 15, (page + 2) * 15).forEach((item) => { $(".list > ul").append(createProjectItem({...item, description: (currLang == "zh-cn"? item.descriptionCN : item.descriptionEN) })); }); page++; if (page == Math.ceil(data.length / 15) - 1) { this.style.display = "none"; } }); };
window.onload事件在页面完全加载后触发,这里使用了异步函数来处理数据获取和页面渲染。
- 使用
fetch分别从./js/all-data.json和./js/translation.json获取数据,并通过await等待数据解析完成,将项目数据存储在data中,翻译数据存储在translation中。- 使用
data.slice(0, 15)取出前 15 条项目数据,遍历这些数据,调用createProjectItem函数生成项目列表项的 HTML 字符串,并将其添加到页面中类名为list的ul元素内。同时根据当前语言currLang决定使用descriptionCN(中文描述)还是descriptionEN(英文描述)。- 为类名为
load-more的元素添加点击事件监听器。当点击时,根据当前页码page取出下一页的 15 条项目数据,同样调用createProjectItem函数生成 HTML 字符串并添加到页面中。每次点击后page自增 1,如果page达到总页数(通过Math.ceil(data.length / 15) - 1计算),则隐藏load-more按钮。$(".lang").click(() => { // 切换页面文字的中英文 if (currLang === "en") { $(".lang").text("English"); currLang = "zh-cn"; } else { $(".lang").text("中文"); currLang = "en"; } $("body") .find("*") .each(function () { const text = $(this).text().trim(); if (translation[text]) { $(this).text(translation[text]); } }); // TODO: 请在此补充代码实现项目描述的语言切换 document.querySelectorAll("body > div.container > div.list > ul > li > div.desc > p").forEach((item) => { item.textContent = currLang == "zh-cn" ? data.find(i => i.descriptionEN == item.textContent).descriptionCN : data.find(i => i.descriptionCN == item.textContent).descriptionEN; }); });
- 为类名为
lang的元素添加点击事件监听器。当点击时,根据当前语言currLang切换语言状态,更新lang元素的文本内容,并将currLang设置为相反的语言。
- 遍历页面中
body内的所有元素,获取其文本内容,检查translation对象中是否有对应的翻译文本,如果有则更新元素的文本内容。- 遍历页面中项目描述的段落元素,根据当前语言
currLang,从data中查找对应的项目,将描述更新为相应语言的描述。function createProjectItem({ name, description, tags, stars, icon }) { return ` <li class="item"> <img src="images/${icon}" > <div class="desc"> <h3>${name}</h3> <p>${description}</p> <ul class="labels"> ${tags.map((tag) => `<li>${tag}</li>`).join("")} </ul> </div> <div class="stars"> +${stars} </div> </li> `; }
- 定义了
createProjectItem函数,接受一个包含项目信息的对象作为参数,返回一个包含项目信息的 HTML 字符串,用于生成页面上的项目列表项。
四、工作流程▶️
- 页面加载时,首先解析 HTML 结构,构建页面的基本布局。
- 加载并应用 CSS 样式,使页面具有美观的外观和合适的布局。
- 执行 JavaScript 代码:
- 初始化变量
data、translation、currLang和page。- 页面加载完成后(
window.onload事件触发),使用fetch获取项目数据和翻译数据。- 解析数据后,先渲染前 15 条项目数据到页面上。
- 为 “加载更多” 按钮添加点击事件监听器,每次点击加载下一页的 15 条项目数据,并在数据全部加载完后隐藏按钮。
- 为语言切换按钮添加点击事件监听器,点击时切换页面语言,更新语言切换按钮的文本,并遍历页面元素更新其文本内容为相应语言的翻译文本,同时更新项目描述的语言。
- 用户在页面上进行操作(点击 “加载更多” 按钮或语言切换按钮)时,相应的事件监听器会被触发,执行相应的操作,更新页面内容。
测试结果






最终效果可参考文件夹下面的 gif 图,图片名称为 effect.gif(提示:可以通过 VS Code 或者浏览器预览 gif 图片)。
![表情[baoquan]-拾光赋](https://blogs.ink/wp-content/themes/zibll/img/smilies/baoquan.gif)


暂无评论内容