【蓝桥杯Web】第十四届蓝桥杯(Web 应用开发)模拟赛 2 期 | 精品题解

这篇具有很好参考价值的文章主要介绍了【蓝桥杯Web】第十四届蓝桥杯(Web 应用开发)模拟赛 2 期 | 精品题解。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

蓝桥杯web,蓝桥杯,# JS题解,JavaScript,蓝桥杯,前端,javascript,算法


🧑‍💼 个人简介:一个不甘平庸的平凡人🍬
🖥️ 蓝桥杯专栏:蓝桥杯题解/感悟
🖥️ TS知识总结:十万字TS知识点总结
👉 你的一键三连是我更新的最大动力❤️!
📢 欢迎私信博主加入前端交流群🌹



🔽 前言

第十四届蓝桥杯 Web 应用开发模拟赛第二期昨天正式开始了(本来写的是今天正式开始了,结果没想到这篇文章写到了凌晨 1 点 😵‍💫),博主也是第一时间为大家带来了题解!这篇题解包含了大学组职业院校组的所有内容。

因为自己在做题时忘记保存代码了,所以写这篇题解时我不得不又重新做了一遍,看在博主这么肝的份上,大佬们给个一键三连加关注吧!🤗

关于蓝桥杯更多的题解请前往专栏:蓝桥杯题解/感悟,欢迎大家的订阅!

本篇只会大概提出题目要求,关于题目的更多细节可自行去模拟赛主页查询:Web 应用开发模拟赛 2 期大学组

话不多说,开撕!

1️⃣ 凭空消失的 TA

题目说在 index.html 中未正常显示表单组件 myform,先运行看一下效果:

蓝桥杯web,蓝桥杯,# JS题解,JavaScript,蓝桥杯,前端,javascript,算法
发现 myform组件里的立即创建取消这两个文本被渲染了,这说明 index.html 确实是引入了 myform,但为何myform没有正常显示呢?

一开始我以为是myform组件里出了问题,可检查一遍后并没有发现问题,最后回到index.html才发现,是因为index.html中未引入element-uijs文件,我们加一行代码引入一下就解决了:

 <!-- 引入 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️⃣ 用户名片

蓝桥杯web,蓝桥杯,# JS题解,JavaScript,蓝桥杯,前端,javascript,算法

要求是需要将这个卡片垂直居中,并且还需要将卡片中左侧文字水平居中,看了一下HTML结构,发现它们都有一个共同的类名center

蓝桥杯web,蓝桥杯,# JS题解,JavaScript,蓝桥杯,前端,javascript,算法

所以对center类名定义样式就行了:

/* TODO 待补充代码 */
.center {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%,-50%);
}

上述代码利用定位将元素垂直水平方向各偏移父元素position: relative)的50%,这个时候元素还不是居中(因为定位偏移的中心点不在元素的中心上而是在元素的边界上):

蓝桥杯web,蓝桥杯,# JS题解,JavaScript,蓝桥杯,前端,javascript,算法

使用transform将元素在水平和垂直的负方向移动自身的50%(transform运动的中心点在元素的中心位置):

蓝桥杯web,蓝桥杯,# JS题解,JavaScript,蓝桥杯,前端,javascript,算法

这里深入说一下一个CSS选择器优先级的问题:

蓝桥杯web,蓝桥杯,# JS题解,JavaScript,蓝桥杯,前端,javascript,算法

图中所示,作用于同一元素的.user-card .points(后代选择器)的样式优先生效于.center (类选择器)的样式,这就映证了网上说的后代选择器的优先级小于类选择器的说法是不够准确的

其实,后代选择器和类选择器没有可比性,后代选择器是选择器组合方式的一种,它是一种组合本身没有任何优先级(严格的用词叫特殊性) 可言。比如.user-card .points在计算特殊性(优先级)时,是分别计算「.user-card」和「.points」的特殊性(优先级),完全不用考虑它们之间是用后代关联的。

按照权重来说.user-card .points的样式优先生效于.center的样式,是因为.user-card .points含有两个类选择器,它的权重比.center高。

蓝桥杯web,蓝桥杯,# JS题解,JavaScript,蓝桥杯,前端,javascript,算法

关于CSS选择器权重、优先级的问题在实际开发中是比较重要的,如果你看到这里对它们还不是很了解,建议你去网上多看看关于它们的内容。

