2022年第十三届蓝桥杯Web应用开发组省赛题解

写下这篇博客的标题时,我不由得想到了三年前第一次参加蓝桥杯的我。当时参加的还是C++组,题目是那些烧脑的算法题,谁能想到在三年后的今天,蓝桥杯竟然有了Web前端的赛题。经过几次考纲改动后,实际比赛的题目其实比我想象中要简单,原本还以为能遇到Webpack配置或者npm之类的问题呢(

蓝桥也没说Web组用的什么自动化测试框架,如果组委会的判题机不抽风的话,我应该是绝大部分题都有把握拿分的,除了某个还原设计图的题目比较头大,这个可能只拿一部分分吧。

一直面试压力还是有的,偶尔做做这种题也挺有乐趣。

1649573874649

主要的考点是HTML,CSS,JavaScript基础,一些调试能力,还有Vue和axios的简单使用,这里就简单说一下思路和核心代码吧。

水果拼盘

介绍

目前CSS3中新增的Flex 弹性布局已经成为前端页面布局的首选方案,本题可以使用Flex属性快速完成布局。

目标

建议使用flex相关属性完成css/style.css中的TODO部分。

1.禁止修改圆盘的位置和图片的大小。

2.相同颜色的水果放在相同颜色的圆盘正中间(例如:苹果是红色的就放在红色的圆盘里)。

image-20220409201334181

image-20220409201345095

这题刚看到题面还感觉可能会有点麻烦的,但直觉告诉我这大概是flex的方向出了问题。

解决方法,打开F12的flex选项框调试验证,是flex-direction和flex-wrap出了问题,修改后获得预期效果。

1
2
3
4
5
6
/* css/style.css */
/* TODO:待补充代码 */
#pond {
flex-direction: column;
flex-wrap: wrap;
}

展开你的扇子

介绍

网站上为了让内容显示不臃肿,我们可以做一个折叠展开的效果。本题将使用CSS3实现元素呈扇形展开的效果。

目标

请完善css/style.css 文件(请勿修改文件夹中已给出的代码,以免造成判题无法通过)。

当鼠标悬浮在元素上,元素呈扇形展开,页面效果如下所示:

image-20220409202024462

具体说明如下:

  • 页面上有12个相同大小的div元素。·这12个div元素具有不同的背景颜色。
  • 前6个div元素(id=”item1”~id=”item6”)均为逆时针转动,其最小转动的角度为10 deg,相邻元素间的角度差为10 deg。
  • 后6个div元素(id=”item7” ~id=”item12”)均为顺时针转动,其最小转动的角度为10 deg,相邻元素间的角度差为10 deg。
  • 注意,元素6 (id=”item6”)和元素7 (id=”item7”),各自反方向转动10 deg,所以它们之间的角度差为20 deg。

这个展开还挺好看的,感觉可以收了当素材用(不是

其实绝大部分CSS题目都给写好了,只需要给每个对应id的div设置一个hover时转动角度就可以,纯送分题。。但总感觉是不是可以优化一下?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
/* css/style.css */
/*TODO:请补充 CSS 代码*/
#box:hover #item1 {
transform: rotate(-60deg);
}

#box:hover #item2 {
transform: rotate(-50deg);
}

#box:hover #item3 {
transform: rotate(-40deg);
}

#box:hover #item4 {
transform: rotate(-30deg);
}

#box:hover #item5 {
transform: rotate(-20deg);
}

#box:hover #item6 {
transform: rotate(-10deg);
}

#box:hover #item7 {
transform: rotate(10deg);
}

#box:hover #item8 {
transform: rotate(20deg);
}

#box:hover #item9 {
transform: rotate(30deg);
}

#box:hover #item10 {
transform: rotate(40deg);
}

#box:hover #item11 {
transform: rotate(50deg);
}

#box:hover #item12 {
transform: rotate(60deg);
}

和手机相处的时光

介绍

现在都提倡健康使用手机,那么统计一下在一周中每天使用手机的情况吧!本题使用ECharts实现统计手机使用时长的折线图,但是代码中存在Bug 需要你去修复。

