第十四届蓝桥杯大赛Web应用与开发省赛职业院校组题解

第十四届蓝桥杯Web应用与开发省赛题解

  • 第十四届蓝桥杯(Web 应用开发)模拟赛 3 期-大学组
  • 第十四届蓝桥杯(Web 应用开发)模拟赛 3 期-职业院校组
  • 第十四届蓝桥杯(Web 应用开发)模拟赛 2 期-大学组
  • 第十四届蓝桥杯(Web 应用开发)模拟赛 2 期-职业院校组
  • 第十三届蓝桥杯大赛(Web 应用开发)国赛-职业院校组
  • 第十三届蓝桥杯大赛(Web 应用开发)省赛-职业院校组

01 电影院排座位(5 分)

.seat-area {margin-top: 50px;display: grid;grid-template-columns: repeat(2, 45px 65px 45px 45px);gap: 10px;
}

02 图⽚⽔印⽣成(5 分)

function createWatermark(text, color, deg, opacity, count) {// 创建水印容器const container = document.createElement('div')container.className = 'watermark'// TODO: 根据输入参数创建文字水印for (let i = 0; i < count; i++) {const span = document.createElement('span')span.innerText = textspan.style.color = colorspan.style.transform = `rotate(${deg}deg)`span.style.opacity = opacitycontainer.appendChild(span)}return container
}

03 收集帛书碎⽚(10 分)

function collectPuzzle(...puzzles) {// TODO: 在这里写入具体的实现逻辑return Array.from(new Set(puzzles.flat()))
}

04 ⾃适应⻚⾯(10 分)

