【蓝桥杯Web】第十五届蓝桥杯(Web 应用开发)模拟赛 2 期 | 全部题解

感觉蓝桥杯的模拟赛一次比一次难了😑

制作不易,代码都是纯手敲,觉得有帮助的伙伴们记得点个赞评论一下,谢谢大家支持😍

话不多说直接上答案

目录

1、想不相等

2、三行情书

3、电影院在线订票

4、老虎机

5、星际通讯

6、蓝桥杯排位赛

7、拼出一个未来

8、超能英雄联盟

HeroList.js

TeamList.js

9、万能合成台

10、账户验证


1、想不相等

这里有个坑,题意说如果不符合要求要抛出错误'...',实际上只需要return即可,不需要用到throw语句,当时这里卡了有一会

/**
 * @param {string} val
 * @return {Object}
 */
var expectFn = function(val) {
  // TODO
  return{
    toBe(_val){
      return val === _val || 'Not Equal'
    },
    notToBe(_val){
      return val !== _val || 'Equal'
    }
  }
};


// console.log(expectFn(5).toBe(5)); // true
// console.log(expectFn(5).notToBe(5)); // "Equal"
// 检测需要,请勿删除
module.exports = expectFn;

2、三行情书

这题要注意的是,span标签原本为行内元素,无法设置宽高,需要将span转换为块级元素

span {
    font-size: 20px;
    color: #837362;
    /* TODO:补充下面的代码 */
    display: block;
    width: 100%;
    white-space: nowrap;
    text-overflow: ellipsis;
    overflow: hidden;
}
p {
    color: #837362;
    /* TODO:补充下面的代码 */
    display: -webkit-box;
    -webkit-box-orient: vertical;
    text-overflow: ellipsis;
    overflow: hidden;
    -webkit-line-clamp: 3;

}

3、电影院在线订票

/* TODO: 
      1. 完成数据请求,生成电影名,价格以及座位情况
      2. 绑定点击事件,实现订票功能
 */

// 获取座位区域节点
const seatAreaNode = document.getElementById("seat-area");
// 获取电影名节点
const movieNameNode = document.getElementById("movie-name");
// 获取电影票价节点
const moviePriceNode = document.getElementById("movie-price");
// 获取已订电影票数量节点
const count = document.getElementById("count");
// 获取已订电影票总价节点
const total = document.getElementById("total");

axios('./data.json').then(res=>{
      let {data} = res
      console.log(data);
      movieNameNode.innerText = data.name
      moviePriceNode.innerText = data.price
      let tpl = ``
      data.seats.map(item=>{
            tpl+=`<div class="row">{{replace}}</div>`
            let _tpl = ''
            item.map(_item=>{
                  _tpl+=_item?`
                  <div class="seat occupied"></div>                
                  `:`<div class="seat"></div>`
            })
            tpl = tpl.replace('{{replace}}',_tpl)
      })
      seatAreaNode.innerHTML = tpl
      ;[...document.getElementsByClassName('seat')].map(node=>{
            if(![...node.classList].includes('occupied')){
                  node.onclick=function(){
                        if([...node.classList].includes('selected')){
                              node.classList.remove('selected')
                              count.innerHTML = parseInt(count.innerHTML) - 1
                              total.innerHTML = parseInt(total.innerHTML) - 20
                        }else{
                              node.classList.add('selected')
                              count.innerHTML = parseInt(count.innerHTML) + 1
                              total.innerHTML = parseInt(total.innerHTML) + 20
                        }
                  }
            }
      })
})

4、老虎机

这题如果读懂题意还是很简单的,要r1、r2和r3减1即可

  // GetResult 中奖结果函数,r1,r2,r3 为最后图片停留位置,以第一列为例,最终显示的元素是 sevenFirst 下的第 r 个 li 元素。
  GetResult(r1, r2, r3) {
    // TODO 待补充代码
    let o1 = document.getElementById('sevenFirst').getElementsByTagName('li'),
    o2 = document.getElementById('sevenSecond').getElementsByTagName('li'),
    o3 = document.getElementById('sevenThird').getElementsByTagName('li'),
    oTip = document.getElementsByClassName('textPanel')[0]
    if(o1[r1-1].dataset.point == o2[r2-1].dataset.point == o3[r3-1].dataset.point){
      oTip.innerHTML ='恭喜你,中奖了'
    }else{
      oTip.innerHTML ='很遗憾,未中奖'
    }
  }
}

5、星际通讯

