赞
踩
这个题解是参考了“海底烧烤店ai”一位非常优秀的全栈领域创作者的博主写的,自己在看的时候发现个人知识点比较欠缺,所以就在题解下面添加了一些知识点,便于理解。
第一次发博客,就是想着如果也有和我一样需要一些知识点便于理解和参考的人能有帮助,如果有任何不妥,请私信我删除,谢谢。
第十四届蓝桥杯(Web 应用开发)模拟赛1期-职业院校组
一、访问网址:https://www.lanqiao.cn/contests/web-2023-zy-1/challenges/共有10道题目:
1.数据类型检测
2.回文字符串
3.水果叠叠乐
4.element-ui 组件二次封装
5.别抖了
6.新课上线啦
7.成语学习
8.分阵营,比高低
9.学海无涯
10.逃离二向箔
大学组额外三道题
访问网址:https://www.lanqiao.cn/contests/web-2023-dx-1/challenges/
①渐变色背景生成器
②http模块应用
③梅楼封的一天
二、题目答案:
第1题《数据类型检测》要求与答案:
封装一个通用的数据类型检测函数
完善 main.js 中 getType 函数中的 TODO 部分,返回传入值的对应数据类型。传入值以及 getType 函数返回值(大小写可忽略)按照如下方式对应:
传入值 | 返回值 |
's' | string |
0 | number |
false | boolean |
undefined | undefined |
Symbol() | Symbol(独一无二的值) |
function fn(){} | function |
123n | Bigint(任意长度的整数) |
null | null |
{} | object(对象) |
[] | array(数组) |
new Date | Date(日期) |
new Map | Map(键控集合) |
new Set | Set(抽象集合) |
/a/ | Regexp(正则表达式) |
解决方法:
在JavaScript里使用typeof来判断数据类型,只能区分基本类型,即 “number”,”string”,”undefined”,”boolean”,”object” 五种。对于数组、对象来说,其关系错综复杂,使用 typeof 都会统一返回 “object” 字符串。此时,我们可以使用Object.prototype.toString.call(var) 能判断具体的类型数组。
Object.prototype.toString.call(null);// ”[object Null]”
Object.prototype.toString.call(undefined);// ”[object Undefined]”
Object.prototype.toString.call(123);// ”[object Number]”
Object.prototype.toString.call(true);// ”[object Boolean]”
slice() 方法可提取字符串的某个部分,并以新的字符串返回被提取的部分。
slice(start,end),slice(8,-1),8代表从第8位(包含)开始截取(代表object空格后面的位置),-1代表截取到倒数第一位(不含),所以正好截取到[object String]中的String。
代码实现:
function getType(data) {
// TODO:待补充代码
if(typeof data !== "object"){
return typeof data;
}
return Object.prototype.toString.call(data).slice(8,-1);
}
在VS Code软件扩展中安装这2个插件,“Code Runner+JavaScript Debugger”
然后按住快捷键“Ctrl+Alt+N”就可以直接运行js文件了,运行结果如下:
第2题《回文字符串》要求与答案:
在JavaScript 中,形如 aba,abba 的字符串都是回文字符串。另外,单字符串、空字符串也是一种特殊的回文字符串。
补充文件isPalindromeStr.js 中的 isPalindromeStr 回文字符串检测工具函数,使其实现我们需要的功能:
对输入参数的类型做校验,保证只正常处理字符串类型参数。
如果所输入的字符串(包括单字符串和空字符串)是回文字符串,则返回true。
其他的情况一律返回false。
解决方法:
代码实现:
function isPalindromeStr(str) {
// 在这里写入具体的实现逻辑
// 返回值是 boolean 类型, 如果是回文字符串应该返回 true, 否则返回 false
return typeof str === "string" &&
(!str || str === [...str].reverse().join(''))
};
module.exports = isPalindromeStr; // 检测需要请勿删除
!str 用来处理空字符串的情况(!""的结果为true)。
[...str].reverse().join('') 代表将str转换为数组,然后通过数组的reverse方法反转,最后再通过join转回字符串。
方法2:
function isPalindromeStr(str) {
// 在这里写入具体的实现逻辑
// 返回值是 boolean 类型, 如果是回文字符串应该返回 true, 否则返回 false
if(typeof str !== "string") return false;
if (!str) return true;
let strLength = str.length; // 存储数组长度
let halfLength = Math.ceil(strLength / 2);//数组的一半长度(向上取整)
for (let i = 0; i < halfLength; i++) {
if (str[i]! == str[strLength - i - 1]) {
return false
}
}
return true
};
module.exports = isPalindromeStr; // 检测需要请勿删除
如果传入的参数不是字符串类型或者不是回文字符串,应该返回 false,其他的则为true。因为是从两头向里进行遍历,所以不需要遍历整个字符串,只需遍历一半即可,在极端情况(str是回文字符串时)就能节约一半的遍历时间。
注意:
方法2在运行过程如果出现“类型注释只能在TypeScript文件中使用”报错,需要在VScode的setting.json配置文件中添加上代码"javascript.validate.enable": false,重启软件就可以了。
第3题《水果叠叠乐》要求与答案:
点击页面上方的水果元素,水果会进入到下方的格子中。当格子中有三个相同水果时会自动消除。格子最多放7 个水果,当格子中水果为 7 个且无法消除时,点击上方水果元素将不在有任何效果。
①页面上方 id=card 中 DOM 元素中的水果元素点击消失的动画效果已在代码中给出,无需操作。
②每次点击页面上方水果元素需要在页面下方的长方格( id=box )元素中添加该元素节点,当下面长方格中有三个相同的水果元素时,从盒子元素删除这三个相同的水果元素节点。
③当页面下方的长方格( id=box )元素中的水果为 7 个且无法消除时,被点击的水果元素节点不在被添加长方格元素中。
解题思路:
点击元素时是需要将这个被点击的元素克隆一份添加到下方的栏中,($(this))的目的是使this变成JQ对象,使用jQuery提供的方法,如clone克隆元素。
$("#card li").on("click", function (e) {
// TODO: 待补充代码
if($("#box li").length === 7) return;
// 向box中添加当前点击元素的克隆
$("#box").append($(this).clone());
// append() 方法在被选元素的结尾插入指定内容
$(this).hide(); // 隐藏当前点击元素
// 找到与当前点击元素类别一样的其它所有元素
const list = $(`#box li[data-id=${this.getAttribute('data-id')}]`);
// getAttribute() 方法通过名称获取属性的值
if (list.length >= 3) {
// each是jQuery遍历元素的方法
list.each((i,item) => {
// 移除元素
item.remove()
})
}
});
第4题《element-ui 组件二次封装》要求与答案:
element-ui 官网上具有单选功能的表格 demo 为:点击表格下方的按钮可以选中指定的某行数据。现在需要我们完善 mytable.vue 文件中的 TODO 部分,实现点击某个单选组件选中该行数据的效果。
解题思路:
需要封装element-ui 的表格组件,实现点击表格组件左侧radio时选中该行,通过这题只需修改两行代码就行。
<!-- TODO:完善单选按钮组件,实现需求(DOM 结构不能修改) -->
<template slot-scope="scope">
<el-radio v-model="currentRow" :label="scope.$index"> </el-radio>
</template>
此时虽然前面的单选可以选择,但是点击选中第二行时,第二行前面的radio并没有被选中,点击取消选中时已经选中的radio并没有被取消。
在查看代码时会发现题中给了我们一个setCurrent方法用来设置当前选中行,并且题目中也明确提示我们redio有一个change方法:
所以说当radio状态改变时应该调用setCurrent方法,最终的代码应该这样写:
<!-- TODO:完善单选按钮组件,实现需求(DOM 结构不能修改) -->
<template slot-scope="scope">
<!-- 绑定change方法调用setCurrent -->
<el-radio v-model="currentRow" :label="scope.$index" @change="setCurrent(scope.row)"> </el-radio>
</template>
methods: {
setCurrent(row) {
this.currentRow = this.tableData.indexOf(row) // 新增
this.$refs.singleTable.setCurrentRow(row); // 设置当前选中行
},
},
第5题《别抖了》要求与答案:
防抖的定义:n 秒后再执行某个函数,若该函数在 n 秒内被重复触发,则重新计时。
节流:指连续触发事件但是在 n 秒中只执行一次函数。
补充文件 debounce.js 中的 debounce 工具函数,使其实现我们需要的功能:接收一个函数以及延迟时间,并返回一个防抖函数。
即使函数在 delay 时间段内多次被调用,也只会在最后一次函数被调用的 delay 时间结束后执行。
防抖函数需要考虑传参情况。
在输入框中输入不同的查询参数时,页面效果(只会在停止输入后,延迟 500ms 才输出内容):
解题思路:
function debounce(fn, delay = 0) {
// TODO: 在这里写入具体的实现逻辑
// 返回一个新的防抖函数
// 即使函数在 delay 时间段内多次被调用,也只会在最后一次函数被调用的 delay 时间结束后执行
let timer = null;
return function (...args) {
if (timer) clearTimeout(timer);
timer = setTimeout(()=>{
fn(...args)
},delay)
}
}
module.exports = debounce; // 检测需要,请勿删除
第6题《新课上线了》要求与答案:
请完善 css/style.css 和 index.html 文件。
请根据 mark/preview 最终效果图和 mark/index.html 上的参数标注来完成页面布局。
在浏览器打开 mark/index.html 页面,鼠标点击页面可以在右侧看到相应的参数标注。
单纯的考察HTML和css页面布局
推荐使用flex布局和定位来做
这里按照自己的习惯来写就可以了
解题思路:
Html部分:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>新课上线啦</title>
<link rel="stylesheet" href="css/style.css" />
</head>
<body>
<!-- TODO:待补充代码 -->
<div class="top">
<img src="./images/bg.png" alt="">
<img src="./images/word.png" alt="">
<img src="./images/small-bg.png" alt="">
<div class="top-d">
<img src="./images/shouzhi.png" alt="">
<span class="fir">扫码咨询</span>
<div class="dir">
购买成功后,一定要扫码添加班主任,获得<span>Java进阶资料</span>,并加入学习群,不错过直播课!
</div>
<img src="./images/erweima.png" alt="">
</div>
<img class="left" src="./images/left.png" alt="">
<span class="lkj">课程大纲</span>
<img class="right" src="./images/right.png" alt="">
</div>
<div class="bot">
<div class="left">
<div class="toc">
<div class="hj"> 第一天 开发原则及设计模式</div>
</div>
<img class="fg" src="./images/bq-jichu.png" alt="">
<div class="lf">
<ul>
<li>第一讲</li>
<li>第二讲</li>
<li>第三讲</li>
<li>第四讲</li>
</ul>
</div>
<ul class="er">
<li>七大开发原则说明</li>
<li>二十三种设计模式分类</li>
<li>安全懒汉&不安全懒汉&饿汉单例模式</li>
<li>枚举类单例&静态内部类模式</li>
</ul>
<div class="bn">
<img class="kj" src="./images/tz.png" alt="">
<div>设计一个实用单例类</div>
</div>
</div>
<div class="left">
<div class="toc">
<div class="hj">第二天 实用设计模式</div>
</div>
<img class="fg" src="./images/bq-jinjie.png" alt="">
<div class="lf">
<ul>
<li>第一讲</li>
<li>第二讲</li>
<li>第三讲</li>
<li></li>
</ul>
</div>
<ul class="er">
<li>工厂& 代理&静态代理模式</li>
<li>简单静态& 抽象工厂</li>
<li> JDK动态代理模式与 spring 源码解析</li>
<li></li>
</ul>
<div class="bn">
<img class="kj" src="./images/tz.png" alt="">
<div>设计一个实用单例类</div>
</div>
<div class="left">
<div class="toc">
<div class="hj">第三天 手把手带你搞懂 “校招求职面试那些事儿”</div>
</div>
<img class="fg" src="./images/bq-bys.png" alt="">
<div class="lf">
<ul>
<li>第一讲</li>
<li>第二讲</li>
</ul>
</div>
<ul class="er">
<li>“设计一个工具实现Spring框架”作业点评</li>
<li>选择比努力更重要的时代</li>
</ul>
</div>
</div>
</body>
</html>
Css部分:
/* TODO:待补充代码 */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: PingFangSC-Regular;
font-size: 14px;
color: #333333;
letter-spacing: 0;
line-height: 14px;
font-weight: 400;
}
ul {
list-style: none;
}
.top {
height: 500px;
width: 1920px;
position: relative;
}
.top img:nth-child(2) {
position: absolute;
top: 100px;
left: 520px;
}
.top img:nth-child(3) {
position: absolute;
top: 440px;
left: 360px;
}
.top-d {
position: absolute;
top: 440px;
left: 360px;
width: 1200px;
height: 120px;
}
.top-d img:nth-child(1) {
margin-left: 174px;
margin-top: 34px;
}
.top-d .fir {
margin-top: -1px;
margin-left: 10px;
font-family: PingFangSC-Semibold;
font-size: 20px;
color: #1e5ef5;
line-height: 20px;
font-weight: 600;
}
.top-d .dir {
margin-left: 172px;
margin-top: 13px;
font-family: PingFangSC-Medium;
font-size: 18px;
color: #333333;
letter-spacing: 0;
text-align: justify;
line-height: 18px;
font-weight: 500;
}
.top-d .dir span {
font-family: PingFangSC-Semibold;
color: #1e5ef5;
font-weight: 600;
}
.top-d img:last-child {
position: absolute;
top: 18px;
left: 947px;
}
.top .lkj {
position: absolute;
top: 620px;
left: 908px;
font-family: PingFangSC-Semibold;
font-size: 26px;
color: #1e5ef5;
letter-spacing: 0;
line-height: 26px;
font-weight: 600;
}
.top .left {
position: absolute;
top: 628px;
left: 874px;
}
.top .right {
position: absolute;
top: 628px;
left: 1031px;
}
.bot {
position: relative;
top: 181px;
left: 360px;
width: 1200px;
height: 456px;
}
.bot .left {
padding-top: 48px;
margin-left: 200px;
width: 390px;
height: 211px;
}
.bot .left .toc {
background: #1e5ef5;
width: 100%;
height: 40px;
border-radius: 8px 8px 0px 0px;
}
.bot .left .toc .hj {
padding-left: 16px;
padding-top: 11px;
font-family: PingFangSC-Medium;
font-size: 18px;
color: #ffffff;
letter-spacing: 0;
line-height: 18px;
font-weight: 500;
}
.bot .left .fg {
position: absolute;
top: 40px;
left: 448px;
}
.bot .left .lf {
background: #e1eaff;
width: 76px;
height: 137px;
}
.bot .left .lf li {
height: 34px;
line-height: 34px;
text-align: center;
font-size: 14px;
color: #1e5ef5;
font-weight: 400;
}
.bot .left .kj {
margin-top: 9px;
}
.bot .left .er {
margin-top: -137px;
margin-left: 78px;
width: 314px;
height: 137px;
font-size: 14px;
color: #333333;
font-weight: 400;
}
.bot .left .er li {
padding-left: 10px;
height: 34px;
line-height: 34px;
border-top: 1px solid #e1eaff;
}
.bot .left .bn {
width: 390px;
height: 40px;
font-size: 14px;
color: #333333;
font-weight: 400;
}
.bot .left .bn div {
margin-left: 78px;
margin-top: -22px;
}
.bot .left:nth-child(2) {
position: absolute;
top: 0;
left: 420px;
}
.bot .left:nth-child(2) .fg {
position: absolute;
top: 40px;
left: 190px;
}
.bot .left:last-child {
position: absolute;
left: -616px;
top: 270px;
}
.bot .left:last-child .toc {
width: 804px;
height: 40px;
}
.bot .left:last-child .lf {
width: 76px;
height: 69px;
}
.bot .left:last-child .er {
position: absolute;
top: 225px;
left: 0;
width: 725px;
}
.bot .left:last-child .fg {
position: absolute;
top: 39px;
left: 414px;
}
第7题《成语学习》要求与答案:
完善 index.html 中的 confirm 方法和 getSingleWord 方法。
1.getSingleWord 方法:点击文字后,在变量 idiom 从左到右第一个空的位置加上该文字。
2.confirm 方法需要校验成语是否输入正确答案,猜中成语result 为true ;猜错成语result 为false。
解题思路:
$set方法是vue中有两种情况不能实现数据的双向绑定
当利用数组索引修改值的时候
修改数组长度的时候
用法是:
this.$set(原数组, 索引值, 需要赋的值)
这里也可以使用数组的splice方法
this.idiom.splice(从数组的第几个索引处修改, 修改的位数, 修改后的值);
这道题中就是
this.idiom.splice(i, 1, val);
数组的find方法
find()方法用于查找数组中符合条件的第一个元素,如果没有符合条件的元素,则返回undefined
arr.find(item=>item>1)
item就是是数组中的元素的意思
item>1条件会返回这个数组中第一次item>1的元素
例如
let arr1 = [1, 2, 3, 4, 5];
let num = arr1.find(item => item > 1);
console.log(num) //輸出的結果是2
let target= this.arr.find(item=>item.tip===this.tip)
this.result=target.word===this.idiom.join('')
这段代码里面的意思就是:
{ word: "热泪盈眶", tip: "形容非常感激或高兴" },
返回寻找数组这里tip和页面上的tip一样的元素
修改result的值等于数组里的word和页面上你输入的成语是否一样
一样的话result等于true否则false
getSingleWord(val) {
for (let i = 0; i < this.idiom.length; i++) {
if (!this.idiom[i]) {
this.idiom[i]=val
this.$set(this.idiom,i,val)
return;
}
}
},
clear(i) {
this.idiom[i] = ""
this.$set(this.idiom, i, "")
},
confirm() {
let target= this.arr.find(item=>item.tip===this.tip)
this.result=target.word===this.idiom.join('')
}
第8题《分阵营,比高低》要求与答案:
补充文件student-grade.js 中的orderStudentGrade 工具函数,访问index.html 页面会按照不同的班级,且班级内降序排列所有学生的成绩。
具体功能说明:
接收所有学生成绩的数组。
将学生按不同的班级分组,且班级内按照总分降序排列(如果学生 A、B 的总分相同,则按照学生在原数据中的先后顺序进行排列,不要在学生成绩的数据对象中添加多余的字段,确保排序后的对象和排序前一致)。
返回分班排序后的对象(如果传入的学生成绩列表为空,则返回一个空对象)
解题思路:
newdata[item.class]?newdata[item.class].push(item):newdata[item.class] = [item]
这段代码是三元表达式
如果newdata对象里面有对应的班级的话就往对应的班级里面添加一个学生成绩否则就创建一个班级对象里面的值是当前循环的学生成绩
Sort方法进行排序
Arr.sort((a,b)=>a-b)
就是成绩从小到大排序
指定某个数据进行排序的方法就是
定义一个值接收a的总分一个值接受b的总分
返回a的总分减去b的总分就是总分从小到大排序
返回b的总分减去a的总分就是总分从大到小排序
function orderStudentGrade(students) {
// TODO: 在这里写入具体的实现逻辑
// 将学生的成绩按班级分组,同一班级中按照总分从高到底排序
if (students.length == 0 || students == []) {
return {};
}
let newdata = {}
students.forEach(item => {
newdata[item.class] ? newdata[item.class].push(item) : newdata[item.class] = [item]
});
for (const item in newdata) {
newdata[item].sort((a, b) => {
let acount = a.math + a.language + a.english + a.physics + a.chemistry
let bcount = b.math + b.language + b.english + b.physics + b.chemistry
return bcount - acount
})
}
return newdata;
}
第9题《学海无涯》要求与答案:
完成数据请求(数据来源./data.json),data.json 中存放的数据为对应月份中小蓝每天的学习时长,单位为分钟(在项目目录下已经提供了axios,考生可自行选择是否使用)。
页面加载完成后,默认显示周统计数据。点击周和月,x 轴对应显示正确的周数(格式为:"x 月 x 周")和月份,Y 轴显示小蓝对应周和对应月学习的总时长。
解题思路:
1.先定义两个空的对象来设置周和月的数据
2.Axios获取数据的方法:
Axios.get(对应的地址).then(res=>{})
res.data就是获取到的数据
对获取到的数据进行截取一周的数据然后用reduce方法进行累加数据
Reduce方法:
Arr.reduce((a,b)=>a+b)
对arr数组里面的元素进行累加操作返回值就是累加后的结果
设置对应的周和月的数据
先调用一下周的重置图标的函数
对周和月按钮的父元素添加点击事件带e参数进行事件委托
e.target.id可以用来判断点击的按钮是月还是周
调用相对应的重置图表的函数
let weekdata = {
x: [],
y: [],
},
monthdata = {
x: [],
y: [],
};
// 定义一个函数:用来修改option对象并重置Echarts图标
function mySetOption(data) {
option.xAxis.data = data.x;
option.series[0].data = data.y;
// 重置图表
myChart.setOption(option);
}
document.querySelector(".tabs").addEventListener("click", function (e) {
if (e.target.id == "week") {
mySetOption(weekdata);
} else if (e.target.id == "month") {
mySetOption(monthdata);
}
});
axios.get("./data.json").then((res) => {
let data = res.data.data;
for (const key in data) {
for (let i = 0, w = 1; i < data[key].length; i += 7, w++) {
let weekcount = data[key]
.slice(i, i + 7)
.reduce((arr, total) => arr + total);
weekdata.x.push(`${key}第${w}周`);
weekdata.y.push(weekcount);
}
monthdata.x.push(key);
monthdata.y.push(data[key].reduce((arr, total) => arr + total));
}
mySetOption(weekdata);
});
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。