前言:
当发出这篇文章的时候已经是:2024年6月1日,今天参加了15届蓝桥杯Web开发的国赛,比赛的时候我只做出了6道题…
14届国赛真题和15国赛真题很像,考察的点有很多类似例如今天也考了grid布局和递归算法和实现github的一些分支的功能等----还考了webpack基础的底层原理,说实话难度要比2023年大,看来是难度再逐渐增加了。
而这篇文章的内容是2023年国赛真题,也只做了6道,之前做完了2022的国赛和省赛,然后这也是我要说的备考没把握好的地方。
1️⃣时间把控不准,导致备赛规划没到位,2023年国赛都没刷完,原本计划刷完2022省国和2023省国的
2️⃣刷题顺序错了,应该先做2023年的再去做2022年的,所以以后不管备考备赛什么,都应该先拿最新的真题去做
最后:
不管最终结果如何,比赛的目的就是去促学和提升自己的,在备赛刷题的时候也巩固了自己的前端基础等等
1.植物灌溉
朋友花园内的植物严重缺水,急需你的帮助,让我们用目前 CSS3 中新增的 Grid
布局去完成灌溉任务吧。
1.1 题目问题
请使用 Grid
布局中的 grid-area
属性完善 css/style.css
中的 TODO 代码,帮助你的朋友顺利完成植物灌溉,最终实现下图效果。
提示:
grid-area:grid-row-start / grid-column-start / grid-row-end / grid-column-end
grid-area: 1 / 2 / 3 / 4;
1.2 题目分析
单纯考查了grid布局,是一个二维的网格布局方案
flex布局是一个一维的线性布局
1.3 题目解答
/* TODO 待补充代码 */
.treatment {
grid-area: 1 / 2 / 4 / 6;
}
2.萌宠小玩家
萌宠小玩家是一款宠物养成类游戏,玩家在游戏中,可以通过给宠物换衣服、跟它玩、吃零食跟宠物进行互动交流。在萌宠小玩家中,玩家可以体验到养成宠物的乐趣,同时也可以结交新朋友,分享自己的养宠心得,是一款适合所有年龄段玩家的休闲娱乐游戏。
2.1 题目问题
请在 js/index.js
文件中补全代码,具体需求如下:
完善
verifyName
方法,在点击穿衣服、不穿衣服、跟它玩、吃零食按钮(四个按钮均已绑定点击事件)时,如果宠物昵称输入框(id=nickname
)的值不存在,则显示报错信息(id=vail_name
)元素;如果该值存在,则将其赋给宠物实例(pet
)的name
属性,并隐藏报错信息(id=vail_name
)元素。如果宠物昵称存在,则点击穿衣服、不穿衣服、跟它玩、吃零食按钮(四个按钮均已绑定点击事件)均会记录不同的日志。现在需要完善
showLog
方法,实现宠物互动记录。showLog
方法的参数record
表示要记录的互动消息。最多记录 10 条最新的互动消息,并将最新的互动消息记录在最上面。每一条日志都应添加到日志列表元素(id=list
)中,DOM 结构如下:// DOM 结构必须按照此写法 <div id="list"> <!-- 最新的互动在最上面且只能记录10条 --> <div>第 2 次互动:你喂小蓝吃了零食,体重 +1kg</div> <div>第 1 次互动:你喂小蓝吃了零食,体重 +1kg</div> </div>
完成后效果如下:
2.2 题目分析
本题就是考察了一些元素显示和隐藏,和使用map进行数据渲染,以及数组常用的方法
2.3 题目解答
// 验证宠物名称,如果存在则把名称赋值给当前实例
verifyName() {
// TODO: 待补充代码
const input = document.querySelector('#nickname')
if(input.value == ''){
document.querySelector('#vail_name').style.display = 'block'
return
}
document.querySelector('#vail_name').style.display = 'none'
pet.name = input.value
}
// 记录日志
showLog(record) {
console.log(record);
// TODO: 待补充代码
if(this.logList.length < 10){
this.logList.unshift(record)
}else{
this.logList.unshift(record)
this.logList.pop()
}
console.log(record);
list.innerHTML = this.logList.map(item => {
return `<div>${item}</div>`
}).join('')
}
3.element-ui 轮播图组件二次封装
element-ui
的轮播图指示点样式默认为长条状,在某些场景下不一定符合设计的要求。如果在某个项目中我们需要使用自定义的指示点,在每个用到轮播图的位置都去写一份自定义指示点的逻辑显然是没有必要的,因此我们可以对组件进行二次封装。
3.1 题目问题
请在 my-carousel.vue
文件中补全代码,具体需求如下:
修改
template
模版和script
脚本内容,使页面展示与图片数量对应的指示点,并使指示点的样式变化和轮播图切换同步(例如当展示到第四张图片时,就给第四个指示点添加.active
类)。效果如下:当用户点击某个指示点时,将轮播图切换到指示点对应的图片。
最终效果可参考文件夹下面的 gif 图,图片名称为 effect.gif(提示:可以通过 VS Code 或者浏览器预览 gif 图片)。
实现上述功能所需的 api 如下:
Carousel
事件参数:
事件名称 | 说明 | 回调参数 |
---|---|---|
change |
幻灯片切换时触发 | 目前激活的幻灯片的索引,原幻灯片的索引 |
<template>
<el-carousel ... @change="onCarouselChange"> ... </el-carousel>
</template>
<script>
module.exports = {
...
methods: {
onCarouselChange(index) {
// 该方法会在轮播图切换至第二页时打印1,第三页时打印2,以此类推
console.log(index);
},
},
};
</script>
Carousel
方法:
方法名 | 说明 | 参数 |
---|---|---|
setActiveItem |
手动切换幻灯片 | 需要切换的幻灯片的索引,从 0 开始 |
使用示例:
<template>
<el-carousel ... ref="carousel"> ... </el-carousel>
</template>
<script>
module.exports = {
...
methods: {
// 调用该方法会使轮播图跳转至第一页
setActive() {
this.$refs.carousel.setActiveItem(0);
},
},
};
</script>
3.2 题目分析
这道题不难,如果平时用过这个ui组件的话,逻辑还是很简单的
3.3 题目解答
<template>
<div class="main">
<el-carousel indicator-position="none" arrow="never" height="85vh" ref="carousel" @change="onCarouselChange">
<el-carousel-item v-for="image in images" :key="image">
<img :src="image" />
</el-carousel-item>
</el-carousel>
<ul class="points">
<!-- TODO: 请修改以下代码实现指示点的正确渲染 -->
<li class="point" :class="{'active': flag == index}" v-for="(image, index) in images" :key="image" @click="onClick(index)"></li>
</ul>
</div>
</template>
<script>
module.exports = {
props: {
images: {
type: Array,
default: () => [],
},
},
// TODO: 请在下面补充代码实现指示点的正确渲染以及点击指示点切换图片的功能
methods: {
onCarouselChange(index) {
// 该方法会在轮播图切换至第二页时打印1,第三页时打印2,以此类推
this.flag = index
},
onClick(id){
this.$refs.carousel.setActiveItem(id)
}
},
data(){
return {
flag: 0
}
},
};
</script>
4.抢红包啦
小蓝想给同学们发一个红包,慰劳大家学习前端的辛苦,可是到了开红包这一步,大家收到的红包金额列表竟然一片空白,这可急坏了小蓝,快来帮小蓝解决这个问题吧!
4.1 题目问题
目前存在的问题是:输入金额和红包个数,点击开红包后原本需要展示的红包金额列表出现一片空白。请实现 js/randomAllocation.js
文件中 randomAllocation
函数,修复此问题。
randomAllocation
函数共接收二个参数,参数 total
为红包总金额,参数 n
为红包个数。抽取到的红包的最小金额为 0.01 元,且最多保留两位小数。每次发放红包的个数为 n
,每个红包的金额随机,最终将本次抽取的所有红包金额组成数组返回。需要注意的是,要确保 n
个红包的金额加起来必须等于总金额 total
。
// 例:总金额为 100 元的 10 个红包,函数的返回结果可能如下:
// 示例 1
[23.34, 71.1, 4.97, 0.28, 0.26, 0.01, 0.01, 0.01, 0.01, 0.01]
// 示例 2
[60.81, 15.26, 12.68, 6.75, 2.66, 0.06, 1.16, 0.3, 0.12, 0.2]
完成后效果如下:
4.2 题目分析
本题主要考察了Math.random()和保留小数点
4.3 题目解答
/**
* @param {*} total 红包总金额
* @param {*} n 红包个数
* @return {*} Array 存放红包金额的数组
*/
function randomAllocation(total, n) {
// TODO: 待补充代码
let arr = []
for(let i = 0; i < n; i++){
let all = (total - (n - i) * 0.01).toFixed(2)
let currentMoney = (Math.random() * all + 0.01).toFixed(2)
total -= currentMoney
arr.push(currentMoney)
}
return arr
}
5.恶龙与公主
恶龙与公主是一个很经典的故事,恶龙抓住公主关在自己的洞府内,骑士激斗并战胜恶龙最后解救公主。下面我们通过编码模拟出这个场景:
- 公主被关在地图中央,骑士最开始在二维地图
[0,0]
的位置,恶龙位置和数量随机生成,左下角固定位置有天使,骑士初始血量为 3。 - 点击“马上营救”按钮,系统随机生成 1-3 步,骑士按照随机生成的步数进行移动(蓝色边框位置变换)。
- 若骑士停留位置(红色边框
class
包含active
)有恶龙,则进行战斗并扣除 2 点血量。 - 若骑士停留位置(蓝色边框
class
包含active
)有天使,则增加 3 点血量。 - 如果血量小于等于 0,则弹出红色背景提示框,提示重伤不治。
- 如果骑士(蓝色边框
class
包含active
)顺利到达公主的位置,则弹出绿色背景提示框,提示营救成功。
5.1 题目问题
请在 js/index.js
文件中补全代码。
最终效果可参考文件夹下面的 gif 图,营救成功图片名称为 effect-1.gif
,营救失败图片名称为 effect-2.gif
(提示:可以通过 VS Code 或者浏览器预览 gif 图片)。
具体需求如下:
补全
js/index.js
中的mazePath
函数,将起点到终点顺时针经过的每个元素(即 class 包含box
)data-index
属性值依次保存在数组中并返回。// 本题中输入的二维数组 dyadicArray 值为 dyadicArray = [ ["start", 1, 2, 3, 4], [5, 6, 7, 8, 9], [10, 11, "end", 13, 14], [15, 16, 17, 18, 19], [20, 21, 22, 23, 24], ]; // 执行 mazePath 函数 pathArr = mazePath(dyadicArray); // 得到的数据为 pathArr = ["start", 1, 2, 3, 4, 9, 14, 19, 24, 23, 22, 21, 20, 15, 10, 5, 6, 7, 8, 13, 18, 17, 16, 11, "end"];
注意:
mazePath
函数检测时使用的输入数据与题目中给出的示例数据可能是不同的。考生的程序必须是通用的,不能只对需求中给定的数据有效。补全
js/index.js
中的moveHandler
函数,需求如下:- 根据点击“马上营救”按钮后获得的随机步数,由外向内顺时针到达指定位置。
- 根据骑士到达位置(
class
包含active
)是否存在恶龙(该元素节点class
包含dragon
)或者天使(该元素节点class
包含angel
)执行函数bloodCalculator(boxEle)
计算出目前目前骑士剩余的血量。 - 根据血量和位置显示正确的提示框:血量为
0
时,执行函数tipRender("warning")
;到达公主所在位置,执行函数tipRender("success")
。
5.2 题目分析
5.3 题目解答
/**
* @description 根据传入的二维数组,得到一维数组
* @param {Array} arr: getDyadicArray 得到的二维数组,存储地图上每个box的 data-index 值
* @return {Array} 一维数组,保存经过的路径
*/
mazePath(arr) {
// TODO:得到起点到终点经过的每个 box 元素的 data-index 的值并依次保存在数组中
const newArr = [];
while(arr.length){
newArr.push(...arr[0]);
arr.shift();
if (arr.length) {
arr = arr[0].map((_, index) => arr.map((row) => row[row.length - 1 - index]));
}
}
console.log(newArr);
return newArr;
},
moveHandler() {
let step = this.element.gameStep.value = this.getStep(this.gameData.step);
const lis = Array.from(document.querySelectorAll('.container li'));
lis.forEach(e=>{
if(e.getAttribute('data-index') === String(this.gameData.pathArr[this.gameData.curPos])){
e.classList.remove('active');
return;
}
})
this.gameData.curPos + step > lis.length-1 ? this.gameData.curPos = lis.length-1 : this.gameData.curPos += step;
lis.forEach(e=>{
if(e.getAttribute('data-index') === String(this.gameData.pathArr[this.gameData.curPos])){
e.classList.add('active');
this.bloodCalculator(e);
if(this.gameData.curBlood === 0){
this.tipRender("warning");
}
if(e.getAttribute('data-index') === 'end'){
this.tipRender("success");
}
return;
}
})
},
6.找到未引用的图片
小蓝在公司负责图文编辑器的开发,每次在编辑器中插入图片都会调用一次上传接口,将图片上传至服务器中,但是文章最终编辑完成时可能并未引用所有上传的图片,这就导致许多“无效文件”的产生,于是小蓝想编写一个维护脚本,定期清理那些未被引用的图片文件。
6.1 题目问题
找到 index.js
中的 findUnlinkImages
函数,完善其中的 TODO 部分。使用 Node.js 中的 fs
等内置模块进行文件操作,查找出 images
目录下未被任何文章(articles
文件夹下的 .md 文档)引用的“无效图片”,最终需要在 findUnlinkImages
这个函数中返回包含这些“无效图片”的数组。
提示:Markdown 中插入图片语法为:

提示:代码中提供了工具函数
traversalDir
、searchImage
可供参考使用。
请保证封装的函数满足所有测试用例,并在终端运行以下命令:
node test.js
如果你的结果正确,则在终端将会输出“测试通过”。
6.2 题目分析
6.3 题目解答
const findUnlinkImages = async function () {
const unlinkImages = []; // 未被任何 md 文件引用的图片的数组
// TODO 请通过 Node.js 在此处继续完成代码编写
let articlesList = await traversalDir(articlesPath)
let imagesList = await traversalDir(imagesPath)
let searchList = []
articlesList.map(e => {
// 以下过程也可以不解构,而是直接后面使用数组的flat()
searchList.push(...searchImage(fs.readFileSync(path.resolve(articlesPath,e))))
})
searchList = new Array(...new Set(searchList))
return imagesList.filter(e => {return !searchList.includes(`../images/${e}`)})
};