24模拟赛3
1. 创意广告牌¶
.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-image: 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-radius: 15px 15px 0 0 ;
transform: skewX(-20deg);
}
2.原子化CSS¶
<div flex="~ col">
<div red></div>
<div yellow></div>
<div blue></div>
</div>
div[flex="~ col"]{
display: flex;
flex-direction: column;
}
flex="~ col"
,其中 ~
代表 flex
本身,表示使用 flex
布局,而 col
代表让 flex
纵向布局
3.神秘咒语¶
key1Button.addEventListener('click', async () => {
// 从后台请求钥匙1的咒语部分
key1Button.disabled = true;
let {data} = await axios.get('/spellone',{
'headers':{
Authorization:'2b58f9a8-7d73-4a9c-b8a2-9f05d6e8e3c7'
}
})
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. 朋友圈¶
const textArea = document.querySelector("#text");
const postBtn = document.querySelector("#post");
document.addEventListener("DOMContentLoaded", function () {
// TODO: 请在此补充页面加载时缓存检查的代码
const value = localStorage.getItem("savedText");
if (value) {
textArea.innerText = value;
}else{
// 不能用这个:
// postBtn.disabled=true
postBtn.setAttribute('disabled','disabled')
}
});
// 当文本框输入内容改变时,动态地设置localStorage缓存,并根据有没有文本改变按钮状态
// 此处使用了防抖函数,避免太过频繁地更新缓存
document.getElementById("text").addEventListener(
"input",
debounce(function () {
// 提示正在保存中
document.getElementById("prompt").textContent = "正在保存中...";
// TODO: 请在此补充用户输入时设置缓存和调整按钮状态的代码
localStorage.setItem("savedText", textArea.value);
if(textArea.value){
// postBtn.disabled=false
postBtn.removeAttribute('disabled')
}else{
postBtn.setAttribute('disabled','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: 请在此补充用户点击“发表”按钮时清空文本框和缓存的代码
textArea.value=''
localStorage.setItem('savedText', "")
postBtn.setAttribute('disabled','disabled')
});
// 防抖工具函数
/**
* @param {function} fn - 回调函数
* @param {string} delay - 函数执行延迟,单位为ms
*/
function debounce(fn, delay) {
// return fn; // 这一行是为了确保页面正常运行,可以去掉
let timer;
return function () {
if (timer) clearTimeout(timer);
timer = setTimeout(() => {
fn();
}, delay);
};
// TODO: 请实现函数防抖的功能
}
// 用户点击“发表”后,创建一条新信息的DOM元素
function createContent(content) {
const div = document.createElement("div");
const d = new Date();
const deleteBtn = document.createElement("button");
deleteBtn.textContent = "删除";
deleteBtn.addEventListener("click", function () {
div.remove();
});
div.innerHTML = `<div><span class="content">${content}</span><span class="date">${d.toLocaleString()}</span></div>`;
div.appendChild(deleteBtn);
return div;
}
5 美食蛋白质揭秘¶
async function fetchData() {
let res;
// TODO:待补充代码
await fetch(MockURL)
.then((response) => response.json())
.then((data) => {
res = data;
})
.catch((error) => console.error("Error:", error));
const container = document.querySelector(".protein-container");
let cont = res.reduce(
(prev, now) =>
prev +
`<div class="protein-item">${now.name} ${now.value}</div>`,
``
);
container.innerHTML = cont;
// 记得echartsInit的第一个数据要是这个:
res.unshift({ name: "表头", icon: "none" })
echartsInit(res);
}
fetchData();
6 营业状态切换¶
function useToggle(state) {
// TODO:待补充代码
const isWorking=ref(state)
const toggleWorking=()=>{
isWorking.value=! isWorking.value
}
return [isWorking, toggleWorking]
}
7. 小说阅读器¶
// run/index.js
const fs = require("fs");
//读取txt小说文件
let readFilePath = "./run/book.txt";
let writeFilePath = "./run/book.json";
let options = "UTF-8";
//请按照要求修改一下两个函数内容。
// run/index.js
//读取txt小说文件,并按对应数据格式返回。
const readFile = (file) => {
//TODO:待补充代码
try {
const book = fs.readFileSync(file).toString()
// 分割字符串 + 去掉两边空字符 + 移除空行
const list = book.split(/\r\n/g).map(t => t.trim()).filter(t => !!t)
const res = { name: list[0], data: []}
const rollReg = /^---([^-]+?)---$/
let i = 2
while (i < list.length) {
let s = list[i]
if (rollReg.test(s)) { // 卷
res.data.push({ isRoll: true, title: rollReg.exec(s)[1] })
} else { // 章节
const j = i + 1
while (i < list.length && list[i] !== '------------') i++
res.data.push({ title: s, content: list.slice(j, i) })
}
i++
}
let result = JSON.stringify(res);
return result;
} catch (err) {
return null;
}
};
//写入json文件中
const writeFile = (file, data) => {
//TODO:待补充代码
fs.writeFileSync(file, data)
};
//以下内容请勿修改,否则将影响结果
let data = readFile(readFilePath);
if (data != null) writeFile(writeFilePath, data);
module.exports = {
writeFile,
readFile,
};
//component
next(value) {
// TODO:待补充代码
let now = this.activeChapter + value;
if(this.chapters[now].isRoll){
now+=value
}
let rollCount = 0;
this.chapters.forEach((element) => {
if (element.isRoll) rollCount++;
});
// console.log(rollCount);
if (now < 1 || now > this.chapters.length - rollCount) return;
else this.activeChapter=now
},
created() {
// TODO:待补充代码
axios("../run/book.json").then((data) => {
// console.log(data);
this.bookName = data.data.name;
this.chapters = data.data.data;
});
},
8. 冰岛人¶
这个没问题,但是过不去
/**
* @description 通过输入的两个人的姓名返回相应的字符串
* @param {array} data 当地的人口信息
* @param {string} name1 要查询的两人名字之一
* @param {string} name2 要查询的两人名字之一
* @return {string} 根据被查询两人的名字返回对应的字符串
* */
function marry(data, name1, name2) {
// TODO:补充代码,实现目标效果
let [firstName1, lastName1] = name1.split(" ");
let [firstName2, lastName2] = name2.split(" ");
// 检查是否都在名单里
const isExist = (name1, name2) => {
for (const item of data) {
if (item.givenName === name1 && item.familyName.indexOf(name2) === 0) {
return true;
}
}
return false;
};
if (!isExist(firstName1, lastName1) || !isExist(firstName2, lastName2)) {
return "NA";
}
// 检查是否为同性
let genderValue = 0;
const checkGender = (name1, name2) => {
for (const item of data) {
if (item.givenName === name1 && item.familyName.indexOf(name2) === 0) {
let gender = item.familyName.slice(
name2.length,
item.familyName.length
);
if (gender === "sson") genderValue += 1;
else if (gender === "sdottir") genderValue += 2;
}
}
};
checkGender(firstName1, lastName1)
checkGender(firstName2, lastName2)
if(genderValue != 3) return "Whatever"
}
module.exports = marry;
这是大佬写的题解,可以过去
function marry(data, name1, name2) {
let [na1, na2] = [name1.split(' '), name2.split(' ')];
let givenArr = Array.from(data,({ givenName }) => givenName);
if(!givenArr.includes(na1[0]) || !givenArr.includes(na2[0])) return 'NA'
let {givenName:gn1, familyName:fn1} = data.find((a)=>a.givenName===na1[0])
let {givenName:gn2, familyName:fn2} = data.find((a)=>a.givenName===na2[0])
let g1 = fn1.endsWith('sson') || fn1.endsWith('m') ? 'M' : 'F',
g2 = fn2.endsWith('sson') || fn2.endsWith('m') ? 'M' : 'F';
if(g1 === g2) return 'Whatever';
function findAncestor(g, f, generation, ance = []) {
if (generation >= 3 || !g) return null; // 出口
let parentName = f.replace(/sson|sdottir/, '');
let {givenName:gn, familyName:fn} = data.find(p => p.givenName === parentName);
if (gn) ance.push(gn+fn);
return findAncestor(gn, fn, generation + 1, ance);
}
// 获取两个人的祖先列表
let ancestors1 = [], ancestors2 = [];
findAncestor(gn1, fn1, 0, ancestors1);
findAncestor(gn2, fn2, 0, ancestors2);
// 检查是否有共同的祖先
console.log(ancestors1, ancestors2)
let commonAncestor = ancestors1.some(ancestor => ancestors2.includes(ancestor));
return commonAncestor ? 'No' : 'Yes';
}
module.exports = marry;
9 这是一个“浏览器”¶
// 1.切换功能
toggleTab(that) {
// TODO: 添加代码,点击标签页,切换到对应标签页的功能
that.clearClass()
this.classList.add("liactive");
that.sections[this.index].classList.add("conactive");
// console.log(this.index);
// TODO结束
}
// 2.清空所有标签页及其内容页类名
clearClass() {
for (var i = 0; i < this.lis.length; i++) {
this.lis[i].className = "";
this.sections[i].className = "";
}
}
// 3.添加标签页
addTab(that) {
// TODO:添加代码,当点击加号,添加新的标签页(对应的内容页也应一并添加)
let newLi = document.createElement('li')
newLi.innerHTML = `<span class="content">标签页${that.lis.length + 1}</span>
<span class="iconfont icon-guanbi">
<span class="glyphicon glyphicon-remove"></span>
</span>`
that.ul.appendChild(newLi)
let newSection = document.createElement('section')
newSection.innerText = `标签页${that.lis.length + 1}的内容`
that.fsection.appendChild(newSection)
that.init()
that.clearClass()
that.lis[that.lis.length - 1].classList.add('liactive')
that.sections[that.lis.length - 1].classList.add('conactive')
// TODO结束
}
// 4.删除功能
removeTab(that, e) {
// 阻止冒泡,不然会触发toggleTab
e.stopPropagation();
let index = this.parentNode.index, flag = 0;
if (that.lis[index].classList.value) {
// 删除的标签页是当前选中的标签页
if (index === that.lis.length - 1) {
flag = -1
} else {
flag = 1
}
that.lis[index + flag].classList.add('liactive')
that.sections[index + flag].classList.add('conactive')
}
that.lis[index].remove()
that.sections[index].remove();
that.init();
for (let i = index; i < that.lis.length; i++) {
that.lis[i].children[0].innerText = `标签页${i+1}`
that.sections[i].innerText = `标签页${i+1}的内容`
// console.log(that.lis[i].children[0].innerText);
}
}
// 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:实现双击修改内容,当文本框失焦时,把修改的值赋给被双击的对象,并作上已修改的标记
// console.log(this);
input.addEventListener("blur", (e) => {
this.innerHTML = input.value;
});
// TODO结束
}
10 趣味加密解密¶
/*
加密函数 encryption 接受两个参数 plainText 和 codes ,能够实现对明文的加密,并返回加密后的密文字符串。
函数参数 plainText 是用户输入的明文,类型为 String 字符串。
函数参数 codes 是用户输入的密码表,类型也为 String 字符串,并且可能存在重复字符,需要进行去重
若去重后 codes 长度小于 2 则应采用默认密码表 defaultCodes 。
*/
function encryption(plainText, codes) {
//TODO
let plainArray = string2Unit8Array(plainText);
// 需要使用去重后的密钥
console.log(plainArray);
codes = [...new Set(codes)].join("");
if (codes.length < 2) codes = defaultCodes;
// 4. 单位长度:log length(code)(256)=2
let len = Math.ceil(Math.log(256) / Math.log(codes.length));
let dive = codes.length;
let ans = [];
for (let i = 0; i < plainArray.length; i++) {
let stringTemp = "";
for (let idx = 0; idx < len; idx++) {
stringTemp = codes[plainArray[i] % dive] + stringTemp;
plainArray[i] /= dive;
}
ans.push(stringTemp);
}
return ans.map((str) => str.split("").reverse().join("")).join("");
}
/*
加密函数 decryption 接受两个参数 cipherText 和 codes ,能够实现对密文的解密,并返回解密之后的明文字符串。
函数参数 cipherText 是用户输入的密文,类型为 String 字符串。
函数参数 codes 是用户输入的密码表,类型也为 String 字符串,并且可能存在重复字符,需要进行去重
若去重后 codes 长度小于 2 则应采用默认密码表 defaultCodes 。
*/
function decryption(cipherText, codes) {
//TODO
codes = [...new Set(codes)].join("");
if (codes.length < 2) codes = defaultCodes;
let len = Math.ceil(Math.log(256) / Math.log(codes.length));
let dive = codes.length;
if (cipherText.length % len) return "ERROR";
let cipherArray = [];
for (let i = 0; i < cipherText.length; i+=len) {
cipherArray.push(cipherText.slice(i,i+len).split('').join(''))
// 不必加reverse,方便下面计算
// cipherArray.push(cipherText.slice(i,i+len).split('').reverse().join(''))
}
console.log(cipherArray);
let ans=[]
cipherArray.forEach((item)=>{
let ansTmp=0
for (let idx = 0; idx < len; idx++) {
ansTmp+=codes.indexOf(item[idx]) * dive**idx
// debugger
}
ans.push(ansTmp)
})
console.log(ans);
return uint8Array2String(ans)
}
/*
调用 encryption("你好,世界","0123456789ABCDEF") 方法,应当返回密文 "4EDB0A5E5ADBFECBC84E8B697E59C8" 。
调用 decryption("4EDB0A5E5ADBFECBC84E8B697E59C8","0123456789ABCDEF") 方法,应当返回明文 "你好,世界" 。
*/
//以下代码请勿删除,否则可能导致检测不通过
export { defaultCodes, encryption, decryption };
11 嘟嘟购物¶
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="./css/element-plus@2.3.7/index.css" />
<link rel="stylesheet" href="./css/index.css" />
<script src="./lib/vue.min.js"></script>
<script src="./css/element-plus@2.3.7/index.full.js"></script>
<script src="./lib/axios.js"></script>
<script src="./lib/vueDemi.js"></script>
<script src="./lib/pinia.min.js"></script>
<script src="./js/store.js"></script>
<title>嘟嘟购物</title>
</head>
<body>
<div id="app">
<div class="c-container">
<div class="w">
<div class="cart-filter-bar">
<em>全部商品</em>
</div>
<!-- 购物车主要核心区域 -->
<div class="cart-warp">
<div class="cart-thead">
<div class="t-checkbox"></div>
<div class="t-goods">商品</div>
<div class="t-price">单价</div>
<div class="t-num">数量</div>
<div class="t-sum">小计</div>
<div class="t-action">操作</div>
</div>
<!-- 商品详细模块 -->
<div class="cart-item-list">
<div class="cart-item check-cart-item" v-for="item in goodsCart">
<div class="p-checkbox">
<input
type="checkbox"
v-model="item.checked"
:name="item.name"
:id="item.id"
class="j-checkbox"
/>
</div>
<div class="p-goods">
<div class="p-img">
<img :src="item.image" alt="" />
</div>
<div class="p-msg">{{item.name}}</div>
</div>
<div class="p-price">{{item.price}}</div>
<div class="p-num">
<div class="quantity-form">
<a
href="javascript:;"
class="decrement"
@click="edit(item.id,-1)"
>-</a
>
<input type="text" class="itxt" v-model="item.num" />
<a
href="javascript:;"
class="increment"
@click="edit(item.id,1)"
>+</a
>
</div>
</div>
<div class="p-sum">{{(item.num*item.price).toFixed(2)}}</div>
<div class="p-action"><a href="javascript:;">删除</a></div>
</div>
</div>
<!-- 结算模块 -->
<div class="cart-floatbar">
<div class="select-all"></div>
<div class="toolbar-right">
<div class="amount-sum">
已经选<em>{{total.number}}</em>件商品
</div>
<div class="price-sum">总价: <em>¥{{total.price}}</em></div>
<div class="btn-area" @click="submit">去结算</div>
</div>
</div>
</div>
</div>
</div>
</div>
</body>
<script type="module">
const { createApp, ref, onMounted, computed } = Vue;
const { createPinia } = Pinia;
const { ElMessage, ElNotification } = ElementPlus;
const app = Vue.createApp({
setup() {
// TODO:补充代码,实现目标效果
let goodsCart = ref([]);
let detail = [];
let goodsStore = useGoodsStore();
const edit = (id, step) => {
let target = goodsCart.value.find((item) => item.id === id);
if (target.num === 1 && step === -1) return;
target.num += step;
};
const total = computed(() => {
const tmp = {
number: 0,
price: 0,
};
goodsCart.value.forEach((item) => {
if (item.checked) {
tmp.number += item.num;
tmp.price += item.num * item.price;
}
});
return tmp;
});
const submit = () => {
if (goodsCart.value.every((item) => !item.checked)) {
ElMessage({
message: "请至少选择一件商品",
type: "warning",
});
return;
}
// 模拟发送请求获取所有商品的库存:
let stock = [];
goodsCart.value.forEach((item) => {
if (item.checked) {
goodsStore
.fetchInventory(item.name)
.then((res) => {
console.log(res);
stock.push({
id: item.id,
stock: res,
});
})
.catch((res) => {
console.log(res);
ElMessage({
message: `结算失败,${res}`,
type: "error",
});
});
}
});
// 库存
goodsCart.value
.filter((item) => item.checked)
.forEach((item) => {
stock.forEach((store) => {
if (store.id === item.id && store.stock < item.num) {
ElMessage({
message: `结算失败,${item.name}库存不足`,
type: "error",
});
return;
}
});
});
ElMessage({
message: `结算成功`,
type: "success",
});
// 发送
};
const getAxios = async () => {
await axios("./js/goods.json").then((res) => {
detail = res.data;
});
goodsStore.store.forEach((item) => {
if (item.stock) {
goodsCart.value.push({
id: item.id,
name: item.name,
});
}
});
goodsCart.value.forEach((item) => {
for (let priceImage of detail) {
if (priceImage.id === item.id) {
item.price = priceImage.price;
item.image = priceImage.image;
item.checked = false;
item.num = 1;
}
}
});
// console.log(goodsCart.value);
};
onMounted(getAxios);
return {
goodsCart,
edit,
total,
submit,
};
// TODOEnd
},
});
app.use(ElementPlus);
app.use(createPinia());
app.mount("#app");
</script>
</html>
<div v-for="item in carList" class="cart-item check-cart-item">
<div class="p-checkbox">
<input v-model="item.checked" type="checkbox" name="" id="" class="j-checkbox">
</div>
<div class="p-goods">
<div class="p-img">
<img :src="item.image" alt="">
</div>
<div class="p-msg">{{item.name}}</div>
</div>
<div class="p-price">{{item.price}}</div>
<div class="p-num">
<div class="quantity-form">
<a href="javascript:;" @click="Edit(item.id,0)" class="decrement" >-</a>
<input type="text" v-model="item.num" class="itxt">
<a href="javascript:;" @click="Edit(item.id,1)" class="increment" >+</a>
</div>
</div>
<div class="p-sum">{{(item.num*item.price).toFixed(2)}}</div>
<div class="p-action"><a href="javascript:;">删除</a></div>
</div>
<!-- 结算模块 -->
<div class="cart-floatbar">
<div class="select-all">
</div>
<div class="toolbar-right">
<div class="amount-sum">已经选<em>{{Total.select}}</em>件商品</div>
<div class="price-sum">总价: <em>¥{{Total.price}}</em></div>
<div class="btn-area" @click="comMit">去结算</div>
</div>
</div>
<script type="module">
const { createApp,reactive,onMounted,computed} = Vue
const { createPinia } = Pinia
const { ElMessage, ElNotification } = ElementPlus
const app = Vue.createApp({
setup() {
// TODO:补充代码,实现目标效果
let store=useGoodsStore();
let carList=reactive([])
let Edit=(id,type)=>{
carList.map(e=>{
if(e.id==id){
e.num=type==1?e.num+1:e.num-1
e.num=e.num<1?1:e.num
}
})
}
let comMit=async()=>{
let commit=carList.filter(s=>s.checked)
if(commit==null || commit.length==0){
ElMessage({
message: `请至少选择一件商品`,
type: 'warning',
})
}
for (let index = 0; index < commit.length; index++) {
const e = commit[index];
let a= await store.fetchInventory(e.name)
if(a<e.num){
ElMessage({
message: `结算失败,${e.name}库存不足`,
type: 'error',
})
break;
}else if(index==commit.length-1){
ElMessage({
message: `结算成功`,
type: 'success',
})
}
}
}
let Total= computed(()=>{
return {
select:carList.reduce((pre,e)=>{return pre+(e.checked*e.num)},0),
price:carList.reduce((pre,e)=>{return pre+(e.checked?e.price*e.num:0)},0).toFixed(2),
}
})
onMounted(async()=>{
axios.get('./js/goods.json')
.then(r=>{
let data=r.data
data.forEach(element => {
let stock= store.store.find(s=>s.id==element.id).stock
element.num=1
element.checked=false
if(stock!=0){
carList.push(element)
}
});
})
})
return {
store,
carList,
Total,
Edit,
comMit
}
// TODOEnd
},
});