image-20220410125402378

image-20220410125411060

  • 用折线图显示了一周当中,每天使用手机的时长。
  • index.html文件里var option = {} 中的内容是 ECharts的配置项,该配置中存在Bug,导致坐标轴显示不正确。
  • 在配置项中, title是用于设置折线图的标题。
  • 在配置项中, series是系列,其中的 data是一周中每天使用手机的时间数据,type是图表的类型为折线图。

之前同学做模拟题的时候说ECharts的题不太好解决,比赛时我读题后选择直接跳过了这道题,回头再过来看,其实这个题挺简单的。

看到这个折线图你的第一反应是什么?我想应该和我一样,直觉告诉我x轴和y轴搞反了。所以将配置对象中的xAxisyAxis的键调换一下,再把显示星期几的数据放到x轴的配置下,折线就能正常显示了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/* index.html */
/*TODO:ECharts 的配置中存在错误,请改正*/
var option = {
title: {
text: "一周的手机使用时长",
},
yAxis: {
type: "value",
},
xAxis: {
type: "category",
data: ["周一", "周二", "周三", "周四", "周五", "周六", "周日"],
},
series: [
{
data: [2.5, 2, 2.6, 3.2, 4, 6, 5],
type: "line",
},
],
};

灯的颜色变化

介绍

我们经常会看到各种颜色的灯光,本题我们将实现一个颜色会变化的灯的效果。

image-20220410130328707

实现效果:

effect

目标

完成js/trafficlights.js 文件中的red、green和trafficlights 函数,达到以下效果:

1.页面加载完成3秒后灯的颜色变成红色。

2.在灯的颜色变成红色的3秒后,灯的颜色变成绿色(即6秒后灯光变成绿色)。

3.随后颜色不再变化。

4.请通过修改display属性来显示不同颜色的灯的图片。

一个常规的DOM操作题,但延时我不确定会不会把时间卡太死,毕竟setTimeout的延时是不准确的。

之前比赛时有想过拿Promise封一下,也不是不行,不过最后没有写。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// js/traaficlights.js
// TODO:完善此函数 显示红色颜色的灯
function red() {
document.getElementById('defaultlight').style.display = 'none';
document.getElementById('redlight').style.display = 'inline-block';
}

// TODO:完善此函数 显示绿色颜色的灯
function green() {
document.getElementById('redlight').style.display = 'none';
document.getElementById('greenlight').style.display = 'inline-block';
}

// TODO:完善此函数
function trafficlights() {
window.onload = () => {
setTimeout(() => {
red();
setTimeout(() => {
green();
}, 3000);
}, 3000);
}
}

trafficlights();

冬奥大抽奖

介绍

蓝桥云课庆冬奥需要举行一次抽奖活动,我们一起做一个页面提供给云课冬奥抽奖活动使用。

image-20220410131943263

目标效果:

effect2

目标

找到index.js 中rolling函数,使用jQuery或者js 完善此函数,达到以下效果:

1.点击开始后,以class 为 li1的元素为起点,黄色背景(.active类)在奖项上顺时针转动。

2.当转动停止后,将获奖提示显示到页面的 id 为award元素中。获奖提示必须包含奖项的名称,该名称需与题目提供的名称完全一致。

3.转动时间间隔和转动停止条件已给出,请勿修改。

好家伙,这抽奖箱动画虽然看起来简单,但写起来还是稍微有点费事的。题目给了jq库,没学过jq的我表示并没法用,于是用原生DOM硬搓的。写的这个代码稍微有点bug,第二次抽奖时没把前一次的状态清除掉,但这个代码需要在规定的编辑区域之外改,怕对判题有影响就没写。。

