惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

量子位
Stack Overflow Blog
Stack Overflow Blog
人人都是产品经理
人人都是产品经理
The GitHub Blog
The GitHub Blog
Engineering at Meta
Engineering at Meta
Vercel News
Vercel News
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Y
Y Combinator Blog
The Cloudflare Blog
Last Week in AI
Last Week in AI
B
Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
T
Tailwind CSS Blog
V
Visual Studio Blog
博客园 - 三生石上(FineUI控件)
小众软件
小众软件
Google DeepMind News
Google DeepMind News
D
DataBreaches.Net
博客园 - 司徒正美
B
Blog RSS Feed
Microsoft Azure Blog
Microsoft Azure Blog
罗磊的独立博客
Hugging Face - Blog
Hugging Face - Blog
L
LangChain Blog

龙辉's Blog

对学某通的登录逆向分析 - 龙辉's Blog 天方云签程序开源 - 龙辉's Blog CTFSHOW-菜狗杯(部分WP) - 龙辉's Blog 记录一次入侵某钓鱼盗号网站的过程 - 龙辉's Blog 贵州师范大学抢课脚本-正方教务系统V8.0.0 - 龙辉's Blog 简单实现每日健康自动打卡 - 龙辉's Blog 弱类型与强类型语言“=”号的不同以及引发的安全问题 - 龙辉's Blog php获取客户端ip以及ip伪造 - 龙辉's Blog XSS经典漏洞复现-手撕某非法获取个人信息网站 - 龙辉's Blog php7.2中each()函数被弃用的替换办法 - 龙辉's Blog
蓝桥杯省赛Web题解及知识点复习 - 龙辉's Blog
博主: Tinker-站长 · 2024-05-28 · via 龙辉's Blog
本次蓝桥杯省赛在4月13号结束,并在省赛中取得了一等奖的成绩,题目放在文末。本次记录主要是复盘一下知识点,引用官方题解,如果大佬们有更好的方法,欢迎交流学习~

我之前留意到一位UP主推荐的这本书,觉得挺吸引人的,于是入手了一本。该书出自外国作者之手并已被译成中文。阅读之后,我发现它的确颇有价值,特别是它为我提供了全新的视角去理解这门语言,尤其是在函数式编程和异步编程领域,让我收获了不一样的见解和领悟。

2024-05-28T14:24:19.png

1、智能停车系统

第一题是“签到题”,也就是证明你来参加过比赛的,
考察的是css中的

flex布局和grid布局

它们是css3新增的响应式布局,比较常用。另外还有浮动、定位、边距等实现布局的方式,在flex布局中,主要分为主轴,和侧轴,默认为主轴方向排列(flex-firection:row),而以下代码分别作用于父元素与子元素
作用于父元素:

display:flex;
justify-content:center; /*沿着轴的方向布局方式(居中)*/

flex-direction:column;   /*改变轴的方向为垂直方向:*/

align-item:center;  /*交叉轴的排列方式(居中)*/

flex-warp:warp;    /*换行*/

子元素

flex-shrink:0;  /*不允许被挤压*/

flex:flex-grow flex-shrink  flex-basis; /*缩写形式*/

order:1;  /*改变顺序*/

因此本题的答案只需要在最后三行添加代码即可

.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; 
}

2024-05-27T04:15:49.png
并且文档中的提示均已给出,直接使用space-around即可实现

2、布局切换

js中较为经典的题目了,同样也是签到题。“干掉他人,留下自己”是这道题的精髓,也就是当按钮被点击的时候,就取消所有样式,再给自己添加上这个样式

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

2024-05-27T04:17:57.png

3、产品 360 度展示

开始上点难度了,考察的是Promise以及asyncawait
Promise的出现是解决回调地狱的问题,而async则是Promise和generator结合的语法糖,使得异步编程同步化 ,在执行同步操作的时候也不会造成阻塞。
2024-05-27T04:26:41.png

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

4、多表单验证

考察的是Elementplus的表单验证 ,对于我来说,最难受的就是做布局的题目了。
这个题我当时想着后面做,结果发现没时间了。

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" },
  ],
});

5、找回连接的奇幻之旅

考察了闭包函数、剩余参数、call、apply以及this的指向问题
这里给大家辨析以下callapply以及bind方法的区别,
call和apply的区别在于第二个参数前者接收的是单个参数(从第二个参数开始,你可以直接列举出需要传递给函数的参数,它们会按照顺序传递。),而后者接收的是一个数组,两个方法都会让函数能够立即执行。
bind方法第二个参数接收的方式与call相同,但是函数不会立即执行。

我理解的闭包函数特点有:
1、让内部函数访问其所在外部函数的作用域中的变量,即使外部函数已经执行完毕,只要内部函数还被引用,这些外部变量就不会被垃圾回收机制回收。
2、维持外部函数局部变量的持久性。即使外部函数执行结束,由于内部函数持有对外部变量的引用,这些变量的值可以跨函数调用被保留下来

function resetableOnce(fn) {
  let done = false; // 标记函数是否已执行
  let result; // 保存函数执行的结果

  /**
   * 保证只执行一次的函数
   * @returns {Any} 返回函数fn的执行结果
   */
  function runOnce(...ags) {
    if (!done) {
      // 如果之前没有执行过,则执行函数fn,并保存结果
      result = fn.apply(this, ags);
      done = true; // 标记为已完成,确保之后不再执行
    }
    // 返回之前执行的结果
    return result;
  }

  /**
   * 重置函数的执行状态
   */
  function reset() {
    done = false; // 重置done为false,允许函数再次执行
  }

  // 返回控制对象
  return { runOnce, reset };
}





6、tree 命令助手

考察知识点:Node.js递归.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;
}

7、Github 明星项目统计

vue3的双向绑定
array的原型方法,filter、map
由于JavaScript单线程的特性,为了不阻塞用户界面和其他任务的执行,它使用异步处理机制来处理耗时操作,因此大量的使用回调函数来处理问题,在js中函数是“一等公民”,也就是能够像变量一样当作参数来传递。而箭头函数与普通函数的区别则在于箭头函数不绑定自己的this值,它会捕获其所在上下文的this值作为自己的this。箭头函数其实就是其它编程语言的lambda表达式。

<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>

8、小蓝驿站

主要还是考察vue3的数据处理以及字符串的原型方法。js是一门面向对象的语言,它实现面向对象的方式与java、python、php等编程语言不同,前者是基于原型实现,后者是基于类实现,在ES6中虽然引入了class的概念,但是它本质上还是原型的语法糖。

// 目标 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>

9、 商品浏览足迹

考察知识点:

  1. axios
  1. 对象去重
  1. Date对象


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;
}


10、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);
          }
        }
      );
    }
  });
}

2024-05-28T14:00:53.png


版权属于:龙辉博客

本文链接:https://blog.eirds.cn/440.html

如果没有特别声明则为本博原创。转载时须注明出处及本声明!