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;
border-radius: 10px; /* 设置圆角为 10px */
background-image: url('../images/woodiness.jpg'); /* 设置背景图片为 woodiness.jpg */
}
.top-sign {
position: relative;
width: 200px;
height: 100px;
background-color: #a87f4a;
display: flex;
justify-content: center;
align-items: center;
font-size: 1rem;
border-top-left-radius: 15px; /* 设置上左角为圆角 15px */
border-top-right-radius: 15px; /* 设置上右角为圆角 15px */
transform: skewX(-20deg); /* 在 x 轴方向倾斜元素 20度 */
}
2、原子化CSS 的代码
直接在css下面加个flex弹性布局的操作,然后竖着。
/* TODO: 实现原子化 flex */
div {
display: flex;
flex-direction: column;
}
3、神秘咒语
简单的token操作,axios知识点,请求的时候在请求头带上token,就可以顺利请求访问到。
// TODO:新增或者修改以下代码
let token = '2b58f9a8-7d73-4a9c-b8a2-9f05d6e8e3c7';
key1Button.addEventListener('click', async () => {
// 从后台请求钥匙1的咒语部分
key1Button.disabled = true;
let {data} = await axios.get('/spellone', {headers: {'Authorization': token}})
spell1.innerHTML = data;
tryOpenTreasureBox();
});
key2Button.addEventListener('click', async () => {
// 从后台请求钥匙2的咒语部分
key2Button.disabled = true;
let {data} = await axios.get('/spelltwo', {headers: {'Authorization': token}})
spell2.innerHTML = data;
tryOpenTreasureBox();
});
4、朋友圈 代码:
防抖考了,会不会在真题的时候考节流。。。
JS练习题
document.addEventListener("DOMContentLoaded", function() {
let textContent = localStorage.getItem('savedText');
document.getElementById('text').value = textContent;
show()
});
document.getElementById("text").addEventListener(
"input",
debounce(function() {
document.getElementById("prompt").textContent = "正在保存中...";
let textContent = document.getElementById('text').value;
localStorage.setItem('savedText', textContent);
show()
setTimeout(function() {
document.getElementById("prompt").textContent = "内容已保存";
}, 750);
}, 200)
);
document.getElementById("post").addEventListener("click", function() {
const content = document.getElementById("text").value;
// 假设 createContent 是一个已定义的函数,用于创建表示内容的DOM元素
const element = createContent(content);
document.querySelector(".contents").appendChild(element);
document.getElementById("prompt").textContent = "发表成功!";
document.getElementById("text").value = '';
localStorage.removeItem('savedText');
show()
});
// 防抖工具函数
/**
* @param {function} fn - 回调函数
* @param {string} delay - 函数执行延迟,单位为ms
*/
function debounce(fn, delay) {
// return fn; // 这一行是为了确保页面正常运行,可以去掉
let timer = null;
return function () {
if (timer) {
clearTimeout(timer);
}
timer = setTimeout(() => {
fn();
}, delay);
}
// TODO: 请实现函数防抖的功能
}
function show(){
if (document.getElementById("text").value !== '') {
document.getElementById("post").removeAttribute('disabled');
} else {
document.getElementById("post").setAttribute('disabled', 'disabled');
}
}
// 用户点击“发表”后,创建一条新信息的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、美食蛋白质揭秘 代码:
JS原生ajax请求 )xhr = new XMLHttpRequest();
open("请求方式","请求路径“);
用onload加载一次就行了,补充一个就是
- onreadystatechange
- 当 readyState 属性发生变化时,调用的事件处理器。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>不同食物的蛋白质占比</title>
<script src="./lib/vue3.global.js"></script>
<script src="./lib/echarts.min.js"></script>
<link rel="stylesheet" href="css/style.css" />
</head>
<body>
<div id="app">
<h2>不同食物的蛋白质占比</h2>
<div class="protein-container">
<!-- TODO:待补充代码,渲染获取的数据 -->
</div>
<div class="echarts" id="main"></div>
</div>
<script>
const { ref, onMounted } = Vue;
const MockURL = "./mock/data.json";
const app = {
setup() {
function echartsInit(data) {
const main = document.getElementById("main");
const myChart = echarts.init(main);
myChart.setOption({
legend: {
data: data,
orient: "vertical",
top: "26%",
right: "2%",
icon: "circle",
textStyle: {
fontSize: 20,
rich: {
one: {
width: 80,
},
two: {
width: 80,
},
three: {
width: 80,
},
},
},
formatter: (name) => {
var total = 0;
var target;
let formateData = data;
for (var i = 0; i < formateData.length; i++) {
if (formateData[i].value) {
total += formateData[i].value;
if (formateData[i].name === name) {
target = formateData[i].value;
}
}
}
var v = ((target / total) * 100).toFixed(2);
let row;
if (name === "表头") row = `食物 含量 占比`;
else row = `{one|${name}} {two|${target}} {three|${v}%}`;
return row;
},
},
color: ["#baf", "#bfa", "#cde", "#f90", "#0c9"],
series: [
{
type: "pie",
radius: ["30%", "50%"],
center: ["32%", "40%"],
data: data,
},
],
});
}
async function fetchData() {
// TODO:待补充代码
let FoodArray = [];
let xhr = new XMLHttpRequest();
xhr.open("GET", MockURL);
xhr.onload = function () {
if (this.status == 200) {
FoodArray = JSON.parse(this.responseText); //这个需要转换一下 因为是JSON格式转换为js对象
let NewFoodArray = [
{ name: "表头", icon: "none" },
]
for (const item of FoodArray) {
NewFoodArray.push(item)
}
// console.log(NewFoodArray);
echartsInit(NewFoodArray) //直接在里面调用就行了
for (const item of FoodArray) {
let div = document.createElement("div");
div.innerHTML = `${item.name} ${item.value}`;
div.className= 'protein-item'
let content =
document.getElementsByClassName("protein-container")[0];
content.appendChild(div);
}
} else {
console.log("请求失败:" + this.status);
}
};
xhr.send();
}
fetchData();
return {
echartsInit,
};
},
};
const vm = Vue.createApp(app);
const mountedApp = vm.mount("#app");
</script>
</body>
</html>
6、营业状态切换
其实就是 自定义一个东西 只不过这里的返回是需要对应上,要记得;
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>营业状态切换</title>
<script src="./lib/vue.global.js"></script>
<!-- 引入Vue.js库 -->
<link rel="stylesheet" href="./css/style.css" />
<!-- 引入样式表 -->
</head>
<body>
<div id="app">
<div class="header">
<h1>营业状态切换</h1>
<!-- 页面标题 -->
</div>
<!-- 显示店铺状态 -->
<p>当前店铺状况: {{ isWorking ? '营业中' : '已打烊' }}</p>
<!-- 根据状态显示相应的图片 -->
<img :src="isWorking ? workImage : restImage" alt="Status Image" />
<!-- 切换店铺状态的开关按钮 -->
<div
class="switch"
@click="toggleWorking"
:class="{ 'switch-on': isWorking }"
>
<span class="switch-inner"></span>
</div>
</div>
<script setup>
const { ref } = Vue; // 引入Vue中的ref函数
function useToggle(state) {
// TODO:待补充代码
let s1 = ref(state);
function s2() {
//调用这里的函数 返回 isWorking 为true 就得到workImage
s1.value = !s1.value;
}
return [s1, s2]; //如果报错 那么就是返回值的问题了
}
const app = Vue.createApp({
setup() {
const [isWorking, toggleWorking] = useToggle(false); // 使用自定义的useToggle函数创建状态和切换函数
const workImage = "./images/open.jpg"; // 营业状态的图片路径
const restImage = "./images/close.jpg"; // 打烊状态的图片路径
return {
isWorking,
toggleWorking,
workImage,
restImage,
};
},
});
app.mount("#app"); // 将Vue应用挂载到id为app的元素上
</script>
</body>
</html>
7、嘟嘟购物 :
这里就是vue3的练习,职业组的一道题,大学组的是一道node题。
就是Pinia和vue3。WatchEffect监听 只要里面的响应式发生变化就会调用一次,还有在页面开始也会调用一次,至于Pinia,直接调用就行了,这里是非工程文件,已经有script引入了Pinia
<!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,index) in goodsArray"
:key="item.id"
>
<div class="p-checkbox">
<input
type="checkbox"
name=""
id=""
class="j-checkbox"
@change="updateCheckedState($event,index)"
/>
</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="decrement(index)"
>-</a
>
<input type="text" class="itxt" :value="item.priceCount" />
<a href="javascript:;" class="increment" @click="add(index)"
>+</a
>
</div>
</div>
<div class="p-sum">
{{(item.price * item.priceCount).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>{{ selectdItemCount }}</em>件商品
</div>
<div class="price-sum">
总价: <em>¥{{ totalItemPrice }}</em>
</div>
<div class="btn-area" @click="submit">去结算</div>
</div>
</div>
</div>
</div>
</div>
</div>
</body>
<script type="module">
const { createApp, onMounted, watchEffect } = Vue;
const { createPinia } = Pinia;
const { ElMessage, ElNotification } = ElementPlus;
const app = Vue.createApp({
setup() {
// TODO:补充代码,实现目标效果
const goodsStock = Array.from(useGoodsStore().store);
const goodId = [];
const goodsArray = ref([]);
const priceCount = ref(1);
for (const item of goodsStock) {
//这个是判断有没有货的操作
if (item.stock !== 0) {
goodId.push(item.id);
} else {
goodId.push(-1);
}
}
const getGoods = () => {
axios.get("./js/goods.json").then((res) => {
const tempArray = [];
// console.log(goodId); //有货的id 没货的id为 -1
for (let i = 0; i < res.data.length; i++) {
if (res.data[i].id === goodId[i]) {
tempArray.push(res.data[i]);
}
}
goodsArray.value = tempArray;
for (const item of goodsArray.value) {
item.priceCount = 1; //默认为1
item.checked = false; //checked按钮默认为false
}
console.log(goodsArray.value);
});
};
const add = (index) => {
goodsArray.value[index].priceCount++;
};
const decrement = (index) => {
if (goodsArray.value[index].priceCount === 1) {
return;
}
goodsArray.value[index].priceCount--;
};
const updateCheckedState = (event, index) => {
//给到响应式数组里面
goodsArray.value[index].checked = event.target.checked;
};
const selectdItemCount = ref(0);
const totalItemPrice = ref(0);
watchEffect(() => {
//就是这里面的响应式发生变化 就会触发watchEffect()
selectdItemCount.value = 0;
totalItemPrice.value = 0;
for (const item of goodsArray.value) {
if (item.checked === true) {
selectdItemCount.value += item.priceCount;
totalItemPrice.value += item.priceCount * item.price;
}
}
totalItemPrice.value = totalItemPrice.value.toFixed(2);
});
//若没有选择商品
const shopNoSelect = () => {
for (const item of goodsArray.value) {
if (item.checked === true) {
return true;
}
}
return false; //如果没有一个true就返回false
};
const submit = async () => {
//提交结算
try {
if (!shopNoSelect()) {
//则提示警告信息:
ElMessage({
message: "请至少选择一件商品",
type: "warning",
});
}
for (const item of goodsArray.value) {
console.log(item.priceCount);
if (item.checked === true) {
let goodsNamePriceCount = await useGoodsStore().fetchInventory(
item.name
);
console.log(goodsNamePriceCount);
if (item.priceCount > goodsNamePriceCount) {
ElMessage.error(`结算失败,${item.name}库存不足`);
return;
}
}
}
ElMessage({
message: "结算成功",
type: "success",
});
} catch (error) {
ElMessage.error(`结算失败,${请求返回的错误信息}`);
}
};
onMounted(() => {
//页面渲染之后,直接调用
getGoods(); //调用
});
return {
//在这个非工程文件当中的vue3 都是需要return一下的
goodsArray,
priceCount,
add,
decrement,
selectdItemCount,
totalItemPrice,
updateCheckedState,
submit,
};
// TODOEnd
},
});
app.use(ElementPlus);
app.use(createPinia());
app.mount("#app");
</script>
</html>
8、冰岛人:
我这种方法是比较简单的 其实还可以用map集合或者 递归 他这里说五代人 并不包含第五代人。
/**
* @description 通过输入的两个人的姓名返回相应的字符串
* @param {array} data 当地的人口信息
* @param {string} name1 要查询的两人名字之一
* @param {string} name2 要查询的两人名字之一
* @return {string} 根据被查询两人的名字返回对应的字符串
* */
function marry(data, name1, name2) {
// TODO:补充代码,实现目标效果
console.log(data); //和NameAll是对应的
let data2 = deepCopy(data);
console.log(data2);
const NameAll = [];
for (let i = 0; i < data2.length; i++) {
NameAll.push(`${data2[i].givenName} ${removeSuffix(data2[i].familyName)}`);
}
console.log(NameAll); // 和data是对应,就是去掉了后面的尾缀
//查询其中一人是否在名单中
const person1 = NameAll.findIndex((name) => name == name1);
const person2 = NameAll.findIndex((name) => name == name2);
console.log(person1);
console.log(person2);
if (person1 == -1 || person2 == -1) {
return "NA";
}
//直接判断性别
const gender1 = getGender(data2[person1].familyName);
const gender2 = getGender(data2[person2].familyName);
if (gender1 === gender2) {
return "Whatever";
}
let nameObj1 = data2[person1];
let nameObj2 = data2[person2];
//前面的代码都已经拦截完毕了,现在开始直接进入查找就行了
//april mikesdottir 和 steve billsson 是no
//april mike 和 steve bill 是 no
if (hasCommonAncestor(data2, nameObj1, nameObj2)) {
return "No";
} else {
return "Yes";
}
}
//深拷贝
function deepCopy(obj) {
if (typeof obj !== 'object' || obj === null) {
return obj;
}
let copy = Array.isArray(obj) ? [] : {};
for (let key in obj) {
if (Object.prototype.hasOwnProperty.call(obj, key)) {
copy[key] = deepCopy(obj[key]);
}
}
return copy;
}
function hasCommonAncestor(data, name1, name2) {
const ancestors1 = computeAncestors(data, name1);
const ancestors2 = computeAncestors(data, name2);
if (ancestors1 == ancestors2) {
return true;
}
return false;
}
//找到最后的祖先
function computeAncestors(data, name) {
//先切割掉 sson和sdottir 不要割掉 m 和 f 知道是祖宗
for (let i = 0; i < data.length; i++) {
data[i].familyName = removeSuffix2(data[i].familyName);
}
let ancestor = null; //设置祖先变量
// console.log(name.familyName == data[7].givenName);
for (let i = 0; i < data.length; i++) {
if (data[i].givenName == name.familyName) {
if (data[i].familyName.charAt(data[i].familyName.length - 1) == 'm') {
ancestor = data[i].givenName;
break;
}
for (let j = 0; j < data.length; j++) {
if (data[j].givenName == data[i].familyName) {
if (data[j].familyName.charAt(data[j].familyName.length - 1) == 'm') {
ancestor = data[j].givenName;
break;
}
for (let k = 0; k < data.length; k++) {
if (data[k].givenName == data[j].familyName) {
ancestor = data[k].givenName;
}
}
}
}
}
}
console.log(ancestor);
return ancestor
}
//递归
/**
* 查询冰岛人名的性别的函数
* @param {String} name 传递进来的冰岛人名
* @return {String} 返回男是 male 女的是female
*/
function getGender(name) {
if (name.endsWith("sson") || name.endsWith("m")) {
return "male"; //男
} else if (name.endsWith("sdottir") || name.endsWith("f")) {
return "female"; //女
}
}
// 使用正则表达式匹配字符串结尾的 'sson'、'sdottir'、'm' 或 'f' 并替换为 ''
function removeSuffix(name) {
return name.replace(/(sson|sdottir|m|f)$/, "");
}
// 使用正则表达式匹配字符串结尾的 'sson'、'sdottir'并替换为 ''
function removeSuffix2(name) {
return name.replace(/(sson|sdottir)$/, "");
}
module.exports = marry;
9、这是一个“浏览器”
也是纯粹的JS题,功能是实现了,但是不知为啥过不了检测。
"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和section
updateNode() {
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 + 1
newTab.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");