这题难度还是比较简单的,因为codonTable里的key都是三位数的

/**
 * @param {string} alienMessage 外星人的密文
 * @return {string}  翻译结果
 */
const translate = (alienMessage) => {
  // TODO:待补充代码
  if(!alienMessage)return ""
  if(alienMessage.length%3!=0)return"无效密语"
  let strArr = [],
  _str = '',
  result = ''
  for(let strIdx in alienMessage){
    _str+=alienMessage[strIdx]
    if(_str == 'XXI')break
    if(_str.length == 3){
      strArr.push(_str)
      _str = ''
    }
  }
  result+=(strArr.map(item=>codonTable[item])+'').replaceAll(',','')
  if(result=='undefined' || !result)return "无效密语"
  return result
};

6、蓝桥杯排位赛

考察的是echart,直接上答案

const { createApp, ref, onMounted } = Vue;
const app = createApp({
  setup() {
    const chartsData = ref([]);
    onMounted(() => {
      // TODO:待补充代码 请求数据,并正确渲染柱形图和地图
      fetch('./mock/map.json').then(res=>res.json()).then(res=>{
        let schoolList = []
        res.map(item=>{
          item.school_power.map((item,idx)=>schoolList.push(item))
        })
        schoolList.sort((a,b)=>b.power-a.power)
        schoolList.length = 10
        showChartBar(schoolList);
        showChinaMap(res);
      })
    });

    // 展示柱状图
    const showChartBar = (schoolList) => {
      const myChart = echarts.init(document.getElementById('chart'));

      let data = chartsData.value.map((item, index) => {
        return item.school_power;
      });
      let result = data.flat(1).sort((a, z) => {
        return z.power - a.power;
      });
      let arr = result.slice(0, 10);
      let school = arr.map((item) => {
        return item.name;
      });
      let power = arr.map((item) => {
        return item.power;
      });

      // 指定配置和数据
      const option = {
        xAxis: {
          type: 'category',
          axisLabel: { interval: 0, rotate: 40 },
          // TODO:待修改  柱状图 x 轴数据 -> 前 10 学校名称
          data: schoolList.map(item=>item.name),
        },
        grid: {
          left: '3%',
          right: '4%',
          bottom: '3%',
          containLabel: true,
        },
        yAxis: {
          type: 'value',
          boundaryGap: [0, 0.01],
        },
        series: [
          {
            // TODO:待修改   柱状图 y 轴数据->学校战力值
            data: schoolList.map(item=>item.power),
            type: 'bar',
            showBackground: true,
            backgroundStyle: {
              color: 'rgba(180, 180, 180, 0.2)',
            },
            itemStyle: {
              color: '#8c7ae6',
            },
          },
        ],
      };

      // 把配置给实例对象
      myChart.setOption(option);
      // 根据浏览器大小切换图表尺寸
      window.addEventListener('resize', function () {
        myChart.resize();
      });
    };

    // 展示地图
    const showChinaMap = (data) => {
      const chinaMap = echarts.init(document.getElementById('chinaMap'));

      // 进行相关配置
      const mapOption = {
        tooltip: [
          {
            backgroundColor: '#fff',
            subtext: 'aaa',
            borderColor: '#ccc',
            padding: 15,
            formatter: (params) => {
              return (
                params.name +
                '热度值:' +
                params.value +
                '<br>' +
                params.data.school_count +
                '所学校已加入备赛'
              );
            },
            textStyle: {
              fontSize: 18,
              fontWeight: 'bold',
              color: '#464646',
            },
            subtextStyle: {
              fontSize: 12,
              color: '#6E7079',
            },
          },
        ],
        geo: {
          // 这个是重点配置区
          map: 'china', // 表示中国地图
          label: {
            normal: {
              show: false, // 是否显示对应地名
            },
          },
          itemStyle: {
            normal: {
              borderColor: 'rgb(38,63,168)',
              borderWidth: '0.4',
              areaColor: '#fff',
            },
            emphasis: {
              //鼠标移入的效果
              areaColor: 'rgb(255,158,0)',
              shadowOffsetX: 0,
              shadowOffsetY: 0,
              shadowBlur: 20,
              borderWidth: 0,
              shadowColor: 'rgba(0, 0, 0, 0.5)',
            },
          },
        },
        visualMap: {
          show: true,
          left: 'center',
          top: 'bottom',
          type: 'piecewise',
          align: 'bottom',
          orient: 'horizontal',
          pieces: [
            {
              gte: 80000,
              color: 'rgb(140,122,230)',
            },
            {
              min: 50000,
              max: 79999,
              color: 'rgba(140,122,230,.8)',
            },
            {
              min: 30000,
              max: 49999,
              color: 'rgba(140,122,230,.6)',
            },
            {
              min: 10000,
              max: 29999,
              color: 'rgba(140,122,230,.4)',
            },
            {
              min: 1,
              max: 9999,
              color: 'rgba(140,122,230,.2)',
            },
          ],
          textStyle: {
            color: '#000',
            fontSize: '11px',
          },
        },
        series: [
          {
            type: 'map',
            geoIndex: 0,
            // TODO:待修改 地图对应数据
            data,
          },
        ],
      };

      // 把配置给实例对象
      chinaMap.setOption(mapOption);
    };

    return {
      chartsData,
      showChartBar,
      showChinaMap,
    };
  },
});

