11 篇文章带有标签 “javascript”

浏览器原生语音合成(TTS)开发经验

最近先后在站点上线了两个纯前端的朗读工具:Read Aloud智能朗读阅读器。两者都基于浏览器的 Web Speech API 实现,没有后端、没有上传、没有第三方语音服务。开发过程中踩了一些坑,也积累了一些可复用的经验,记录如下。

一、Web Speech API 基础

浏览器 TTS 的入口非常简洁:

const synth = window.speechSynthesis;
const utterance = new SpeechSynthesisUtterance(text);
synth.speak(utterance);

window.speechSynthesis 负责全局的语音队列,SpeechSynthesisUtterance 则是每一次发音的单元。在真正可用之前,建议先做兼容性判断:

if (!window.speechSynthesis) {
  alert('当前浏览器不支持 Web Speech API,无法使用朗读功能。');
  return;
}

目前 Safari、Chrome、Edge 等现代浏览器都支持该 API,但不同浏览器在语音质量、语音名、事件触发等方面差异明显,后面会详细说。

二、语音列表是异步加载的

第一次调用 speechSynthesis.getVoices() 时,返回的数组经常为空。这是因为浏览器需要异步加载系统语音包。

剪贴板备份是什么

剪贴板备份是一款纯前端、无需后端的浏览器剪贴板历史管理工具。它支持保存文本、HTML、RTF、图片等多种剪贴板格式,利用浏览器 IndexedDB 本地持久化存储,随时恢复或下载历史内容。

核心功能

  • 多格式剪贴板捕获:支持保存文本、HTML、RTF、URL 列表、PNG / JPEG / GIF / WebP 图片等多种剪贴板格式。
  • 本地持久化存储:所有备份数据通过 IndexedDB 存储在浏览器本地,刷新页面或关闭浏览器后数据不丢失。
  • 多格式预览:支持按格式切换预览,文本、HTML、图片分别渲染,HTML 内容经 DOMPurify 安全过滤。
  • 一键恢复复制:点击复制按钮即可将备份内容还原到系统剪贴板,图片自动转换为 PNG 格式以兼容 Clipboard API。
  • 逐格式下载:每个备份的每种格式均可单独下载为对应文件(txt、html、rtf、png 等)。
  • 相对时间显示:备份时间以"刚刚""5 分钟前""2 小时前"等相对时间展示,直观易读。
  • 全页粘贴支持:不仅可以在粘贴区域粘贴,在页面任意位置按 Ctrl+V 均可触发备份。
  • 批量清空:支持一键删除所有备份,操作前需确认,防止误删。

使用方式

  1. 打开 剪贴板备份
  2. 点击页面粘贴区域并按 Ctrl + V 粘贴内容,或在页面任意位置直接粘贴。
  3. 备份自动保存并显示在列表中,可预览、复制或下载。
  4. 点击 清空全部 可删除所有历史备份。

二维码识别器是什么

二维码识别器是一款纯前端在线 QR 码识别工具,基于 jsQR 库实现。它支持图片上传、拖拽、剪贴板粘贴以及摄像头实时扫码四种方式,所有图片处理均在浏览器本地完成,不会上传到任何服务器,保护隐私安全。

核心功能

  • 图片上传识别:点击或拖拽图片文件到识别区域,即可自动解析二维码内容。
  • 剪贴板粘贴识别:直接按 Ctrl / ⌘ + V 粘贴剪贴板中的图片,无需先保存文件。
  • 摄像头实时扫码:调用设备摄像头,持续扫描画面中的二维码,适合快速识别实物上的 QR 码。
  • 前后摄像头切换:支持在设备的前置与后置摄像头之间切换,适应不同扫码场景。
  • 双指缩放对焦:摄像头模式下支持双指捏合缩放画面,双击重置缩放,方便对准远距离或微小二维码。
  • UTF-8 中文支持:底层使用 TextDecoder('utf-8') 解码二进制数据,确保中文、日文等非 ASCII 字符正确显示。
  • 链接自动识别:识别结果若为 URL,自动渲染为可点击的超链接,一键跳转。
  • 一键复制结果:识别后点击"复制识别结果"按钮,快速将内容复制到剪贴板。
  • 纯前端隐私安全:所有图像处理在本地完成,图片不离开浏览器,无需担心隐私泄露。

使用方式