3️⃣ 芝麻开门

这题简单的考察了Promise,最终实现以下效果:

蓝桥杯web,蓝桥杯,# JS题解,JavaScript,蓝桥杯,前端,javascript,算法
代码:

/**
 * @description: 调用函数,开启弹窗,记录输入框的内容,并通过 promise 异步返回输入框中的内容
 * @return {Promise}
 */
function mPrompt() {
  // 弹窗必须使用以下结构 template 保存的是弹窗的结构字符串,可以先转化为 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对象,并在点击事件中做出不同的处理(rejectresolve)即可。

4️⃣ 宝贵的一票

要求是实现一个动态列表的表单,可以新增选项和删除选项,最终效果:

蓝桥杯web,蓝桥杯,# JS题解,JavaScript,蓝桥杯,前端,javascript,算法
添加的思路:

  • 添加选项时先获取当前选项的个数,如果当前选项个数以及为2了,那么就需要先向前两个选项添加删除号(x)。
  • 当前选项的个数小于2时,再添加一各选项,选项的总数也不会超过2,所以这时只需添加普通的选项即可。
  • 当前选项的个数大于或等于2时,需要添加带有删除号(x)的选项。

删除的思路:

  • 点击删除号(x)时先删除当前选项。
  • 遍历余下的选项列表,更新它们的序号。
  • 在遍历的时候判断余下的选项个数,若剩余的选项小于等于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的内部并不过,大部分都只是考察你对数据的处理,比如这一题,本质就是对数据格式的转换。

源数据格式:

{
    "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 }
}

字段对应表:

英文名称 中文名称
wheat 小麦
soybean 大豆
potato 马铃薯
corn 玉米

需要转换成的数据格式:

[
	['全部', '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 = ["全部"];

// 获取数据
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 活动

就是按照官方给的最终效果图,去实现下面这个页面:

蓝桥杯web,蓝桥杯,# JS题解,JavaScript,蓝桥杯,前端,javascript,算法

没啥技术含量,全靠堆HTML和CSS,这里就不放代码了。

但这个题是我认为是整场模拟赛里最坑人的题,特别废时间,我建议这个题要么放到最后再写(因为完成度50%以上就能得到分,其它题不行),要么完成差不多后就直接去做下面的题,别死扣细节,不然吃亏的都是你!

7️⃣ 资讯接口

题目要求使用 NodeJS 去创建一个服务器并响应一个/news接口:

  1. 通过在 app.js 书写代码,创建一个服务器,使服务在 8080 端口运行。
  2. 访问 /news 返回资讯数据,访问其他任意路径均返回字符串 404 。

代码:

// TODO: 待补充代码
const http = require("http");
// 创建http服务
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": "国内焦点"
                },
                {
                  "channelId": "5572a108b3cdc86cf39001ce",
                  "name": "国际焦点"
                }
              ]))
            break;
    
        default:
            res.end('404')
            break;
    }
})

app.listen(8080);

8️⃣ 绝美宋词

相当于是使用Vue做一个搜索功能:

蓝桥杯web,蓝桥杯,# JS题解,JavaScript,蓝桥杯,前端,javascript,算法

代码:

<body>
  <div id="app">
    <h1 style="text-align: center">输入关键字,找一首词</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:'', // 输入内容
        list:[], // 源数据
        showList:[] // 进行展示的数据
      },
      created(){
      	// 获取数据
        axios.get("./data.json").then(res=>{
          this.list = res.data
        })
      },
      methods:{
      	// 搜索函数
        search(){
          if (this.val) {
          	// 输入内容不为空,使用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 {
          	// 输入内容为空,重置数据
            this.showList = []
          }
        },
        // 替换关键字进行高亮的函数
        highlight(str){
          let reg = new RegExp(this.val,'g');
          // replace第二个参数中$&代表插入匹配的子串。
          return str.replace(reg, `<span class="highlight">$&</span>`)
        }
      }
    })
  </script>
</body>

因为需要将关键字包上一层<span class="highlight"></span>来进行高亮,所以我使用了v-html指令来确保数据能以html的格式进行渲染,并配合replace替换关键字。

9️⃣ 平地起高楼

相当于是一道算法题,将一维数据转成树形结构,源数据:

[
  {
    id: "51", // 区域 id
    name: "四川省", // 区域名字
    pid: "0", // 区域的父级区域 id
  },
  {
    id: "5101",
    name: "成都市",
    pid: "51", // 成都的父级是四川省,所以 pid 是 51
  },
  // ...
];

转换成树结构:

[
  {
    id: "51", // 地址 id
    name: "四川省", // 地址名
    pid: "0", // 该地址的父节点 id
    children: [
      {
        id: "5101",
        name: "成都市",
        pid: "51",
        children: [
          {
            id: "510101",
            name: "市辖区",
            pid: "5101",
            children: [], // 如果该区域节点没有子集,children 则为空数组!!!
          },
          // ...
        ],
      },
      // ...
    ],
  },
  // ...
];

这题说复杂也复杂,说简单也简单,关键在于你怎么想了,想复杂的话能写几十行代码,想简单的话几行代码即可,我这里使用递归的方式进行解答。

首先需要先知道,convertToTree函数接收的参数regions代表一维数据数组,rootId代表树形结构中根节点的pidconvertToTree函数返回的是指定根节点(pid=rootId的)的树结构,所以我们只需逐渐降低rootId,递归调用convertToTree函数不断获取下一层的树形结构即可。

代码:

function convertToTree(regions, rootId = "0") {
  // TODO: 在这里写入具体的实现逻辑
  // 将平铺的结构转化为树状结构,并将 rootId 下的所有子节点数组返回
  // 如果不存在 rootId 下的子节点,则返回一个空数组
  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函数执行一次就找到了一层数据,每一个数据被找到时就开始以该数据为根节点去递归调用convertToTree函数找下一层的数据。每一次调用convertToTree函数就会遍历一遍regions数组,如果最终的树形结构有三层,那么就需要遍历三遍regions数组。

如果你不想定义新的变量(如上面定义的arr)或者想炫技,你可以使用数组的reduce方法进行递归,说到这你可能会有疑问:reduce不是用来求和的吗?如果单纯的将reduce归类于求和函数,你的知识面就太过单薄了。

先来看看怎么使用reduce解答吧:

function convertToTree(regions, rootId = "0") {
  // TODO: 在这里写入具体的实现逻辑
  // 将平铺的结构转化为树状结构,并将 rootId 下的所有子节点数组返回
  // 如果不存在 rootId 下的子节点,则返回一个空数组
  return  regions.reduce((res,current)=>{
    if (current['pid'] === rootId) {
      current.children = convertToTree(regions,current['id']);
      res.push(current);
    }
    return res;
  },[])
}

module.exports = convertToTree; // 检测需要,请勿删除

reduce的第二个参数是一个空数组,所以:

  • 第一次执行时,res=[]current=regions[0]。然后进行判断,如果current是根节点的话就以currentid作为下一层根节点pid递归调用convertToTree得到下一层的数据赋值给current.children,之后将current添加进res中,随后returnres
  • 第二次执行时,res为第一次执行返回的数组,current=regions[1]
  • 第三次执行时,res为第二次执行返回的数组,current=regions[2]

使用reduce跟使用for循环原理一样,只是看上去会给人一种很高级的感觉。

🔟 收快递了

这一题使用的是上一题我们转换后的树形结构:

[
  {
    id: "51", // 地址 id
    name: "四川省", // 地址名
    pid: "0", // 该地址的父节点 id
    children: [
      {
        id: "5101",
        name: "成都市",
        pid: "51",
        children: [
          {
            id: "510101",
            name: "市辖区",
            pid: "5101",
            children: [],
          },
          // ...
        ],
      },
      // ...
    ],
  },
  // ...
];

要求是:

  • 输入"市辖区"时,返回 [ “四川省”, “成都市”, “市辖区” ]。
  • 输入"成都市", 则返回 [ “四川省”, “成都市” ]。
  • 输入"四川省", 则返回 [ “四川省” ]。
  • 如果不存在该地址,则返回一个 null

我是思路是:

  • 先递归遍历获取到指定name对象的pid。(相当于是从上向下找)
  • 再根据此pid与父对象id相对应的关系递归查询父对象。
  • 查询到父对象后更新pid,并保存父对象的name字段,然后开始新一轮的递归。(这时相当于是从下向上找)
function findRegion(regions, regionName) {
  // TODO: 在这里写入具体的实现逻辑
  // 需要从树状结构的行政信息中,遍历找到目标区域的行政信息,如输入:成都市,返回 [四川省,成都市]
  // 如果所输入的位置信息不存在,则返回 null
  let arr = [],pid;

  // 根据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)
      }
    }
  }

  // 根据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') {
          // 表示还没到根节点,更新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数组 push name的过程是从树的底层向顶层进行的,所以最后得到的arr顺序是反的,需要reverse反向以下。

