5个JavaScript入门实战小案例:巩固基础语法

作者:小圆点时间:2026-10-30 19:07:13浏览:667

通过交互式计数器、汇率换战器、动态待办清单、实时字数统计与随机名言生成器5个经典入门案例,系统巩固JavaScript变量、函数、DOM操作、事件流及数组对象等核心基础语法。

初学 JavaScript 时,很多学习者能够熟记变量声明、循环语句或函数语法的概念,但一面对空白的代码编辑器,往往不知道如何把这些孤立的知识点组合成能工作的实际功能。巩固基础语法的最佳途径,不是反复死记API手册,而是在明确的交互目标驱动下,完成结构小巧、针对性强的微型实战项目。本文提炼出 5 个入门级实战小案例,分别聚焦不同维度的语法核心,帮助你在真实编码中理清数据流动与界面渲染的逻辑。

一、案例设计与核心语法映射

一个合格的入门练习应该兼顾直观性与知识密度。5 个案例从最简单的单一状态控制,逐步过渡到多数据聚合与逻辑抽象,涵盖了前端交互开发中最常用的基础语法模块。

5个JavaScript入门实战小案例:巩固基础语法
图1:5个实战案例对应的JavaScript基础语法模块分布图

二、入门案例的通用开发与调试流程

动手写代码之前,先建立规范的开发次序,可以有效避免“页面报错却不知从何查起”的困境。无论是简单的计数器还是多节点渲染的待办列表,标准的前端微案例开发均遵循固定的五步流水线。

5个JavaScript入门实战小案例:巩固基础语法
图2:JavaScript入门小案例的标准开发与调试流程

三、案例一:交互式数值计数器

计数器是所有前端状态管理的基石。它的目标是提供加、减、重置按钮,改变界面上显示的数值,并在数值达到正负临界时通过颜色区分状态。

1. 巩固知识点

  • 变量声明:掌握 const(固定DOM引用)与 let(可变计数状态)的使用边界。
  • DOM操作:使用 document.querySelector 选取目标元素,使用 textContent 修改页面文本。
  • 事件监听:通过 addEventListener('click', callback) 处理用户点击。

2. 代码实现

<!-- HTML 结构 -->
<div class="counter-box">
  <h3>当前计数:<span id="count-display">0</span></h3>
  <button id="btn-decrement">减少 -1</button>
  <button id="btn-reset">重置 0</button>
  <button id="btn-increment">增加 +1</button>
</div>

<script>
  // 1. 获取DOM节点
  const display = document.querySelector('#count-display');
  const btnDecrement = document.querySelector('#btn-decrement');
  const btnReset = document.querySelector('#btn-reset');
  const btnIncrement = document.querySelector('#btn-increment');

  // 2. 定义状态变量
  let count = 0;

  // 3. 封装渲染函数
  function updateDisplay() {
    display.textContent = count;
    if (count > 0) {
      display.style.color = '#2e7d32'; // 正数绿色
    } else if (count < 0) {
      display.style.color = '#d32f2f'; // 负数红色
    } else {
      display.style.color = '#1e293b'; // 归零常规色
    }
  }

  // 4. 事件监听与状态变更
  btnIncrement.addEventListener('click', function () {
    count++;
    updateDisplay();
  });

  btnDecrement.addEventListener('click', function () {
    count--;
    updateDisplay();
  });

  btnReset.addEventListener('click', function () {
    count = 0;
    updateDisplay();
  });
</script>
语法注意:切勿直接用 display.textContent++。虽然 JavaScript 的隐式类型转换可能会在某些场景下计算成功,但它会使原本属于数字类型的状态和属于字符串类型的 DOM 内容耦合在一起,埋下类型混乱的隐患。始终保持“内部状态变量计算完毕,再显式同步给视图”的模式。

四、案例二:简易汇率换算器

该案例接收用户输入的金额(如人民币),选择换算目标(如美元、欧元),点击换算后输出对应格式化金额。核心在于对表单输入值的提取、数据类型转换以及防御性校验。

1. 巩固知识点

  • 输入值类型转换:表单元素的 input.value 默认返回字符串,需要通过 parseFloat() 或 Number() 显式转换。
  • 数值校验:使用 Number.isNaN() 检验输入是否合法,防止计算输出 NaN。
  • 数值格式化:使用 Number.prototype.toFixed(2) 保留两位小数。

2. 代码实现

<!-- HTML 结构 -->
<div class="converter-box">
  <input type="number" id="cny-input" placeholder="输入人民币金额(CNY)" />
  <select id="target-currency">
    <option value="0.14">美元 (USD, 汇率 0.14)</option>
    <option value="0.13">欧元 (EUR, 汇率 0.13)</option>
    <option value="21.5">日元 (JPY, 汇率 21.5)</option>
  </select>
  <button id="btn-convert">开始换算</button>
  <p id="convert-result">折合金额:--</p>
</div>