app.mount('#app');

7、拼出一个未来

// 定义拖放事件的处理函数
function drop(event) {
    // 检查是否拖动的拼图块不是当前目标拼图块
    // draggedPiece 被拖动的拼图块元素。this 目标位置的拼图块元素。
    if (draggedPiece !== this) {
       // TODO:待补充代码 
       let saveArr = [
            [draggedPiece.children[0].src,draggedPiece.children[0].dataset.id]
            ,[this.children[0].src,this.children[0].dataset.id]
        ]
        draggedPiece.children[0].src = saveArr[1][0]
        draggedPiece.children[0].dataset.id = saveArr[1][1]
        this.children[0].src = saveArr[0][0]
        this.children[0].dataset.id = saveArr[0][1]
        let imgDataIdList = [...document.getElementById('puzzle-container').getElementsByTagName('img')].map(item=>item.dataset.id)
        console.log(imgDataIdList);
        if(imgDataIdList == '1,2,3,4,5,6,7,8,9'){
            document.getElementById('success-message').classList.remove('hide')
            document.getElementById('success-message').classList.add('show')
        }else{
            document.getElementById('success-message').classList.remove('show')
            document.getElementById('success-message').classList.add('hide')
        }
    }

    // 重置正在拖动的拼图块
    draggedPiece = null;
}

8、超能英雄联盟

这里我只改动了两个地方

HeroList.js

// TODO:补全代码,实现目标效果
const HeroList = {
  template: `
  <div class="hero-list">
    <h2>可选英雄</h2>
    <ul>
      <li class="hero-item" v-for="(item,idx) in list">
        <span>{{item.name}}</span>
        <span>{{item.ability}}</span>
        <span>{{item.strength}}</span>
        <button @click="clickEvent(idx)" disabled v-if="item.btnInfo.disabled">
        {{item.btnInfo.text}}</button>
        <button @click="clickEvent(idx)" v-else="item.btnInfo.disabled">
        {{item.btnInfo.text}}</button>
      </li>
    </ul>
  </div>
  `,
  setup() {
    let store = useHeroStore(),
    list = ref([])
    axios('./js/heroes.json').then(({data})=>{
      data.map(item=>{
        item.btnInfo = {
          text:'添加至队伍',
          disabled:false
        }
      })
      list.value = data
      store.heroes = list.value
    })
    return{
      list,
      clickEvent(idx){
        list.value[idx].btnInfo.text = '已添加'
        list.value[idx].btnInfo.disabled = true
      }
    }
  },
};
// TODOEnd

TeamList.js

// TODO:补全代码,实现目标效果
const TeamList = {
  template: `
  <div class="team-list">
      <h2>我的队伍</h2>
      <ul>
        <li class="team-item" v-for="(item,idx) in list">
          <span>{{item.name}}</span>
          <span>{{item.strength}}</span>
          <button @click="removeHero(item,idx)">移除</button>
        </li>
      </ul>
      <button class="sort-button" @click="sortStrength">按实力排序</button>
      <p class="total-strength">当前队伍战斗力:{{count}} </p>
  </div>
  `,
  setup() {
    let store = useHeroStore(),
    list = Vue.ref([]),
    count = Vue.ref(0)
    Vue.watch(()=>store.heroes,nv=>{
      count.value = 0
      list.value = nv.filter(item=>{
        if(item.btnInfo.disabled){
          count.value += item.strength
          return true
        }
      })
    },{deep:true})
    return {
      list,
      count,
      removeHero(item,idx){
        store.heroes[item.id-1].btnInfo.text = '添加至队伍里'
        store.heroes[item.id-1].btnInfo.disabled = false
      },
      sortStrength(){
        list.value.sort((a,b)=>b.strength - a.strength)
      },
    }
  },
};
// TODOEnd