@media (max-width: 800px) {.menu {height: 54px;line-height: 54px;margin-bottom: 25px;}.icon-menu {color: #a0a0a0;margin-left: 20px;display: inline-block !important;}.icon-menu:hover {color: white;cursor: pointer;}.collapse {display: none;}input[type='checkbox']:checked ~ .collapse {display: flex;flex-direction: column;background-color: #252525;}.dropdown:hover ul {display: flex;flex-direction: column;}.row {margin-top: 20px;display: flex;flex-wrap: wrap;}.box {margin-bottom: 15px;}#tutorials img {margin: 0;}
}

05 外卖给好评(15 分)

<template><div class="block"><span class="demonstration">请为外卖评分:span><ul class="rate-list"><li>送餐速度:<el-rate @change="changeScore" show-score="true" v-model="speed">el-rate>li><li>外卖口味:<el-rate @change="changeScore" show-score="true" v-model="flavour">el-rate>li><li>外卖包装:<el-rate @change="changeScore" show-score="true" v-model="pack">el-rate>li>ul>div>
template>
<script>
module.exports = {data() {return {speed: 0, // 送餐速度flavour: 0, // 外卖口味pack: 0, // 外卖包装}},/* TODO:待补充代码 */methods: {changeScore() {if (this.speed && this.flavour && this.pack) {this.$emit('change', {speed: this.speed,flavour: this.flavour,pack: this.pack,})}},},
}
script>

06 视频弹幕(15 分)

发送按钮点击事件

document.querySelector('#sendBulletBtn').addEventListener('click', () => {// TODO:点击发送按钮,输入框中的文字出现在弹幕中bulletConfig.value = document.querySelector('#bulletContent').valuerenderBullet(bulletConfig, videoEle, true)
})

renderBullet()

/*** @description 根据 bulletConfig 配置在 videoEle 元素最右边生成弹幕,并移动到最左边,弹幕最后消失* @param {Object} bulletConfig 弹幕配置* @param {Element} videoEle 视频元素* @param {boolean} isCreate 是否为新增发送的弹幕,为 true 表示为新增的弹幕**/
function renderBullet(bulletConfig, videoEle, isCreate = false) {const spanEle = document.createElement('SPAN')spanEle.classList.add(`bullet${index}`)if (isCreate) {spanEle.classList.add('create-bullet')}// TODO:控制弹幕的显示颜色和移动,每隔 bulletConfig.time 时间,弹幕移动的距离  bulletConfig.speed// 解构配置对象const { isHide, speed, time, value } = bulletConfig// 获取视频容器的宽度和高度const { width, height } = getEleStyle(videoEle)// 给元素添加样式spanEle.innerText = valuespanEle.style.color = `#${getRandomNum(999999)}`spanEle.style.position = 'absolute'spanEle.style.top = `${getRandomNum(height)}px`spanEle.style.left = `${width}px`spanEle.style.display = isHide ? 'none' : 'block'// 将配置好的SPAN标签追加到视频容器中videoEle.appendChild(spanEle)// 控制弹幕移动let left = widthconst timer = setInterval(() => {left -= speedspanEle.style.left = `${left}px`if (left <= -spanEle.clientWidth) {videoEle.removeChild(spanEle)clearInterval(timer)}}, time)
}

07 ISBN 转换与⽣成(20 分)

// 将用户输入的带分隔符的 isbn 字符串转换只有纯数字和大写 X 字母的字符串
// 入参 str 为转换为包含任意字符的字符串
function getNumbers(str) {// TODO: 待补充代码return str == '' ? '' : str.match(/\d|X/g).join('')
}// 验证当前 ISBN10 字符串是否有效
// 入参 str 为待判断的只有纯数字和大写 X 字母的字符串
function validISBN10(str) {// TODO: 待补充代码const reg = new RegExp(/\d{10}|(\d{9}X{1})/)if (!reg.test(str)) return falseconst num = str.split('')if (num.length != 10) return false // 上面那个正则有问题,这里加个判断const sum = num.slice(0, 9).reduce((prev, cur, index) => prev + Number(cur) * ++index, 0)const remainder = sum % 11const contrast = num[9] == 'X' ? 10 : num[9]return contrast == remainder
}// 将用户输入的 ISBN-10 字符串转化为 ISBN-13 字符串
// 入参 isbn 为有效的 ISBN-10 字符串
function ISBN10To13(isbn) {// TODO: 待补充代码const str = '978' + isbn.substring(0, 9)const sum = str.split('').reduce((prev, cur) => {cur = Number(cur) // 转数字格式return (prev += cur % 2 == 0 ? cur * 3 : cur)}, 0)const remainder = sum % 10const verify = remainder == 0 ? 0 : 10 - remainderreturn str + verify
}

08 全球新冠疫情数据统计(20 分)

<div id="app"><header><div>全球新冠疫情数据统计div>header><main><div class="title"><h2>{{curCountry}}h2>div><div class="boxes"><div class="box1"><h3>确诊h3><div class="number"><span class="font-bold">新增:{{newConfirmed}}span>div><div class="number"><span class="font-bold">总计:{{totalConfirmed}}span>div>div><div class="box2"><h3>死亡h3><div class="number"><span class="font-bold">新增:{{newDeaths}}span>div><div class="number"><span class="font-bold">总计:{{totalDeaths}}span>div>div>div><select v-model="selectCountry"><option :value="0">Select Countryoption><option v-for="item in data" :value="item">{{item.Country}}option>select><div id="chart" style="width: 100%; height: 50vh">div>main>
div>
<script>var vm = new Vue({el: "#app",methods: {// TODO: 请修改该函数代码实现题目要求initChart () {// 初始化图表this.chart = echarts.init(document.getElementById("chart"));this.chartOptions = {title: {text: "全球感染人数前30国家累计确诊人数统计",x: "center",},tooltip: {trigger: "axis",axisPointer: {type: "shadow",label: { show: true },},},// 设置x轴数据xAxis: {// TODO:这里需要显示国家名称缩写,因为有些国家的全称太长,会导致界面不美观data: this.countryCodeList,axisLabel: {show: true,interval: 0,},},yAxis: {type: "value",name: "确诊数量",},// 设置y轴数据series: [{// TODO:设置图表中的总确证数data: this.totalConfirmedList,type: "bar",itemStyle: {normal: { color: "#a90000" },},},],};// 调用此方法设置 echarts 数据this.chart.setOption(this.chartOptions);},},// TODO: 请在此添加代码实现组件加载时数据请求的功能async mounted () {this.data = (await axios.get('./js/covid-data.json')).datathis.initChart();},computed: {countryCodeList () {return this.data.map(e => e.CountryCode)},totalConfirmedList () {return this.data.map(e => e.TotalConfirmed)}},data () {return {data: [],selectCountry: 0,newConfirmed: 0,totalConfirmed: 0,newDeaths: 0,totalDeaths: 0,curCountry: '请选择国家'}},watch: {// 监听下拉列表值,动态切换数据selectCountry (val) {this.curCountry = val.CountryCode || this.curCthis.newConfirmed = val.NewConfirmed || 0this.totalConfirmed = val.TotalConfirmed || 0this.newDeaths = val.NewDeaths || 0this.totalDeaths = val.TotalDeaths || 0}}});
script>

09 ⻣架屏(25 分)

实现思路: 此题主要难点在于 styleclass 的处理,将当前渲染对象传入对应方法,判断返回对象具有的属性

/** 骨架屏渲染组件*/
let ItemTemplate = ``
// TODO: 请补充完整Template,完成组件代码编写
ItemTemplate += `


`Vue.component('item', {name: 'item',template: ItemTemplate,props: ['paragraph', 'active'],data() {return { typeList: ['rect', 'circle'], classPrefix: 'ske ske-', activeClass: ' ske-ani' }},watch: {},methods: {// 判断是 rows or colsarrIs(obj) {if (obj?.rows) return obj.rowselse if (obj?.cols) return obj.colselse return []},// 判断class类classIs(obj) {if (this.typeList.includes(obj.type)) {return this.classPrefix + obj.type + (this.active ? this.activeClass : '')} else {return this.classPrefix + obj.type}},// 判断样式styleIs(obj) {if (obj?.style && obj?.rowStyle) return { ...obj.style, ...obj.rowStyle }else if (obj?.style) return obj.styleelse if (obj?.rowStyle) return obj.rowStyleelse if (obj?.colStyle) return obj.colStyleelse return {}},},
})

10 组课神器(25 分)

ajax()

async function ajax({ url, method = 'get', data }) {let result// TODO:根据请求方式 method 不同,拿到树型组件的数据// 当method === "get" 时,localStorage 存在数据从 localStorage 中获取,不存在则从 /js/data.json 中获取// 当method === "post" 时,将数据保存到localStorage 中,key 命名为 dataif (method === 'get') {const dataList = localStorage.getItem('data')result = dataList ? JSON.parse(dataList) : (await axios({ url, method })).data.data}if (method === 'post') {// result = (await axios({ url, method, data })).datalocalStorage.setItem('data', JSON.stringify(data))}return result
}

treeMenusRender()

实现思路: 递归生成DOM树

function treeMenusRender(data, grade = 0) {let treeTemplate = ''// TODO:根据传入的 treeData 的数据生成树型组件的模板字符串grade++for (obj of data) {treeTemplate +=grade === 3? `${obj.id}" data-grade="${grade}">${obj.tag}${obj.label} 0人完成|0人提交报告`: `${obj.id}" data-grade="${grade}">${grade === 2 && 15}px">${obj.label}`if (obj?.children) treeTemplate += `${treeMenusRender(obj.children, grade)}`treeTemplate += ``}return treeTemplate
}

treeDataRefresh()

实现思路: 利用字符串替换的方式,将拖动的元素插入到对应节点,最后将替换完成的字符串转JSON对象重新赋值给 treeData

  • 首先将 treeData 转字符串
  • 调用 getDragElement() 方法,将被拖拽的元素对象和放入元素对象转字符串
  • 根据题目要求对 treeDataStr 进行替换
  • treeDataStr 转JSON对象并赋值给 treeData
function treeDataRefresh({ dragGrade, dragElementId }, { dropGrade, dropElementId }) {if (dragElementId === dropElementId) return// TODO:根据 `dragElementId, dropElementId` 重新生成拖拽完成后的树型组件的数据 `treeData`let dragStr = JSON.stringify(getDragElement(treeData, dragElementId))let dropStr = JSON.stringify(getDragElement(treeData, dropElementId))let treeDataStr = JSON.stringify(treeData)if (dragGrade === dropGrade) {treeDataStr = treeDataStr.replace(dragStr, '')treeDataStr = treeDataStr.replace(dropStr, dropStr + ',' + dragStr)}if (dragGrade - dropGrade == 1) {if (dropStr.includes(dragStr)) dropStr = dropStr.replace(dragStr, '')const newDragStr = `${dragStr},`const newDropStr = dropStr.replace('[', '[' + newDragStr)treeDataStr = treeDataStr.replace(dragStr, '')treeDataStr = treeDataStr.replace(dropStr, newDropStr)}// 处理多余字符treeDataStr = treeDataStr.replace(',,', ',').replace('[,', '[').replace(',]', ']')treeData = JSON.parse(treeDataStr)
}
getDragElement()

通过传入的 id 获取被拖拽的节点对象

function getDragElement(data, id) {for (const obj of flatObj(data)) {if (obj.id == id) return obj}
}
flatObj()

此方法将 treeData 扁平化

function flatObj(obj) {return obj.reduce((prev, cur) => {prev = [...prev, cur]if (cur?.children) prev = [...prev, ...flatObj(cur.children)]return prev}, [])
}


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部