当前位置: 首页 > news >正文

跟着 MDN 学JavaScript day_12:实战挑战——构建交互式笑话生成器

引言

经过了数组基础知识的学习和技能测试的检验,现在迎来一个综合性实战挑战——构建一个交互式笑话生成器。这个项目将之前学到的变量、字符串、数组、函数、DOM操作以及事件处理等知识点融会贯通,让你在完成一个有趣的小应用的过程中,体验JavaScript如何将静态的网页变得生动活泼。点击按钮可以随机生成笑话,输入自定义名字可以替换故事中的角色,选择不同的计量单位还能改变温度和重量的制式。这个项目看似简单,但涵盖了前端开发中数据获取、随机选择、字符串替换、条件判断和DOM更新等多个核心环节。


一、项目起点——准备工作的三个文件

在开始编写JavaScript代码之前,需要先下载并准备好项目的三个初始文件:index.htmlstyle.cssraw-text.txtindex.html文件包含了页面的基本结构,其中有输入自定义名字的文本框、公制与美制单位选择的单选按钮、生成笑话的按钮以及一个用于展示笑话的段落元素。

<!DOCTYPEhtml><html><head><metacharset="utf-8"><metahttp-equiv="X-UA-Compatible"content="IE=edge,chrome=1"><metaname="viewport"content="width=device-width"><title>笑话机</title><linkhref="style.css"rel="stylesheet"></head><body><div><labelfor="customname">输入自定义名字:</label><inputid="customname"type="text"placeholder="李雷"></div><div><labelfor="metric">公制</label><inputid="metric"type="radio"name="measure"value="metric"checked><labelfor="american">美制</label><inputid="american"type="radio"name="measure"value="american"></div><div><buttonclass="randomize">生成随机笑话</button></div><pclass="story"></p></body></html>

style.css文件定义了页面的样式,值得注意的是,展示笑话的段落初始状态下visibility被设置为hidden,这意味着在没有生成笑话之前,用户看不到黄色的段落区域。