<script>
  const inputEl = document.querySelector('#cny-input');
  const currencySelect = document.querySelector('#target-currency');
  const convertBtn = document.querySelector('#btn-convert');
  const resultText = document.querySelector('#convert-result');

  // 纯函数:计算并返回换算结果
  function calculateExchange(amount, rate) {
    return (amount * rate).toFixed(2);
  }

  convertBtn.addEventListener('click', function () {
    const rawVal = inputEl.value.trim();
    const amount = parseFloat(rawVal);
    const rate = parseFloat(currencySelect.value);

    // 边界与防御性检查
    if (rawVal === '' || Number.isNaN(amount) || amount < 0) {
      resultText.textContent = '错误:请输入大于等于0的合法金额!';
      resultText.style.color = '#d32f2f';
      return;
    }

    const convertedVal = calculateExchange(amount, rate);
    const currencyName = currencySelect.options[currencySelect.selectedIndex].text.split(' ')[0];
    resultText.textContent = `折合金额:${convertedVal} ${currencyName}`;
    resultText.style.color = '#345e82';
  });
</script>
易错提醒:input.value 哪怕设置了 type="number",在 JS 层面读取出来的也是 string。如果不做显式转换而直接进行加法,会发生字符串拼接(例如 "100" + 0.14 = "1000.14")。虽然乘法会触发隐式转换,但养成显式声明类型的习惯可以规避绝大多数隐蔽 Bug。

五、案例三:动态待办事项清单(Todo List)

待办列表是训练 DOM 树动态增删与数组同步的试金石。它涵盖输入新项目、生成 DOM 节点追加到页面、点击标记完成以及从列表中彻底移除节点。

5个JavaScript入门实战小案例:巩固基础语法
图3:待办列表中DOM事件委托机制与动态节点挂载流程

1. 巩固知识点

  • 动态创建节点:document.createElement('li')。
  • DOM树装配:parentNode.appendChild(childNode)。
  • 事件委托(Event Delegation):不在每个子节点单独监听,而是在父级 <ul> 上统一监听,通过 e.target 区分具体点击来源。
  • 字符串清洗:使用 String.prototype.trim() 过滤空白提交。

2. 代码实现

<!-- HTML 结构 -->
<div class="todo-app">
  <input type="text" id="todo-input" placeholder="输入待办事项后回车..." />
  <button id="todo-add-btn">添加事项</button>
  <ul id="todo-list"></ul>
</div>

<script>
  const todoInput = document.querySelector('#todo-input');
  const addBtn = document.querySelector('#todo-add-btn');
  const todoList = document.querySelector('#todo-list');

  function createTodoItem(text) {
    const li = document.createElement('li');
    li.className = 'todo-item';

    const span = document.createElement('span');
    span.textContent = text;
    span.className = 'todo-text';

    const deleteBtn = document.createElement('button');
    deleteBtn.textContent = '删除';
    deleteBtn.className = 'btn-delete';

    li.appendChild(span);
    li.appendChild(deleteBtn);
    return li;
  }

  function handleAdd() {
    const text = todoInput.value.trim();
    if (text === '') {
      alert('待办内容不能为空');
      return;
    }
    const itemNode = createTodoItem(text);
    todoList.appendChild(itemNode);
    todoInput.value = ''; // 清空输入框
    todoInput.focus();
  }

  // 点击添加按钮
  addBtn.addEventListener('click', handleAdd);

  // 监听回车键添加
  todoInput.addEventListener('keydown', function (e) {
    if (e.key === 'Enter') {
      handleAdd();
    }
  });

  // 事件委托:在父级 ul 上监听所有子项的操作
  todoList.addEventListener('click', function (e) {
    const target = e.target;

    // 如果点击的是删除按钮,移除其所属的 li 节点
    if (target.classList.contains('btn-delete')) {
      const li = target.parentElement;
      li.remove();
    }

    // 如果点击的是文字本身,切换完成下划线样式
    if (target.classList.contains('todo-text')) {
      target.style.textDecoration = 
        target.style.textDecoration === 'line-through' ? 'none' : 'line-through';
      target.style.color = 
        target.style.textDecoration === 'line-through' ? '#94a3b8' : '#1e293b';
    }
  });
</script>

六、案例四:实时字符计数与输入截断提醒

该案例模拟常见于社交平台或表单备注框的字数限制功能。用户在输入框内键入文字时,实时显示当前字数与剩余允许字数;当超出阈值时,自动触发视觉警示并禁止提交。

1. 巩固知识点

  • 输入事件类型:使用 input 事件而非 keydown 或 change。input 事件在每一次文字输入、粘贴、删除时都会即时触发。
  • 字符串长度:通过 str.length 获取实际字符数。
  • 动态样式类操作:使用 element.classList.add()、remove() 或 toggle() 切换预置 CSS 类。
  • 模板字符串:使用反引号 `当前输入 ${cur} / ${max}` 构建动态提示文案。

2. 代码实现

<!-- HTML 结构 -->
<div class="char-counter-box">
  <textarea id="feedback-text" rows="4" placeholder="请输入您的意见(最多100字)..."></textarea>
  <div class="counter-status">
    <span id="char-info">0 / 100 字</span>
    <span id="warning-msg" style="color: #d32f2f; display: none;">已超出最大限制!</span>
  </div>
