????? 個人簡介:一個不甘平庸的平凡人??
??? 藍橋杯專欄:藍橋杯題解/感悟
??? TS知識總結(jié):十萬字TS知識點總結(jié)
?? 你的一鍵三連是我更新的最大動力??!
?? 歡迎私信博主加入前端交流群??
?? 前言
第十四屆藍橋杯 Web 應(yīng)用開發(fā)模擬賽第二期昨天正式開始了(本來寫的是今天正式開始了,結(jié)果沒想到這篇文章寫到了凌晨 1 點 ?????),博主也是第一時間為大家?guī)砹祟}解!這篇題解包含了大學組和職業(yè)院校組的所有內(nèi)容。
因為自己在做題時忘記保存代碼了,所以寫這篇題解時我不得不又重新做了一遍,看在博主這么肝的份上,大佬們給個一鍵三連加關(guān)注吧!??
關(guān)于藍橋杯更多的題解請前往專欄:藍橋杯題解/感悟,歡迎大家的訂閱!
本篇只會大概提出題目要求,關(guān)于題目的更多細節(jié)可自行去模擬賽主頁查詢:Web 應(yīng)用開發(fā)模擬賽 2 期大學組
話不多說,開撕!
1?? 憑空消失的 TA
題目說在 index.html
中未正常顯示表單組件 myform
,先運行看一下效果:
發(fā)現(xiàn) myform
組件里的立即創(chuàng)建
和取消
這兩個文本被渲染了,這說明 index.html
確實是引入了 myform
,但為何myform
沒有正常顯示呢?
一開始我以為是myform
組件里出了問題,可檢查一遍后并沒有發(fā)現(xiàn)問題,最后回到index.html
才發(fā)現(xiàn),是因為index.html
中未引入element-ui
的js
文件,我們加一行代碼引入一下就解決了:
<!-- 引入 element-ui 樣式 -->
<link rel="stylesheet" href="./element-ui-2.15.10/index.css" />
<!-- 新增:引入 element-ui js文件 -->
<script src="./element-ui-2.15.10/index.js"></script>
2?? 用戶名片
要求是需要將這個卡片垂直居中,并且還需要將卡片中左側(cè)文字水平居中,看了一下HTML結(jié)構(gòu),發(fā)現(xiàn)它們都有一個共同的類名center
:
所以對center
類名定義樣式就行了:
/* TODO 待補充代碼 */
.center {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
}
上述代碼利用定位將元素垂直水平方向各偏移父元素(position: relative
)的50%,這個時候元素還不是居中(因為定位偏移的中心點不在元素的中心上而是在元素的邊界上):
使用transform
將元素在水平和垂直的負方向移動自身的50%(transform
運動的中心點在元素的中心位置):
這里深入說一下一個CSS選擇器優(yōu)先級的問題:
圖中所示,作用于同一元素的.user-card .points
(后代選擇器)的樣式優(yōu)先生效于.center
(類選擇器)的樣式,這就映證了網(wǎng)上說的后代選擇器的優(yōu)先級小于類選擇器的說法是不夠準確的。
其實,后代選擇器和類選擇器沒有可比性,后代選擇器是選擇器組合方式的一種,它是一種組合,本身沒有任何優(yōu)先級(嚴格的用詞叫特殊性) 可言。比如.user-card .points
在計算特殊性(優(yōu)先級)時,是分別計算「.user-card」和「.points」的特殊性(優(yōu)先級),完全不用考慮它們之間是用后代關(guān)聯(lián)的。
按照權(quán)重來說.user-card .points
的樣式優(yōu)先生效于.center
的樣式,是因為.user-card .points
含有兩個類選擇器,它的權(quán)重比.center
高。
關(guān)于CSS選擇器權(quán)重、優(yōu)先級的問題在實際開發(fā)中是比較重要的,如果你看到這里對它們還不是很了解,建議你去網(wǎng)上多看看關(guān)于它們的內(nèi)容。
3?? 芝麻開門
這題簡單的考察了Promise
,最終實現(xiàn)以下效果:
代碼:
/**
* @description: 調(diào)用函數(shù),開啟彈窗,記錄輸入框的內(nèi)容,并通過 promise 異步返回輸入框中的內(nèi)容
* @return {Promise}
*/
function mPrompt() {
// 彈窗必須使用以下結(jié)構(gòu) template 保存的是彈窗的結(jié)構(gòu)字符串,可以先轉(zhuǎn)化為 DOM 再通過 appendChild 方式插入到 body 中
const template = `
<div class="modal">
<div class="message-box">
<div class="message-header">請輸入咒語</div>
<div class="message-body">
<input type="text">
</div>
<div class="message-footer">
<button class="btn btn-small" id='cancel'>取消</button>
<button class="btn btn-small btn-primary" id='confirm'>確定</button>
</div>
</div>
</div>
`;
const div = document.createElement("div");
// TODO:待補充代碼
div.innerHTML=template
document.body.append(div);
let val = div.getElementsByTagName("input")[0];
return new Promise((resolve, reject) => {
document.getElementById("cancel").onclick = function() {
div.remove()
reject(false)
}
document.getElementById("confirm").onclick = function() {
div.remove()
resolve(val.value)
}
});
}
代碼很簡單,按照題目要求返回一個Promise
對象,并在點擊事件中做出不同的處理(reject
,resolve
)即可。
4?? 寶貴的一票
要求是實現(xiàn)一個動態(tài)列表的表單,可以新增選項和刪除選項,最終效果:
添加的思路:
- 添加選項時先獲取當前選項的個數(shù),如果當前選項個數(shù)以及為2了,那么就需要先向前兩個選項添加刪除號(x)。
- 當前選項的個數(shù)小于2時,再添加一各選項,選項的總數(shù)也不會超過2,所以這時只需添加普通的選項即可。
- 當前選項的個數(shù)大于或等于2時,需要添加帶有刪除號(x)的選項。
刪除的思路:
- 點擊刪除號(x)時先刪除當前選項。
- 遍歷余下的選項列表,更新它們的序號。
- 在遍歷的時候判斷余下的選項個數(shù),若剩余的選項小于等于2了,需要刪除每個選項后面的刪除號(x)。
代碼:
// 點擊加號邏輯
$(".add").click(function () {
// TODO 待補充代碼
// 當前列表長度
let cl = $(".list").children().length;
// 長度為2時為前兩個選項加上x號
if (cl === 2) {
$(".list").children().each((index,item)=>{
$(item).append(`
<div class="col-sm-1">
<img class="del-icon" src="./images/x.svg" alt="" />
</div>`)
})
}
if (cl < 2) {
// 當前列表長度小于2時,添加不帶x號的選項
$(".list").append(initRender(`選項${cl + 1}`));
}else {
// 當前列表長度大于等于2時,添加帶x號的選項
$(".list").append(`<div class="mb-3 row item">
<label class="col-sm-2 col-form-label txt">選項${cl + 1}</label>
<div class="col-sm-9">
<input type="text" class="form-control" />
</div>
<div class="col-sm-1">
<!-- 刪除圖標 -->
<img class="del-icon" src="./images/x.svg" alt="" />
</div>
</div>`);
}
});
// 點擊 x 刪除邏輯,列表小于 2 項時不顯示刪除圖標
$(document).on("click", ".del-icon", function () {
// TODO 待補充代碼
// 刪除這一條
$(this).parent().parent().remove()
// 遍歷
$(".list").children().each((index,item)=>{
// 修改剩下的列表序號
$(item).children('label').text(`選項${index + 1}`)
if($(".list").children().length <= 2) {
// 列表長度小于等于2時,請求x號
$(item).children()[2].remove()
}
})
});
5?? 粒粒皆辛苦
這是一道ECharts
題,從歷屆藍橋杯Web比賽、模擬賽等可以看出每一次比賽都至少會有一道ECharts的題,不過這些ECharts
題涉及到的ECharts
的內(nèi)部并不過,大部分都只是考察你對數(shù)據(jù)的處理,比如這一題,本質(zhì)就是對數(shù)據(jù)格式的轉(zhuǎn)換。
源數(shù)據(jù)格式:
{
"2017": { "wheat": 431, "soybean": 142, "potato": 232, "corn": 642 },
"2018": { "wheat": 417, "soybean": 156, "potato": 258, "corn": 643 },
"2019": { "wheat": 416, "soybean": 168, "potato": 269, "corn": 650 },
"2020": { "wheat": 436, "soybean": 174, "potato": 277, "corn": 680 },
"2021": { "wheat": 441, "soybean": 186, "potato": 289, "corn": 692 },
"2022": { "wheat": 445, "soybean": 201, "potato": 315, "corn": 706 }
}
字段對應(yīng)表:
英文名稱 | 中文名稱 |
---|---|
wheat | 小麥 |
soybean | 大豆 |
potato | 馬鈴薯 |
corn | 玉米 |
需要轉(zhuǎn)換成的數(shù)據(jù)格式:
[
['全部', '2017', '2018', '2019', '2020', '2021', '2022'],
['小麥', 431, 417, 416, 436, 441, 445],
['大豆', 142, 156, 168, 174, 186, 201],
['馬鈴薯', 232, 258, 269, 277, 289, 315],
['玉米', 642, 643, 650, 680, 692, 706]
]
代碼:
// TODO: 待補充代碼
let dataObj = {
wheat: ["小麥"],
soybean: ["大豆"],
potato: ["馬鈴薯"],
corn: ["玉米"]
};
let sourceTip = ["全部"];
// 獲取數(shù)據(jù)
axios.get("./data.json").then(res=>{
let data = res.data.data;
for (const key1 in data) {
sourceTip.push(key1);
for (const key2 in data[key1]) {
dataObj[key2].push(data[key1][key2]);
}
}
let newSource = [];
newSource.push(sourceTip);
for (const key in dataObj) {
newSource.push(dataObj[key]);
}
option.dataset.source = newSource;
myChart.setOption(option);
})
代碼和邏輯都比較簡單,就不多說了。
6?? 618 活動
就是按照官方給的最終效果圖,去實現(xiàn)下面這個頁面:
沒啥技術(shù)含量,全靠堆HTML和CSS,這里就不放代碼了。
但這個題是我認為是整場模擬賽里最坑人的題,特別廢時間,我建議這個題要么放到最后再寫(因為完成度50%以上就能得到分,其它題不行),要么完成差不多后就直接去做下面的題,別死扣細節(jié),不然吃虧的都是你!
7?? 資訊接口
題目要求使用 NodeJS
去創(chuàng)建一個服務(wù)器并響應(yīng)一個/news
接口:
- 通過在
app.js
書寫代碼,創(chuàng)建一個服務(wù)器,使服務(wù)在 8080 端口運行。 - 訪問
/news
返回資訊數(shù)據(jù),訪問其他任意路徑均返回字符串 404 。
代碼:
// TODO: 待補充代碼
const http = require("http");
// 創(chuàng)建http服務(wù)
const app = http.createServer();
app.on("request",(req,res)=>{
res.setHeader("Content-type", "text/html;charset=utf8");
switch (req.url) {
case '/news':
res.end(JSON.stringify([
{
"channelId": "5572a108b3cdc86cf39001cd",
"name": "國內(nèi)焦點"
},
{
"channelId": "5572a108b3cdc86cf39001ce",
"name": "國際焦點"
}
]))
break;
default:
res.end('404')
break;
}
})
app.listen(8080);
8?? 絕美宋詞
相當于是使用Vue
做一個搜索功能:
代碼:
<body>
<div id="app">
<h1 style="text-align: center">輸入關(guān)鍵字,找一首詞</h1>
<!-- TODO:待補充代碼 -->
<div class="search-form">
<input @input="search" v-model="val" type="text" id="search" class="search" placeholder="詞牌名 詞句 詞人"/>
<ul class="suggestions">
<li v-for="item in showList" :key="item.title">
<span class="poet" v-html="highlight(item.poetry_content)"></span>
<span class="title" v-html="highlight(item.title) + '-' + highlight(item.author)"></span>
</li>
</ul>
</div>
</div>
<script>
let vm = new Vue({
el:'#app',
// TODO:待補充代碼
data:{
val:'', // 輸入內(nèi)容
list:[], // 源數(shù)據(jù)
showList:[] // 進行展示的數(shù)據(jù)
},
created(){
// 獲取數(shù)據(jù)
axios.get("./data.json").then(res=>{
this.list = res.data
})
},
methods:{
// 搜索函數(shù)
search(){
if (this.val) {
// 輸入內(nèi)容不為空,使用filter過濾
this.showList = this.list.filter(item=>{
return item.poetry_content.includes(this.val) || item.title.includes(this.val) || item.author.includes(this.val)
})
}else {
// 輸入內(nèi)容為空,重置數(shù)據(jù)
this.showList = []
}
},
// 替換關(guān)鍵字進行高亮的函數(shù)
highlight(str){
let reg = new RegExp(this.val,'g');
// replace第二個參數(shù)中$&代表插入匹配的子串。
return str.replace(reg, `<span class="highlight">$&</span>`)
}
}
})
</script>
</body>
因為需要將關(guān)鍵字包上一層<span class="highlight"></span>
來進行高亮,所以我使用了v-html
指令來確保數(shù)據(jù)能以html
的格式進行渲染,并配合replace
替換關(guān)鍵字。
9?? 平地起高樓
相當于是一道算法題,將一維數(shù)據(jù)轉(zhuǎn)成樹形結(jié)構(gòu),源數(shù)據(jù):
[
{
id: "51", // 區(qū)域 id
name: "四川省", // 區(qū)域名字
pid: "0", // 區(qū)域的父級區(qū)域 id
},
{
id: "5101",
name: "成都市",
pid: "51", // 成都的父級是四川省,所以 pid 是 51
},
// ...
];
轉(zhuǎn)換成樹結(jié)構(gòu):
[
{
id: "51", // 地址 id
name: "四川省", // 地址名
pid: "0", // 該地址的父節(jié)點 id
children: [
{
id: "5101",
name: "成都市",
pid: "51",
children: [
{
id: "510101",
name: "市轄區(qū)",
pid: "5101",
children: [], // 如果該區(qū)域節(jié)點沒有子集,children 則為空數(shù)組!??!
},
// ...
],
},
// ...
],
},
// ...
];
這題說復(fù)雜也復(fù)雜,說簡單也簡單,關(guān)鍵在于你怎么想了,想復(fù)雜的話能寫幾十行代碼,想簡單的話幾行代碼即可,我這里使用遞歸的方式進行解答。
首先需要先知道,convertToTree
函數(shù)接收的參數(shù)regions
代表一維數(shù)據(jù)數(shù)組,rootId
代表樹形結(jié)構(gòu)中根節(jié)點的pid
。convertToTree
函數(shù)返回的是指定根節(jié)點(pid=rootId
的)的樹結(jié)構(gòu),所以我們只需逐漸降低rootId
,遞歸調(diào)用convertToTree
函數(shù)不斷獲取下一層的樹形結(jié)構(gòu)即可。
代碼:
function convertToTree(regions, rootId = "0") {
// TODO: 在這里寫入具體的實現(xiàn)邏輯
// 將平鋪的結(jié)構(gòu)轉(zhuǎn)化為樹狀結(jié)構(gòu),并將 rootId 下的所有子節(jié)點數(shù)組返回
// 如果不存在 rootId 下的子節(jié)點,則返回一個空數(shù)組
let arr = [];
for (let i = 0; i < regions.length; i++) {
if (regions[i]['pid'] === rootId) {
regions[i].children = convertToTree(regions,regions[i]['id']);
arr.push(regions[i])
}
}
return arr
}
module.exports = convertToTree; // 檢測需要,請勿刪除
從整個過程來看,convertToTree
函數(shù)執(zhí)行一次就找到了一層數(shù)據(jù),每一個數(shù)據(jù)被找到時就開始以該數(shù)據(jù)為根節(jié)點去遞歸調(diào)用convertToTree
函數(shù)找下一層的數(shù)據(jù)。每一次調(diào)用convertToTree
函數(shù)就會遍歷一遍regions
數(shù)組,如果最終的樹形結(jié)構(gòu)有三層,那么就需要遍歷三遍regions
數(shù)組。
如果你不想定義新的變量(如上面定義的arr
)或者想炫技,你可以使用數(shù)組的reduce方法進行遞歸,說到這你可能會有疑問:reduce
不是用來求和的嗎?如果單純的將reduce
歸類于求和函數(shù),你的知識面就太過單薄了。
先來看看怎么使用reduce
解答吧:
function convertToTree(regions, rootId = "0") {
// TODO: 在這里寫入具體的實現(xiàn)邏輯
// 將平鋪的結(jié)構(gòu)轉(zhuǎn)化為樹狀結(jié)構(gòu),并將 rootId 下的所有子節(jié)點數(shù)組返回
// 如果不存在 rootId 下的子節(jié)點,則返回一個空數(shù)組
return regions.reduce((res,current)=>{
if (current['pid'] === rootId) {
current.children = convertToTree(regions,current['id']);
res.push(current);
}
return res;
},[])
}
module.exports = convertToTree; // 檢測需要,請勿刪除
reduce
的第二個參數(shù)是一個空數(shù)組,所以:
- 第一次執(zhí)行時,
res=[]
,current=regions[0]
。然后進行判斷,如果current
是根節(jié)點的話就以current
的id
作為下一層根節(jié)點pid
遞歸調(diào)用convertToTree
得到下一層的數(shù)據(jù)賦值給current.children
,之后將current
添加進res
中,隨后return
出res
。 - 第二次執(zhí)行時,
res
為第一次執(zhí)行返回的數(shù)組,current=regions[1]
- 第三次執(zhí)行時,
res
為第二次執(zhí)行返回的數(shù)組,current=regions[2]
- …
使用reduce
跟使用for
循環(huán)原理一樣,只是看上去會給人一種很高級的感覺。
?? 收快遞了
這一題使用的是上一題我們轉(zhuǎn)換后的樹形結(jié)構(gòu):
[
{
id: "51", // 地址 id
name: "四川省", // 地址名
pid: "0", // 該地址的父節(jié)點 id
children: [
{
id: "5101",
name: "成都市",
pid: "51",
children: [
{
id: "510101",
name: "市轄區(qū)",
pid: "5101",
children: [],
},
// ...
],
},
// ...
],
},
// ...
];
要求是:
- 輸入"市轄區(qū)"時,返回 [ “四川省”, “成都市”, “市轄區(qū)” ]。
- 輸入"成都市", 則返回 [ “四川省”, “成都市” ]。
- 輸入"四川省", 則返回 [ “四川省” ]。
- 如果不存在該地址,則返回一個
null
。
我是思路是:
- 先遞歸遍歷獲取到指定
name
對象的pid
。(相當于是從上向下找) - 再根據(jù)此
pid
與父對象id
相對應(yīng)的關(guān)系遞歸查詢父對象。 - 查詢到父對象后更新
pid
,并保存父對象的name
字段,然后開始新一輪的遞歸。(這時相當于是從下向上找)
function findRegion(regions, regionName) {
// TODO: 在這里寫入具體的實現(xiàn)邏輯
// 需要從樹狀結(jié)構(gòu)的行政信息中,遍歷找到目標區(qū)域的行政信息,如輸入:成都市,返回 [四川省,成都市]
// 如果所輸入的位置信息不存在,則返回 null
let arr = [],pid;
// 根據(jù)name獲取字對象的pid
function getPid(list) {
for (let i = 0; i < list.length; i++) {
if (list[i].name === regionName) {
arr.push(list[i].name)
// 查詢到pid了
pid = list[i].pid
return
}else if (list[i].children.length > 0) {
getPid(list[i].children)
}
}
}
// 根據(jù)pid查詢父對象
function addfName(list,pfid) {
for (let i = 0; i < list.length; i++) {
if (list[i].id === pfid) {
arr.push(list[i].name)
pid = list[i].pid
if (pid !== '0') {
// 表示還沒到根節(jié)點,更新pid后從regions開始新的遞歸查詢
addfName(regions,pid)
}
return
}else if (list[i].children.length > 0) {
addfName(list[i].children,pid)
}
}
}
getPid(regions)
addfName(regions,pid)
return arr.length > 0 ? arr.reverse() : null
}
module.exports = findRegion; // 檢測需要,請勿刪除
向arr
數(shù)組 push name
的過程是從樹的底層向頂層進行的,所以最后得到的arr
順序是反的,需要reverse
反向以下。
這種解法性能消耗較大,在比賽有限的時間中也想不到好的替換方法(因為博主是個算法菜鳥??),如果大佬們有好的解法,歡迎在評論區(qū)或加入我們的交流群進行交流。
下面是職業(yè)院校組與大學組不一樣的幾個題:
?? 偷梁換柱(職業(yè)院校組)
考察了數(shù)據(jù)攔截,可以使用Object.defineProperty
或者 Proxy
,要求:
- 如果新屬性值在 0 -150 之間(包含 0 和 150),則直接更新。
- 如果新屬性值小于 0,則屬性值更新為 0。
- 如果新屬性值大于 150,則屬性值更新為 150。
使用Object.defineProperty:
// 請不要更改這個對象里面的內(nèi)容
let person = {
age: 0,
};
// TODO:在這里寫入具體的實現(xiàn)邏輯
// 對 person 的 age 屬性更新行為進行攔截
// 如果輸入的年齡在 0 - 150 之間,則認為是合法
// 否則,如果小于 0,則返回 0;如果大于 150,則返回 150
function defineReactive(obj, key, value) {
Object.defineProperty(obj, key, {
get() {
return value;
},
set(newVal) {
if (newVal !== value) {
newVal > 0
? newVal > 150
? (value = 150)
: (value = newVal)
: (value = 0)
}
}
})
}
defineReactive(person,'age',person.age)
module.exports = person; // 檢測需要,請勿刪除
注意,千萬不要直接這樣寫:
Object.defineProperty(person,'age',{
set:(newVal)=>{
newVal > 0
? newVal > 150
? (person.age = 150)
: (person.age = newVal)
: (value = 0)
},
get:()=>{
return person.age
}
})
直接這樣寫會陷入死循環(huán),因為在Setter
中訪問了person.age
,這又會導(dǎo)致觸發(fā)Getter
并且對person.age
賦值又會觸發(fā)person.age
,一直觸發(fā)下去,完全就是一個死循環(huán),這也就是為什么我們在上面的代碼塊中套了一層defineReactive
函數(shù)的原因。
在defineReactive
函數(shù)中的value
相當于是閉包中的變量,它其實并不是真正的person.age
,所以對value
的一切操作都不會導(dǎo)致死循環(huán)。
使用Proxy:
// 請不要更改這個對象里面的內(nèi)容
let person = {
age: 0,
};
// TODO:在這里寫入具體的實現(xiàn)邏輯
// 對 person 的 age 屬性更新行為進行攔截
// 如果輸入的年齡在 0 - 150 之間,則認為是合法
// 否則,如果小于 0,則返回 0;如果大于 150,則返回 150
person = new Proxy(person,{
get: function(obj, key) {
return obj[key];
},
set: function(obj, key, value) {
value > 0
? value > 150
? (obj[key] = 150)
: (obj[key] = value)
: (obj[key] = 0)
}
})
module.exports = person; // 檢測需要,請勿刪除
?? 大電影(職業(yè)院校組)
要求實現(xiàn)一個收藏的功能:
- 點擊收藏圖標,收藏圖標在空心(
images/hollow.svg
)和實心 (images/solid.svg
)中進行切換。 - 點擊收藏圖標后,僅在收藏圖標為實心圖形時,成功提示框(
id=toast__container
,原題中說的是class=toast__container
,但實際是id
而不是class
)元素顯示,2 秒后該提示框自動隱藏或者點擊提示框上面的關(guān)閉按鈕(class=toast__close
)該提示框隱藏。使用display
屬性設(shè)置元素的顯示隱藏。
完成后,最終頁面效果如下:
代碼:
// TODO:待補充代碼
let timer;
$(".card-body-option-favorite img").each((i,t)=>{
$(t).click(function(){
if ($(this).attr('src') === './images/hollow.svg') {
// 切換圖片路徑
this.src = "./images/solid.svg"
// 顯示彈窗
$('#toast__container').show()
// 添加定時器,兩秒后關(guān)閉彈窗
timer = setTimeout(()=>{
$('#toast__container').hide()
},2000)
} else {
this.src = "./images/hollow.svg"
}
})
})
// 點擊彈窗的關(guān)閉按鈕
$('.toast__close').click(function () {
$('#toast__container').hide()
if (timer) {
clearTimeout(timer)
}
})
?? 乾坤大挪移心法(職業(yè)院校組)
這時一道很常見的循環(huán)調(diào)用的題,要求如下:
-
mentalMethod
需要返回一個函數(shù),可以一直進行調(diào)用,但是最后一次調(diào)用不傳參。 -
函數(shù)通過以下方式執(zhí)行,返回結(jié)果均為
'戰(zhàn)勝峨眉,武當,少林'
(注意逗號為英文逗號)。mentalMethod('峨眉')('武當')('少林')(); mentalMethod('峨眉','武當')('少林')(); mentalMethod('峨眉','武當','少林')();
代碼:
function mentalMethod(...args) {
// TODO 待補充代碼
let a =''
a += args.join(',')
let fn = function (...rest) {
if (rest.length > 0) {
// 如果原本a有值,需要在加新值之前添加一個,分割
a += a.length > 0 ? ',' + rest.join(',') :rest.join(',');
// 繼續(xù)返回fn這個函數(shù)
return fn
}else {
// 沒有參數(shù)代表是最后一次調(diào)用,這時直接返回結(jié)果
return '戰(zhàn)勝' + a
}
}
return fn
}
這題是利用了閉包,在外界調(diào)用fn
函數(shù)時能夠使用函數(shù)mentalMethod
內(nèi)層的變量。
?? 不能說的秘密(職業(yè)院校組)
題目要求實現(xiàn)一個隨機密碼生成器,完善 generatePassword.js
中的 generatePassword
函數(shù),實現(xiàn)根據(jù)規(guī)則隨機生成密碼的功能。密碼長度已由 input
框(id=passwordLength
)的屬性進行了限制最小 4,最大 20。
- 生成的密碼必須包含已選中的選項且只能由已選中的選項組成。
- 特殊符號如下:!@#$%^&*(){}[]=<>/,. 。
- 本題封裝方法時只需要考慮長度符合要求( 4-20 )且有已選中條件的情況,其他情況無需處理。
最終效果:
思路:
- 首先需要理解好題目的要求,密碼長度最小為4,為什么最小為4呢?因為題目還要求生成的密碼必須包含已選中的選項,而題中給的選項正好有4個,這一點很重要。
- 根據(jù)用戶的配置生成一個字典數(shù)組,數(shù)組中存的是密碼可能所含有的所有字符。
- 根據(jù)長度進行遍歷,一次次的隨機向字典數(shù)組里取一個字符添加到密碼字符串中。
代碼:
/**
* @function_name generatePassword ->生成密碼的函數(shù)
* @param {*} lower 是否小寫
* @param {*} upper 是否大寫
* @param {*} number 是否是數(shù)字
* @param {*} symbol 是否是特殊符號
* @param {*} length 密碼長度
* @return {*} string
*/
function generatePassword(lower, upper, number, symbol, length) {
//TODO:待補充代碼
// 特殊字符
let sy = '!@#$%^&*(){}[]=<>/,.';
// 存放字典的數(shù)組
let arr = [];
// 密碼結(jié)果
let str = '';
// 向str中添加字符的函數(shù),list代表字典。
function addStrItem(list) {
// 表示從list中隨機選一個字符添加到str中
str += list[Math.floor(Math.random()*list.length)]
}
// 添加大寫字母
if (upper) {
// 生成全部大寫字母數(shù)組
// Array(26)表示生成長度為26的空數(shù)組
// fill用來向數(shù)組中填充內(nèi)容,不填充內(nèi)容是無法正常使用數(shù)組遍歷的方法的
let upperList = Array(26).fill('').map((item,index) => {
return String.fromCharCode(index + 65)
});
// 添加到字典中
arr.push(...upperList)
// 此時就在所有大寫字母中隨機選一個添加到str中,確保了該選項對應(yīng)的值在密碼中存在。
addStrItem(upperList)
}
// 添加小寫字母
if (lower) {
let lowerList = Array(26).fill('').map((item,index) => {
return String.fromCharCode(index + 97)
})
arr.push(...lowerList)
addStrItem(lowerList)
}
// 添加數(shù)字
if(number) {
let numberList = Array(10).fill('').map((item,index)=>index)
arr.push(...numberList);
addStrItem(numberList)
}
if(symbol){
letsymbolList = sy.split('')
arr.push(...letsymbolList);
addStrItem(letsymbolList)
}
// 添加剩余長度的字符
while (str.length < length) {
addStrItem(arr)
}
return str
}
靜態(tài) String.fromCharCode() 方法返回由指定的 UTF-16
代碼單元序列創(chuàng)建的字符串。
- 小寫字母的
UTF-16
代碼單元序列為97-122 - 大寫字母的
UTF-16
代碼單元序列為65-90
?? 結(jié)語
至此,《 第十四屆藍橋杯(Web 應(yīng)用開發(fā))模擬賽 2 期 》的題解就結(jié)束了,這期模擬賽整體上來說并不算很難,但考察的知識點還是比較多的,特別是對基礎(chǔ)知識以及常見算法的考察(相信你在做題的過程中也能察覺到),所以博主還是建議大家在做題的過程中好好總結(jié),好好復(fù)習,祝大家都能在正式比賽中取得滿意的成績!
記錄一下考試成績,因各種原因?qū)е嘛@示的解題時間有誤,本人實際是做了大概三個小時左右,大學組十個題滿分才 150,最后得出的 178 分應(yīng)該也是受解題時間的影響。
總結(jié)來說,比較耗時的題就是第 6 題了,大家可以注意一下,在正式比賽時做好規(guī)劃。
如果本篇文章對你有所幫助,還請客官一件四連!??文章來源:http://www.zghlxwxcb.cn/news/detail-786928.html
文章來源地址http://www.zghlxwxcb.cn/news/detail-786928.html
到了這里,關(guān)于【藍橋杯Web】第十四屆藍橋杯(Web 應(yīng)用開發(fā))模擬賽 2 期 | 精品題解的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!