整体思路是根据转动次数判断出现在应该亮哪个卡片,然后把上一个卡片的激活状态去掉,需要取两次DOM,在动画结束之后把当前卡片的innerText拿到,打印在上方的显示框就可以了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
// js/index.js
// TODO:请完善此函数
function rolling() {
time++; // 转动次数加1
// console.log(time);
let nowDOMList = time;
if (time > 8) {
nowDOMList = time % 8;
if (nowDOMList === 0) {
nowDOMList = 8;
}
}
let prevDOMList = nowDOMList - 1;
if (prevDOMList === 0) {
prevDOMList = 8;
}

let query = `li${nowDOMList}`;
let prevQuery = `li${prevDOMList}`

let dom = document.getElementsByClassName(query)[0];
dom.className += ' active';

let prevDOM = document.getElementsByClassName(prevQuery)[0];
prevDOM.className = prevDOM.className.substring(0, 3);


clearTimeout(rollTime);
rollTime = setTimeout(() => {
window.requestAnimationFrame(rolling); // 进行递归动画
// dom.className = dom.className.substring(0, 3);
}, speed);
// time > times 转动停止
if (time > times) {
clearInterval(rollTime);
let awardName = dom.innerText;
document.getElementById('award').innerText = `恭喜您抽中了${awardName}!!!`;
time = 0;
return;
}
}

蓝桥知识网

介绍

蓝桥为了帮助大家学习,开发了一个知识汇总网站,现在想设计一个简单美观的首页。本题请根据要求来完成一个首页布局。

目标

请根据mark.png 图片上的参数标注,补充css/style.css和 index.html文件中的代码。对于mark.png上未标注的参数,请结合效果图自行调整。

页面版心宽度为1024px,请保证版心居中,让页面呈现如下图所示的效果:

image-20220410132623546