body{font-family:sans-serif;width:350px;}label{font-weight:bold;}div{padding-bottom:20px;}input[type="text"]{padding:5px;width:150px;}p{background:#FFC125;color:#5E2612;padding:10px;visibility:hidden;}

raw-text.txt文件则包含了项目所需的JavaScript代码片段,分为三个部分:定义变量和函数、纯文本字符串、事件监听器和未完成的函数定义。整个项目的核心任务就是将这些代码片段正确地组织到main.js文件中,并补全未完成的result()函数。这种"半成品代码填空"的模式在学习和面试中都很常见,它考察的是对已有代码结构的理解能力以及在特定约束下完成功能的能力。


二、初始化变量和函数——搭建项目的骨架

开发的第一步是将raw-text.txt中第一部分代码复制到main.js文件中。这部分代码定义了三个重要的DOM元素引用和一个工具函数。

  • customName通过getElementById获取了输入框元素,用户在这里输入的名字将替换故事中的默认角色名;
  • randomize通过querySelector获取了按钮元素,这是触发笑话生成的关键控件;
  • story通过querySelector获取了用于展示笑话的段落元素。
constcustomName=document.getElementById('customname');constrandomize=document.querySelector('.randomize');conststory=document.querySelector('.story');functionrandomValueFromArray(array){returnarray[Math.floor(Math.random()*array.length)];}

randomValueFromArray函数是整个笑话生成器的随机引擎。它接受一个数组作为参数,利用Math.random()生成0到1之间的随机小数,乘以数组长度后得到一个浮点数,再通过Math.floor()向下取整获得一个随机的索引值,最终返回数组中该索引位置的元素。这个函数是笑话每次都不一样的关键所在。理解这个函数的工作原理很重要,因为后续的笑话生成过程中会多次调用它来从不同的备选数组中随机抽取内容。


三、存储文本字符串——笑话的原料仓库

接下来需要处理raw-text.txt中的第二部分代码。这部分包含了笑话生成所需的所有文本素材,分别存储在一个长字符串和三个短数组中。

storyText变量保存的是笑话的模板框架,其中使用了特殊的占位符::inserta::insertb::insertc:。这些占位符就像是模板中的空槽,等待被具体的内容填充。

conststoryText="今天气温 34 摄氏度,:inserta:出去遛弯。当走到:insertb:门前时,突然就:insertc:。人们都惊呆了,李雷全程目睹但并没有慌,因为:inserta:是一个 140 公斤的胖子,天气又辣么热。";constinsertX=["怪兽威利","大老爹","圣诞老人"];constinsertY=["肯德基","迪士尼乐园","白宫"];constinsertZ=["自燃了","在人行道化成了一坨泥","变成一条鼻涕虫爬走了"];

三个数组的职责分工如下:

数组含义示例元素
insertX角色选项怪兽威利、大老爹、圣诞老人
insertY地点选项肯德基、迪士尼乐园、白宫
insertZ结局选项自燃了、化成了一坨泥、变成鼻涕虫爬走了

这种将变化部分抽取为数组的设计体现了很好的编程思维——将可变数据与固定模板分离,既便于维护又使得内容组合灵活多变。三个数组各包含三个元素,这意味着总共可以生成 3×3×3 = 27 种不同组合的笑话,再加上自定义名字和单位转换的变体,故事的可能性更加丰富。


四、事件处理器与补全函数——让按钮真正工作

raw-text.txt的第三部分代码复制到main.js后,项目就具备了基本的事件监听结构。randomize.addEventListener为按钮绑定了点击事件,每当用户点击"生成随机笑话"按钮时,result函数就会被调用执行。

randomize.addEventListener('click',result);functionresult(){if(customName.value!==''){letname=customName.value;}if(document.getElementById("american").checked){letweight=Math.round(300);lettemperature=Math.round(94);}story.textContent=;story.style.visibility='visible';}

此时的result函数只是一个未完成的骨架,包含了两个条件判断的框架和一行尚未赋值的输出语句:

  • 第一个if:检查customName输入框的值是否为空,如果不为空,说明用户输入了自定义名字,需要将name变量设置为该值;
  • 第二个if:检查美制单位单选按钮是否被选中,如果选中则需要将温度和重量从公制转换为美制;
  • 输出语句story.textContent还没有被赋予正确的值,这正是需要补全的核心部分。

五、补全result函数——笑话生成的完整流程

5.1 初始化副本

在函数体的开头,需要将newStory变量初始化为storyText的值。这里创建新变量而非直接修改storyText至关重要,因为storyText是原始模板,如果直接在其上进行替换操作,第二次点击按钮时将无法再次替换已经消失的占位符。每次都从一个全新的副本开始操作,才能保证每次点击都能生成一个完整的新笑话。

letnewStory=storyText;

5.2 随机选取元素

接下来需要从三个备选数组中各自随机选取一个元素。将randomValueFromArray(insertX)的返回值赋给xItem,同样地将从insertYinsertZ中随机选取的元素分别赋给yItemzItem。这三个变量分别代表本次笑话中角色、地点和结局的具体内容。

letxItem=randomValueFromArray(insertX);letyItem=randomValueFromArray(insertY);letzItem=randomValueFromArray(insertZ);

5.3 字符串替换

字符串替换是补全函数的核心步骤。newStory中包含三个占位符需要替换,而且:inserta:出现了两次(第一次作为角色出现,第二次作为"140公斤的胖子"的主语)。

replace方法每次只替换找到的第一个匹配项,因此对于出现两次的占位符需要调用两次replace方法。这些替换操作可以利用replace方法的返回值进行链式调用,让代码更加简洁流畅。

newStory=newStory.replace(":inserta:",xItem);newStory=newStory.replace(":inserta:",xItem);// 第二次替换newStory=newStory.replace(":insertb:",yItem);newStory=newStory.replace(":insertc:",zItem);

5.4 自定义名字替换

第一个if块用于处理自定义名字的替换。当用户在输入框中输入了名字时,需要将newStory中的默认名字"李雷"替换为用户输入的名字。注意这里需要使用name变量中存储的值来进行替换,而不是直接使用customName.value。这种先检查再替换的逻辑确保了当输入框为空时,故事中使用默认名字。

if(customName.value!==''){letname=customName.value;newStory=newStory.replace("李雷",name);}

5.5 单位转换

第二个if块处理单位转换。当美制单位被选中时,需要进行两个转换:

  • 摄氏度 → 华氏度:华氏度 = 摄氏度 × 9 ÷ 5 + 32
  • 公斤 → 磅:1公斤 ≈ 2.2磅

使用Math.round()对转换结果进行取整,让显示的数值更加整洁。然后在转换后的数值后面拼上对应的美制单位字符串。最后再使用两个字符串替换操作,将模板中的"34 摄氏度"和"140 公斤"分别替换为计算出的temperatureweight值。

if(document.getElementById("american").checked){letweight=Math.round(140*2.2)+" 磅";lettemperature=Math.round(34*9/5+32)+" 华氏度";newStory=newStory.replace("140 公斤",weight);newStory=newStory.replace("34 摄氏度",temperature);}

5.6 输出结果

整个替换逻辑完成后,将story.textContent赋值为newStory,同时将story.style.visibility设置为visible,使原本隐藏的笑话段落显示出来。至此,一个完整的笑话生成器就完成了。

story.textContent=newStory;story.style.visibility='visible';

六、关键技术点解析——从模板到随机故事的魔法

6.1 模板替换模式

这个项目的核心设计模式是模板替换storyText相当于一个带有特殊标记的模板字符串,占位符:inserta:等标记了内容应该插入的位置。这种模式在实际开发中非常常见,比如邮件模板、代码生成器、内容管理系统等场景都会用到类似的思路。相比于拼接字符串的方式,模板替换让代码的结构更加清晰,修改模板内容时不需要改动替换逻辑。

6.2 replace方法详解

replace方法是实现替换的关键工具。它接受两个参数:

  • 第一个参数:要查找的子字符串或正则表达式
  • 第二个参数:替换后的新字符串

关键特性replace方法不会修改原字符串,而是返回一个新的字符串——这是字符串不可变特性的体现。项目中利用这一特性,每次都在newStory的副本上进行操作,完美地保护了原始模板不被破坏。

6.3 随机选择技巧

Math.random()Math.floor()的组合是实现随机选择的标准做法:

Math.random() → [0, 1) 之间的伪随机浮点数 × array.length → [0, array.length) 范围 Math.floor() → 向下取整 → [0, array.length - 1] 的有效索引

这种技巧在抽奖、随机排序、随机推荐等场景中广泛使用。randomValueFromArray函数将其封装成了一个通用的工具函数,体现了良好的代码复用意识。


七、调试技巧——确保代码正确加载

在开发过程中,有时会遇到JavaScript文件未能正确加载的情况。MDN提供了一个简单有效的调试技巧:暂时删除JavaScript文件的所有内容,添加一段效果明显的测试代码来验证文件是否正确加载并执行。

document.querySelector("html").style.backgroundColor="red";

如果浏览器窗口背景变成了红色,说明JavaScript文件已经被成功加载并执行。这种"最小可行测试"的思路值得学习——当系统出现问题时,将其简化到最基本的程度来隔离问题来源。确认加载正常后,再逐步恢复代码,如果中途又出现问题,就能准确定位问题所在。

另外需要注意的是,除了在HTML中引入JavaScript文件之外,完全不需要编辑HTML本身。这种关注点分离的设计原则让HTML负责结构、CSS负责样式、JavaScript负责行为,三者各司其职,互不干扰。


总结

通过构建这个笑话生成器,我们完成了一次完整的JavaScript小型项目实践。从获取DOM元素引用、定义随机选取函数,到设置事件监听器、实现模板字符串的多重替换,再到处理用户输入和条件分支,整个流程串联了JavaScript基础阶段的多个核心知识点。

这个项目特别值得回味的是其模板替换的设计思路。通过占位符将固定内容与可变内容分离,再借助replace方法进行精准替换,最后通过随机函数为每次生成带来惊喜。这种模式可以轻松扩展到更复杂的场景中,比如生成邮件、报告、合同等需要模板化输出的应用。

完成这个挑战意味着你已经具备了将零散的JavaScript知识整合为完整应用的能力。更重要的是,你体验了从一个半成品代码出发,在理解现有结构的基础上填补空白、完善功能的开发过程——这正是实际工作中最常见的开发模式之一。带着这份成就感,继续向JavaScript更深层次的知识迈进吧。


还在为 JavaScript 代码写得像“意大利面条”、逻辑混乱难以维护而头秃?收藏本文持续跟进,后续将系统分享 JS 高效语法糖、浏览器兼容与 Polyfill 实战、手写核心源码解析、常见坑点避雷指南,从基础语法到进阶逻辑一站式打通,助你快速提升前端开发硬实力!

http://www.jsqmd.com/news/976913/

相关文章:

  • PN7160 NFC天线匹配实战:从原理到调优,解决通信距离与稳定性难题
  • Agent记忆系统:基于LangChain的Memory开发实战
  • GPT-4四大能力跃迁:从指令遵循到跨模态推理的工程实证
  • 计算机小程序毕设实战-基于springboot+微信小程序的云浮市特色农产品交易的设计与实现java 特色农产品销售系统 特色农产品线上交易【完整源码+LW+部署说明+演示视频,全bao一条龙等】
  • 2026 南京梅雨季漏水抢修指南!本地防水公司 TOP9 权威盘点,卫生间免砸砖防水、阳台渗漏一站式解决 - 吉林同城获客
  • 在Windows上用Anaconda+TensorFlow 2.x复现U-Net细胞分割(附完整代码与数据集)
  • 2026年锻压机品牌/源头厂家最新推荐榜:半轴、轨道、道岔、螺栓、汽配、航空、航天、军品、船舶锻压机/自由锻/三向锻高强智造精选 - 企业推荐官【官方】
  • 超自动化运维:实现IT服务管理现代化的关键
  • pyltp加载自定义词典踩坑实录:解决专业术语(如‘亚硝酸盐’)分词不准的问题
  • Text-to-X多模态系统实战:从文本指令到PPT/视频/试题一键生成
  • GEO优化对搜索关键词有要求吗
  • 南方新华合资加盟开始了!号召人力资源公司、小猎企、SOHO猎头加入,我们一起开分公司 - 榜单推荐
  • 航班延误预测:面向运控决策的实时风险评估系统设计
  • WeChatMsg:三步实现微信聊天记录永久保存与智能分析的完整指南
  • C#从零开始:自己实现一个截屏工具
  • Horos:macOS平台专业级开源医疗影像查看器完全指南
  • RookieAI终极指南:3步打造专业级AI自瞄系统
  • OpenGL ES开发避坑:GLM库的#include用尖括号还是双引号?一次讲清预处理器搜索路径
  • 如何用网盘直链下载助手彻底告别下载限速:终极解决方案
  • 告别手动建模!用Python脚本在AutoCAD Plant 3D里一键生成水平四通(附完整代码解析)
  • 深耕金属包装二十载:东莞万鑫隆的全链路马口铁盒定制之道 - 变量人生001
  • m4s-converter:如何永久保存B站视频的完整指南
  • 2026 年江苏锂电工具源头厂家深度评测:5 大维度综合评分揭晓排名 - 新闻快传
  • 抖音批量下载终极指南:快速保存无水印视频的完整解决方案
  • FPGA项目避坑:用XADC和VGA显示心电波形时,如何解决采样率与显示刷新的矛盾?
  • 从《电话》看技术入侵:一个黎巴嫩村庄如何被一部电话彻底改变(附原文精读笔记)
  • 2026年 平锻机/快锻机/温锻机厂家推荐排行榜:高精度锻造工艺与智能高效装备的优质品牌深度解析 - 企业推荐官【官方】
  • 终极游戏库管理神器:Playnite一站式整合20+平台与模拟器游戏
  • 如何免费为Photoshop添加专业级WebP支持:WebPShop插件终极指南
  • 计算机小程序毕设实战-基于SSM的图书馆自习室座位预约小程序基于ssm+微信小程序的自习室预约小程序的设计与实现【完整源码+LW+部署说明+演示视频,全bao一条龙等】