1.分一分
如果给你一个数组,你能很快将它分割成指定长度的若干份吗?
1.1 题目问题
请在 js/index.js
文件中补全函数 splitArray
中的代码,最终返回按指定长度分割的数组。
具体要求如下:
- 将待分割的(一维)数组升序排序。
- 将排序后的数组从下标为 0 的元素开始,按照从
id=sliceNum
的输入框中获取到的数值去分割,并将分割好的数据存入一个新数组中。如:输入框中值为 n,将原数组按每 n 个一组分割,不足 n 个的数据为一组。 - 将得到的新数组返回(即
return
一个二维数组)。
例如:
var arr = [3, 1, 4, 2, 5, 6, 7];
// 分割成每 1 个一组
var newA = splitArray(arr, 1);
console.log(newA); // => [[1],[2],[3],[4],[5],[6],[7]]
// 分割成每 2 个一组
newA = splitArray(arr, 2);
console.log(newA); // => [[1,2],[3,4],[5,6],[7]]
// 分割成每 4 个一组
newA = splitArray(arr, 4);
console.log(newA); // => [[1,2,3,4],[5,6,7]]
// 分割成每 7 个一组
newA = splitArray(arr, 7);
console.log(newA); // => [[1,2,3,4,5,6,7]]
上述仅为示例代码,判题时会随机提供数组对该函数功能进行检测。
完成后的效果见文件夹下面的 gif 图,图片名称为 effect.gif
(提示:可以通过 VS Code 或者浏览器预览 gif 图片)。
1.2 题目分析
排序可以使用数组的sort方法
完成分割可以使用数组的slice方法做成切片然后push到需要返回的数组中去
1.3 题目解答
const splitArray = (oldArr, num) => {
// TODO:请补充代码实现功能
let newArr = []
oldArr.sort((a, b) => a - b)
for(let i = 0 ; i < oldArr.length; i += num){
const a = oldArr.slice(i, num+i)
newArr.push(a)
}
return newArr
}
2.新鲜的蔬菜
厨房里新到一批蔬菜,被凌乱地堆放在一起,现在我们给蔬菜分下类,把相同的蔬菜放到同一个菜板上,拿给厨师烹饪美味佳肴吧。
2.1 题目问题
完成 css/style.css
中的 TODO 部分。所有元素的大小都已给出,无需修改,
完成后效果如下(图中灰色线条为布局参考线无需实现):
2.2 题目分析
本题主要是考察了对flex布局的应用,以及结构伪类选择器的使用
2.3 题目解答
/* TODO:待补充代码 */
#box1{
display: flex;
justify-content: center;
align-content: center;
flex-wrap: wrap;
}
#box2{
display: flex;
justify-content: space-between;
}
#box2 .item:nth-child(2){
align-self: flex-end;
}
#box3 {
display: flex;
justify-content: space-evenly;
}
#box3 .item:nth-child(2){
align-self: center;
}
#box3 .item:nth-child(3){
align-self: flex-end;
}
3.水果消消乐
消消乐是一款益智类休闲游戏,在排队等待做核酸的时候可以打开手机玩一会,陪你度过这漫长且无聊的等待期。
3.1 题目问题
请完善 js/index.js
文件。
具体说明如下:
- 点击开始按钮后,该按钮被隐藏,方格上的图片显示后又隐藏。
- 点击方格,方格中的图片显示,页面显示两张图片后,比较图片是否相同。
- 如果图片上的水果相同,方格即可消除,并得 2 分;如果图片上的水果不相同,图片隐藏,并扣 2 分(分数可以为负数)。
- 在文本 “当前分数为:” 的冒号后面会实时统计当前的得分情况。
完成后的效果见文件夹下面的 gif 图,图片名称为 effect.gif
(提示:可以通过 VS Code 或者浏览器预览 gif 图片)。
3.2 题目分析
本题主要是利用事件监听,来控制元素的显示和隐藏
要注意的点是事件监听的事件对象e和如何获取子节点父节点等
以及两个水果相同的时候控制隐藏和消失的不是display而是visibility或者是opacity。因为display是直接相当于消除了该元素,会影响布局的结构,而visibility和opacity只是让这个元素单单的隐藏
3.3 题目解答
// TODO:请补充代码
function startGame() {
document.querySelector("#start").style.display = "none";
const img = document.querySelectorAll("img")
for(let i = 0; i < img.length; i++ ){
img[i].style.display= 'inline-block'
}
setTimeout(() => {
for(let i = 0; i < img.length; i++ ){
img[i].style.display= 'none'
}
}, 1000);
let count = 0
let alt = ''
let prevObj = null
let score = 0
const scoreobj = document.querySelector('#score')
const arr = document.querySelectorAll('.img-box')
for(let i = 0; i < arr.length; i++){
arr[i].addEventListener('click', (e) => {
if(count === 0 ){
prevObj = e.target
e.target.children[0].style.display= 'inline-block'
alt = e.target.children[0].alt
count = 1
}else{
e.target.children[0].style.display= 'inline-block'
setTimeout(() => {
if(e.target.children[0].alt === alt){
e.target.style.visibility = 'hidden'
prevObj.style.opacity = 0
count = 0
score += 2
scoreobj.innerHTML = `${score}`
}else{
prevObj.children[0].style.display = 'none'
e.target.children[0].style.display= 'none'
count = 0
score -= 2
scoreobj.innerHTML = `${score}`
}
}, 500)
}
})
}
}
4.用什么来做计算A
古以算盘作为计算工具。算盘常为木制矩框,内嵌珠子数串,定位拨珠,可做加减乘除等运算。站在前人的肩膀上,后人研究出计算器,便利了大家的生活,我们不用带着笨重的计算工具出门,打开手机上的计算器就可以了。
4.1 题目问题
请完善 js/index.js
文件,当鼠标点击计算器上的按钮时,能够正常进行计算。
具体说明如下:
- 点击按钮会在计算式子区域显示当前输入的计算式子,当点击等号(=) 后,在结果显示区域应该显示出正确的结果。
- 计算器需要具有加(+)、减(-)、乘(x)、除(÷)、开二次方(√)、重置(AC)、小数点(.)、括号运算这八个功能。
- 计算器的计算遵循四则混合运算的法则,括号的优先级最高,其次是乘除,加减的优先级最低。
效果说明如下:
- 能够正确进行加、减、乘、除的混合运算,样例如下所示:
- 能够正确进行开二次方,输入一个可以平方的数,点击开方(√)按钮即可在结果显示区域显示结果。如果输入的值是不能平方,结果显示 NaN,样例如下所示:
-
点击重置按钮(AC),可以清空计算式子显示区域和结果显示区域的值。
-
能够进行小数的加减乘除运算,样例如下所示:
完成后的效果见文件夹下面的 gif 图,图片名称为 effect.gif
(提示:可以通过 VS Code 或者浏览器预览 gif 图片)。
4.2 题目分析
本题最关键的核心就是eval函数。eval函数可以将传入的字符串变成代码去执行
其次就是判断字符串相等和一些字符串常用的方法
而解决开二次方,则需要用到JS内置的Math构造函数的sqrt()
4.3 题目解答
解法1
// TODO:请补充代码
const show1 = document.querySelector('#formula')
const show2 = document.querySelector('#result')
let process = ''
const button = document.querySelectorAll('.calc-button')
for ( let i = 0; i < button.length; i++ ) {
button[i].addEventListener('click', function (e) {
if(e.target.innerHTML === 'AC'){
show1.value = ''
process = ''
show2.value = ''
}else if(e.target.innerHTML === '='){
console.log(process);
show2.value = eval(process)
}else if(e.target.innerHTML === '÷'){
process += '/'
show1.value += e.target.innerHTML
}else if(e.target.innerHTML === 'x'){
process += '*'
show1.value += e.target.innerHTML
}else if(e.target.innerHTML === '√'){
console.log(eval(process));
if(eval(process) < 0 ){
show2.value = NaN
}
show2.value = Math.sqrt(eval(process))
}else{
show1.value += e.target.innerHTML
process += e.target.innerHTML
}
})
}
解法2
// TODO:请补充代码
const calculator = document.querySelector('.calculator');
// 事件委托(无需遍历所有按钮)
calculator.addEventListener('click', (event) => {
if (event.target.className == 'calc-button') {
// 当点击的是以下 3 种按钮时 需要做特殊处理。
switch(event.target.textContent) {
case '=' :
const resultStr1 = formula.value.replaceAll('x', '*').replaceAll('÷', '/');
result.value = eval(resultStr1);
return;
case 'AC' :
formula.value = '';
result.value = '';
return;
case '√' :
result.value = Math.sqrt(formula.value);
return;
}
formula.value += event.target.textContent;
}
});
5.开学礼物大放送
又是一年开学季,蓝桥为大家准备了开学礼物,想制作一个页面来宣传一下该活动。
5.1 题目问题
请完善 css/style.css
和 index.html
文件。
请根据 mark/preview
最终效果图和 mark/index.html
上的参数标注来完成页面布局。
效果图如下:
5.2 题目分析
看结构就知道考察了定位、flex方面的一些知识
5.3 题目解答
考察的只是简答的页面实现,每个人的实现方式不同,代码差异也很大,这里就不放代码了
6.权限管理
你有没有想过,在我们日常浏览的网页中,那些新闻或者商品内容是如何被输入到数据库中的呢?大家虽然没有用过,但是肯定听过“后台管理系统”,运营人员就是通过它将批量的商品上传到数据库并呈现在网页中的。那么随便一个人就可以通过该管理系统操作这些商品数据吗?当然不行,这就涉及到了权限管理问题。
6.1 题目问题
请在 js/index.js
文件中补全代码,最终实现管理用户权限的功能。
具体需求如下:
-
实现异步数据读取和渲染功能。
-
使用 ajax 异步获取
./js/userList.json
中的用户数据,并以正确的方式显示在页面下的用户权限表格中(注意:调试完成后请将请求地址写死为./js/userList.json
)。 -
页面初始化时,左边用户列表显示 7 个用户(页面数据和结构不能随意篡改),右边的管理员列表无选项。效果如下:
-
-
实现左/右单个、多个或全部互移功能。
- 选中任意一个或多个(按 Ctrl 键可多选)左/右边用户/管理员列表中的用户,并点击选中移动到右/左边按钮,即可将选中的用户/管理员移动至另一边的管理员/用户列表中。效果如下:
- 点击全部移动到右/左边按钮,则将左/右边用户/管理员列表中的用户全部移动到右/左边的管理员/用户列表中(即:左/右边列表被清空)。效果如下:
-
实现用户权限表格中的权限,随用户移动发生变化功能。
- 页面下的用户权限表格中所有用户的权限,会根据页面上方所处列表不同发生相应改变,即管理员列表中的用户权限为管理员,用户列表中的用户权限为普通用户。
完成后效果如下:
6.2 题目分析
本题主要考察了ajax进行请求数据的知识,我们可以用ajax中的xhr技术来完成
还考察了对文档对象模型的考察,以及操作节点
还有就是css的伪类选择器:checked
6.3 题目解答
$(function () {
// 使用 ajax 获取 userList.json 数据并渲染到页面
getData();
// 为按钮添加事件
$("#add").click(function () {
// TODO:补充代码,实现功能
changeAccess(true,document.querySelectorAll('#leftSelect>option:checked'))
});
$("#addAll").click(function () {
// TODO:补充代码,实现功能
changeAccess(true,document.querySelectorAll('#leftSelect>option'))
});
$("#remove").click(function () {
// TODO:补充代码,实现功能
changeAccess(false,document.querySelectorAll('#rightSelect>option:checked'))
});
$("#removeAll").click(function () {
// TODO:补充代码,实现功能
changeAccess(false,document.querySelectorAll('#rightSelect>option'))
});
});
/**
* 修改权限
* @param {Object} right 要修改的权限
* @param {Object} changeList 要修改权限的用户列表
*/
function changeAccess(right, changeList) {
// TODO:补充代码,实现功能
if(right) fn('#rightSelect')
else fn('#leftSelect')
function fn(who){
for(let i = 0;i<changeList.length;i++){
document.querySelector(who).appendChild(changeList[i])
const tr = document.querySelectorAll('#userList>tr')
tr.forEach(e=>{
if(e.firstChild.innerText==changeList[i].value){
e.lastChild.innerText = right?'管理员':'普通用户'
}
})
}
}
}
// 异步获取数据
function getData() {
// TODO:补充代码,实现功能
const xhr = new XMLHttpRequest();
xhr.open("GET", "./js/userList.json");
xhr.addEventListener("loadend", () => {
const res = JSON.parse(xhr.response)
// 一定要注意不能篡改页面数据结构,意思就是不能自己加表格的表头
// 因此就不要用map了
res.forEach(item => {
const tr = document.createElement('tr')
const power = item.right ? '管理员' : '普通用户'
tr.innerHTML = `<td>${item.name}</td><td>${power}</td>`
document.querySelector(".user-list").appendChild(tr)
})
});
xhr.send()
}
7.一起会议吧
网络会议已经成为当下最流行的会议模式,为网络会议提供支持的当然是一些优秀的会议软件。
1.1 题目问题
请在 index.html
文件中补全代码,最终实现网络会议中参会人员列表的几个展示效果。
具体需求如下:
-
实现异步数据读取和渲染功能。
-
使用 axios 异步获取
./js/userList.json
中的用户数据(注意:调试完成后请将请求地址写死为./js/userList.json
),并显示在登录窗口及参会人员窗口中。效果如下:
-
-
实现登录、注销切换功能。
- 在登录窗口选取用户登录后,登录窗口切换为注销窗口,具体变化为:登录标题变为注销字样;选择用户下拉框变为显示当前登录用户名;登录按钮变为注销按钮。参会人员窗口显示,并默认只显示当前登录用户信息。效果如下:
1.2 题目分析
computed中计算当前用户列表有哪些,返回一个数组,根据图标点击的状态筛选出相应的用户对象,状态改变了,就会重新计算。
1.3 题目解答
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>一起会议吧</title>
<link rel="stylesheet" type="text/css" href="./css/index.css" />
<link rel="stylesheet" href="./css/iconfont/iconfont.css" />
</head>
<body>
<div id="app">
<!-- TODO:请在下面实现需求 -->
<!-- 登录/注销窗口 -->
<div class="login">
<div class="left-tools">
<a class="close-btn"></a>
<a class="shrink-btn"></a>
</div>
<h3>{{ !isLogin ? '登录' : '注销' }}</h3>
<p v-if="!isLogin">
选择用户:<select id="selectUser" v-model="currentUser">
<option v-for="user in userList" :key="user.id" :value="user">{{ user.name }}</option>
</select>
</p>
<p v-if="isLogin">当前用户为:{{ currentUser.name }}</p>
<a class="login-btn" @click="handleLogin">{{ !isLogin ? '登录' : '注销' }}</a>
</div>
<!-- 右侧显示用户列表窗口按钮 -->
<button id="show" class="right-btn" v-if="isLogin" v-show="!isShow" @click="isShow = true">
<span class="iconfont icon-left-arrow"></span>
</button>
<!-- 用户列表窗口 -->
<div class="user-dialog" v-if="isLogin" v-show="isShow">
<!-- 用户列表窗口上侧工具栏 -->
<ul class="tools">
<li class="tools-left">
<button :class="{ active: currentState == 1 }" @click="currentState = 1">
<span class="iconfont icon-close"></span>
</button>
<button :class="{ active: currentState == 2 }" @click="currentState = 2">
<span class="iconfont icon-dialog"></span>
</button>
<button :class="{ active: currentState == 3 }" @click="currentState = 3">
<span class="iconfont icon-list"></span>
</button>
</li>
<li class="tools-right">
<button class="show-list" @click="isShow = false">
<span class="iconfont icon-retract"></span>
</button>
</li>
</ul>
<!-- 用户列表 -->
<ul class="say-list">
<li>
<span class="iconfont icon-microphone"></span>
</li>
<li class="line"></li>
<li>正在讲话:{{ currentSay }};</li>
</ul>
<ul class="user-list">
<li v-for="user in filterUserList" :key="user.id">
<img class="header" :src="user.imgPath" />
<div class="user-name">
<span v-if="user.isHost" class="iconfont icon-user header-icon"></span>
<span class="iconfont icon-microphone"></span>
{{ user.name }}
</div>
</li>
</ul>
</div>
</div>
<script type="text/javascript" src="./js/vue.js"></script>
<script type="text/javascript" src="./js/axios.min.js"></script>
<script type="text/javascript">
// TODO:请在下面实现需求
new Vue({
el: "#app",
data: {
userList: [], // axios获取的用户列表
isLogin: false, // 登录标志
isShow: true, // 展示用户列表标志
currentUser: {}, // 当前登录用户对象
currentState: 2 // 当前选择页面呈现的方式
},
async mounted() {
let { data } = await axios.get('./js/userList.json')
this.userList = data
this.currentUser = this.userList[0]
},
methods: {
handleLogin() {
if(this.isLogin) {
// 注销重置
this.currentState = 2
this.isShow = true
}
this.isLogin = !this.isLogin
}
},
computed: {
filterUserList() {
if(this.currentState == 2) {
return this.userList.filter(u => u.id == this.currentUser.id)
} else if(this.currentState == 3) {
return this.userList.filter(u => u.id == this.currentUser.id).concat(this.userList.filter(u => u.id != this.currentUser.id))
} else {
return []
}
},
currentSay() {
return this.userList.find(u => u.isHost).name
}
}
});
</script>
</body>
</html>
8.天气趋势A
日常生活中,气象数据对于人们的生活具有非常重要的意义,数据的表现形式多种多样,使用图表进行展示使数据在呈现上更加直观。
1.1 题目问题
请在 index.html
文件中补全代码,具体需求如下:
-
完成数据请求(数据来源
./js/weather.json
),weather.json
中存放的数据为12
个月对应的温度数据。在项目目录下已经提供了axios
,考生可自行选择是否使用。注意:调试完成后请将请求地址写死为./js/weather.json
。 -
把
data
中的月份数据monthList
, 在class=month
标签下面的li
上完成渲染,点击月份则切换对应月份的温度数据同时被点击的月份会变成激活状态(.active 类
),x 轴为日期,y 轴为温度,默认显示1
月份数据。 -
如果点击的月份是当天(通过时间函数动态获取的时间)所在月份,本月和未来七天切换的
tab
(即id=currentMonth
元素)显示,其他月份currentMonth
元素不显示。- 默认显示本月数据。
- 点击本月显示当月数据,点击未来七天显示从当天(包含当天)开始未来七天的数据,当显示未来七天数据时 x 轴需要显示为月/日格式。
- 点击
tab
上本月和未来七天会切换激活状态(.active
)。
以当天为 5 月 29 号为例,未来七天
x
轴显示示例(即 x 轴显示成:5/29,5/30,5/31,6/1,6/2,6/3,6/4):
本月和未来七天 切换效果见文件夹下 effect-1.gif
。
最终效果见文件夹下面的 gif 图,图片名称为 effect-2.gif
(提示:可以通过 VS Code 或者浏览器预览 gif 图片)
1.2 题目分析
本题主要是考查如何异步更新图标数据的问题
以及内置的Date构造函数的使用
1.3 题目解答
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>天气趋势</title>
<meta
name="viewport"
content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no"
/>
<link rel="stylesheet" type="text/css" href="css/style.css" />
<script src="./js/axios.js"></script>
<script src="js/vue.min.js" type="text/javascript" charset="utf-8"></script>
<script
src="js/echarts.min.js"
type="text/javascript"
charset="utf-8"
></script>
</head>
<body>
<div id="app">
<div class="top-bar">2022年 Y 城全年温度统计图</div>
<!-- 主体 -->
<div class="container">
<!-- 月份 -->
<div class="month">
<ul>
<!-- TODO:待补充代码 在下面的 li 标签中完成 12个月份 (即 monthList) 的渲染 -->
<li
:class="{active:active == i}"
v-for="(m,k,i) in monthList"
@click="changeMonth(i)"
>
{{m}}
</li>
</ul>
</div>
<div class="chart">
<!-- TODO:待补充代码 -->
<!-- currentMonth 未来七天和本月 tab 切换,只有当前月才显示 -->
<div id="currentMonth" v-if="currentMonth == active">
<div class="title">
<h3>{{isfuture ? '未来七天天气' : typeTitle}}</h3>
<div class="type">
<span id="seven" :class="{active:isfuture}" @click="future"
>未来7天</span
>
<span
id="current"
:class="{active:!isfuture}"
@click="changeMonth(active)"
>本月</span
>
</div>
</div>
</div>
<div id="chart"></div>
</div>
</div>
</div>
</body>
</html>
<script>
// TODO:待补充代码
var vm = new Vue({
el: "#app",
data: {
chart: null, // 图表
chartOptions: null, // 图表配置项
typeTitle: "本月天气",
active: 0,
isfuture: false,
currentMonth: new Date().getMonth(),
weatherData: [],
monthList: {
January: "1月",
February: "2月",
March: "3月",
April: "4月",
May: "5月",
June: "6月",
July: "7月",
August: "8月",
September: "9月",
October: "10月",
November: "11月",
December: "12月",
},
},
mounted: async function () {
let { data } = await axios.get("./js/weather.json");
this.weatherData = data.map((v) => Object.values(v).flat(1));
// 初始化 echarts
this.$nextTick(() => {
this.initChart();
});
},
methods: {
async initChart() {
// 初始化图表
this.chart = echarts.init(document.getElementById("chart"));
// 配置项
this.chartOptions = {
grid: {
top: 35,
bottom: 5,
left: 10,
right: 10,
containLabel: true,
},
tooltip: {
trigger: "axis",
axisPointer: {
lineStyle: {
color: {
type: "linear",
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [
{
offset: 0,
color: "rgba(255,255,255,0)",
},
{
offset: 0.5,
color: "rgba(255,255,255,1)",
},
{
offset: 1,
color: "rgba(255,255,255,0)",
},
],
global: false,
},
},
},
},
xAxis: [
{
type: "category",
boundaryGap: false,
axisLabel: {
formatter: "{value}",
fontSize: 12,
margin: 20,
textStyle: {
color: "#bfbfbf",
},
},
axisLine: {
lineStyle: {
color: "#e9e9e9",
},
},
splitLine: {
show: true,
lineStyle: {
color: "#f7f7f7",
},
},
axisTick: {
show: false,
},
// x 轴显示的数据,日期
data: [
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
],
},
],
yAxis: [
{
boundaryGap: false,
type: "value",
axisLabel: {
textStyle: {
color: "#bfbfbf",
},
formatter: `{value}\u2103`,
},
nameTextStyle: {
color: "#fff",
fontSize: 12,
lineHeight: 40,
},
splitLine: {
lineStyle: {
color: "#f7f7f7",
},
},
axisLine: {
show: true,
lineStyle: {
color: "#e9e9e9",
},
},
axisTick: {
show: false,
},
},
],
series: [
{
name: "天气",
type: "line",
smooth: false,
showSymbol: false,
symbolSize: 0,
zlevel: 3,
itemStyle: {
color: "#ff6600",
borderColor: "#a3c8d8",
},
lineStyle: {
normal: {
width: 3,
color: "#ff6600",
},
},
areaStyle: {
normal: {
color: new echarts.graphic.LinearGradient(
0,
0,
0,
1,
[
{
offset: 0,
color: "#ff6600",
},
{
offset: 0.8,
color: "#ff9900",
},
],
false
),
},
},
// Y 轴显示的数据,即温度数据
data: [
23, 19, 30, 31, 18, 20, 16, 15, 23, 27, 29, 30, 32, 23, 25, 20,
22, 24, 34, 24, 21, 26, 23, 24, 25, 23, 25, 28, 32, 20,
],
},
],
};
// 调用此方法设置 echarts 数据
this.chart.setOption(this.chartOptions);
this.changeMonth(0);
},
changeMonth(m) {
this.active = m;
this.isfuture = false;
let x = [...new Array(this.weatherData[m].length).keys()].map(
(v) => v + 1
);
let y = this.weatherData[m];
this.chartOptions.xAxis[0].data = x;
this.chartOptions.series[0].data = y;
this.chart.setOption(this.chartOptions);
},
future() {
this.isfuture = true;
let date = new Date();
let d = date.getDate();
let x = [];
let y = this.weatherData[date.getMonth()].slice(d - 1, d + 6);
if (y.length != 7) {
y = y.concat(this.weatherData.slice(0, 7 - y.length));
}
for (
let i = +date;
i < +date + 7 * 1000 * 60 * 60 * 24;
i += 1000 * 60 * 60 * 24
) {
x.push(new Date(i).getMonth() + 1 + "/" + new Date(i).getDate());
}
console.log(x, y);
this.chartOptions.xAxis[0].data = x;
this.chartOptions.series[0].data = y;
this.chart.setOption(this.chartOptions);
},
},
});
</script>
9.JSON生成器
JSON 已经是大家必须掌握的知识点,JSON 数据格式为前后端通信带来了很大的便利。在开发中,前端开发工程师可以借助于 JSON 生成器快速构建一个 JSON 用来模拟数据。
1.1 题目问题
请在 index.js
文件中补全 generateData
函数代码,并最终返回一个 js 对象(说明 : generateData
生成的数据会由插件自动转化成 JSON
)。
在左侧的输入框中输入指定格式的数据模板,点击生成 JSON 按钮,右侧会自动生成对应格式的 JSON
数据。
-
数据模板中对象的
key
对应的value
如果是{{}}
并且符合下述规则,则根据下述规则解析,否则一律返回原始value
值。具体规则如下:{{bool()}}
表示随机生成布尔值。{{integer(n, m)}}
表示生成 n-m 之间(包含 n、m )的随机整数(注意:n<m
)。
附目标 1 测试用例:
{ isPass: '{{bool()}}', age: '{{integer(3, 5)}}', goodsNumber:2, isShow:false, tag:'phone', fn:'{{integer}}' }
-
数据模板中
{{repeat()}}
(此项只会出现在数组首位)表示重复生成数组中的数据,如:"repeat(5, 7)"
则表示随机生成5-7
条数组数据,repeat
中值只包含一个数字,如"repeat(5)"
表示生成5
条数组数据。附目标 2 测试用例(3 组):
// (1)随机生成 `2-5` 条数组数据 [ "{{repeat(2, 5)}}", { isActive: "{{bool()}}", age: "{{integer(20, 40)}}", num: 2, boolean: true, str: "str", isTel: "{{bool}}", fn: "{{fn()}}", }, ] // (2)固定生成 `7` 条数组数据 [ ("{{repeat(7)}}", { isTrue: "{{bool()}}", score: "{{integer(3, 7)}}", tag: "android", isSamll: true, fn: "{{fn()}}", }) ] // (3)无 repeat 的情况 [ { maxNum: 10 } ];
注意:本题不考虑用户输入和传参不合法的情况,只处理合法的数据格式即可,实际测试中 key
和 value
为非固定值。提供的测试用例仅为方便测试代码使用,实际使用中需要对所有符合要求的数组/对象结构的模板生效。
1.2 题目分析
主要是考察了对正则的理解和使用
以及eval和Math的相关使用
注意:eval执行字符串里面的代码的时候如果出现{{ 代码 }}
包裹的字符串,{{}}不会被执行和返回-----类似于vue的插值表达式
1.3 题目解答
/*
* @param {*} 左侧输入框输入的值转化成的 js 数据
* @return {*} 根据传入的数据生成对应的 js 格式数据
*/
let generateData = (data) => {
// TODO:待补充代码
//正则表达式用于匹配字符
//匹配形如 {{repeat(n1, n2, ..., nk)}} 的字符串模式
let reg1 = /^\{\{(repeat\([\d,\s]+\))\}\}$/
let reg2 = /^\{\{bool\(\)\}\}$/
let reg3 = /^\{\{integer\([\d,\s]+\)}\}$/
//不是数组进入
if(!Array.isArray(data)){
for(let k in data){
//将bool和integer进行转换并运行
if(reg2.test(data[k])||reg3.test(data[k])){
data[k]=eval(data[k]);
}
}
return data;
}
//记录重复生成的次数
let len = reg1.test(data[0]) ? eval(data[0]) : 1
let result = []//记录结果
while (result.length !== len) {
let obj = {...data[1]}//扩展成一个对象
for (let k in obj) {
if(reg2.test(obj[k]) || reg3.test(obj[k])) {
obj[k] = eval(obj[k])
}
}
result.push(obj)
}
function repeat(a,b){
//如果b是空值,则返回啊,否则返回随机值
return b ? Math.random() * (b-a+1) + a | 0 : a
}
function integer(a, b) {
return Math.random() * (b - a + 1) + a | 0
}
function bool() {
return Math.random() > 0.5
}
return result
};
module.exports = { generateData };
10.商城管理系统
在商城管理系统中,超级管理员和普通管理员因为权限不同,登录进入后看到的菜单也会是不同的。
1.1 题目问题
请在 js/auth.js
文件中补全 getMenuListAndAuth
函数代码。
在登录页 login.html
点击管理员登录和超级管理员登录时会根据管理员的权限不同,在商城首页 index.html
的左侧显示不同的菜单列表。但是后端同学给的数据是不符合前端展示要求的,所以我们需要做些处理,假如后端提供的数据是这样的:
[
{ parentId: -1, name: "商品管理", id: 1, auth: "cart" },
{ parentId: 1, name: "商品列表", id: 4, auth: "cart-list" },
{ parentId: -1, name: "添加管理员", id: 10, auth: "admin" },
];
其中数据中对象字段的含义说明:
id
表示当前节点parentId
表示父级节点,如果为-1
则表示顶级数据auth
表示权限
具体需求如下:
- 将待处理数据(一维数组)根据
parentId
字段值处理成树形结构存入menus
变量中。
把数据处理成如下格式(每一项都必须有 children
字段,没有子级时,children
为空数组):
[
{
parentId: -1,
name: "商品管理",
id: 1,
auth: "cart",
children: [
{
parentId: 1,
name: "商品列表",
id: 4,
auth: "cart-list",
children: [],
},
],
},
{
parentId: -1,
name: "添加管理员",
id: 10,
auth: "admin",
children: [],
},
];
注意:js/auth.js
中的 menuList
仅为后端返回的数据结构示例,非固定数据。实际使用中,后端返回的数据转化成树形结构时层级可能更多,封装方法时务必考虑通用性。
- 将待处理数据中的
auth
字段提取出来并存入auths
变量中,左侧菜单会根据传入的权限列表数组和auths
对比后进行菜单渲染。
经过 getMenuListAndAuth
处理后 auths
的结果为:
["cart", "cart-list", "admin"];
完成后的效果见文件夹下面的 gif 图,图片名称为 effect.gif
(提示:可以通过 VS Code 或者浏览器预览 gif 图片)。
1.2 题目分析
考察了递归算法和数组的去重
1.3 题目解答
const getMenuListAndAuth = (menuList) => {
// TODO:待补充代码
const arr = menuList.map(item => item.auth)
const auths = arr.filter((item, index) => arr.indexOf(item) === index)
const menus = getMenuList(menuList, -1)
function getMenuList(menuList, parentId) {
let arr = []
menuList.forEach(item => {
if (item.parentId == parentId) {
arr.push(item)
item.children = getMenuList(menuList, item.id)
}
})
return arr
}
return { menus, auths }; // menus 转化后的树形结构数据,auths 转化后的权限列表数组
};