设计稿:(真想吐槽,哪有这样画设计稿的?我在公司见的实习产品经理画的都比这好。。。组委会下次出题能不能上点心

mark

其实这个题是我比赛时最后才做的,因为这个设计稿确实画的有点太。。。感觉分值不太高,写起来还麻烦,所以就先做了后面的大编程题。

我的代码在banner部分做的并没有很好还原,感觉怎么算都算不出logo和导航栏中间的365px,其他的感觉应该差不太多,拿flex稍微搞搞就可以了。如果组委会允许用less或者sass,写css部分感觉会舒服一点。

这个题估计应该是拿不到很高的分了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
<!-- index.html -->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"
/>
<title>蓝桥知识网</title>
<link rel="stylesheet" href="./css/style.css" />
</head>
<body>
<!--TODO:请补充代码-->
<div class="webview">
<div class="header-bg">
<div class="container">
<div class="nav">
<div class="logo">
蓝桥知识网
</div>
<div class="nav-list">
<ul>
<li>首页</li>
<li>热门技术</li>
<li>使用手册</li>
<li>知识库</li>
<li>练习题</li>
<li>联系我们</li>
<li>更多</li>
</ul>
</div>
</div>
<div class="banner">
<h1>蓝桥云课</h1>
<p>随时随地丰富你的技术栈!</p>
<button>加入我们</button>
</div>
</div>
</div>
<div class="main">
<div class="card-box container">
<div class="card">
<p class="card-title">
人工智能
</p>
<div class="card-content">
人工智能亦称智械、机器智能,指由人制造出来的机器所表现出来的智能。通常人工智能是指通过普通计算机程序来呈现人类智能的技术。
</div>
</div>
<div class="card">
<p class="card-title">
前端开发
</p>
<div class="card-content">
前端开发是创建 WEB 页面或 APP 等前端界面呈现给用户的过程,
通过 HTML,CSS 及 JavaScript 以及衍生出来的各种技术、框架、解决方案,来实现互联网产品的用户界面交互。
</div>
</div>
<div class="card">
<p class="card-title">
后端开发
</p>
<div class="card-content">
后端开发是实现页面的交互逻辑,通过使用后端语言来实现页面的操作功能,例如登录、注册等。
</div>
</div>
<div class="card">
<p class="card-title">
信息安全
</p>
<div class="card-content">
ISO(国际标准化组织)的定义为:为数据处理系统建立和采用的技术、
管理上的安全保护,为的是保护计算机硬件、软件、数据不因偶然和恶意的原因而遭到破坏、更改和泄露。
</div>
</div>
</div>
</div>
<div class="footer">
<div class="container">
<p class="copyright">© 蓝桥云课 2022</p>
<p>京公网安备 11010102005690 号 | 京 ICP 备 2021029920 号</p>
</div>
</div>
</div>
</body>
</html>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
/*
css/style.css
TODO:请补充代码
*/

* {
margin: 0;
padding: 0;
}

.webview {
display: flex;
align-items: flex-start;
justify-content: center;
flex-direction: column;
}

.header-bg {
width: 100%;
background-color: #a6b1e1;
height: 500px;
}

.container {
width: 1024px;
/* border: 1px solid red; */
margin: 0 auto;
text-align: center;
}

.nav {
margin-top: 13px;
height: 46px;
width: 100%;
font-size: 16px;
color: white;
display: flex;
justify-content: space-between;
}

.nav > .logo {
font-size: 18px;
margin-left: 16px;
}

.nav-list > ul {
list-style: none;
}

.nav-list > ul li {
display: inline-block;
padding-right: 16px;
font-size: 16px;
}

.banner {
height: 427px;
width: 100%;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
}

.banner h1 {
font-size: 45px;
color: black;
font-weight: 400;
margin-top: 30px;
margin-bottom: 62px;
}

.banner p {
color: white;
font-size: 21px;
font-weight: 200;
margin-bottom: 36px;
}

.banner button {
background: transparent;
border: 0;
height: 45px;
width: 100px;
color: #efbfbf;
border-radius: 2px;
font-size: 18px;
box-shadow: inset 0 0 0 2px #efbfbf;
}

.footer {
height: 79px;
width: 100%;
border-top: 1px solid #aaa;
}

.main {
width: 100%;
display: flex;
align-items: center;
justify-content: center;
}

.footer p {
font-size: 14px;
color: #aaa;
}

.copyright {
margin-bottom: 10px;
margin-top: 30px;
}

.card-box {
display: flex;
margin-top: 74px;
height: 302px;
flex-wrap: wrap;
}

.card {
flex-basis: 502px;
height: 144px;
text-align: left;
}

.card-title {
font-size: 30px;
font-weight: 200;
color: black;
margin-bottom: 15px;
}

.card-content {
font-size: 18px;
color: #aaa;
line-height: 1.4em;
}

布局切换

介绍

经常用手机购物的同学或许见过这种功能,在浏览商品列表的时候,我们通过点击一个小小的按钮图标,就能快速将数据列表在大图(通常是两列)和列表两种布局间来回切换。

本题需要在已提供的基础项目中使用Vue 2.x知识,实现切换商品列表布局的功能。

image-20220410133412473

目标

请在index.html文件中补全代码,最终实现数据渲染及切换布局的效果。具体需求如下:

1.完成数据请求(数据来源goodsList.json,请勿修改该文件中提供的数据)。在项目目录下已经提供了axios,考生可自行选择是否使用。效果如下:

image-20220410133501019

2.点击“列表效果”的图标,图标背景色变为红色(即class=active) ,“大图效果”的图标背景色变为灰色(即 class=active 被移除),布局切换为列表效果。效果如下:

image-20220410133526439

3.点击“大图效果”的图标,图标背景色变为红色(即class=active) ,“列表效果”的图标背景色变为灰色(即class=active 被移除),布局切换为大图效果。效果如下:

image-20220410133736691

Vue接口联调常规题,这个题的关键点有两个,一个是axios异步请求本地json文件,另一个是如何判断和切换当前状态。

给出的axios是直接引入的,直接用全局的axios函数就可以,不用再新建实例然后封装一层之类的。做题的时候被这里卡了一下,当时一度想换fetch API,后来才发现是axios用错了。。在mounted里调用了接口后对接好数据,把大图模式和列表模式的数据用v-for渲染一下,绑定下接口数据基本就可以了,接下来要考虑如何切换状态。

切换状态我采用的是一个listModeActive状态变量,判断当前是不是列表模式,需要为切换按钮添加绑定事件并通过Vue处理,点击大图模式则listModeActive设置为false,反之为true,用v-if或者v-show控制两种模式的开闭,最后记得绑定一下动态class(active状态)就可以啦。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>布局切换</title>
<script type="text/javascript" src="./js/vue.js"></script>
<link rel="stylesheet" type="text/css" href="./css/index.css" />
<script
src="./js/axios.min.js"
type="text/javascript"
charset="utf-8"
></script>
</head>
<body>
<div id="app" v-cloak>
<!-- TODO:请在下面实现需求 -->
<div class="bar">
<a class="grid-icon" @click="gridMode" :class="!listModeActive ? 'active' : ''"></a>
<a class="list-icon" @click="listMode" :class="listModeActive ? 'active' : ''"></a>
</div>
<!--grid 示例代码,动态渲染时可删除-->
<ul class="grid" v-if="!listModeActive">
<li v-for="(item, index) in goodsList" :key="index">
<a :href="item.url" target="_blank"> <img :src="item.image.large" /></a>
</li>
</ul>
<ul class="list" v-else>
<li v-for="(item, index) in goodsList" :key="index">
<a :href="item.url" target="_blank"> <img :src="item.image.small" /></a>
<p>{{ item.title }}</p>
</li>
</ul>
</div>
</body>
</html>
<script type="text/javascript">
var vm = new Vue({
el: "#app",
data: {
goodsList: [],
listModeActive: false,
},
mounted() {
// TODO:补全代码实现需求
axios('./goodsList.json')
.then(res => {
console.log(res.data);
this.goodsList = res.data;
})
},
methods: {
gridMode() {
this.listModeActive = false;
},
listMode() {
this.listModeActive = true;
}
},
});
</script>

购物车

介绍

网上购物已经成为现代人生活中不可或缺的一部分,那么人们最常用到的购物车功能又是如何实现的呢?

本题需要在已提供的基础项目中,使用Vue 2.x 的知识,解决购物车商品管理过程中遇到的问题。

当前出现的问题是:

  • 在“商品列表”中点击N次“加入购物车”按钮,会在购物车列表中出现N个该商品,且初始数量为1。
  • 在“购物车”中点击商品数据后的加号(“+”)按钮,会在购物车列表中重复出现该商品,且初始数量为1。
  • 在“购物车”中点击商品数据后的减号(“-”)按钮,并未将商品从购物车中移出。

目标

请在index.html文件中补全代码,最终实现购物车商品管理的功能。注意:请勿修改js/goods.js文件中提供的数据!

具体需求如下:

(1)修改addToCart方法,实现将商品加入到购物车的功能。即:

 1. 点击“加入购物车”按钮后,如果购物车中不存在该商品,则将该商品添加到购物车末尾,并初始化数量为1;
 2. 如果购物车中已存在该商品,则只在原数量上+1即可。

(2)完善removeGoods方法,实现移出购物车商品功能。即:

  1. 点击购物车商品后对应的减号(“-”)按钮,将其数量在原数量上-1;
  2. 如果减后数量为0,则将该商品从购物车中移除。

目标情况:

effect3

一个改bug题,其实原题给的代码根本就没写完,也算是改半成品吧。这个题目的关键点是判断好何时才要在购物车列表中添加物品项,从目标情况的图中可以看出,加入购物车操作其实也是可以当做增加购买数量的,但在这个题目里它把两个按钮的功能做了耦合,这就要我们判断当前的商品到底是不是在购物车里,如果之前没有添加过,那么需要往购物车列表推入一个商品信息,但如果之前就有,那么就添加一次商品购买数量。

此外,同时还应该做到数量降为0时把购物车的此内容弹出,并且不能影响此商品可以重新再次加入购物车(原题的代码如果不仔细改真的会影响到,所以得看清楚判断条件是什么)

这里我选择的是暴力匹配id的做法,对于添加购物车操作,首先寻找此物品是否在购物车列表中存在,如果存在则记录其id,当id存在时直接通过id定位到购物车的商品对象,并使其数量++,如果没有,说明是首次加入,那么就需要给其数量值赋为1,并将商品推入购物车列表。删除就简单一些了,暴力找id,找到后让num–,如果num减到了0,那就执行splice把它弹出去。

有一个坑点是修改值时不能直接去改传入的goods,之前以为这题是考双向绑定失效,还用$set写的赋值,但纯属是想多了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
<!-- index.html -->
<script>
new Vue({
el: '#app',
data: {
cartList:[],
goodsList:[]
},
mounted() {
this.goodsList = GoodsArr;
},
methods:{
addToCart(goods){
// TODO:修改当前函数,实现购物车加入商品需求
let found = 0;
let index = -1;
for (let i = 0; i < this.cartList.length; i++) {
if (this.cartList[i].id === goods.id) {
found = true;
index = i;
break;
}
}
if (found) {
this.cartList[index].num++;
} else {
goods.num = 1;
this.cartList.push(goods);
this.cartList = JSON.parse(JSON.stringify(this.cartList));
}
},
removeGoods(goods){
// TODO:补全代码实现需求
for (let i = 0; i < this.cartList.length; i++) {
if (this.cartList[i].id === goods.id) {
this.cartList[i].num--;
if (this.cartList[i].num === 0) {
this.cartList.splice(i, 1);
}
break;
}
}
}
}
});
</script>

寻找小狼人

介绍

“狼人杀”是一款多人参与的策略类桌面游戏。本题我们一起完成一个简易的狼人杀游戏,让我们找到其中的狼人。

image-20220410140824945

目标

在本题index.html 已经给出的数组中,我们可以通过数组的 filter 方法: cardList.filter((item) => item.category == "werewolf")返回一个都是狼人的新数组。但是技术主管为了考验大家的技术,规定了在代码中任何地方都不能出现 filter 关键字。所以我们需要封装一个myarray方法来实现类似数组filter的功能。

1.狼人比较狡猾,筛选狼人的条件可能会变化,例如item.name,请实现一个通用的方法。

2.完成封装后,页面效果会自动完成,效果见文件夹下effect.gif(请使用VS Code或者浏览器打开gif图片)。

effect9

这个题给的题干挺多的,其他的代码也一大堆,看起来是个很头疼的题,其实感觉也是变着法的送分。。考察的是函数式编程,this作用域以及如何手撕数组操作方法,这里手撕的是filter,面试手撕reduce都不少了,filter也就很简单了,连call都用不着。。

首先获取一下this,它代表当前要处理的数组,传入的cb(callback)函数是用来判断当前元素是否符合它的判断条件的,所以只需要来一轮遍历,遍历时调用cb判断下item是否符合条件,符合则push到答案数组中,最后返回这个数组就好。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// js/myarray.js
// 返回条件为真的新数组
Array.prototype.myarray = function (cb) {
// TODO:待补充代码
let arr = this;
let ans = [];
for (let item of arr) {
if (cb(item)) {
ans.push(item);
}
}
return ans;
};

课程列表

介绍

分页是前端页面中必不可少的一项功能,下面让我们一起来完成一个课程列表的分页吧。

目标

  1. 完成数据请求(数据来源js/carlist.json)。在项目目录下已经提供了axios,考生可自行选择是否使用。
  2. 完成数据分页显示,每页5条数据,默认当前页码为第一页(即 pageNum= 1 ),按照顺序第一页显示1-5条,第二页显示6-10条,依此类推。将每条数据显示到list-group元素中。使用已有代码中 list-group,不要修改list-group元素的DOM 结构。动态渲染时,list-group示例代码可删除。
  3. 当页码为第一页时,上一页为禁用状态(class=disabled),点击无任何变化。
  4. 当页码为最后一页时,下一页为禁用状态(class=disabled),点击无任何变化。
  5. 在 id 为pagination元素中正确显示当前页码和总页码(即最大页码)。当前页码变量使用pageNum,总页码变量使用maxPage。请勿修改当前页码和总页码的变量名称,以免造成判题无法通过。

effect10

一个常规的前端分页,这题存在的意义大概是让你体会到MV*框架是多么方便吧。。

因为这题需要手撕DOM,不是Vue编程题。。。

切题思路大概是这样:

  • 首先搞定axios,把数据先能获取到,根据数据长度处理分页总页数
  • 根据html文件提供的渲染列表模板转换成DOM元素结构(根据template反推渲染函数),写一个工厂函数生成对应的DOM节点
  • 封装DOM更新逻辑,每次更新时通过获取当前页面数算出列表渲染数据的上下限,先把原来的DOM全部删掉,再生成新的DOM节点刷新上去
    • 吐槽:应该不会有神仙选手在这里手撕diff算法打patch更新吧。。
  • 完善翻页逻辑,边界情况应当着重处理,当页面为第一页或者最后一页时应当封禁掉对应按钮的操作,此外不要忘了更改当前页数,最后执行更新DOM操作。
  • 无尽的调试……
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
// js/index.js
let pageNum = 1; // 当前页码,默认页码1
let maxPage; // 最大页数

// TODO:待补充代码

let eachPageData = [];
let pageRangeStart, pageRangeEnd;

function generateDom(title, price, desc) {
let dom = document.createElement('div');
dom.setAttribute('class', 'list-group');
let a = document.createElement('a');
a.setAttribute('href', '#');
a.setAttribute('class', 'list-group-item list-group-item-action');
let subDiv = document.createElement('div');
subDiv.setAttribute('class', 'd-flex w-100 justify-content-between');
let endH5 = document.createElement('h5');
endH5.innerText = title;
endH5.setAttribute('class', 'mb-1');
let endSmall = document.createElement('small');
endSmall.innerText = `${(price / 100).toFixed(2)}元`;
subDiv.appendChild(endH5);
subDiv.appendChild(endSmall);

let subP = document.createElement('p');
subP.setAttribute('class', 'mb-1');
subP.innerText = desc;

a.appendChild(subDiv);
a.appendChild(subP);

dom.appendChild(a);
return dom;
}


function update() {
pageRangeStart = (pageNum - 1) * 5;
pageRangeEnd = pageRangeStart + 5;

let list = document.getElementById('list');
list.innerText = '';
for (let i = pageRangeStart; i < pageRangeEnd; i++) {
if (i >= listData.length) {
break;
}
let dom = generateDom(listData[i].name, listData[i].price, listData[i].description);
list.appendChild(dom);
}
let pageTip = document.getElementById('pagination');
pageTip.innerText = `共 ${maxPage} 页,当前 ${pageNum} 页`
}

let listData = [];
axios('js/carlist.json')
.then(res => {
listData = res.data;
// console.log(listData);
maxPage = Math.floor(listData.length / 5);
if (listData.length % 5 > 0) {
maxPage++;
}
update();
})


// 点击上一页
let prev = document.getElementById("prev");
prev.onclick = function () {
// TODO:待补充代码
if (pageNum === 1) {
prev.className = 'page-item disabled';
} else {
pageNum--;
if (pageNum === 1) {
prev.className = 'page-item disabled';
} else {
prev.className = 'page-item';
}
next.className = 'page-item';
update();
}
};
// 点击下一页
let next = document.getElementById("next");
next.onclick = function () {
// TODO:待补充代码
if (pageNum === maxPage) {
next.className = 'page-item disabled';
} else {
pageNum++;
if (pageNum === maxPage) {
next.className = 'page-item disabled';
} else {
next.className = 'page-item';
}
prev.className = 'page-item';
update();
}
};

总结

Web组比赛第一年,题目出的还是有点保守了,感觉有些题难度系数还能再提一下。大部分题目还是可以的,我只有T6的原型图不太满意,其他题目质量感觉都不错,后面编程题也很考察DOM和Vue的编程功底,还有JavaScript的基础特性,题目的区分度能有一些保障。

希望能给个省一去国赛玩玩吧,孩子之前C++组真的打不到一等QAQ

如果题解有错或有更好的解法也欢迎联系我~

打赏
  • 版权声明: 本博客所有文章除特别声明外,著作权归作者所有。转载请注明出处!
  • Copyrights © 2018-2022 Shawn Zhou
  • Hexo 框架强力驱动 | 主题 - Ayer
  • 访问人数: | 浏览次数:

感谢打赏~

支付宝
微信