作为前端开发的主力语言,
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
项目名称stringicon
项目 icon 路径stringstars
项目新增 star 数量numberdescriptionCN
项目中文描述stringdescriptionEN
项目英文描述stringtags
项目标签列表array 2. 页面初始化时利用createProjectItem
函数创建前 15 个项目数据(即all-data.json
数组中的前 15 项)的列表元素并加载到页面中。当用户点击 加载更多 按钮时,则按顺序再显示 15 个项目数据。直到所有项目数据都展示完毕(共 60 个)。所有项目展示完毕后需要隐藏 加载更多 按钮。项目展示效果如图所示:
3. 当用户点击页面右上方的中英文切换按钮时,根据用户的选择改变项目描述使用的语言(不改变原有项目展示数量)。当用户选择英语模式时的项目展示效果如图所示:
最终效果可参考文件夹下面的 gif 图,图片名称为 effect.gif(提示:可以通过 VS Code 或者浏览器预览 gif 图片)。
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}" alt="">
<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>
`;
}
<!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">
用于设置页面在移动端的显示效果,使其适应设备宽度,禁止用户缩放。js/jquery-3.6.0.min.js
,以便在 JavaScript 中使用 jQuery 提供的功能。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>
是加载更多数据的按钮。js/index.js
,用于实现页面的交互功能。: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
伪类设置鼠标悬停时的背景颜色变化。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}" alt="">
<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 字符串,用于生成页面上的项目列表项。四、工作流程▶️
data
、translation
、currLang
和 page
。window.onload
事件触发),使用 fetch
获取项目数据和翻译数据。