Lanqiao Cup Web Programming Training Materials

website·Indexed 30 days ago

https://lanqiaoweb.netlify.app

A collection of teacher training courseware and mock exams for the Lanqiao Cup competitions. It covers frontend development topics including HTML/CSS, DOM operations, ES6, Vue3, Element-Plus, Pinia, Echarts, and Node.js, featuring practical problems and solutions from the 13th, 14th, and 15th provincial and national competitions.

Tokens
28.2K
Snippets
126
Records
137
Agent score
75%

What's inside Lanqiao Cup Web Training

  1. Get file and directory metadata using fs.stat()

    The fs.stat() method retrieves status information about a file or directory. The resulting stats object provides properties to determine the file type and size.
    const fs = require('fs');
    
    fs.stat('example.txt', (err, stats) => {
      if (err) {
        console.error(err);
        return;
      }
      console.log('File size in bytes:', stats.size);
      console.log('Is it a file?', stats.isFile());
      console.log('Is it a directory?', stats.isDirectory());
      console.log('Is it a symbolic link?', stats.isSymbolicLink());
    });
  2. Parse and write text files using Node.js fs module

    To process a structured text file (e.g., a novel with chapters) into JSON and save it, use fs.readFileSync for reading and fs.writeFileSync for writing. The process involves splitting the content by newlines, trimming whitespace, and using regular expressions to identify volumes and chapters.
    // Reading the file
    const data = fs.readFileSync(file, 'UTF-8');
    const lines = data.split('\n');
    
    // Example logic: 
    // 1. First line is the book title: lines[0].trim()
    // 2. Iterate through lines to match 'Volume' or 'Chapter' using regex
    // 3. Collect content until a separator (e.g., '-------------') is found
    
    // Writing the processed JSON data
    fs.writeFileSync(file, JSON.stringify(processedData), 'UTF-8');
  3. Implement a basic Markdown to HTML parser in Node.js

    This example demonstrates how to build a Markdown parser using regular expressions to convert Markdown syntax (headings, blockquotes, unordered lists, images, bold text, and inline code) into HTML. The implementation uses a Parser class for regex matching and a Reader class to manage line-by-line processing.
    class Parser {
      constructor() {
        this.heading = /^(#{1,6}\s+)/;
        this.blockQuote = /^(\>\s+)/;
        this.unorderedList = /^((*|-){1}\s+)/;
        this.image = /\!\[(.*?)\]\((.*?)\)/g;
        this.strongText = /\*{2}(.*?)\*{2}/g;
        this.codeLine = /\`{1}(.*?)\`{1}/g;
        this.hr = /^(\*{3,}|-{3,})/
      }
    
      parseLineText(lineText) { this.lineText = lineText; }
      isEmptyLine() { return this.lineText === ""; }
      parseEmptyLine() { return "<br/>"; }
      isHeading() { return this.heading.test(this.lineText); }
      parseHeading() {
        const temp = this.lineText.split(" ");
        const headingLevel = temp[0].length;
        const title = temp[1].trim();
        return `<h${headingLevel}>${title}</h${headingLevel}>`;
      }
      isUnorderedList() { return this.unorderedList.test(this.lineText); }
      parseUnorderedList() {
        const tempStr = this.lineText.replace(this.unorderedList, "");
        return "<li>" + tempStr + "</li>";
      }
      isHr() { return this.hr.test(this.lineText); }
      parseHr() { return "<hr>"; }
      isBlockQuote() { return this.blockQuote.test(this.lineText); }
      parseBlockQuote() {
        const tempStr = this.lineText.replace(this.blockQuote, "");
        return "<p>" + tempStr + "</p>";
      }
      isImage() { return this.image.test(this.lineText); }
      parseImage(str) {
        return str.replace(this.image, (result, str1, str2) => {
          return '<img src="' + str2 + '" alt="' + str1 + '">';
        });
      }
      isStrongText() { return this.strongText.test(this.lineText); }
      parseStrongText(str) {
        return str.replace(this.strongText, (result, str1) => {
          return "<b>" + str1 + "</b>";
        });
      }
      isCodeLine() { return this.codeLine.test(this.lineText); }
      parseCodeLine(str) {
        return str.replace(this.codeLine, (result, str1) => {
          return "<code>" + str1 + "</code>";
        });
      }
      inlineParse() {
        let str = this.lineText;
        if (this.isCodeLine()) str = this.parseCodeLine(str);
        if (this.isImage()) str = this.parseImage(str);
        if (this.isStrongText()) str = this.parseStrongText(str);
        return str;
      }
    }
    
    class Reader {
      constructor(text) {
        this.text = text;
        this.lines = this.text.split("\n");
        this.parser = new Parser();
      }
    
      runParser() {
        let currentLine = 0;
        let hasParsed = [];
        while (currentLine < this.lines.length) {
          this.parser.parseLineText(this.lines[currentLine]);
          if (this.parser.isEmptyLine()) {
            hasParsed.push(this.parser.parseEmptyLine());
            currentLine++;
            continue;
          }
          if (this.parser.isHeading()) {
            hasParsed.push(this.parser.parseHeading());
            currentLine++;
            continue;
          }
          if (this.parser.isHr()) {
            hasParsed.push(this.parser.parseHr());
            currentLine++;
            continue;
          }
          if (this.parser.isBlockQuote()) {
            const tempParsed = ["<blockquote>"];
            while (currentLine < this.lines.length && this.parser.isBlockQuote()) {
              tempParsed.push(this.parser.parseBlockQuote());
              currentLine++;
              if (currentLine < this.lines.length) this.parser.parseLineText(this.lines[currentLine]);
            }
            tempParsed.push("</blockquote>");
            hasParsed.push(...tempParsed);
            continue;
          }
          if (this.parser.isUnorderedList()) {
            const tempParsed = ["<ul>"];
            while (currentLine < this.lines.length && this.parser.isUnorderedList()) {
              tempParsed.push(this.parser.parseUnorderedList());
              currentLine++;
              if (currentLine < this.lines.length) this.parser.parseLineText(this.lines[currentLine]);
            }
            tempParsed.push("</ul>");
            hasParsed.push(...tempParsed);
            continue;
          }
          hasParsed.push(this.parser.inlineParse());
          currentLine++;
        }
        return hasParsed.join("");
      }
    }
    
    module.exports = function parseMarkdown(markdownContent) {
      return new Reader(markdownContent).runParser();
    };
  4. Integrate Echarts with Vue.js for dynamic data visualization

    To integrate Echarts within a Vue.js application, initialize the chart instance inside the mounted hook using $nextTick to ensure the DOM element is available. Use echarts.init() to bind the chart to a DOM element and setOption() to apply the configuration object. When updating data dynamically (e.g., switching months or views), update the specific properties of the chartOptions object and call this.chart.setOption(this.chartOptions) again to refresh the visualization.
    // Inside Vue instance
    mounted() {
      this.$nextTick(() => {
        this.initChart();
      });
    },
    methods: {
      initChart() {
        this.chart = echarts.init(document.getElementById('chart'));
        this.chartOptions = {
          xAxis: { type: 'category', data: [] },
          yAxis: { type: 'value' },
          series: [{ type: 'line', data: [] }]
        };
        this.chart.setOption(this.chartOptions);
      },
      updateChart(newData, newXAxis) {
        this.chartOptions.xAxis[0].data = newXAxis;
        this.chartOptions.series[0].data = newData;
        this.chart.setOption(this.chartOptions);
      }
    }
  5. Handle HTTP request bodies in Node.js

    In Node.js, the http.ClientRequest object (the req object in a server handler) provides data as a stream. To capture the full request body (e.g., for PUT or POST requests), you must listen for the data event to accumulate chunks and the end event to process the final result.
    let result = '';
    req.on('data', data => {
        // Accumulate data chunks
        result += data;
    });
    req.on('end', () => {
        // Request body fully received
        if (result) {
            send(res, 0, '', result); // Example: send result back to client
        }
    });
  6. Submit files for Lanqiao Frontend Competition

    Follow these strict submission guidelines to avoid disqualification or loss of points:

    • Packaging: Compress folders into ZIP files (e.g., 01 folder becomes 01.zip, 02 folder becomes 02.zip).
    • No Single Files: Do not submit individual files; always submit a compressed folder.
    • No Passwords: Do not set a password on the ZIP archives.
    • Final Check: Verify that all answers have been submitted at least 20 minutes before the exam ends.
  7. Implement a Bar Chart with Vue and ECharts

    This example demonstrates how to integrate ECharts within a Vue.js application to visualize data fetched via axios. Key implementation details include mapping API response arrays to ECharts xAxis and series data, and updating the chart dynamically when a user selects a specific item from a dropdown.
    // Inside a Vue instance
    methods: {
      initChart() {
        this.chart = echarts.init(document.getElementById("chart"));
        this.chartOptions = {
          title: {
            text: "Global Confirmed Cases",
            left: "center"
          },
          tooltip: {
            trigger: "axis",
            axisPointer: { type: "shadow" }
          },
          xAxis: {
            // Map data to labels (e.g., Country Codes)
            data: this.allData.map((item) => item.CountryCode),
            axisLabel: { show: true, interval: 0 }
          },
          yAxis: {
            type: "value",
            name: "Confirmed Count"
          },
          series: [{
            // Map data to values (e.g., Total Confirmed)
            data: this.allData.map((item) => item.TotalConfirmed),
            type: "bar",
            itemStyle: { normal: { color: "#a90000" } }
          }]
        };
        this.chart.setOption(this.chartOptions);
      }
    }
  8. Implement dependent dropdowns and address management

    This example shows how to synchronize two dropdown lists (Province and City) where the second list updates based on the selection of the first. It also includes logic for managing a list of addresses, including validation and dynamic HTML generation for the address list.
    // Update city dropdown based on selected province
    function provincechange() {
      var province = document.getElementById("param_province");
      var num = province.selectedIndex;
      var city = document.getElementById("param_city");
      var citystemp = citys[num];
      city.length = citystemp.length;
      for (var i = 0; i < citystemp.length; i++) {
        city.options[i].text = citystemp[i];
        city.options[i].value = citystemp[i];
      }
      city.options[0].selected = true;
    }
    
    // Save address and prepend to the list
    function saveInfo() {
      var province = document.getElementById("param_province").value;
      var city = document.getElementById("param_city").value;
      var address = document.getElementById("param_address").value;
      var mark = document.getElementById("param_mark").value;
      var name = document.getElementById("param_name").value;
      var phone = document.getElementById("param_phone").value;
    
      if (!province || !city || !address || !name || !phone) {
        document.querySelector(".warning-dialog").style.display = "block";
        return false;
      }
    
      // Logic to determine label based on 'mark' value
      var markClass = "", markInfo = "";
      switch (mark) {
        case "0": markClass = "home"; markInfo = "家"; break;
        case "1": markClass = "company"; markInfo = "公司"; break;
        case "2": markClass = "school"; markInfo = "学校"; break;
      }
    
      var addressInfoStr = `<li class="show-area">
        ${markInfo ? `<label class="${markClass}">${markInfo}</label>` : ""}
        <span>${province + city}</span>
        <div class="show-address"><span>${address}</span></div>
        <div class="show-info"><span>${name}</span><span>${phone}</span></div>
      </li>`;
    
      document.querySelector(".address-list").innerHTML = addressInfoStr + document.querySelector(".address-list").innerHTML;
      document.querySelector(".address-list").style.display = "block";
    }
  9. Common ECharts Implementation Patterns for Competitions

    When implementing ECharts in technical assessments, focus on these high-frequency technical points:

    1. Data Processing: Transforming raw API responses (JSON) into arrays compatible with ECharts using .map() or .find().
    2. Axis Configuration: Correctly assigning data to xAxis.data and series[].data.
    3. Chart Rendering: Using myChart.setOption(option) to apply configurations.
    4. Responsiveness: Adding a window resize listener calling chart.resize() to ensure the chart scales with the browser.
  10. Element Plus exam focus and preparation

    For technical assessments, Element Plus questions typically focus on 'Form Configuration' and 'Basic Component Configuration'. The difficulty is generally low to medium. Since the necessary APIs are usually provided during the exam, focus on Vue.js fundamentals rather than memorizing the full Element Plus API documentation.
  11. Prepare for Lanqiao Frontend Provincial Competition

    To maximize scores in the Lanqiao Frontend Provincial Competition, prioritize tasks based on the following difficulty and point distribution:

    1. High Priority (Must-win points):
      • HTML + CSS: Short time investment, typically 5-20 points.
      • Element-Plus & Vue 3 Basics/API: Usually one question, 10-15 points.
      • ECharts: Data operation tasks, usually one question, 10-25 points.
    2. Medium Priority:
      • ES6 Function Encapsulation: Aim for points, but skip overly complex encapsulation tasks to focus on other problems first.
      • DOM Operations: Aim for maximum points.
      • Vue 3 Intermediate: Ensure all basic key points are reviewed.
    3. Advanced/High-Score Targets:
      • Complex data structures, recursion, and 2D arrays.
      • Node.js comprehensive tasks (University group only): Medium-high difficulty, 15-20 points.
  12. Write files using the Node.js fs module

    Use fs.writeFile() for asynchronous writing and fs.writeFileSync() for synchronous writing. Synchronous writing blocks the event loop until the operation completes. Both methods typically take the file path, data, and encoding (default 'utf8').
    const fs = require('fs');
    
    // Asynchronous write
    fs.writeFile('example.txt', 'Hello, world!', 'utf8', (err) => {
      if (err) throw err;
      console.log('File written successfully.');
    });
    
    // Synchronous write
    try {
      fs.writeFileSync('example.txt', 'Content here', 'utf8');
      console.log('File written successfully');
    } catch (err) {
      console.error('Error writing file:', err);
    }