</div>

<script>
  const textarea = document.querySelector('#feedback-text');
  const charInfo = document.querySelector('#char-info');
  const warningMsg = document.querySelector('#warning-msg');
  const MAX_LIMIT = 100;

  textarea.addEventListener('input', function () {
    const currentLength = textarea.value.length;
    const isExceeded = currentLength > MAX_LIMIT;

    // 动态更新文本信息
    charInfo.textContent = `${currentLength} / ${MAX_LIMIT} 字`;

    if (isExceeded) {
      charInfo.style.color = '#d32f2f';
      warningMsg.style.display = 'inline';
      textarea.style.borderColor = '#d32f2f';
    } else {
      charInfo.style.color = '#64748b';
      warningMsg.style.display = 'none';
      textarea.style.borderColor = '#e2e8f0';
    }
  });
</script>
理解 input 与 change 的区别:初学者常误用 change 事件监听输入框。change 仅在输入框失去焦点(Blur)时才触发,无法做到“打一个字变一下数字”的实时同步体验;而 input 无论键盘打字、拼音选词还是鼠标右键粘贴,都会立刻产生事件通知。

七、案例五:随机名言展示器

该案例维护一个由多个对象构成的数组,每个对象包含名言内容与作者信息。点击“换一句”按钮时,程序利用数学内置对象生成不重复或随机的下标,提取对应对象并渲染到页面卡片中。

1. 巩固知识点

  • 对象数组(Array of Objects):理解 [ { quote: '...', author: '...' } ] 的数据组织结构。
  • Math 内置对象:掌握 Math.random()(生成 0 到 1 之间的浮点数)与 Math.floor()(向下取整)组合获取随机数组索引。
  • 对象属性访问:掌握点语法 obj.quote 与 obj.author。

2. 代码实现

<!-- HTML 结构 -->
<div class="quote-card">
  <blockquote id="quote-text">点击下方按钮获取名言</blockquote>
  <p id="quote-author" style="text-align: right; color: #64748b;">--</p>
  <button id="btn-next-quote">随机换一句</button>
</div>

<script>
  // 1. 数据源:对象数组
  const quoteList = [
    { text: "代码是写给人看的,顺便能在机器上运行。", author: "Harold Abelson" },
    { text: "简单胜于复杂,清晰胜于隐晦。", author: "Tim Peters" },
    { text: "先让它跑起来,再让它做正确,最后让它变快。", author: "Kent Beck" },
    { text: "控制复杂度是计算机科学最本质的目标。", author: "Edsger W. Dijkstra" },
    { text: "优秀的程序员不是写代码最多的,而是删代码最多的。", author: "业内谚语" }
  ];

  const quoteTextEl = document.querySelector('#quote-text');
  const quoteAuthorEl = document.querySelector('#quote-author');
  const nextBtn = document.querySelector('#btn-next-quote');

  let lastIndex = -1;

  function renderRandomQuote() {
    let randomIndex;
    // 循环判断:确保两次连续点击不会随机到同一条数据
    do {
      randomIndex = Math.floor(Math.random() * quoteList.length);
    } while (quoteList.length > 1 && randomIndex === lastIndex);

    lastIndex = randomIndex;
    const currentQuote = quoteList[randomIndex];

    quoteTextEl.textContent = `“${currentQuote.text}”`;
    quoteAuthorEl.textContent = `—— ${currentQuote.author}`;
  }

  nextBtn.addEventListener('click', renderRandomQuote);

  // 页面加载完成自动展示第一条
  renderRandomQuote();
</script>

八、基础语法巩固总结与进阶路线

通过上述 5 个案例的练习,可以清楚看到一个典型 JavaScript 前端交互的运转脉络:以数据为中心,以事件为诱因,以 DOM 为媒介。

案例名称 涉及的数据结构 关键 DOM / Web API 巩固的语言特性
交互式计数器 基础数值 (Number) querySelector, textContent, click let/const 作用域、算术运算符
汇率换算器 浮点数、字符串 value, toFixed, options parseFloat、isNaN 防御性校验、纯函数
动态待办清单 DOM 节点树、事件对象 createElement, appendChild, remove 事件冒泡、事件委托、trim 清洗
字符实时统计 字符串 (String) input 事件, style, classList length 属性、三元表达式、模板字面量
随机名言生成 对象数组 (Array of Objects) Math.random, Math.floor 数组索引寻址、do-while 循环、对象属性提取
5个JavaScript入门实战小案例:巩固基础语法
图4:JavaScript从语法微实战到工程化开发的能力演进全景图

下一步练习建议

  1. 尝试数据持久化:为“待办清单”案例接入 localStorage.setItem() 与 localStorage.getItem(),实现刷新浏览器后数据不丢失。
  2. 尝试网络数据接入:为“随机名言”案例引入 fetch(),从公共 API 异步拉取真实的名言列表,体会异步编程与网络加载状态的处理。
  3. 重构为模块化结构:尝试把每个小案例的代码按“状态定义、事件绑定、渲染函数”分成不同文件或模块进行引入,提前适应模块化工程思维。
作者最新文章
相关文章
更多