IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    蓝桥杯十五届省赛Web应用开发题目答案解析

    Veen Zhao发表于 2024-04-14 22:06:00
    love 0

    去年报了个蓝桥杯Web,昨天刚打完省赛,10道题基本无压力 ::(呵呵) ([DarkBText]果然是圈钱杯[/DarkBText]),最后一道可能会扣点分,整理一下赛后直播的答案,也包括职业院校组的,给需要的小伙伴们:

    1. 智能停车系统 ⭐️

    考点: flex 布局
    解题答案:

    .cars {
      position: absolute;
      z-index: 2;
      display: flex;
      width: 600px;
      height: 600px;
      flex-direction: column;
     /* TODO: 请在下方编写题目代码,不要更改其他选择器里的代码 */
      flex-wrap: wrap;  
      align-content:space-between; 
      justify-content:space-between; 
    }

    2. 分享点滴 ⭐️

    考察:对象的遍历,字符串基本操作
    答案1:

    function appendParamsToURL(url, params) {
      // 创建一个空字符串来存储参数字符串
      let str = "";
    
      // 遍历参数对象中的每个键
      for (const key in params) {
        // 将键值对追加到字符串中
        str += `${key}=${params[key]}&`;
      }
    
      // 移除字符串末尾的 "&" 符号
      str = str.slice(0, -1);
    
      // 判断是否原始 URL 已包含查询字符串(通过是否包含 "?" 符号来判断)
      // 如果已包含查询字符串,则设置 sym 变量为 "&",用于以 "&" 作为分隔符追加参数
      // 否则,设置 sym 变量为 "?",作为查询字符串的起始符号
      let sym = url.includes("?") ? "&" : "?";
    
      // 连接原始 URL、sym 符号和参数字符串,并返回最终的 URL
      return `${url}${sym}${str}`;
    }

    答案2:

    function appendParamsToURL(url, params) {
      // 使用 Object.entries() 获取参数对象的所有键值对并按照规则拼接
      const paramArray = Object.entries(params).map(
        ([key, value]) => `${key}=${value}`
      );
      // 使用join方法拼接参数字符串
      const paramString = paramArray.join("&");
      // 判断URL中是否已包含参数
      let sym = url.includes("?") ? "&" : "?";
      // 返回拼接后的URL
      return `${url}${sym}${paramString}`;
    }

    3. 布局切换 ⭐️

    考察 DOM 操作、class 类名操作

      option.addEventListener('click', function () {
           for (const otherOption of layoutOptions) {
                // 移除其他选项的 active 类
                otherOption.classList.remove('active');
             }
            // TODO:待补充代码
            this.classList.add('active'); // 为当前选项添加active类
      }

    4. 产品 360 度展示 ⭐️⭐️

    考察:Promise、循环
    答案1:

    const pipeline = async (initialValue, sequence) => {
      let res = initialValue;
      for (const fn of sequence) {
        res = await fn(res);
      }
      return res;
    };

    答案2:

    const pipeline = (initialValue, sequence) => {
      let res = Promise.resolve(initialValue);
      for (const fn of sequence) {
        res = res.then((result) => fn(result));
      }
      return res;
    };

    5. 多表单验证 ⭐️

    考察element-plus组件的使用

    const validateName = (rule, value, callback) => {
      if (value === "") {
        callback(new Error("请输入姓名"));
      } else {
        const reg = /[^\u4e00-\u9fa5]/g;
        if (reg.test(value)) {
          callback(new Error("只能输入汉字"));
        }
        callback();
      }
    };
    // TODO-3:书写表单校验规则,并绑定到对应表单上
    const rules = reactive({
      name: [
        { required: true, message: "请输入姓名", trigger: "blur" },
        { validator: validateName, trigger: "blur" },
      ],
      sex: [{ required: true, message: "请选择性别", trigger: "change" }],
      age: [{ required: true, message: "请输入年龄", trigger: "blur" }],
      isCompetition: [
        { required: true, message: "请选择是否参加过编程比赛", trigger: "change" },
      ],
      isEntrepreneurship: [
        { required: true, message: "请选择是否有过创业经历", trigger: "change" },
      ],
    });

    6. 找回连接的奇幻之旅 ⭐️⭐️⭐️

    考察:函数封装、闭包

    function resetableOnce(fn) {
      let done = false; // 标记函数是否已执行
      let result; // 保存函数执行的结果
    
      /**
       * 保证只执行一次的函数
       * @returns {Any} 返回函数fn的执行结果
       */
      function runOnce() {
        if (!done) {
          // 如果之前没有执行过,则执行函数fn,并保存结果
          result = fn.apply(this, arguments);
          done = true; // 标记为已完成,确保之后不再执行
        }
        // 返回之前执行的结果
        return result;
      }
    
      /**
       * 重置函数的执行状态
       */
      function reset() {
        done = false; // 重置done为false,允许函数再次执行
      }
    
      // 返回控制对象
      return { runOnce, reset };
    }

    7. 悠然画境 ⭐️⭐️

    考察数组操作、字符串操作

    function generateAndDisplayImages(imageCount, selectedText) {
      // TODO:待补充代码 根据数量和用户输入在页面上生成图片并显示到 .right-panel 元素中
      let count = 0;
      artDataArray.forEach((el) => {
        let tags = el.tags.split("、");
        tags.forEach((tag) => {
          if (selectedText.includes(tag)) {
            count++;
          }
        });
        el["count"] = count;
        count = 0;
      });
    
      artDataArray.sort((a, b) => {
        return b.count - a.count; // 从小到大 -> a.age - b.age
      });
      let b = artDataArray.slice(0, imageCount);
      return b;
    }

    8. 简易 JSX 解析器 ⭐️⭐️

    考察 dom 操作、字符串方法

    /**
     * 将驼峰式命名转换为短横线命名
     * @param {string} str - 驼峰式命名的字符串
     * @returns {string} - 转换后的短横线命名字符串
     */
    function camelToDash(str) {
      let result = "";
      let hasUppercase = false; // 标记字符串中是否包含大写字母
    
      for (let i = 0; i < str.length; i++) {
        let char = str.charAt(i);
    
        // 检查当前字符是否为大写字母
        if (char === char.toUpperCase()) {
          hasUppercase = true;
          if (i > 0) {
            result += "-"; // 在大写字母前添加短横线
          }
          result += char.toLowerCase(); // 将大写字母转换为小写字母并添加到结果中
        } else {
          result += char; // 如果不是大写字母,直接添加到结果中
        }
      }
    
      // 如果字符串中没有大写字母,则直接返回原字符串
      if (!hasUppercase) {
        return str;
      }
    
      return result;
    }
    
    const jsx = (type, config) => {
      /* TODO: 请完善 jsx 函数的代码实现 */
      const dom = document.createElement(type);
      for (let key in config) {
        const prop = config[key];
        if (key === "style") {
          // 处理样式
          let styleStr = Object.entries(prop)
            .map((item) => {
              return `${camelToDash(item[0])}:${item[1]}`;
            })
            .join(";");
          dom.setAttribute("style", styleStr);
        } else if (typeof prop === "function") {
          dom[key] = prop;
        } else if (key === "children") {
          // 处理 children
          if (typeof prop === "string") {
            dom.appendChild(document.createTextNode(prop));
          } else {
            prop.forEach((child) =>
              typeof child === "string"
                ? dom.appendChild(document.createTextNode(child))
                : dom.appendChild(child)
            );
          }
        } else {
          // 处理其他属性
          dom.setAttribute(key, prop);
        }
      }
      return dom;
    };

    9. tree 命令助手 ⭐️⭐️⭐️

    考察 fs、递归函数

    function generateTree(dirPath) {
      // 读取目录下的所有文件和文件夹
      const files = fs.readdirSync(dirPath);
      const tree = [];
    
      files.forEach(file => {
        const filePath = path.join(dirPath, file);
        const isDirectory = fs.statSync(filePath).isDirectory();
    
        if (isDirectory) {
          // 如果是目录,则递归生成子目录的文件树
          const subtree = generateTree(filePath);
          tree.push({ name: file, children: subtree });
        } else {
          // 如果是文件,则直接添加到文件树
          tree.push({ name: file });
        }
      });
    
      return tree;
    }

    10. Github 明星项目统计 ⭐️⭐️⭐️

    考察 vue3 v-for、Echarts 数据处理

    <select name="language" id="language" @change="changeHandle" v-model="language">
      <option v-for="language in languages" :value="language">{{language}}</option>
    </select>
    <script>
      setup() {
           const changeHandle = () => {
              let newData = chartData.value.filter(item => item.language === language.value);
              if (language.value === 'All') {
                newData = chartData.value;
              }
              newData = newData.slice(pageStart.value - 1, pageEnd.value);
              xData.value = newData.map(item => item.name);
              yData.value = newData.map(item => item.stars);
              initChart();
            };
      }
    </script>

    11. 小蓝驿站 ⭐️⭐️⭐️

    考察 vue3 v-for、ref、数据处理

    // 目标 1
    <ul class="contacts-list">
      <!-- 使用 Vue 的 v-for 指令循环渲染 sortedContacts 中的每个联系人组 -->
      <li
        class="contacts-group"
        v-for="(group, groupIndex) in sortedContacts"
        :key="groupIndex"
      >
        <!-- 如果联系人组中有联系人,则显示该组的标题 -->
        <div v-if="group.contacts.length > 0" class="contacts-group-title">
          {{ group.letter }}
        </div>
        <!-- 使用 v-for 指令循环渲染每个联系人 -->
        <ul>
          <li
            class="contact-item"
            v-for="(contact, contactIndex) in group.contacts"
            :key="contactIndex"
          >
            <!-- 显示联系人名字 -->
            <span class="contact-name">{{ contact.name }}</span>
            <button class="del-contact-button">删除</button>
          </li>
        </ul>
      </li>
    </ul>
    <script>
        setup() {
            // 目标 2
        const addContact = () => {
          // TODO:待补充代码 目标 2
          if (newContact.value.trim() !== "") {
            // 获取新联系人名字的首字母并转为大写
            const firstLetter = newContact.value[0].toUpperCase();
            // 查找是否有相同首字母的联系人组
            const groupIndex = contacts.value.findIndex(
              (group) => group.letter === firstLetter
            );
            if (groupIndex > -1) {
              // 如果找到了相同首字母的联系人组,就添加到该组
              contacts.value[groupIndex].contacts.push({ name: newContact.value });
            } else {
              // 如果没有找到相同首字母的联系人组,就新建一个组,并添加到联系人列表
              const newGroup = {
                letter: firstLetter,
                contacts: [{ name: newContact.value }],
              };
              contacts.value.push(newGroup);
            }
          }
          // TODO:END
          // 添加完成清空联系人输入框
          newContact.value = "";
        };
      }
    </script>

    12. 商品浏览足迹 ⭐️⭐️⭐️

    考察 axios 请求、数据处理

    window.onload = async ()=> {
          const res = await  axios("./js/data.json");
          const newData = getData(res.data);
          showData(newData);
    };
    /**
     * 将同一天浏览的相同商品去重并作为数组返回
     * @param {Array} defaultData json 文件中读取到的原始数据
     * @returns 去重后的数据,数据结构与 defaultData 相同
     */
    const removeDuplicates = defaultData => {
      let newData = [];
      // TODO:在下面补充代码,最终完成该函数封装
      defaultData.forEach((defaultGoods) => {
        const defaultDate = new Date(defaultGoods.viewed_on);
        const dD = `${defaultDate.getFullYear()}-${
          defaultDate.getMonth() + 1
        }-${defaultDate.getDate()}`;
        defaultGoods.date = dD;
    
        let hadThisGoods = false;
        newData.forEach((tmpGoods) => {
          const tmpDate = new Date(tmpGoods.viewed_on);
          const tD = `${tmpDate.getFullYear()}-${
            tmpDate.getMonth() + 1
          }-${tmpDate.getDate()}`;
          if (tmpGoods.id == defaultGoods.id && tD == dD) {
            hadThisGoods = true;
          }
        });
        if (!hadThisGoods) {
          newData.push(defaultGoods);
        }
      });
      return newData;
    }
    
    /**
     * 将去重后的数据根据字段 viewed_on(格式化为 YYYY-MM-DD) 降序排序
     * @param {*} defaultData 去重后的数据
     * @returns 根据字段 viewed_on(格式化为 YYYY-MM-DD) 降序排序
     */
    const sortByDate = defaultData => {
      let newData = [];
      // TODO:在下面补充代码,最终完成该函数封装
      function sortByProperty(property, asc) {
        return function (value1, value2) {
          let a = new Date(value1[property]);
          let b = new Date(value2[property]);
          // 默认升序
          if (asc == undefined) {
            return a - b;
          } else {
            return asc ? a - b : b - a;
          }
        };
      }
      newData = defaultData.sort(sortByProperty("date", false));
      return newData;
    }
    /**
     * 将去重排序后的所有商品数据,作为一个对象存储并返回,
     * 该对象的所有 `key` 为浏览商品的当天日期(即,字段 viewed_on 格式化为 YYYY-MM-DD),
     * `value` 为当天浏览的所有商品(以数组形式表现)。
     * @param {Array} defaultData 重后的所有商品数据
     * @returns 
     */
    const transformStructure = defaultData => {
      let newData = {};
      // TODO:在下面补充代码,最终完成该函数封装
      //  月份和日期 不足10的前面补0
      defaultData.forEach(item=>{
        let date=new Date(item.date) ;
        let y = date.getFullYear()
        let m = date.getMonth()+1
        m=m<10?'0'+m:m
        let d = date.getDate();
        d=d<10?'0'+d:d
        item.date=`${y}-${m}-${d}`;   
      })
      newData = defaultData.reduce((aD, item) => {
        console.log(item);
        if (!aD[item.date]) {
          aD[item.date] = [];
          aD[item.date].push(item);
        } else {
          if (!aD[item.date].includes(item.date)) {
            aD[item.date].push(item);
          }
        }
        return aD;
      }, {});
      return newData;
    }

    13. 扫雷游戏 ⭐️⭐️⭐️⭐️

    考察二维数组操作、递归

    function mineSweeperAlgorithms(arr, { row, col }) {
      if (flagData[row][col]) return;
    
      flagData[row][col] = true;
    
      const { positionWithoutMineArr, count } = getAroundAndCount(arr, {
        row,
        col,
      });
    
      if (count == 0) {
        // 如果当前格子周围没有地雷,递归执行扫雷算法
        positionWithoutMineArr.forEach((around) => {
          mineSweeperAlgorithms(arr, around);
        });
      }
    }

    14.NPM Download Simulator ⭐️⭐️⭐️⭐️

    考察:获取数据类型、 promise.race

    function myRace(iterable) {
      return new Promise((resolve, reject) => {
        if (!(Symbol.iterator in Object(iterable))) {
          reject(
            new TypeError(
              `${Object.prototype.toString
                .call({ iterable })
                .slice(-8, -1)
                .toLocaleLowerCase()} is not iterable`
            )
          );
          return;
        }
        const promises = Array.from(iterable);
        let resolvedOrRejected = false;
        for (const promise of promises) {
          Promise.resolve(promise).then(
            (value) => {
              if (!resolvedOrRejected) {
                resolvedOrRejected = true;
                resolve(value);
              }
            },
            (reason) => {
              if (!resolvedOrRejected) {
                resolvedOrRejected = true;
                reject(reason);
              }
            }
          );
        }
      });
    }

    当然,web只要最终实现的效果和题目中描述的一致,那就能得分,上面答案只是参考。总体感觉难度不大,希望能进一波国赛吧



沪ICP备19023445号-2号
友情链接