这种解法性能消耗较大,在比赛有限的时间中也想不到好的替换方法(因为博主是个算法菜鸟😬),如果大佬们有好的解法,欢迎在评论区或加入我们的交流群进行交流。


下面是职业院校组与大学组不一样的几个题:

💠 偷梁换柱(职业院校组)

考察了数据拦截,可以使用Object.defineProperty 或者 Proxy,要求:

  • 如果新属性值在 0 -150 之间(包含 0 和 150),则直接更新。
  • 如果新属性值小于 0,则属性值更新为 0。
  • 如果新属性值大于 150,则属性值更新为 150。

使用Object.defineProperty:

// 请不要更改这个对象里面的内容
let person = {
  age: 0,
};
// TODO:在这里写入具体的实现逻辑
// 对 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
  }
})

直接这样写会陷入死循环,因为在Setter中访问了person.age,这又会导致触发Getter并且对person.age赋值又会触发person.age,一直触发下去,完全就是一个死循环,这也就是为什么我们在上面的代码块中套了一层defineReactive函数的原因。

defineReactive函数中的value相当于是闭包中的变量,它其实并不是真正的person.age,所以对value的一切操作都不会导致死循环。

使用Proxy:

// 请不要更改这个对象里面的内容
let person = {
  age: 0,
};
// TODO:在这里写入具体的实现逻辑
// 对 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; // 检测需要,请勿删除

💠 大电影(职业院校组)

要求实现一个收藏的功能:

  • 点击收藏图标,收藏图标在空心(images/hollow.svg)和实心 (images/solid.svg)中进行切换。
  • 点击收藏图标后,仅在收藏图标为实心图形时,成功提示框(id=toast__container,原题中说的是class=toast__container,但实际是id而不是class)元素显示,2 秒后该提示框自动隐藏或者点击提示框上面的关闭按钮(class=toast__close)该提示框隐藏。使用 display 属性设置元素的显示隐藏。

完成后,最终页面效果如下:

蓝桥杯web,蓝桥杯,# JS题解,JavaScript,蓝桥杯,前端,javascript,算法

代码:

// 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()
      	// 添加定时器,两秒后关闭弹窗
	    timer = setTimeout(()=>{
	        $('#toast__container').hide()
	    },2000)
    } else {
      this.src = "./images/hollow.svg"
    }
  })
})

// 点击弹窗的关闭按钮
$('.toast__close').click(function () {
  $('#toast__container').hide()
  if (timer) {
    clearTimeout(timer)
  }
})

💠 乾坤大挪移心法(职业院校组)

这时一道很常见的循环调用的题,要求如下:

  • mentalMethod 需要返回一个函数,可以一直进行调用,但是最后一次调用不传参

  • 函数通过以下方式执行,返回结果均为 '战胜峨眉,武当,少林'(注意逗号为英文逗号)。

    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(',');
            // 继续返回fn这个函数
            return fn
        }else {
        	// 没有参数代表是最后一次调用,这时直接返回结果
            return '战胜' + a
        }
        
    }
    return fn
}

这题是利用了闭包,在外界调用fn函数时能够使用函数mentalMethod内层的变量。

💠 不能说的秘密(职业院校组)

题目要求实现一个随机密码生成器,完善 generatePassword.js 中的 generatePassword 函数,实现根据规则随机生成密码的功能。密码长度已由 input 框(id=passwordLength)的属性进行了限制最小 4,最大 20

  • 生成的密码必须包含已选中的选项且只能由已选中的选项组成。
  • 特殊符号如下:!@#$%^&*(){}[]=<>/,. 。
  • 本题封装方法时只需要考虑长度符合要求( 4-20 )且有已选中条件的情况,其他情况无需处理。

最终效果:

蓝桥杯web,蓝桥杯,# JS题解,JavaScript,蓝桥杯,前端,javascript,算法

思路:

  • 首先需要理解好题目的要求,密码长度最小为4,为什么最小为4呢?因为题目还要求生成的密码必须包含已选中的选项,而题中给的选项正好有4个,这一点很重要。
  • 根据用户的配置生成一个字典数组数组中存的是密码可能所含有的所有字符
  • 根据长度进行遍历,一次次的随机向字典数组里取一个字符添加到密码字符串中。

代码:

/**
 * @function_name generatePassword ->生成密码的函数
 * @param {*} lower 是否小写
 * @param {*} upper 是否大写
 * @param {*} number 是否是数字
 * @param {*} symbol 是否是特殊符号
 * @param {*} length 密码长度
 * @return {*} string
 */
function generatePassword(lower, upper, number, symbol, length) {
  //TODO:待补充代码
  // 特殊字符
  let sy = '!@#$%^&*(){}[]=<>/,.';
  // 存放字典的数组
  let arr = [];
  // 密码结果
  let str = '';

  // 向str中添加字符的函数,list代表字典。
  function addStrItem(list) {
  	// 表示从list中随机选一个字符添加到str中
    str += list[Math.floor(Math.random()*list.length)]
  }

  // 添加大写字母
  if (upper) {
    // 生成全部大写字母数组
    // Array(26)表示生成长度为26的空数组
    // fill用来向数组中填充内容,不填充内容是无法正常使用数组遍历的方法的
    let upperList = Array(26).fill('').map((item,index) => {
      return String.fromCharCode(index + 65)
    });
    // 添加到字典中
    arr.push(...upperList)
    // 此时就在所有大写字母中随机选一个添加到str中,确保了该选项对应的值在密码中存在。
    addStrItem(upperList)
  }
  // 添加小写字母
  if (lower) {
    let lowerList = Array(26).fill('').map((item,index) => {
      return String.fromCharCode(index + 97)
    })
    arr.push(...lowerList)
    addStrItem(lowerList)
  }
  // 添加数字
  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
}

静态 String.fromCharCode() 方法返回由指定的 UTF-16 代码单元序列创建的字符串。

  • 小写字母的 UTF-16 代码单元序列为97-122
  • 大写字母的 UTF-16 代码单元序列为65-90

🔼 结语

至此,《 第十四届蓝桥杯(Web 应用开发)模拟赛 2 期 》的题解就结束了,这期模拟赛整体上来说并不算很难,但考察的知识点还是比较多的,特别是对基础知识以及常见算法的考察(相信你在做题的过程中也能察觉到),所以博主还是建议大家在做题的过程中好好总结,好好复习,祝大家都能在正式比赛中取得满意的成绩!

记录一下考试成绩,因各种原因导致显示的解题时间有误,本人实际是做了大概三个小时左右,大学组十个题满分才 150,最后得出的 178 分应该也是受解题时间的影响。
蓝桥杯web,蓝桥杯,# JS题解,JavaScript,蓝桥杯,前端,javascript,算法
总结来说,比较耗时的题就是第 6 题了,大家可以注意一下,在正式比赛时做好规划。

如果本篇文章对你有所帮助,还请客官一件四连!❤️

蓝桥杯web,蓝桥杯,# JS题解,JavaScript,蓝桥杯,前端,javascript,算法文章来源地址https://www.toymoban.com/news/detail-786928.html