9、万能合成台

这题的含金量还是比较高,考察了很多方面的知识点

这题我选择用了字符串来解

// state 辅助记录当前合成栏内容的全局变量
let state = [
  ['', '', ''],
  ['', '', ''],
  ['', '', '']
];

let targetItemName = ''; //辅助记录当前合成栏的可能目标合成物品每次 onPickItem 执行后,前端界面会根据此全局变量的值更改图标 

/** 检查当前的合成配方是否能够合成某个物品。如果配方合法,返回一个合成的目标物品名,否则返回一个空字符串。
 * @param {*} map 为一个 3*3 的二维数组,第一维为物品的每一横行,第二维为每一横行物品下的每个纵列
 */ 

function checkRecipe(map) {
  // TODO:待补充代码
  let rule = structuredClone(window.recipes)
  //用字符串来玩这道题
  let rMap = map.map(item=>{
    return (item+'').replaceAll(',',' ').trim()
  }),
  rRule = {},
  result = ''
  for (let key in rule) {
    rRule[key] = []
    for (let idx in rule[key]) {
      rRule[key][idx] = rule[key][idx].map(item=>(item+'').replaceAll(',',' ').trim())
    }
  }
  for(let key in rRule){
    for (const item of rRule[key]) {
      let _itemStr = ''
      //判断纵向是否拥有空位
      if((rMap+'')[0]==','){
        _itemStr = ','+item
      }else if((rMap+'')[(rMap+'').length-1]==','){
        _itemStr = item+','
      }else{
        _itemStr = item+''
      }
      if(_itemStr == rMap)result = key
    }
  }
  return result
}

/** 更新 state 中的物品位置
 * @param {string} name  为此次修改为的物品,可能为空字符串(通过右下角清空),也可能为物品
 * @param {Array<Number>} pos 为一个两个元素的数字数组,分别指示物品的所在横行与所在纵列
 */
function onPickItem(name, pos) {
  // TODO:待补充代码
  state[pos[0]-1][pos[1]-1] = name
  
  targetItemName = checkRecipe(state) || '';
}

10、账户验证

这题有个坑,最后清空了输入框的值依旧不给过,然后换了一种思路就可以了,上代码:

<!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/element-plus@2.3.7/index.css">
  <script src="./js/vue3.global.js"></script>
  <script src="./css/element-plus@2.3.7/index.full.js"></script>
  <script type="importmap">
      {
        "imports":{
          "vue-demi":"./js/index.mjs",
          "vue":"./js/vue.esm-browser.prod.js",
          "pinia":"./js/pinia.esm-browser.js"
        }
      }
  </script>
  <script src="./js/pinia.esm-browser.js" type="module"></script>
</head>

<body>
  <!-- app根组件开始 -->
  <div id="app">
    <div class="header">
      <img class="back-btn" src="images/arrow.png" />
      <span id="main_title">使用手机号登录</span>
      <span class="blank"></span>
    </div>
    <component :is="showName"></component>
  </div>
  <!-- app根组件结束 -->

  <!-- phone组件开始 -->
  <template id="phone">
    <div>
      <ul class="phone">
        <span>输入手机号码</span>
        <li>
          <input type="text" v-model="phoneVal" autofocus id="numberInput" />
        </li>
        <li>
          <input type="checkbox" v-model="isSure" name="" id="checkbox" />
          <span>已阅读并同意
            <a href="javascript:;">服务协议</a>
            和
            <a href="javascript:;">隐私保护指引</a>
          </span>
        </li>
        <button id="btn" @click="nextStep">下一步</button>
      </ul>
    </div>
  </template>
  <!-- phone组件结束 -->

  <!-- check组件开始 -->
  <template id="check">
    <ul class="number">
      <span>输入短信验证码</span>
      <li class="hassend">已向
        <i>{{handlePhoneVal}}</i>
        发送验证码
      </li>
      <li class="code-container">
        <input type="number" class="code" min="0" max="9" required>
        <input type="number" class="code" min="0" max="9" required>
        <input type="number" class="code" min="0" max="9" required>
        <input type="number" class="code" min="0" max="9" required>
        <input type="number" class="code" min="0" max="9" required>
        <input type="number" class="code" min="0" max="9" required>
      </li>
      <a href="javascript:;" id="resend" @click="resentCode">重新发送</a>
    </ul>
  </template>
  <!-- check组件结束 -->

  <!-- success组件开始 -->
  <template id="success">
    <div class="success">
      <ul>
        <div>验证成功!</div>
        <div>5s后将自动跳转</div>
      </ul>
    </div>
  </template>
  <!-- success组件结束 -->
