第十四届蓝桥杯(Web 应用开发)模拟赛 3 期-大学组
以下是第十四届蓝桥杯(Web 应用开发)模拟赛 3 期-大学组题解;博主只是个专科生,技术有限,题都是自己苦思冥想写出来的;官网检测全部通过,仅供大家参考。
01 网页PPT
这题主要考察 使用 jQuery 操作 class 类样式动态切换和元素显隐
-
元素显隐可以使用 jQuery 的 show() 和 hide() 方法,配合 siblings() 就可以实现当前元素显示时其他同级元素全部隐藏
-
类样式切换,可以使用 jQuery 的 toggleClass() 方法进行动态切换
function switchPage(e) {
// TODO: 请补充该函数,实现根据activeIndex切换页面的功能,并且在到达最后一页或第一页时给相应的按钮添加disable类
$('section').eq(activeIndex).show().siblings().hide()
$('.btn.left').toggleClass('disable', activeIndex === 0)
$('.btn.right').toggleClass('disable', activeIndex + 1 === sectionsCount)
$('.page').text(`${activeIndex + 1} / ${sectionsCount}`)
}
02 西游记之西天取经
这题主要考察对于 CSS 中 animation 动画属性值的熟悉度,通过题目描述可知,需要一直循环播放动画,所以给 animation 属性加上 infinite 属性即可。
/* TODO 填空 */
animation: a1 0.8s steps(8) infinite; /* 给所有的 animation 属性添加上 infinite 属性值 */
03 商品销量和销售额实时展示看板
这题看似是考察 echarts ,实际上是考察数据处理,即 对于 Object 对象 API 的熟悉度;分别使用 Object.keys() 和 Object.values() 函数提取图表中 xAxis 和 series 所需要的值。
// TODO:补全 `yAxis` 的设置,要求“销售额”(即,配置项 `name`)的位置(即,配置项 `position`)在图表的左侧,“销量”(即,配置项 `name`)的位置(即,配置项 `position`)在图表的右侧。
yAxis: [
{
type: 'value',
name: '销售额',
position: 'left',
},
{
type: 'value',
name: '销量',
position: 'right',
},
],
// TODO:补全代码,正确给 X 轴的时间,以及 Y 轴的商品的销售额 saleObj 和销量赋值 countObj。
charData.xAxis.data = Object.keys(result.data.saleObj)
charData.series[0].data = Object.values(result.data.saleObj)
charData.series[1].data = Object.values(result.data.countObj)
04 蓝桥校园一卡通
这题主要考察使用原生 js 进行表单验证,即 正则表达式的使用 和 使用原生 js 进行 dom 操作
- 正则表达式,题目描述中有给相关规则,直接拿来用即可
- 操作 dom 进行表单验证这个也很基础,不多赘述
submit.onclick = () => {
// TODO 待补充代码
const id = studentId.value // 获取学号
const name = studentName.value // 获取姓名
const collegeStr = college.value // 获取学院
// 定义正则验证对象
const idReg = /^\d{1,12}$/
const nameReg = /^[\u4e00-\u9fa5]{2,4}$/
// 验证输入文本格式是否符合要求
const idCheck = idReg.test(id)
const nameCheck = nameReg.test(name)
// 获取提示文本dom节点
const vail_name = document.querySelector('#vail_name')
const vail_studentId = document.querySelector('#vail_studentId')
if (!nameCheck) { // 验证姓名
vail_name.style.display = 'block'
studentName.parentNode.classList.add('has-error')
}
if (!idCheck) { // 验证学号
vail_studentId.style.display = 'block'
studentId.parentNode.classList.add('has-error')
}
if (nameCheck && idCheck) { // 姓名学号都符合要求展开卡片
vail_name.style.display = 'none' // 姓名输入框提示文本隐藏
vail_studentId.style.display = 'none' // 姓名输入框提示文本隐藏
// 渲染数据
item[0].innerHTML = `姓名:${name}`
item[1].innerHTML = `学号:${id}`
item[2].innerHTML = `学院:${collegeStr}`
// 添加 showCard 类显示放大一卡通的动画,请勿删除
cardStyle.classList.add('showCard')
}
}
05 会员权益领取中心
此题略...
06 心愿便利贴
这题考察对于 element-ui 表单组件的熟悉度,配置 element-ui 表单组件的验证规则,题目描述中有给相关 API ,对于熟悉 element-ui 的小伙伴而言,看一眼题目描述就知道怎么写了。
rules: {
// TODO 待补充验证的代码
name: [
{ required: true, message: '请输入姓名', trigger: 'blur' },
{ min: 2, max: 4, message: '长度在 2 到 4 个字符', trigger: 'blur' }
],
content: [
{ required: true, message: '请输入许愿内容', trigger: 'blur' },
{ min: 1, max: 30, message: '长度在 1 到 30 个字符', trigger: 'blur' }
],
},
07 消失的 Token
这题主要考察对于 vuex 的熟悉度,因为开启了命令空间,需要操作访问时需要加上 前缀,即 user
// TODO 修改下面错误代码
var app = new Vue({
el: '#app',
data () { },
computed: {
welcome () {
return store.getters.welcome
},
// 因为开启了命名空间需要拼上 user/ 前缀
username () {
return store.getters['user/username']
},
token () {
return store.getters['user/token']
}
},
methods: {
// 回车/点击确认的回调事件
login (username) {
username && store.commit('user/login', { username, token: 'sxgWKnLADfS8hUxbiMWyb' })
username && store.commit('say', '登录成功,欢迎你回来!')
}
}
})
</script>
08 封装 Promisefy 函数
这题主要考察 js 函数封装和 Promise
- 首先可以看到这个promisefy函数是怎么用的,参数是一个函数
- 调用promisefy函数的结果被存到readFileSync里,
- 而readFileSync在后面可以看到直接接个小括号传两个参了
- 并且还能.then和.catch
- 所以调用这个promisefy返回的是一个参数为(textPath, 'utf8')的函数
- 并且这个函数的调用结果还是个promise对象,
- 不然不是promise对象那来的then方法
- 那这个promise对象里面怎么判断读取文件成功或失败呢 * 学过node就知道了
const promisefy = fn => {
// TODO 此处完成该函数的封装
return (textPath, coding) =>
new Promise((resolve, reject) => {
fn(textPath, coding, (err, contrast) => {
if (err) reject(err)
resolve(contrast)
})
})
}
09 趣购
做这题时,博主第一次接触元素拖拽,刚开始迷迷糊糊的,不知道怎么用,摸索摸索,最后竟然还真做出来了
这题主要考察元素拖拽,题目描述中有给相关API,根据描述选择使用即可。然后是总价和数量的计算,通过 vue 的计算属性特性来做,成功解决。
<!-- TODO: 补充拖拽事件,请不要改动任何 id 属性 -->
<template>
<div class="container">
<div class="good-list">
<div v-for="good in goods" :key="good.name" @dragstart="dragstartHandler" class="good">
<img :src="good.cover" />
<span>{{ good.name }}</span>
<span>¥{{ good.price }}</span>
</div>
</div>
<!-- @dragover.prevent取消拖拽释放默认事件 -->
<div id="trolley" class="trolley" @dragover.prevent @drop="dropHandler">
<span id="bought" class="bought" v-if="bought.length !== 0">{{ bought.length }}</span>
<img src="./images/trolley.jpeg" />
</div>
<div class="result">
<div>
购物车商品:
<span id="goods">{{ goodsDetail }}</span>
</div>
<div>
购物车商品总计:
<span id="total">{{ totalPrice }}</span>
</div>
</div>
</div>
</template>
<script>
module.exports = {
data() {
return {
goods: [...], // 数据省略...
bought: [],
good: {},
}
},
// TODO: 请补充实现代码
computed: {
totalPrice() {
// 计算商品总价
return this.bought.reduce((pre, cur) => pre + cur.price, 0)
},
goodsDetail() {
// 拼接购物车字符串
return this.goods
.map(item => item.name)
.reduce((pre, cur) => {
const count = this.bought.filter(item => item.name === cur).length
return count === 0 ? pre : `${pre} ${cur}*${count}`
}, '')
},
},
methods: {
dragstartHandler($event) {
const e = $event.target.parentNode.children // 获取当前拖拽元素
this.good.name = e[1].innerText // 获取商品名
this.good.price = Number(e[2].innerText.slice(1)) // 获取商品价格
},
dropHandler() {
this.bought.push(this.good) // 购物车列表中添加一个商品
this.good = {} // 将当前商品置空
},
},
}
</script>
10 分页组件
平时开发时,分页都是直接使用别人的组件,第一次自己动手写一个分页组件,不得不说还是蛮复杂的,需要考虑的点比较多。
ajax() 数据请求
首先完成数据请求,获取到分页数据,题目中提供了 axios ,拿来即用,没什么好说的。
async function ajax({ url, method = 'get', data, query: { currentPage, pageSize } }) {
// TODO:根据函数参数 `query` 对象 `currentPage, pageSize` 获得当前页的数据
let result = { data: [], total: 0 }
await axios({ url, method }).then(res => {
result.data = res.data.data.slice((currentPage - 1) * pageSize, currentPage * pageSize)
result.total = res.total
})
return result
}
renderPagination() 分页按钮渲染
因为有时需要显示 ... ,所以需要做一些判断
renderPagination(indexArr) {
let template = '' // TODO: 根据 indexArr 数组生成分页组件的字符串模板 template
indexArr.forEach((v, k) => {
// 前置添加 ...
if (this.totalPages === v && this.currentPage <= this.totalPages - (this.pagerCount - 2))
template += `<li class="number more">...</li>`
// 添加分页按钮
template += `<li class="number ${this.currentPage === v ? 'active' : null}">${v}</li>`
// 后置添加 ...
if (indexArr[1] >= this.pagerCount - 2 && k === 0)
template += `<li class="number more">...</li>`
})
this.root.innerHTML = `
<div class="pagination">
<div class="btn btn-left" id="btn-prev"><</div>
<ul class="pager">${template} </ul>
<div class="btn btn-right" id="btn-next">></div>
</div>`
}
initEvents() 分页按钮事件绑定与数据切换
这里就是根据点击前后按钮切换到对应的分页数据,也就是切换一下 currentPage 的值即可
initEvents() {
this.root.querySelector('#btn-prev').addEventListener('click', () => {
// TODO:"<" 按钮的点击事件, 点击时 this.currentPage - 1
this.currentPage = this.currentPage === 1 ? 1 : this.currentPage - 1
this.initPagination()
})
this.root.querySelector('#btn-next').addEventListener('click', () => {
// TODO:">" 按钮的点击事件, 点击时 this.currentPage + 1
this.currentPage = this.currentPage === this.totalPages ? this.totalPages : this.currentPage + 1
this.initPagination()
})
this.root.querySelector('.pager').addEventListener('click', e => {...})
}
createPaginationIndexArr() 创建分页数组
具体思路,看代码注释即可,这里不再赘述了
const createPaginationIndexArr = (currentPage, totalPages, pagerCount) => {
// TODO:根据传参生成分页数组 indexArr
let indexArr = []
// 初始化一个最大页码数-2的数组
const initArr = Array.from(Array(pagerCount - 2).keys(), n => n + 1)
// 判断当前页是否为 pagerCount - 2
if (initArr.includes(currentPage)) {
indexArr = initArr
// 如果总页数大于或等于最大按钮书减一则添加一个按钮
if (totalPages >= pagerCount - 1) indexArr.push(pagerCount - 1)
}
// 如果总页数小于最大按钮数直接返回
if (totalPages < pagerCount) return indexArr
if (!initArr.includes(currentPage)) {
indexArr.push(1)
if (currentPage > totalPages - initArr.length) {
let min = initArr.length
for (let i = 0; i < pagerCount - 1; i++) {
indexArr.push(totalPages - min)
min--
}
return indexArr
}
for (let i = 0; i < pagerCount - 2; i++) {
indexArr.push(currentPage + (i - Math.floor(initArr.length / 2)))
}
}
indexArr.push(totalPages)
return indexArr
}