到了这里,关于【蓝桥杯Web】第十四届蓝桥杯(Web 应用开发)模拟赛 2 期 | 精品题解的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 第十四届蓝桥杯模拟赛(第一期)——C语言版

    问题描述 十进制整数 2 在十进制中是 1 位数,在二进制中对应 10 ,是 2 位数。 十进制整数 22 在十进制中是 2 位数,在二进制中对应 10110 ,是 5 位数。 请问十进制整数 2022 在二进制中是几位数? 答案提交 这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果

    2023年04月09日
    浏览(61)
  • 第十四届蓝桥杯单片机第二场模拟赛程序

    第十四届蓝桥杯单片机第二场模拟赛程序(少量bug) 题目来源于4T评测网 www.4t.wiki 使用大赛组委会提供的国信长天单片机竞赛实训平台,完成本试题的程序设计与调试。程序编写、调试完成后,选手需通过考试系统提交以准考证号命名的hex文件。不符合以上文件提交要求的作

    2023年04月14日
    浏览(56)
  • 2023第十四届蓝桥杯模拟赛第二期个人题解(Java实现)

    2023第十四届蓝桥杯校内模拟赛第三期个人题解(Java实现) 蓝桥杯真题——单词分析(Java实现) 这篇文章为个人题解,假如我写的解法有误,欢迎大家在评论区指正👏👏!!!希望这篇文章对你有帮助❤❤ 请找到一个大于 2022 的最小数,这个数转换成二进制之后,最低的

    2023年04月23日
    浏览(165)
  • 蓝桥杯第十四届蓝桥杯模拟赛第三期考场应对攻略(C/C++)

    这里把我的想法和思路写出来,恳请批评指正! 目录 考前准备 试题1: 试题2: 试题3: 试题4: 试题5: 试题6: 试题7: 试题8: 试题9: 试题10: 总结: 考前五分钟,开十个源文件,并把头文件等必须写的部分写出来,写完的程序一定要有顺序地保留 问题描述 请找到一个

    2024年02月02日
    浏览(167)
  • 第十四届蓝桥杯校模拟赛-编程大题详解+代码(二)

    前言: 这几天有不少小伙伴催促我尽快更新后五道编程题题解,然鄙人实在水平有限,实事求是,能力不足,不堪众望。思索良久,第九题有解题思路且已完成部分解题,但未完全完成,第十题尚未有思路。在此愿有大佬指点一二! 目录 一、做不完的核酸 问题描述 1.1 代码

    2024年02月02日
    浏览(52)
  • 第十四届蓝桥杯模拟赛(第三期)(大学B组)Java组

    修改了第六题余数为0时输出应为7的问题 修改了第五题和第九题可能超时的问题 前些天参加了第十四届蓝桥杯模拟赛(第三期),收获颇丰,自己也走了一点点弯路,记录一下自己考试中犯的一些错误。也希望在这期间可以提高一下自己的编程水平。 纯小白大佬请喷! 问题

    2023年04月24日
    浏览(54)
  • 2022 第十四届蓝桥杯模拟赛第二期题目题解(比赛时使用方法)

    目录 第一题:最小的2022 第二题:经过天数 第三题:特殊的十六进制数 第四题:矩阵的最小路径 第五题:质数拆分 第六题:拷贝时间 第七题:单词去重 第八题:最短回文串 第九题:多少个X? 第十题:最小交换 问题描述 请找到一个大于 2022 的最小数,这个数转换成二进

    2023年04月11日
    浏览(71)
  • 【蓝桥杯嵌入式】第十四届蓝桥杯嵌入式[模拟赛2]客观题及详细题解

    解析 USART_CR1:控制寄存器1,其中的M位定义了数据字的长度,由软件对其设置和清零。 USART_CR2:控制寄存器2。 USART_BRR:波特率寄存器。 USART_DR:数据寄存器。 (如果现场不记得,可以查阅芯片手册) 答案: A 解析 在STM32微控制器中,DMA可编程的数据传送数目:最大为65535。(如果现场不

    2023年04月10日
    浏览(67)
  • 【蓝桥杯嵌入式】第十四届蓝桥杯嵌入式[模拟赛1]程序设计试题及详细题解

    模拟赛1的题目中需要的准备的知识点不多,其中只用到了 串口 、 LCD 、 LED 、 按键 、 定时器的PWM输出 、以及 ADC 等几个模块,题目要求也简单详细并且数量不多,非常适合入门比赛,以及整合自己比赛的模块。 与模拟赛2相比,当然是模拟赛2的试题比较难啦,虽然需要的模

    2023年04月13日
    浏览(147)
  • 【蓝桥杯嵌入式】第十四届蓝桥杯嵌入式[模拟赛2]程序设计试题及详细题解

    这次的模拟赛试题模块还是一些常见模块: LCD 、 LED 、 按键 、 定时器 以及 串口 ,相对比较常规,相比于真正的省赛也比较简单。但是它 适合刚刚学完各个模块需要做真题的同学 ,可以借此来巩固自己之前所学;对于已经能够掌握各个模块的同学也是有帮助的,就是平台

    2023年04月13日
    浏览(134)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包