</body>
<script type="module">
  import { createPinia, defineStore } from 'pinia'
  const { createApp, reactive, toRefs,provide,inject,ref,watch } = Vue
  const { ElNotification } = ElementPlus

  const app = createApp({
    setup() {
      let data = reactive({
        showName: "phone"
      })
      // TODO:补全代码实现目标需求
      //定义全局通信数据池
      const code = ref([])
      const phoneVal = ref('')
      const createCode = function(){    //随机生成二维码
        let res = ''
        function *_create(){
          let count = 0
          while(++count <= 6){
            yield Math.floor(Math.random()*10)
          }
        }
        for (const iterator of _create()) {
          res+=iterator
        }
        return res
      }
      const handlePhone = num =>{
        let res = ''
        for(let idx in num){
          if(idx>2 && idx<num.length-2){
            res+='*'
          }else{
            res+=num[idx]
          }
        }
        return res
      }
      //将通信数据派发渗透到子组件树
      provide('code',code)
      provide('phoneVal',phoneVal)
      provide('createCode',createCode)
      provide('data',data)
      provide('handlePhone',handlePhone)


      return {
        ...toRefs(data)
      }
    }
  })
  app.use(ElementPlus)
  app.use(createPinia())

  app.component("phone", {
    template: "#phone",
    setup() {
      // TODO:补全代码实现目标需求
      let isSure = ref('')
      let phoneVal = inject('phoneVal')
      let code = inject('code')
      let createCode = inject('createCode')
      let data = inject('data')

      //验证手机
      function verifyPhone(num){
        if(num.length!=11)return false
        return ((num[0]==1) && num[1]==8)
      }

      return {
        isSure,
        phoneVal,
        nextStep(){
          if(!isSure.value)
            return ElNotification({
              title: '发送失败',
              message: '请先阅读并同意下方协议',
              type: 'error',
            })
          if(!verifyPhone(phoneVal.value))
            return ElNotification({
              title: '发送失败',
              message: '无效的手机号码',
              type: 'error',
            })
          code.value = createCode()
          ElNotification({
            title: '发送成功',
            message: '您在验证码为'+code.value,
            type: 'success',
          })
          data.showName = 'check'
        }
      }
    }
  })
  app.component("check", {
    template: "#check",
    setup() {
      // TODO:补全代码实现目标需求
    let phoneVal = inject('phoneVal'),
      handlePhoneVal = inject('handlePhone')(phoneVal.value),
      data = inject('data'),
      code = inject('code'),
      createCode = inject('createCode'),
      rVal = ''
      setTimeout(()=>{    //将代码放入宏队列以此获取dom,用onMounted也行

        let oCodeIptList = [...document.getElementsByClassName('code')]
        
        oCodeIptList[0].focus() //第一个默认聚焦

        oCodeIptList.map(item=>{
          item.oninput=function(){
            if(item.value){   //如果输入了值就聚焦下一个,否则聚焦上一个 
              item?.nextElementSibling && item?.nextElementSibling.focus()
            }else{
              item?.previousElementSibling && item?.previousElementSibling.focus()
            }
            rVal = (oCodeIptList.map(item=>item.value)+'').replaceAll(',','')  //这里很关键,之前我用了这种方式之后,清空六个输入框的检测就给通过了
            trackVal(rVal)
          }
        })
        
        function trackVal(val){
          if(val.length>=6){
            if(val == code.value){
              ElNotification({
                title: '验证成功',
                message: "欢迎回来",
                type: 'success',
              })
              data.showName = 'success'
            }else{
              ElNotification({
                title: '验证失败',
                message: "您输入的验证码有误",
                type: 'error',
              })
              ;[...document.getElementsByClassName('code')].map(item=>item.value = '') //清空输入框
              ;[...document.getElementsByClassName('code')][0].focus() //重新聚焦第一个
            }
          }
        }
      })

      return {
        handlePhoneVal,
        resentCode(){
          code.value = createCode()
          ElNotification({
            title: '发送成功',
            message: '您在验证码为'+code.value,
            type: 'success',
          })
        }
      }
    }
  })
  app.component("success", {
    template: "#success"
  })
  app.mount('#app')

</script>

</html>

  • 13
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值