图片识别模式 打开 二维码识别器。 点击"图片识别"标签(默认)。 拖拽图片到识别区域,或点击选择文件,也可以直接粘贴剪贴板图片。

扫雷是什么

扫雷是一款经典的浏览器本地益智游戏。无需下载安装,打开网页即可游玩,支持简单、中等、困难三种难度,同时适配桌面端与移动端操作。

核心功能

  • 三种难度可选:简单(9×9,10 颗雷)、中等(16×16,40 颗雷)、困难(30×16,99 颗雷),一键切换。
  • 首次点击保护:第一次点击永远不会踩到雷,确保开局安全。
  • 自动展开空区:翻开无雷的空白格子时,自动级联展开周围相邻区域。
  • 插旗标记:支持右键或长按标记疑似地雷位置,实时显示剩余雷数。
  • 双模式切换:移动端提供"点击翻开 / 点击插旗"模式切换按钮,操作更直观。
  • 长按插旗:移动端支持长按格子快速插旗,并伴随触觉反馈(若设备支持)。
  • 计时器:从第一次点击开始计时,精确到秒。
  • 表情按钮:重置按钮随游戏状态变化(😊 / 😵 / 😎),点击即可重新开始。
  • 动画效果:翻开格子、踩雷爆炸、胜利庆祝均配有流畅的 CSS 动画。
  • 彩色数字提示:周围雷数 1~8 分别用不同颜色显示,便于快速判断。

使用方式

  1. 打开 扫雷
  2. 选择难度(默认简单)。
  3. 点击格子开始游戏,首次点击安全无雷。
  4. 根据数字提示推理雷的位置,用右键或长按插旗标记。
  5. 翻开所有安全格子即可获胜,踩到雷则游戏结束。
  6. 点击表情按钮 😊 随时重新开始。

操作说明

坦克大战是什么

坦克大战是一款纯前端运行的经典坦克射击游戏,基于 HTML5 Canvas 构建。玩家控制坦克消灭所有敌人、保护基地,采用关卡制推进,每关敌人数量和强度逐渐增加,支持道具收集和丰富的自定义配置。

核心功能

  • 经典关卡制玩法:消灭所有敌人即可进入下一关,每关难度递增。
  • 6 种道具系统:生命+1、火力提升(散射穿甲弹)、速度提升、护盾、炸弹(全屏清敌)、冻结敌人。
  • 完整音效系统:基于 Web Audio API 合成射击、爆炸、移动、通关、游戏结束等音效。
  • 自定义游戏配置:支持调整玩家速度、射击冷却、初始生命、敌人数量与速度、道具生成间隔、地图元素数量等参数。
  • 实时侧边栏状态:显示分数、关卡、生命值(心形)、敌人进度条、活跃道具计时、游戏时间、历史最高分。
  • 暂停与音效控制:游戏中可随时暂停/继续,一键开关音效。
  • 本地最高分记录:通过 localStorage 保存历史最高分,刷新不丢失。
  • 响应式布局:适配不同屏幕尺寸,三栏布局自动调整为纵向排列。

操作说明

  • WASD / 方向键:控制坦克移动
  • 空格键:发射子弹
  • 回车键:开始游戏 / 重新开始
  • P 键:暂停 / 继续游戏
  • M 键:开关音效

得分规则

  • 击毁敌人坦克:100 分
  • 通关奖励:500 分
  • 道具得分:20 分
  • 基地被摧毁:游戏结束

技术栈

  • HTML5 Canvas
  • JavaScript(原生,无框架依赖)
  • Web Audio API(音效合成)
  • localStorage(最高分持久化)
  • 无后端、无依赖、纯静态页面
笔记

调试二维码识别与生成工具的几点经验

下午折腾了两个纯前端二维码工具:一个识别器、一个生成器。记录下调试过程中踩过的几个坑,免得以后重复踩。

1. 中文二维码识别出来是空的

用的是 jsQR。识别英文二维码没问题,但中文二维码识别结果直接为空。

查了下,jsQR 返回的对象里有两个字段:

  • code.data:legacy 字符串,对多字节字符支持不好
  • code.binaryData:原始字节数组

正确做法是用 binaryData 配合 TextDecoder 按 UTF-8 解码:

function decodeQRData(code) {
  if (code.binaryData && code.binaryData.length) {
    const bytes = new Uint8Array(code.binaryData);
    return new TextDecoder('utf-8').decode(bytes);
  }
  return code.data || '';
}

图片识别和摄像头扫码两处都要走这个解码逻辑。

2. 中文二维码生成后扫描乱码

生成器中 qr.addData(value) 对中文支持不行,需要先做一次 UTF-16 到 UTF-8 的字节转换:

JSON 格式化 / 压缩 是什么

JSON 格式化 / 压缩是一款纯前端在线 JSON 处理工具,无需联网、无需上传数据,所有操作均在浏览器本地完成。支持格式化、压缩、转义与去转义,适合开发者在日常工作中快速处理 JSON 数据。

核心功能

  • 格式化:将压缩的 JSON 文本一键展开为带缩进的可读格式,便于查看与调试。
  • 压缩:去除 JSON 中所有不必要的空格与换行,生成最小体积的 JSON 字符串。
  • 转义:将 JSON 对象序列化为转义后的字符串,方便嵌入代码或配置文件。
  • 去转义:将转义后的 JSON 字符串还原为原始内容,支持带引号或不带引号的输入。
  • 一键复制:处理结果可直接复制到剪贴板,无需手动选中。
  • 一键清空:快速清空输入与输出区域,方便处理下一段数据。
  • 实时错误提示:JSON 解析失败时,状态栏会显示具体错误信息,帮助定位问题。
  • 深色模式支持:自动跟随系统主题,也支持手动切换,长时间使用不刺眼。
  • 左右分屏布局:输入与输出并排显示,大屏对比查看更高效,移动端自动切换为上下布局。

使用方式

  1. 打开 JSON 格式化 / 压缩
  2. 将 JSON 文本粘贴到左侧输入框。
  3. 点击工具栏上的 格式化压缩转义去转义 按钮进行处理。
  4. 处理结果即时显示在右侧输出框,点击 复制结果 即可复制到剪贴板。

技术栈

  • HTML + CSS + JavaScript
  • 无后端、无依赖、纯静态页面
  • 支持深色模式与响应式布局

使用 Claude Code:HTML 超乎寻常的妙用

Thariq: Using Claude Code: The Unreasonable Effectiveness of HTML

Markdown 已成为智能体(agent)与我们沟通时占主导地位的文件格式。它简单、可移植,具备一定的富文本能力,且易于编辑。Claude 甚至已经相当擅长在 Markdown 文件中使用 ASCII 绘制图表。

但随着智能体变得越来越强大,我感到 Markdown 已成为一种受限的格式。我发现自己很难阅读超过一百行的 Markdown 文件。我想要更丰富的可视化效果、色彩和图表,并且希望能轻松分享它们。

我也越来越不亲自编辑这些文件,而是将它们用作规格说明、参考文件、头脑风暴输出等。当我确实需要编辑时,我通常会让 Claude 来编辑,这就削弱了 Markdown 最大的一个优势。

我开始更偏爱 HTML 作为输出格式,而不是 Markdown,并且越来越多地看到 Claude Code 团队中的其他人也在使用它。以下就是原因。

(如果你想先看一些示例,可以在这里看到一大堆:https://thariqs.github.io/html-effectiveness ,不过记得回来看更多关于"为什么"的内容。)

为什么选择 HTML?

信息密度

与 Markdown 相比,HTML 能够传达更丰富得多的信息。

TypeScript 入门

TypeScript 安装

安装 tsc,它是 TypeScript 的编译器。

npm i -g typescript

查看版本

tsc -v
Version 5.5.3

安装 ts-node,它是 TypeScript 的运行时。

npm i -g ts-node

查看版本

ts-node -v
v10.9.2

Hello World

使用 tsc --init 命令快速创建一个 tsconfig.json 文件。

tsc --init

Created a new tsconfig.json with:                                                                                       
                                                                                                                     TS 
  target: es2016
  module: commonjs
  strict: true
  esModuleInterop: true
  skipLibCheck: true
  forceConsistentCasingInFileNames: true


You can learn more at https://aka.ms/tsconfig

创建一个 hello.ts 文件。

function hello(name: string) {
  console.log(`Hello, ${name}!`);
}

hello("TypeScript");

使用 tsc 命令编译 hello.ts 文件。

tsc hello.ts

编译后生成一个 hello.js 文件。