码道:当闹钟遇见大模型——「闹钟计时器 AI 对话」项目开发全记
这是一篇迟到的项目手记。它记录了一个纯粹由好奇心驱动的练手项目:把一只普通的闹钟、一个计时器、一块秒表,和一位能听懂人话的 AI 助手,装进同一个网页里。没有后端,没有框架,没有构建工具,只有一份 HTML5、一份 CSS3、一份 JavaScript,以及一条精心设计的系统提示词。
仓库地址:https://atomgit.com/gcw_xixvC6Lo/naozhongjishiqi
码道流程:
一、为什么会想做这个项目
事情的开头是某天深夜,我盯着手机屏幕上密密麻麻的时间管理 App 发呆:一个管闹钟的、一个管番茄钟的、一个管秒表的、一个管日程的……它们各自为政,界面上还都挤满了广告和会员入口。我在想,这些东西真的需要拆成四五个应用吗?它们能不能被塞进一个古朴的、没有任何依赖的单文件网页里?
几乎同时,我的收藏夹里躺着一份 GitCode AI 的官方示例代码,是用 Python 写的:
import os
import requests
import json
API_URL = "https://api-ai.gitcode.com/v1/chat/completions"
headers = {"Authorization": f"Bearer <你的Key>"}
def query(payload):
response = requests.post(API_URL, headers=headers, json=payload, stream=True)
for line in response.iter_lines():
if not line.startswith(b"data:"):
continue
if line.strip() == b"data:[DONE]" or line.strip() == b"data: [DONE]":
return
yield json.loads(line.decode("utf-8").lstrip("data:").rstrip("/n"))
chunks = query({
"model": "deepseek-ai/DeepSeek-V4-Flash",
"messages": [{"role": "user", "content": "告诉我一个有关宇宙的有趣事实?"}],
"stream": True,
"max_tokens": 2048,
"temperature": 0.6,
"top_p": 0.95,
"frequency_penalty": 0,
"thinking_budget": 2048,
})
for chunk in chunks:
print(chunk["choices"])
这段代码干净利落:指定模型、组装消息、流式接收、逐行打印。但它只是一个"终端里的聊天机器人",和"生活里的工具"之间还隔着十万八千里。
两个念头碰撞到一起,项目就这样诞生了——做一个纯前端的「闹钟计时器 AI 对话」:时间工具负责管理你的每一分钟,AI 助手负责理解你想怎么使用这些工具,两者靠一条 JSON 协议打通。
二、需求分析:先想清楚到底要做什么
和大多数练手项目一样,最危险的不是写代码本身,而是"什么都想要"。开写之前,我强迫自己在纸上列了一张需求清单,并且反复删减。
2.1 功能需求
- 闹钟模块:设定时与分,支持同时存在多个闹钟,每个闹钟可以独立开与关;到点时要能真正"吵醒"用户——声音加上视觉反馈。
- 计时器模块:以分钟和秒为单位设定倒计时,支持开始、暂停、重置,最好还能有"+1 分钟""+5 分钟"这种快捷加时,方便煮面、午休这样的场景。
- 秒表模块:毫秒级精度,支持开始、暂停、继续、记圈数。
- AI 对话模块:调用 GitCode AI 接口,让用户用自然语言和这张页面交流;更重要的是,AI 要能理解时间语义——用户说"设个7点的闹钟",它应该自动把闹钟设好,而不是回一句"好的呢"。
- 顶部实时显示当前时间,界面在手机和电脑上都能正常使用。
2.2 技术约束
- 语言限定为 HTML5 + CSS3 + JavaScript,没有后端服务的预算,所以 AI 调用必须由浏览器直接完成。
- API 调用的参考代码是 Python,需要完整翻译成 JavaScript。
- 系统提示词(System Prompt)必须约束模型输出结构化 JSON,前端才能稳定渲染与执行。
- 仓库要有一份能读的 README,跑起来要快——纯静态页面,打开就能用。
2.3 主动砍掉的需求
- 不做数据持久化。闹钟设置存内存里,刷新页面就没了——对练手项目来说这是可接受的成本,也意味着代码更短、职责更单一。
- 不做账号体系、不做云同步、不做推送通知。YAGNI(You Aren’t Gonna Need It)原则在个人项目里尤其适用:需求里没写的东西,说明你暂时不需要它。
清单一旦明确,实现路径就清晰了:一个单文件 index.html,承载全部结构与逻辑。
三、技术选型:为什么坚持"零依赖"
选型的讨论在团队项目里往往要开一场会,在个人项目里则更像是一次自我说服。我的原则只有一条:每一层技术都恰好承担它该承担的职责,绝不多引入一个英雄。
- HTML5:提供语义化骨架——工具区三个 Tab、AI 对话面板、输入框与按钮。原生标签足够表达这一切。
- CSS3:负责全部视觉。渐变背景、玻璃拟态卡片、响应式栅格、关键词动画——CSS 变量统一管理色板,媒体查询处理小屏堆叠,全程没有任何图片资源。
- JavaScript:原生的
fetch发起网络请求,ReadableStream按帧读取 SSE 流,Web Audio API现场合成提示音,setInterval驱动时钟与倒计时。ES6 以后的浏览器 JavaScript 已经足够现代,除非项目复杂到需要状态管理,否则引入框架就是在给未来制造维护成本。 - AI 服务:
deepseek-ai/DeepSeek-V4-Flash。选它的理由很实际——它便宜、快,而且指令遵循能力强,这正是"提示词约束 JSON 输出"这个玩法最依赖的素质。
再看一眼最终的项目体积:一个 index.html(约 28KB),一个 README.md。没了。把复杂度关进笼子里,是这次选型最满意的成果。
四、系统提示词的设计:让模型"按合同交货"
如果说时间工具是这座房子,那么 AI 对话就是房子的门厅——而系统提示词,是门厅里的那套门禁规则。它决定了客人们(模型的输出)以什么姿态走进来。
4.1 一份"接口文档式"的提示词
最初我想得很简单:让模型正常聊天不就行了?但很快发现两个痛点。第一,输出不稳定——它可能在你面前输出一段 markdown,也可能在 JSON 外面套一层代码块;第二,输出不可用——它把"设闹钟"这件事回答得天花乱坠,却唯独没有告诉我该填几点几分。
于是我把系统提示词从一段"角色描述"重写为一份"接口文档":
{
"intent": "set_alarm | set_timer | chat",
"reply": "对用户说的话(气泡正文)",
"emoji": "贴合语境的 emoji",
"advice": "给用户的额外建议,没有则为空",
"alarm_time": "HH:MM(intent=set_alarm 时有效)",
"reminder_seconds": "倒计时秒数(intent=set_timer 时有效,否则为 0)"
}
提示词里明确规定了三件事:
- 只输出一个合法 JSON 对象,禁止 markdown 代码块,禁止任何解释性文字;
- 字段是死契约:六个键名一个不多一个不少;
- 取值有边界:
intent只允许三个枚举值,alarm_time必须符合HH:MM格式,reminder_seconds必须是正整数。
4.2 为什么这样有效
大模型的强项是"自由生成",而应用的强项是"精确执行"。两者之间的桥梁,就是把生成空间的边界画清楚。当我告诉模型"你只需要在这三个意图里选一个,在六个字段里填值"时,它就不再是一个滔滔不绝的聊天机器人,而成了一条可以被程序直接消费的数据管线。这套思路,和我们给第三方写的 API 文档没有任何本质区别——prompt 即 schema,schema 即程序。
后端的角色则像一名质检员:intent 不是规定的枚举值就归为 chat;alarm_time 不符合正则就拒绝执行。软约束交给模型,硬约束交给代码,各守各的边界。
五、Python 到 JavaScript:一次"翻译"记录
这是整个项目里最机械、也最容易出 Bug 的部分,我索性把两边的对应关系写成了一张对照表放进了 README:
| Python | JavaScript |
|---|---|
requests.post(..., stream=True) | fetch(API_URL, {method:"POST", body}) |
for line in response.iter_lines() | response.body.getReader() + TextDecoder |
line.startswith(b"data:") 过滤行 | line.startsWith("data:") 过滤行 |
data:[DONE] 结束标记 | "[DONE]" 结束标记 |
chunk["choices"] | json.choices[0].delta.content 增量累积 |
Bearer <token> 请求头 | 同样的请求头(前端公开可见) |
5.1 流式接收的核心代码
真正有技术含量的只有一小段——如何把 SSE 流一段段读进来:
const reader = resp.body.getReader();
const decoder = new TextDecoder();
let full = "";
while (true) {
const { done, value } = await reader.read();
if (done) break;
full += decoder.decode(value, { stream: true });
}
之后把整段 full 按换行符切分,逐行处理以 data: 开头的负载,跳过空行与 [DONE],并把 choices[0].delta.content 累积成完整文本。这里有个细节:一个 SSE 事件的行可能被网络包截成两半,所以先用 TextDecoder 的 stream 模式解码、再按行切分,才能保证解析正确。
5.2 容错解析
模型虽然被约束了,但它终究不是机器,偶尔还是会失控。所以我写了三层兜底:先去掉可能出现的 markdown 代码块前缀后缀,再用 JSON.parse 解析,最后逐字段校验"六件套"是否齐全。任何一层失败,前端都会展示原始文本作为降级方案——宁可让用户看到一段话,也不能让用户看到一场解析异常。
六、意图联动:AI 从"说话"到"办事"
这是我认为整个项目最有趣的设计——让模型的输出直接驱动 App 的行为。前端拿到 JSON 后执行 applyIntent:
function applyIntent(data) {
if (data.intent === "set_alarm" && /^(\d{1,2}):(\d{2})$/.test(data.alarm_time)) {
const [h, m] = data.alarm_time.split(":").map(Number);
if (h < 24 && m < 60) {
alarms.push({ hour: h, minute: m, label: "AI 设定", enabled: true, firedToday: false });
renderAlarms();
switchTab("alarm");
return `⏰ 已自动设置闹钟 ${pad2(h)}:${pad2(m)}`;
}
}
if (data.intent === "set_timer" && data.reminder_seconds > 0) {
startTimer(data.reminder_seconds * 1000);
return `⏳ 已启动 ${fmtClock(data.reminder_seconds * 1000)} 倒计时`;
}
return "";
}
用户说「帮我设置早上7点的闹钟」,模型返回 intent = "set_alarm"、alarm_time = "07:00",前端立刻添加对应闹钟、切换 Tab、弹出提示;用户说「倒计时10分钟」,reminder_seconds = 600,前端立刻启动倒计时。AI 不再停留在"嘴炮"层面,而是真正接管了工具。这就是我之前说的"提示词即协议"在真实场景里兑现的样子。
七、三个时间工具的实现细节
7.1 闹钟:从"零到一"到"一到多"
闹钟的难点不在"响",而在"管理"。我用一个数组持有所有闹钟对象(hour / minute / label / enabled / firedToday),把它们渲染成可独立开关的列表项。开关是一段 CSS 实现的小滑块,状态切换时立刻重渲染。闹钟的触发逻辑放在每秒一次的全局时钟心跳里:遍历所有已启用的闹钟,逐项比对当前 时:分:秒,命中且今天还没响过就触发声音与闪光提示。firedToday 字段解决了"同一时刻重复响铃"的问题——严格说它记录的是日期字符串,保证每天只响一次。
7.2 计时器:别让"暂停"吃掉时间
计时器踩过一个经典的坑:如果只用"剩余秒数减一"的写法,那么浏览器切到后台、或者 setInterval 被节流的时候,倒计时就会变慢。正确的做法是以时间戳为基准:记录开始时刻 timerTotalStart,在每次心跳里用"现在减去开始时刻"算出真实剩余时间:
timerLeftMs = Math.max(0, timerTotalMs - (now.getTime() - timerTotalStart));
这样即使用户把页面挂在后台半小时,回来时剩余时间依然是准确的。此外我还给最后 10 秒加了一个红色脉冲动画,并顺手用 document.title 做了"标签页倒计时"——切走也能瞥见还剩多久。
7.3 秒表:毫秒级精度与圈数
秒表反而最简单:用一个基准值 swBase 叠加"开始至今的增量"得出总耗时,setInterval 每 30 毫秒刷新一次显示。暂停时把增量合并进基准值,继续时重新记录起点——这其实是闹钟休眠场景里"暂停不丢时间"问题的镜像解。记圈时就地取当前累计值插入列表顶部,第几圈、用了多久一目了然。
八、音效:用 Web Audio API 现场"合鸣"
三件工具都需要提示音,但我既不想引入音频文件,也不确定用户网络。查了一圈,发现浏览器内置的 Web Audio API 就能现场合成。于是写了这个小小的蜂鸣函数:
function beep(times = 3, freq = 880) {
...
for (let i = 0; i < times; i++) {
const osc = audioCtx.createOscillator();
...
osc.start(start);
osc.stop(start + 0.3);
}
}
每个音符是一个正弦波振荡器,通过 GainNode 做音量包络,制造出"叮—叮—叮"的效果。闹钟用高音(986Hz)、计时结束用更高的音(1318Hz),听觉上天然区分场景。需要提醒后辈的是:浏览器的自动播放策略会拦截未交互时的音频,所以我注册了一个全局的 pointerdown 监听,用户第一次点击页面时即初始化 AudioContext,这也顺带成了"唤醒音效"的仪式。
九、联调与踩坑实录
任何项目不踩几个坑就不完整。这里记录三个印象最深的。
9.1 模型真的会"画蛇添足"
即便系统提示词白纸黑字写着"禁止 markdown 代码块",模型仍然偶发地在 JSON 外面包一层 ```json。第一次撞见时我怀疑是自己解析写错了,打印原始报文才恍然大悟。解决方案就是前面说的三层容错。这件事给我上了一课:提示词是降低概率的手段,不是消除风险的保证,防御代码永远是必需的。
9.2 秒表的"死循环"Bug
开发秒表初版时,我写了一个 while (now - swStartT < swBase) 的空转循环,本意是"等基准时间追上",实际写出来却把主线程直接卡死。排查时浏览器标签页完全无响应,吓得我差点 Ctrl+W。删掉那一行之后一切正常——永远不要在 UI 主线程里旋转等待,时间戳算术就能解决的事,别用循环去"熬"。
9.3 fetch 跨域的"隐形坑"
纯前端直连 https://api-ai.gitcode.com 会触发浏览器的 CORS 预检,本地用 file:// 协议直接打开时问题尤其明显。最后的妥协方案是 README 里推荐用 python3 -m http.server 起一个本地静态服务,页面从这个同源服务加载,跨域问题迎刃而解。这也是为什么我在 README 里把"方式一:直接打开"和"方式二:起本地服务"写得清清楚楚——文档的每一句,背后都可能踩着一次真实的坑。
十、测试与验证:三组请求见真章
项目的验收环节自带喜感——我直接用 Node 把「QAI 调用 + JSON 解析 + 意图判断」整条链路跑了一遍,测了三组典型输入,结果全部符合预期:
输入:帮我设一个早上7点的闹钟
{"intent":"set_alarm","reply":"好的,已经帮你设好早上7点的闹钟了。",
"emoji":"⏰","advice":"建议提前10分钟起床,避免迟到哦。",
"alarm_time":"07:00","reminder_seconds":0}
:联动结果 ⏰ 自动设置闹钟 07:00,与预期完全一致。
输入:倒计时10分钟
{"intent":"set_timer","reminder_seconds":600}
:联动结果 ⏳ 启动 600 秒倒计时。
输入:讲个冷笑话
{"intent":"chat","reply":"为什么数学书总是很忧伤?因为它有太多的问题。"}
:无联动动作,正常对话。
三个方向的用例——设定类、计时类、闲聊类——全部在真实网络环境下跑通,模型对意图的识别准确率相当可靠。这验证了整套「提示词协议 + JSON 解析 + 前端联动」的方案是站得住脚的。
十一、README 与工程化收尾
写 README 时,我给自己立了一个标准:一位完全陌生的开发者,克隆仓库后循着文档走,必须在三分钟内跑起来。 因此 README 里放了:一句话介绍与特性表、架构与意图联动逻辑说明、一张完整的"Python 转 JavaScript 对照表"、两种运行方式(直接打开 / http.server)、API Key 配置入口、注意事项(含密钥暴露的警告)以及 To Do 清单。文档写到这个颗粒度,项目才算真正闭环。
十二、安全反思:一枚"公开的钥匙"
有个问题是绕不过去的,必须坦白:纯前端直连 AI API,意味着 API Key 会出现在浏览器的网络面板里,任何拿到页面的人都能看到。 这在生产环境是绝对禁止的,正确做法是在服务端做一层代理,把 Key 藏到环境变量里。但作为演示型练手项目,把 Key 放进前端是这个项目"零后端"约束下的必然代价。我在 README 的注意事项里用加粗字体写明了这一点,并给出了后续规划:提供一个 Node.js 代理版本。「清楚地知道自己的妥协在哪儿」,我认为这是安全意识的第一步。
十三、复盘:三句话总结这次开发
第一句:时间是工具的,对话是未来的
把时间工具和 AI 塞进同一张网页,看似是功能叠加,实质是交互范式的转变——用户不再"操作界面",而是"对机器说话"。虽然今天的自然语言指令还很初级,但这个方向让我看到英"对话框即界面"的雏形。
第二句:提示词是新一代的接口文档
这次开发中收益最大、也最希望分享的经验,是把系统提示词当作接口契约来设计。字段枚举、取值边界、输出纪律,一条条写进提示词,模型的输出就从"作文"变成了"数据"。这套方法适用于任何想稳定消费大模型输出的场景:Agent 工具调用、表单自动填充、数据抽取……一法通,百法通。
为了证明这一点,尝试过一次"没有协议"的对照组:同一个"帮我设置早上7点的闹钟",去掉系统提示词再去问,模型给出的回复是一整段流畅的自然语言:"好的,我帮你设置一个早上7点的闹钟。建议你睡前把手机放在床头,早上闹钟响的时候不要立刻按掉,再眯五分钟就真的迟到了……"内容很贴心,但程序完全无从下手:闹钟的小时数藏在自然语言里,前端既没有字段可读,也没有接口可调,这段话对"执行"而言毫无用处。同一个意图,有协议就能自动设好闹钟,没协议就只能停在"谈心"层面。差异不在模型能力,而在契约的清晰度。
另外值得补充的是,这套协议还顺带解决了"错误怎么报"的问题。模型偶尔会给出异常的 alarm_time(比如 25:90),或者 reminder_seconds 是负数——这种时候协议里的取值边界就是最好的过滤器:正则校验不过就直接判为无效并降级为普通聊天,前端连写大量异常分支的力气都省了。接口文档的意义,从来不止于"告诉别人能传什么参数",更在于"告诉别人什么样的请求会被拒绝"。
第三句:克制是个人项目的最高美德
没有框架、没有构建、没有后端,一个 28KB 的文件完成全部功能。克制带来了可读性(任何前端开发者都能三分钟看懂)、可迁移性(拷走这份代码到哪里都能跑)和可维护性(改一个字段不用翻三个文件)。给复杂度设上限,是普通工程师与优秀工程师之间的分水岭。
十四、未来展望:它还能长成什么样
项目交付之后,我把这些想法写进了 README 的 To Do 清单,也在这里展开说说:
- 持久化:用
localStorage保存闹钟与计时配置,刷新不丢;再接上 Notification API 做系统级通知,闹钟响时即使切到别的标签页也能提醒。 - 多轮记忆:让 AI 记住上下文,比如"再推迟5分钟"这种延续性指令。
- 更多意图:秒表联动(“帮我记录50米成绩”)、时钟显示切换(“显示伦敦时间”)都可以通过扩展 JSON 协议的枚举值与处理函数轻松加入。
- 代理版:提供一个可选的 Node.js 中间层,把 Key 藏进环境变量,一步到位解决安全顾虑。
- 分享与主题:支持导出"今日专注报告",换肤功能让页面在白天模式与夜间模式之间切换。
如果读者感兴趣,这套"时间工具 + AI 意图联动"的骨架完全可以复用去改造其他场景——把"闹钟/计时器"换成"待办/番茄钟",把 AI 的角色从"时间管家"换成"学习教练",一样的架构,换一套提示词和渲染逻辑即可。
十五、结语
回看整个项目,最让我满足的瞬间,不是三组验证用例全部通过的片刻,而是第一次对页面说出"帮我设置早上7点的闹钟",眼睁睁看着闹钟列表里真的多出一行 07:00 的时候。那一刻,工具终于开始听懂了人话。
技术的浪漫,往往就藏在这种"刚刚好"的时刻里:一段会翻译的 Python、一条会约束的提示词、一句会执行的 JavaScript,合起来,让一块冷冰冰的屏幕学会了陪你过日子。
愿你的每一个「码道」项目,都能找到属于自己的、"刚刚好"的那一瞬间。
附:项目源码与本篇手记均维护在
https://atomgit.com/gcw_xixvC6Lo/naozhongjishiqi,其中 README 提供完整的快速上手指引。项目基于华为云 CodeArts(码道)环境完成开发与交付。@TOC
欢迎使用Markdown编辑器
你好! 这是你第一次使用 Markdown编辑器 所展示的欢迎页。如果你想学习如何使用Markdown编辑器, 可以仔细阅读这篇文章,了解一下Markdown的基本语法知识。
新的改变
我们对Markdown编辑器进行了一些功能拓展与语法支持,除了标准的Markdown编辑器功能,我们增加了如下几点新功能,帮助你用它写博客:
- 全新的界面设计 ,将会带来全新的写作体验;
- 在创作中心设置你喜爱的代码高亮样式,Markdown 将代码片显示选择的高亮样式 进行展示;
- 增加了 图片拖拽 功能,你可以将本地的图片直接拖拽到编辑区域直接展示;
- 全新的 KaTeX数学公式 语法;
- 增加了支持甘特图的mermaid语法1 功能;
- 增加了 多屏幕编辑 Markdown文章功能;
- 增加了 焦点写作模式、预览模式、简洁写作模式、左右区域同步滚轮设置 等功能,功能按钮位于编辑区域与预览区域中间;
- 增加了 检查列表 功能。
功能快捷键
撤销:Ctrl/Command + Z
重做:Ctrl/Command + Y
加粗:Ctrl/Command + B
斜体:Ctrl/Command + I
标题:Ctrl/Command + Shift + H
无序列表:Ctrl/Command + Shift + U
有序列表:Ctrl/Command + Shift + O
检查列表:Ctrl/Command + Shift + C
插入代码:Ctrl/Command + Shift + K
插入链接:Ctrl/Command + Shift + L
插入图片:Ctrl/Command + Shift + G
查找:Ctrl/Command + F
替换:Ctrl/Command + G
合理的创建标题,有助于目录的生成
直接输入1次#,并按下space后,将生成1级标题。
输入2次#,并按下space后,将生成2级标题。
以此类推,我们支持6级标题。有助于使用TOC语法后生成一个完美的目录。
如何改变文本的样式
强调文本 强调文本
加粗文本 加粗文本
标记文本
删除文本
引用文本
H2O is是液体。
210 运算结果是 1024.
插入链接与图片
链接: link.
图片:
带尺寸的图片:
居中的图片:
居中并且带尺寸的图片:
当然,我们为了让用户更加便捷,我们增加了图片拖拽功能。
如何插入一段漂亮的代码片
去博客设置页面,选择一款你喜欢的代码片高亮样式,下面展示同样高亮的 代码片.
// An highlighted block
var foo = 'bar';
生成一个适合你的列表
- 项目
- 项目
- 项目
- 项目
- 项目1
- 项目2
- 项目3
- 计划任务
- 完成任务
创建一个表格
一个简单的表格是这么创建的:
| 项目 | Value |
|---|---|
| 电脑 | $1600 |
| 手机 | $12 |
| 导管 | $1 |
设定内容居中、居左、居右
使用:---------:居中
使用:----------居左
使用----------:居右
| 第一列 | 第二列 | 第三列 |
|---|---|---|
| 第一列文本居中 | 第二列文本居右 | 第三列文本居左 |
SmartyPants
SmartyPants 是一个文本转换工具,主要功能是将普通的 ASCII 标点符号自动转换为更美观的印刷体标点符号。例如:
| 原始符号 | 转换后 | 说明 |
|---|---|---|
"引号" | “引号” | 直引号变弯引号 |
'单引号' | ‘单引号’ | 直单引号变弯单引号 |
-- | – | 两个连字符变短破折号 |
--- | — | 三个连字符变长破折号 |
... | … | 三个点变省略号 |
创建一个自定义列表
-
Markdown
- Text-to- HTML conversion tool Authors
- John
- Luke
如何创建一个注脚
一个具有注脚的文本。2
注释也是必不可少的
Markdown将文本转换为 HTML。
KaTeX数学公式
您可以使用渲染LaTeX数学表达式 KaTeX:
Gamma公式展示 Γ ( n ) = ( n − 1 ) ! ∀ n ∈ N \Gamma(n) = (n-1)!\quad\forall n\in\mathbb N Γ(n)=(n−1)!∀n∈N 是通过欧拉积分
Γ ( z ) = ∫ 0 ∞ t z − 1 e − t d t . \Gamma(z) = \int_0^\infty t^{z-1}e^{-t}dt\,. Γ(z)=∫0∞tz−1e−tdt.
你可以找到更多关于的信息 LaTeX 数学表达式here.
新的甘特图功能,丰富你的文章
- 关于 甘特图 语法,参考 这儿,
UML图表
可以使用UML图表进行渲染,例如下面产生的一个序列图:
- 关于 UML图表 语法,参考 这儿,
流程图
- 关于 Mermaid 语法,参考 这儿,
FLowchart流程图
我们依旧会支持flowchart.js的流程图语法:
- 关于 Flowchart流程图 语法,参考 这儿.
导出与导入
导出
如果你想尝试使用此编辑器, 你可以在此篇文章任意编辑。当你完成了一篇文章的写作, 在上方工具栏找到 文章导出 ,生成一个.md文件或者.html文件进行本地保存。
导入
如果你想加载一篇你写过的.md文件,在上方工具栏可以选择导入功能进行对应扩展名的文件导入,
继续你的创作。
注脚的解释 ↩︎
更多推荐




所有评论(0)