蓝桥杯Web开发【模拟题三】15届

1.创意广告牌

在"绮幻山谷"的历史和"梦幻海湾"的繁华交汇之处,一块创意广告牌傲然矗立。它以木质纹理的背景勾勒出古朴氛围,上方倾斜的牌子写着"绮幻山谷的风吹到了梦幻海湾",瞬间串联了过去与现在,历史与现实。这独特的设计将风景、时光和情感交织在城市的喧嚣中,为路人带来一份令人陶醉的艺术享受。

1.1 问题题目

这个题目不多说了,只要知道这些css应该都能写出来,不会的平时多查查文档就记住了。

完善 css/style.css 的 TODO 部分,完成以下目标:

  1. 设置 .billboard 元素的圆角为 10px,背景图片为 images 文件夹下的 woodiness.jpg
  2. 设置 .top-sign 元素上面两个角是圆角 15px,下面两个角是直角,元素 X 轴倾斜 -20 度。

完成后效果如下:

1.2 题目分析

这个题目不多说了,只要知道这些css应该都能写出来,不会的平时多查查文档就记住了。

1.3 源代码

.billboard {position: relative;background-color: #8e6534;color: #fff;padding: 20px;box-shadow: 0px 5px 15px rgba(0, 0, 0, 0.3);background-size: cover;/* TODO:待补充代码  设置圆角 10px,背景图片为woodiness.jpg  */border-radius: 10px;background: url('../images/woodiness.jpg');
}.top-sign {position: relative;width: 200px;height: 100px;background-color: #a87f4a;display: flex;justify-content: center;align-items: center;font-size: 1rem;/* TODO:待补充代码   上面两个角是圆角 15px,下面两个角是直角  元素 x 轴倾斜 20度*/border-top-left-radius: 15px;border-top-right-radius: 15px;transform: skewX(-20deg);
}

2.原子化 CSS

原子化 CSS 是一种近期十分流行的 CSS 构建方式,而属性化(Attributify)的原子化 CSS 进一步的简化了 CSS 的编写。

例如,传统上我们实现 flex 需要在元素上创建 class 等标识,然后在 CSS 中通过选择器选择到该元素:

<style>
.box {display: flex;
}
</style>
<div class="box"></div>

而通过属性化的原子化 CSS,我们仅需:

<div flex></div>

即可完成同样效果。

2.1 问题题目

本题代码中 div 的其中一个属性为: flex="~ col" ,其中 ~ 代表 flex 本身,表示使用 flex 布局,而 col 代表让 flex 纵向布局。

  • 请补充 css/style.css 中的 TODO 部分,实现相关功能,让 div 完成所需布局。

完成后的界面如图所示:

在这里插入图片描述

2.2 题目分析

这个题目主要需要知道的是css的属性选择器,可以查文档看看就知道了,不会的话其实看看其他的css应该也能联想到哈。

2.3 源代码

/* TODO: 实现原子化 flex */
[flex="~ col"] {display:flex;flex-direction: column;justify-content: space-between;
}

3.神秘咒语

你作为一位勇敢的冒险家,发现了这两把钥匙,但你需要通过向服务器发送请求获取钥匙对应的咒语部分。每次点击钥匙按钮,会发送请求并将咒语部分显示在页面上。然而,这个神秘的宝藏箱对安全性要求很高,所以你需要在请求中携带正确的令牌(Token)才能获取到咒语。

3.1 问题题目

完善 index.js 中的 TODO 部分,通过新增或者修改代码,完成以下目标:

  • 点击钥匙 1钥匙 2 按钮时会通过 axios 发送请求,在发送请求时需要在请求头中添加 Authorization 字段携带 tokentoken 的值为 2b58f9a8-7d73-4a9c-b8a2-9f05d6e8e3c7

完成后效果如下所示:

在这里插入图片描述

3.2 问题分析

这个考的也就是请求头携带参数,还不会的得抓紧学一下XML,fetch,axios了,这个从蓝桥杯模拟题的趋势来看,考的很频繁,甚至后面的题目发个请求就有3,5分。

3.3 问题解答

// TODO:新增或者修改以下代码key1Button.addEventListener('click', async () => {// 从后台请求钥匙1的咒语部分key1Button.disabled = true;let {data} =  await axios.get('/spellone', {headers:{Authorization: '2b58f9a8-7d73-4a9c-b8a2-9f05d6e8e3c7'}})console.log(data);spell1.innerHTML = data;tryOpenTreasureBox();
});key2Button.addEventListener('click', async () => {// 从后台请求钥匙2的咒语部分key2Button.disabled = true;let {data} =  await axios.get('/spelltwo', {headers:{Authorization: '2b58f9a8-7d73-4a9c-b8a2-9f05d6e8e3c7'}})spell2.innerHTML = data;tryOpenTreasureBox();
});

4.朋友圈

在我们使用朋友圈这类带文字编辑功能的应用时,通常需要内容临时保存的功能,这样下一次编辑才不用从头开始。

本题请实现一个能够实时保存用户输入内容的朋友圈发布页面。

4.1 问题题目

请在 index.js 文件中补全代码,具体需求如下:

  1. 请将 debounce 函数补充完整,实现一个延迟为 delay 毫秒的防抖函数。
  2. 用户在输入框(id=text)输入文字时,将用户输入的内容存入localStorage中,缓存的key名称为savedText;页面加载时检查localStorage中是否有缓存文本数据,若有则将输入框(id=text)内容设置为相应的文本;当用户点击“发表”按钮(id=post)时,清空输入框(id=text)中的内容,并将localStorage内缓存的文本数据移除。
    • 此阶段的页面效果可以查看 effect-1.gif 文件。
  3. 当输入框中没有文字时,将“发表”按钮(id=post)的disabled属性值设置为disabled;如果输入框中有文字则移除该属性。
    • 注意:当用户点击“发表”按钮和初次进入页面时也会改变输入框的内容,此时也需要对按钮的情况作出判断。
    • 页面最终效果可以查看 effect-2.gif 文件。

4.2 问题分析

其实这个还算挺简单的,就是一个非常常规的防抖,会的自然肯定是会的,不会的可以花几分钟时间看看视频学一下,很快的。

4.3 问题解答

实现防抖函数

// 防抖工具函数
/*** @param  {function} fn  - 回调函数* @param  {string} delay - 函数执行延迟,单位为ms*/function debounce(fn, delay) {let timer = nullreturn function () {timer ? clearTimeout(timer) : ''timer = setTimeout(() => {fn()}, delay);}
}

将内容存储到localStorage中

// 当文本框输入内容改变时,动态地设置localStorage缓存,并根据有没有文本改变按钮状态
// 此处使用了防抖函数,避免太过频繁地更新缓存
document.getElementById("text").addEventListener("input",debounce(function() {// 提示正在保存中document.getElementById("prompt").textContent = "正在保存中...";// TODO: 请在此补充用户输入时设置缓存和调整按钮状态的代码localStorage.setItem('savedText', document.getElementById("text").value)document.getElementById("post").removeAttribute('disabled')// TODO-END// 过一段时间后提示保存完成,模拟上传数据至后台的效果setTimeout(function() {document.getElementById("prompt").textContent = "内容已保存";}, 750);}, 200)
);

这个就是对页面的一些动态展示了,需要理清页面渲染的流程是怎么样的,什么时候显示什么,什么情况下该显示什么,经过一些判断后添加必要的属性,类名等就行。

document.getElementById("post").addEventListener("click", function() {const content = document.getElementById("text").value;const element = createContent(content);document.querySelector(".contents").appendChild(element);document.getElementById("prompt").textContent = "";// TODO: 请在此补充用户点击“发表”按钮时清空文本框和缓存的代码document.getElementById("text").value = ''localStorage.removeItem('savedText')document.getElementById("post").setAttribute('disabled', 'disabled')
});

页面初次加载的缓存

document.addEventListener("DOMContentLoaded", function() {// TODO: 请在此补充页面加载时缓存检查的代码const text = localStorage.getItem('savedText')if (text) {document.getElementById("text").value = text}else{document.getElementById("post").setAttribute('disabled', 'disabled')}
});

5.美食蛋白质揭秘

《美食蛋白质揭秘》带您深入了解不同食物的蛋白质占比。通过精心设计的饼图,揭示食物中蛋白质的奥秘,助您做出更明智的饮食选择。探索这个神奇的蛋白质世界,解开食物比例的秘密,为您的健康饮食之路指引方向!

5.1 问题题目

找到 index.html 中的 TODO 部分,完成以下目标:

  1. 在不使用任何第三方库的情况下完成数据请求,请求地址必须使用提供的变量 MockURL,数据中 name 表示食物名称,value 表示蛋白质含量,将数据正确渲染到 .protein-container 中,使用 .protein-item 元素渲染数据,元素中显示食物名称和蛋白质含量,正确渲染后的 DOM 如下所示:
<div class="protein-container"><div class="protein-item">鸡胸肉 30</div> <div class="protein-item">牛肉 26</div> <!-- 省略代码...... -->
</div>
  1. 在请求完成后,调用 echartsInit 方法渲染图表,参数 data 须是下面的数据结构图标才会正确渲染:
[{ name: "表头", icon: "none" },// 原有数据{ value: 30, name: "鸡胸肉" },// 省略 .......
];

完成后效果如下:

在这里插入图片描述

5.2 问题分析

这里的小坑就是拿到的数据渲染出来是不对的,要去除掉多余的数据

5.3 问题解答

                const arr = ref([])onMounted(() => {fetchData()})async function fetchData() {// TODO:待补充代码const res = await fetch(`${MockURL}`)const data = await res.json()arr.value = dataechartsInit( [{ name: "表头", icon: "none" }, ...arr.value])arr.value.shift(arr.value)}return { // 返回setup,这样模版才能访问到arr,echartsInit,};
    <div id="app"><h2>不同食物的蛋白质占比</h2><div class="protein-container" ><!-- TODO:待补充代码,渲染获取的数据 --><div class="protein-item" v-for="item in arr" :key="item.name">{{item.name}} {{item.value}}</div> </div><div class="echarts" id="main"></div></div>

6.营业状态切换

营业状态切换是一个基于 Vue.js 的店铺管理功能,该功能允许用户通过简单的界面切换店铺的营业状态。页面上展示了当前店铺的状况,并根据状态显示相应的图片。用户可以通过点击开关按钮来切换店铺的营业状态,从而实现营业中和已打烊之间的切换。

6.1 问题题目

找到 index.html 文件中的 useToggle 函数,完善其中的 TODO 部分,完成以下目标:

  • 这个 useToggle 函数用于创建一个可切换状态的逻辑,它接受一个初始状态 state 作为参数,并返回一个包含状态(truefalse)和切换状态函数的数组。

完成后效果如下:

在这里插入图片描述

6.2 问题分析

这个题目要实现切换状态,通过观察题目可以看到,需要返回的是一个Boolean值,这个是来确定页面该如何渲染的,第二个需要返回的是一个函数,用来切换状态的。

首先我们要想要的是,返回的值肯定需要是一个ref(),响应式的值,因为我们知道啊,在页面不刷新的情况下,ref(),响应式数据发生变化,页面也会发生变化的,那么想到这个就好办了。

6.3 问题解答

        function useToggle(state) {// TODO:待补充代码const isWorking = ref(state)const toggleWorking = ()=> {isWorking.value = !isWorking.value}return [isWorking, toggleWorking]}

7.小说阅读器

小蓝想自己开发一个简易版的小说阅读器,其功能包括两部分:

  1. 将指定格式的 .txt 文件读取成固定的 JSON 格式并存储在指定 .json 文件中。
  2. 然后再将该 .json 文件内容以小说的章节结构显示在网页中。

7.1 问题题目

使用 Node.jsfs 模块 进行文件读写操作,完成 index.js 中的 TODO 部分。实现对 txt 文件的小说数据进行处理,最终可以展示在 index.html 中。具体要求如下:

  1. run/index.js 中,完成 readFile(file)writeFile(file,data) 函数的编写,实现读取 txt 小说文件,处理数据后写入 JSON 文件中。要求如下:

    • readFile 函数读取文件(文件路径使用参数 file ,小说内容格式查看 run/book.txt ),并处理成指定格式的 JSON 数据,存储在 result 中返回(需要考虑去除首尾多余的空格)。格式如下:

      txt 中格式解析为 json 中对应字段
      《武魂大陆》"name":"《武魂大陆》",
      第一卷:初入武魂{ "isRoll": true, "title": "第一卷:初入武魂" },
      第1章:意外觉醒 主人公林风在一次偶然的意外中觉醒了自己的武魂,他的武魂是一只神秘的火凤凰。{"title": "第1章:意外觉醒","content": ["主人公林风在一次偶然的意外中觉醒了自己的武魂,他的武魂是一只神秘的火凤凰。", "第二段", "第三段"]},
    • 具体 json 格式如下:

      {
      "name":"《武魂大陆》",
      "data":
      [{ "isRoll": true, "title": "第一卷:初入武魂" },{"title": "第1章:意外觉醒","content": ["主人公林风在一次偶然的意外中觉醒了自己的武魂,他的武魂是一只神秘的火凤凰。", "这个突如其来的力量使他既困惑又兴奋,他意识到自己获得了一种独特而强大的力量。", "从那一刻起,他踏上了在武魂大陆的修炼之旅。",..."他的修炼之旅仍在继续,他对未来充满了期待和决心。无论面对怎样的挑战和困难,林风都坚信自己的武魂将引领他走向辉煌的未来。第一章内容"]},{"title": "第2章:武魂学院","content": ["林风进入了武魂学院,这是他展示自己才华和实力的舞台。", ...]}...]
      }
      
    • writeFile 函数中,实现将 readFile 函数中读取出来的数据,即 data 参数,写入 file 参数的文件中。

    • 读写文件格式统一为 UTF-8(即,run/index.js 中定义好的变量 options )。以上功能实现完成后,在终端运行 node run/index.js 命令后检验 book.json 文件中的内容是否正确写入。

  2. component/myComponent.vue 文件 created 方法中,使用 axios 请求 run 文件夹下的 book.json 文件,并渲染到界面中,即:book.json 数据中的 name 字段为书名,对应响应数据 bookNamedata 字段为书的章节列表与内容,对应响应数据 chapters(书名和章节列表及内容的 DOM 渲染本题已提供)。

  3. component/myComponent.vue 文件 next 方法中,实现章节的切换,即点击 上一章 ,参数 value 为 -1 ,切换为上一章内容。点击 下一章 ,参数 value 为 1 ,切换为下一章内容。需要考虑边缘情况,即:当前页面已经是第一章时,“上一章”按钮点击失效;当前页面为最后一章时,“下一章”按钮点击失效。效果如下图:

完成后在浏览器中查看 index.html 效果如下:

  • 第1章

在这里插入图片描述

  • 动图

7.2 问题分析

7.3 问题解答

const fs = require('fs')let readFilePath = './run/book.txt'
let writeFilePath = './run/book.json'
let options = 'UTF-8'//读取txt小说文件,并按对应数据格式返回。
const readFile = (file) => {try {let result = nulllet arr = {name: '',data: []}let res = fs.readFileSync(file, { encoding: options })res = res.split('------------\n\n')for (let i = 0; i < res.length; i++) {const lines = res[i].trim().split('\r\n').filter((item) => {return item !== '' && item !== '------------' && item !== '    '})arr.name = lines[0].slice(0, 8)lines.splice(0, 1)let temp1 = []let temp2 = []for (let i = 0; i < lines.length; i++) {if (lines[i].slice(0, 3) === '---') {if (temp2.length > 0) {temp2.forEach((item) => {arr.data.push(item)})}temp1.push({isRoll: true,title: lines[i].split('---'[1]).filter((item) => item !== '').join('')})arr.data.push(temp1[0])temp1 = []temp2 = []} else if (lines[i].slice(0, 1) === '第') {temp2.push({ title: lines[i], content: [] })} else {temp2[temp2.length - 1].content.push(lines[i].trim())}}if (temp2.length > 0) {temp2.forEach((item) => {arr.data.push(item)})}}result = arrreturn JSON.stringify(result)} catch (err) {return null}
}//写入json文件中
const writeFile = (file, data) => {try {fs.writeFileSync(file, data, { encoding: options })} catch (err) {console.log(err)}
}// 执行读取文件
let data = readFile(readFilePath)
// console.log(data)
if (data != null) writeFile(writeFilePath, data)
module.exports = {writeFile,readFile
}

component组件

next(value) {// TODO:待补充代码this.activeChapter += valueif (this.activeChapter <= 0) {this.activeChapter = 1return}if (this.activeChapter >= this.chapters.length - 1) {this.activeChapter = this.chapters.length - 1return}//跳过卷if (this.activeChapter % 11 === 0 && value == 1) {this.activeChapter += 1}if (this.activeChapter % 11 === 0 && value == -1) {this.activeChapter -= 1}},},//通过axios发起请求json数据,并渲染界面。created() {// TODO:待补充代码axios.get('../run/book.json').then((res) => {this.bookName = res.data.namethis.chapters = res.data.data})},

8.冰岛人

2018 年世界杯,冰岛队因 1:1 平了强大的阿根廷队而一战成名。好事者发现冰岛人的名字后面似乎都有个“松”(son),于是有网友科普如下:

“冰岛人沿用的是维京人古老的父系姓制,孩子的姓等于父亲的名加后缀,如果是儿子就加 sson,女儿则加 sdottir。维京人的后裔是可以通过姓的后缀判断性别的,其他人则是在姓的后面加 m 表示男性,加 f 表示女性。”

因为冰岛人口较少,为避免近亲繁衍,本地人交往前先用个 App 查一下两人祖宗若干代有无联系。本题就请你实现这个 App 的功能。

8.1 问题题目

请在 js/index.js 文件中补全函数 marry 中的代码,该函数接收三个参数,第一个参数 data 表示当地人口数据信息,第二、三个参数 name1name2 是将要查询能否通婚的两个人的名字。

冰岛人沿用的是维京人古老的父系姓制,孩子的姓等于父亲的名加后缀,如果是儿子就加 sson,女儿则加 sdottir维京人的后裔是可以通过姓的后缀判断性别的,其他人则是在姓的后面加 m表示男性,加 f 表示女性

marry 根据 data 中当地人口数据信息,返回一个字符串,返回字符串的规则如下:

  • 若两人为同性,则返回字符串 Whatever
  • 若有一人不在名单内,则返回字符串 NA
  • 若两人为异性,且五代以内(默认自己为第一代,注意不包括第五代)无公共祖先,则返回字符串 Yes
  • 若两人为异性,但五代以内(默认自己为第一代,注意不包括第五代)有公共祖先,则返回字符串 No

在页面两个输入框 #name1#name2 中 分别输入要查询的两人的名字,然后点击查询按钮( #btn ),在页面中会显示两人能否通婚的字符串。

输入的名字的格式为“名 姓”,即名字在前,姓氏在后,名字与姓氏之间用一个空格分开。其中姓氏不加后缀

完成效果如下图所示:

图片描述

当地人口信息的数据结构如下:

[{"givenName":"chris","familyName":"smithm"},{"givenName": "mike","familyName": "jacksson"},{"givenName": "jack","familyName": "chrissson"},//...
]

中:

  • givenName 是名字。
  • familyName 是姓氏。
  • 数据保证每个人的 givenName 在数据中是唯一的。

说明:

以数据中全名为 mike jacksson 的人为例,mike 是他的名,jacksson 是他的姓,他的姓的后缀为 sson ,姓去掉后缀 ssonjack,那么就证明名为 mike 的人是名为 jack 的人的儿子。在数据中,我们可以看到名为 jack 的人的全名是 jack chrissson,那么名为 jack 的人就是名为 chris 的人的儿子。chris 的全名为 chris smithm,其姓的后缀为 m ,并不是 ssonsdottir,对于 chris ,并不能向上追溯他的父亲是谁了,那么 chris 就是他们这一代的祖宗,通过祖宗姓的后缀为 m 我们可以知道祖宗是男性。

这样就构成了一种关系:jackmike 的父亲,chrisjack 的父亲,即 chrisjack 的爷爷,同时 chris 还是 jackmike 这一代的祖宗。

可以参考下面图解:

图片描述

这里给出几个测试用例供考生使用(注意:其中姓氏不加后缀):

  • 分别输入 tracy timjames eric,结果为 Yes
  • 分别输入 will robintracy tim,结果为 No
  • 分别输入 bob adameric steve,结果为 Whatever
  • 分别输入 x manapril mikes,结果为 NA

8.2 问题分析

首先的话,我是打算先进行基本的判断,是否是不存在的人,是否是同性,然后直接输出结果

找出每个人的祖先数组,然后再进行判断,查看是否满足题目要求,然后返回对应的结果。

8.3 问题解答

/*** @description 通过输入的两个人的姓名返回相应的字符串* @param {array} data 当地的人口信息* @param {string} name1 要查询的两人名字之一* @param {string} name2 要查询的两人名字之一* @return {string} 根据被查询两人的名字返回对应的字符串* */function marry(data, name1, name2) {function getAncestors(person, data) {let ancestors = []//找出person的父亲或者母亲while (1) {data.forEach((item) => {if (item.givenName === /(\w+)(sson|sdottir)$/gi.exec(person.familyName)[1]) {ancestors.push(item)}})//判断是不是最后一个人了,查询ancestors的最后一个元素的familyName的后缀既不是sson也不是sdottirif (!ancestors[ancestors.length - 1].familyName.endsWith('sson') && !ancestors[ancestors.length - 1].familyName.endsWith('sdottir')) {break}//将personIndex的数据改成最新的数据person = ancestors[ancestors.length - 1]}if (ancestors.length >= 4) {ancestors.pop()}return ancestors}// 获取个人信息let person1 = data.find((person) => person.givenName === name1.split(' ')[0])let person2 = data.find((person) => person.givenName === name2.split(' ')[0])// 如果其中一个人不在名单内,则返回 NAif (!person1 || !person2) {return 'NA'}let sex1 = ''let sex2 = ''// 获取性别if (person1.familyName.endsWith('sson')) {sex1 = 'male'} else if (person1.familyName.endsWith('sdottir')) {sex1 = 'female'}if (person2.familyName.endsWith('sson')) {sex2 = 'male'} else if (person2.familyName.endsWith('sdottir')) {sex2 = 'female'}// 如果两个人为同性,则返回 Whateverif (sex1 === sex2) {return 'Whatever'}// 获取两个人的祖先数组(循环)let ancestors1 = getAncestors(person1, data)let ancestors2 = getAncestors(person2, data)console.log(ancestors1, ancestors2)// 判断是否有公共祖先let hasCommonAncestor = falsefor (let ancestor1 of ancestors1) {for (let ancestor2 of ancestors2) {if (ancestor1 === ancestor2) {hasCommonAncestor = truebreak}}}// 如果有公共祖先,则返回 No;否则返回 Yesif (hasCommonAncestor) {return 'No'} else {return 'Yes'}
}module.exports = marry

9.这是一个”浏览器“

各种类型的浏览器都是一页一页标签页的效果,小蓝现在也想模拟实现一个这样的效果,请你帮助小蓝实现。

9.1 问题题目

完善 js/index.js 文件,找到其中的 TODO 部分,完成代码,达到以下目标:

  1. 补全 js/index.js 中的 toggleTab 函数,实现当点击标签页时,标签页与其内容页变为选中状态(即标签页加上类名 liactive ,内容页加上类名 conactive)。

    上述且后文描述中的标签页是指 .fisrstnav ul 下的每个 li 标签,内容页是指 .tabscon 下的每个 section 标签。

    完成效果如下:

    图片描述

  2. 完善 js/index.js 中的 editTab 函数,实现当双击标签页文字或者内容页文字时出现输入框,当输入框失焦时,原标签页文字或内容页文字替换为输入框中输入的值。

    上述且后文描述中的标签页文字是指类名为 contentspan 标签中的文本;内容页文字是指 .tabscon 下的每个 section 标签的文本;输入框是指双击后出现的 input 标签。

    完成效果如下:图片描述

  3. 补全 js/index.js 中的 addTab 函数,实现当点击 .tabadd 时,页面添加新的标签页(即创建一个 li 标签作为子元素插入到 .firstnav ul 节点下)和内容页(即创建一个 section 标签作为子元素插入到 .tabscon 节点下),新标签页及其内容页默认是选中状态。标签页及其内容页内容替换规则:

    • 标签页的内容分别按照序号 “标签页1、标签页2、标签页3…” 依次递增。

    • 内容页的内容分别按照序号 “标签页1的内容、标签页2的内容、标签页3的内容…” 依次递增。

    .firstnav ul 的 DOM 结构为:

    <ul><li><span class="content">标签页1</span><span class="iconfont icon-guanbi"><span class="glyphicon glyphicon-remove"></span></span></li><li><span class="content">标签页2</span><span class="iconfont icon-guanbi"><span class="glyphicon glyphicon-remove"></span></span></li><li><span class="content">标签页3</span><span class="iconfont icon-guanbi"><span class="glyphicon glyphicon-remove"></span></span></li>
    </ul>
    

    .tabscon 的 DOM 结构为:

    <div class="tabscon"><section>标签页1的内容</section><section>标签页2的内容</section><section>标签页3的内容</section>
    </div>
    

    完成效果如下:

    图片描述

  4. 补全 js/index.js 中的 removeTab 函数,实现当点击某个标签页的 .icon-guanbi 时,该标签页及其内容页从页面中删除,所有标签页及其内容页的内容仍以目标 3 中的规则开始重新排,标签页的选中状态也随之改变。标签页状态改变规则:

    • 若删除的标签页是当前选中的标签页,且非最后一个,则该标签页临近的下一个标签页变为选中状态。
    • 若删除的标签页是当前选中的标签页,且为最后一个,则该标签页临近的上一个标签页变为选中状态。
    • 若删除的标签页不是当前选中的标签页,则标签页选中状态不变。

    完成后效果如下:

    图片描述

9.2 问题分析

9.3 问题解答

"use strict";
class Tab {// 构造方法constructor(id) {// 获取元素this.main = document.querySelector(id);this.add = this.main.querySelector(".tabadd");this.ul = this.main.querySelector(".fisrstnav ul");this.fsection = this.main.querySelector(".tabscon"); //content页面this.init();}// 初始化init() {this.updateNode();// init初始化操作让相关元素绑定事件this.add.onclick = this.addTab.bind(this.add, this);for (var i = 0; i < this.lis.length; i++) {this.lis[i].index = i;this.lis[i].onclick = this.toggleTab.bind(this.lis[i], this);this.remove[i].onclick = this.removeTab.bind(this.remove[i], this);this.spans[i].ondblclick = this.editTab;this.sections[i].ondblclick = this.editTab;}}// 更新所有的li和sectionupdateNode() {this.lis = this.main.querySelectorAll("li");this.remove = this.main.querySelectorAll(".icon-guanbi");this.sections = this.main.querySelectorAll("section");this.spans = this.main.querySelectorAll(".content");}// 1.切换功能toggleTab(event) {// TODO: 添加代码,点击标签页,切换到对应标签页的功能var num = this.getAttribute("num");if (num != null && !(this.classList.contains("liactive"))) return; //阻止冒泡event.clearClass(); //this.clearClass不行 因为指向的是元素this.className = 'liactive'event.sections[this.index].className = 'conactive'// TODO结束}// 2.清空所有标签页及其内容页类名clearClass() {for (var i = 0; i < this.lis.length; i++) {this.lis[i].className = "";this.sections[i].className = "";}}// 3.添加标签页addTab(event) {// TODO:添加代码,当点击加号,添加新的标签页(对应的内容页也应一并添加)event.clearClass(); //清除一下let newTab = document.createElement('li');let lengthTab = event.lis.length + 1newTab.className = 'liactive'newTab.innerHTML = `<span class="content">标签页${lengthTab}</span><span class="iconfont icon-guanbi"><span class="glyphicon glyphicon-remove"></span></span>`event.ul.appendChild(newTab);//添加section内容let newTabScon = document.createElement('section');newTabScon.className = 'conactive';newTabScon.innerHTML = `标签页${lengthTab}的内容`;event.fsection.appendChild(newTabScon);event.updateNode(); //需要更新一下节点event.init();// TODO结束}// 4.删除功能
removeTab(event) {let index = Array.from(event.remove).indexOf(this); // 获取点击的删除按钮在数组中的索引var lis = document.getElementsByTagName("li");for (let index = 0; index < lis.length; index++) {if (lis[index] == this.parentElement) {this.parentElement.setAttribute('num', index);}
}if (event.lis[index].classList.contains('liactive')) { // 如果要删除的标签页是当前选中的标签页if (index < event.lis.length - 1) { // 不是最后一个标签页event.lis[index + 1].click(); // 选中临近的下一个标签页} else if (index > 0) { // 是最后一个标签页event.lis[index - 1].click(); // 选中临近的上一个标签页}}event.ul.removeChild(event.lis[index]); // 从页面中删除对应的标签页event.fsection.removeChild(event.sections[index]); // 从页面中删除对应的内容页event.updateNode(); // 更新节点
}// 5.修改功能editTab() {var str = this.innerHTML;window.getSelection? window.getSelection().removeAllRanges(): document.Selection.empty();this.innerHTML = '<input type="text" />';var input = this.children[0];input.value = str;input.select(); //让文本框里的文字处于选定状态// TODO:实现双击修改内容,当文本框失焦时,把修改的值赋给被双击的对象,并作上已修改的标记let li = this;input.onblur = function () {li.innerHTML = this.value}// TODO结束}
}
var tab = new Tab("#tab");

10. 趣味加密解密

小蓝正在制作一个趣味加密解密在线工具网站,本题请你帮助他封装两个 JS 函数 encryptiondecryption ,以实现明文的加密及密文的解密。

10.1 问题题目

请在 index.js 文件中补全 encryption 函数和 decryption 函数代码的 TODO 部分,完成加密解密功能,即:

在左侧的输入框中输入明文,点击 加密 按钮调用 encryption 函数后,对明文进行加密,并输出到右侧的输入框中,反之同理

功能展示

index.js 文件中的代码说明如下:

名称类型描述
defaultCodes常量默认密码表,当输入的密码表长度小于 2 时采用请勿进行修改 ,否则可能造成考生提交的函数与检测用例所采用的默认密码表不一致,导致检测无法通过
string2Unit8Array函数接受一个类型为字符串的参数 str能够返回 strUTF8 格式解码后的 Unit8Array 数组
uint8Array2String函数接受一个类型为 Array 数组的参数 arr能够返回 arrUTF8 格式编码之后的 String 字符串
encryption函数接受两个参数,分别是明文字符串 plainText 和用户输入的密码表字符串 codes函数应当返回加密之后的密文字符串
decryption函数接受两个参数,分别是密文字符串 cipherText 和用户输入的密码表字符串 codes函数应当返回解密之后的明文字符串

index.js 文件中 encryption 函数和 decryption 函数的补完要求如下:

  • 函数无需进行dom操作,只需要返回明文或密文
  • 函数应当对用户输入的密码表字符串 codes 进行去重后再使用
  • 若去重后的 codes 长度小于 2 ,应当采用默认密码表 defaultCodes

以下是 加密流程 ,解密流程请 自行逆推

序号名称说明
1字符解码将输入的明文以 UTF8 编码格式解码为 Unit8Array 数组
2检查密码表若输入的密码表去重后的长度小于 2 ,则采用默认密码表 defaultCodes
3进制转换按照采用的密码表长度确定进制,然后对 Unit8Array 数组中的字符编码进行进制转换若使用了长度为 n 的密码表( n为大于 1 的任意整数 ),则应当将编码转为 n 进制,使得编码符号能够和密码表中的字符 一一对应例如,若使用了长度为 2 的密码表 ,明文为 “1” ,则需要将 “1” 的 10 进制字符编码 “49” 转换为 2 进制 “110001”以此类推
4确定单位长度根据采用的密码表的长度,确定字符编码需要几个符号表示例如,若使用了长度为 2 的密码表,则单位长度应为 8 ,因为在 2 进制下 1 个字节 8 个比特,需要 8 个符号表示以此类推在解密时,检查密码表后,若遇到长度并非单位长度整数倍的密文,则应立即返回字符串 “ERROR”
5补齐编码在不足单位长度的编码前 补齐 数字 0例如,若使用了长度为 2 的密码表,则单位长度应为 8 ,而字符 “1” 的 2 进制编码为 “110001” ,故补齐为 “00110001”以此类推
6编码映射将补齐之后的字符编码,按照密码表中每个字符的次序,替换数字为密码表中的字符 ,得到密码数组例如,使用了文本 “密码” 作为密码表,则应当将字符编码中的 “0” 映射为 字符 “密” ,将 “1” 映射为字符 “码”则明文 “12” 的编码数组 [00110001,00110010][00110001,00110010] 应当映射为密码数组 [“密密码码密密密码”,“密密码码密密码密”][“密密码码密密密码”,“密密码码密密码密”]以此类推
7翻转密码并输出将每个密码中的字符顺序进行翻转,拼接为密文后返回例如,若明文 “12” 的密码数组为 [“密密码码密密密码”,“密密码码密密码密”][“密密码码密密密码”,“密密码码密密码密”],则应当翻转为 [“码密密密码码密密”,“密码密密码码密密”][“码密密密码码密密”,“密码密密码码密密”] 后,再拼接为密文 “码密密密码码密密密码密密码码密密” 并输出以此类推

关于单位长度的详细说明:

对于二进制,每个位有两种状态(0 和 1),所以一个字节(8 位)可以表示 256 种不同的状态,因为 2 的 8 次方等于256。因此在 2 进制下,需要 8 个符号表示,即单位长度为 8。

然而,在三进制系统中,每个位有三种可能的状态,分别是 0 、1 和 2 。但要想表示够 256 种状态,需要多少位呢?让我们来计算:

3^5 = 243,不够 256。

3^6 = 729,超过 256。

因此,用三进制表示,至少需要 6 位,即在 3 进制下,需要 6 个符号表示,即单位长度为 6。

关于其它进制的单位长度,以此类推。

10.2 问题分析

10.3 问题解答

function encryption(plainText, codes) {// 去重、检查密码表codes = [...new Set(codes)].join("");codes = codes.length < 2 ? defaultCodes : codes;// 进制为密码表长度const radix = codes.length;// 通过进制计算单位长度const unitLength = Math.ceil(8 / Math.log2(radix));// 对明文编码得到8位无符号整型数组const uint8Array = string2Unit8Array(plainText);// 对编码后的8位无符号整型数组进行加密return [...uint8Array].map((u) => {// 转换成指定进制const bits = converter(u, radix);// 根据单位长度进行补零while (bits.length < unitLength) bits.unshift(0);// 对照密码表进行编码映射并反转取字符串return bits.map((bit) => codes[bit]).reverse().join("");}).join("");function converter(decNumber, base) {const stack = [];while (decNumber > 0) {stack.push(decNumber % base);decNumber = Math.floor(decNumber / base);}return stack.reverse();}
}function decryption(cipherText, codes) {// 去重、检查密码表codes = [...new Set(codes)].join("");codes = codes.length < 2 ? defaultCodes : codes;// 进制为密码表长度const radix = codes.length;// 通过进制计算单位长度const unitLength = Math.ceil(8 / Math.log2(radix));// 若密文长度不是单位长度的倍数,则返回错误if (cipherText.length % unitLength !== 0) return "ERROR";// 按照单位长度对密文进行解码const decodedArray = [];for (let i = 0; i < cipherText.length; i += unitLength) {const slice = cipherText.slice(i, i + unitLength);const codeArray = [];// 查找每一个密文符号对应的索引值for (let j = 0; j < slice.length; j++) {codeArray.push(codes.indexOf(slice[j]));}// 若解码结果长度超过单位长度,则移除多余的部分while (codeArray.length > unitLength) codeArray.shift();// 根据进制和解码出来的索引值转换成原始值(十进制):系数*进制^权重之和decodedArray.push(codeArray.reduce((total, value, index) => total + value * Math.pow(radix, index)));}// 最后将解码后的数组实例化为Uint8Array(8 位无符号整型数组)并转换为字符串return uint8Array2String(Uint8Array.from(decodedArray));
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/14790.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

EPIC免费领取《骑士精神2》 IGN9分神作骑士精神2限时免费领

EPIC免费领取《骑士精神2》 IGN9分神作骑士精神2限时免费领 最近Epic一直为玩家们送出各种游戏&#xff0c;从《龙腾世纪审判》到《模拟农场22》&#xff0c;而就在今天&#xff0c;epic又为玩家们送出了IGN评分9分高分的骑士精神2.这款游戏&#xff0c;该游戏是一款由Tripwir…

vue连接mqtt实现收发消息组件超级详细

基本概念&#xff1a; MQTT&#xff08;Message Queuing Telemetry Transport&#xff09;是一种基于发布/订阅模式的轻量级消息传输协议&#xff0c;专为低带宽、高延迟或不稳定的网络环境设计。以下是MQTT实现收发消息的基本原理&#xff1a; 客户端-服务器模型&#xff1a…

数据量较小的表是否有必要添加索引问题分析

目录 前言一、分析前准备1.1、准备测试表和数据1.2、插入测试数据1.3、测试环境说明 二、具体业务分析2.1、单次查询耗时分析2.2、无索引并发查询服务器CPU占用率分析2.3、添加索引并发查询服务器CPU占用率分析 三、总结 前言 在一次节日活动我们系统访问量到达了平时的两倍&am…

【小沐学GIS】GDAL库安装和使用(C++、Python)

文章目录 1、简介2、下载和编译&#xff08;C&#xff09;2.1 二进制构建2.1.1 Conda2.1.2 Vcpkg 2.2 源代码构建2.2.1 nmake.opt方式构建2.2.2 generate_vcxproj.bat方式构建 2.3 命令行测试2.3.1 获取S57海图数据 2.4 代码测试2.4.1 读取tiff信息 3、Python3.1 安装3.2 测试3…

零基础入门篇④ 初识Python(注释、编码规范、关键字...)

Python从入门到精通系列专栏面向零基础以及需要进阶的读者倾心打造,9.9元订阅即可享受付费专栏权益,一个专栏带你吃透Python,专栏分为零基础入门篇、模块篇、网络爬虫篇、Web开发篇、办公自动化篇、数据分析篇…学习不断,持续更新,火热订阅中🔥专栏订阅地址 👉Python从…

C语言 | Leetcode C语言题解之第110题平衡二叉树

题目&#xff1a; 题解&#xff1a; int height(struct TreeNode* root) {if (root NULL) {return 0;}int leftHeight height(root->left);int rightHeight height(root->right);if (leftHeight -1 || rightHeight -1 || fabs(leftHeight - rightHeight) > 1) {…

Android硬件渲染环境初始化

Android硬件渲染环境初始化 一.硬件加速渲染的开启1.ThreadedRenderer的初始化2.RenderProxy的创建 二.RenderProxy中组件的初始化1.RenderThread的创建2.CanvasContext的创建3.DrawFrameTask的初始化 三.RenderThread的启动1.RenderThread中组件的初始化2.RenderThread中任务的…

arXiv AI 综述列表(2024.05.20~2024.05.24)

公众号&#xff1a;EDPJ&#xff08;进 Q 交流群&#xff1a;922230617 或加 VX&#xff1a;CV_EDPJ 进 V 交流群&#xff09; 每周末更新&#xff0c;完整版进群获取。 Q 群在群文件&#xff0c;VX 群每周末更新。 目录 1. Beyond Traditional Single Object Tracking: A …

基于yolov2深度学习网络的昆虫检测算法matlab仿真,并输出昆虫数量和大小判决

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 matlab2022A 3.部分核心程序 .......................................................... for i 1:12 % 遍历结…

播兔短剧模板:图鸟UI在前端短剧平台中的应用与实践

一、引言 随着移动互联网的快速发展&#xff0c;短剧平台因其短小精悍、内容丰富的特点&#xff0c;逐渐成为用户休闲娱乐的新宠。为了满足短剧平台对前端技术的需求&#xff0c;图鸟播兔短剧模板应运而生。该模板基于图鸟UI进行开发&#xff0c;采用纯前端技术&#xff0c;支…

【C语言回顾】文件操作

前言1. 文件打开模式2. 示例代码2.1 打开和关闭文件2.2 读写文件2.3 二进制文件操作 结语 #include<GUIQU.h> int main { 上期回顾: 【C语言回顾】动态内存管理 个人主页&#xff1a;C_GUIQU 专栏&#xff1a;【C语言学习】 return 一键三连; } 前言 各位小伙伴大家好&…

分享:怎么才能保证大数据查询的准确性?

随着大数据应用到金融风控领域&#xff0c;大数据越来越重要了&#xff0c;很多朋友在查大数据的时候都会遇到一个问题&#xff0c;那就是自己查询的大数据什么信息都没有&#xff0c;要么就是很少&#xff0c;这是什么原因呢?要怎么才能保证大数据查询的准确性呢?下面小编就…

Java进阶学习笔记3——static修饰成员方法

成员方法的分类&#xff1a; 类方法&#xff1a;有static修饰的成员方法&#xff0c;属于类&#xff1a; 成员方法&#xff1a;无static修饰的成员方法&#xff0c;属于对象。 Student类&#xff1a; package cn.ensource.d2_staticmethod;public class Student {double scor…

双拼打字,可以尝试这个练习平台

本文将介绍由本人开发的双拼练习平台打字侠&#xff0c;以及一些对新手学习双拼的建议。课程一共233课&#xff0c;共分为两大部分&#xff1a; 韵母键位&#xff0c;主要练习双拼中韵母对应的键盘键位&#xff0c;同时提供可视化的键盘指法示意图。 实战练习&#xff0c;同时…

Selenium常用命令(python版)

日升时奋斗&#xff0c;日落时自省 目录 1、Selenium 2、常见问题 1、Selenium 安装Python和配置环境没有涉及 注&#xff1a;如有侵权&#xff0c;立即删除 首先安装selenium包&#xff0c;安装方式很简单 pip install selenium 注:我这里已经安装好了&#xff0c;所以…

怎么一键消除路人?教你三个消除方法

怎么一键消除路人&#xff1f;在数字时代&#xff0c;摄影已成为我们记录生活、表达情感的重要方式。然而&#xff0c;完美的照片背后往往隐藏着一些不那么完美的元素——比如那些不经意间闯入镜头的路人。他们或许只是匆匆过客&#xff0c;但却足以破坏你精心构图的美好瞬间。…

分割文本文件

分割一个.txt文件&#xff0c;可以选择在命令行中使用split指令&#xff0c;或者编写一段脚本进行操作。以下是一个简单的Python脚本来分割文本文件&#xff1a; def split_file(file, lines):# Open source filewith open(file, r) as source:count 0atEOF Falsewhile not …

shell笔记脚本3

执行脚本文件demo2.sh, 观察打印VAR4效果 执行脚本文件后, 在交互式Shell环境打印VAR4, 观察打印VAR4效果 结论 全局变量在当前Shell环境与子Shell环境中可用, 父Shell环境中不可用 小结 自定义变量的分类 自定义局部变量: 就是在一个脚本文件内部使用 var_namevalue 自…

128天的创意之旅:从初心到成就,我的博客创作纪念日回顾

文章目录 &#x1f680;机缘&#xff1a;初心的种子——回望创作之旅的启航&#x1f308;收获&#xff1a;成长的果实——128天创作之旅的宝贵馈赠❤️日常&#xff1a;创作与生活的交织&#x1f44a;成就&#xff1a;代码的艺术&#x1f6b2;憧憬&#xff1a;未来的蓝图 &…

Mujoco仿真【xml文件的学习 3】

在学习Mujoco仿真的过程中&#xff0c;为了与时俱进&#xff0c;之前的mujoco210版本不再使用&#xff0c;改用了mujoco-3.1.4版本&#xff0c;下面继续mujoco仿真的学习&#xff01; 先前关于mujoco的学习博客汇总如下&#xff1a; 强化学习&#xff1a;MuJoCo机器人强化学习…