搜索
首页web前端js教程Markdown 中的交互组件

最近我实现了一个日历,结果非常好,我想记录该方法并与更广泛的受众分享。我真的很想在文章中得到我的工作的实际可测试结果。

我已经调整我的网站一段时间了,这个想法开始了下一次迭代。最终导致了又一次全面重建,但这个故事并不是关于我与完美主义的斗争。这是关于转动这个:

HTML comes with a lot of ready to use and flexible elements, but date selector
has a handful of limitations and the need to write your own calendar / date
input emerges sooner rather than later. In this tutorial I'll walk you through
implementing a calendar view and show how you can extend its functionality to fit
your booking widget or dashboard filter.

Here's how the final result might look like:

<!--render:custom-calendar-component/CalendarExample.ssi.tsx-->

进入此:

Interactive Components in Markdown

设置

我的网站在 Deno 上运行,并从最近开始使用 Hono 和 Hono/JSX,但该方法适用于任何基于 JS 的运行时和 JSX。

正如您已经注意到的,博客文章是带有属性的 Markdown 文件,这些属性在构建时使用 Marked 和 Front Matter 转换为静态 HTML。

经过一番反复思考,我决定了这个工作流程:

  • 我用markdown写文章
  • 我在与文章相同的文件夹中创建了一个 JSX 组件
  • 我使用 HTML 注释在 Markdown 中“导入”组件
  • 它的神奇功效

评论需要某种前缀,例如渲染并且基本上只是该组件的路径:

<!--render:custom-calendar-component/CalendarExample.ssi.tsx-->

也可以在路径后添加道具,但对于我的用例来说,不需要它,所以我跳过了这一部分。

渲染 HTML

在浏览器上添加任何内容之前,我们需要从 JSX 组件渲染 HTML。为此,我们“只”需要使用自定义渲染器覆盖 HTML 渲染逻辑:

export default class Renderer extends Marked.Renderer {
  constructor(private baseUrl: string, options?: Marked.marked.MarkedOptions) {
    super(options);
  }

  override html(html: string): string {
    const ssiMatch = /<!--render:(.+)-->/.exec(html);
    if (ssiMatch?.length) {
      const filename = ssiMatch[1];
      const ssi = SSIComponents.get(filename);
      if (!ssi) return html;
      const content = render(createElement(ssi.Component, {}));
      return [
        content,
        `<script type="module" src="%24%7Bssi.script%7D"></script>`,
      ].join("");
    }
    return html;
  }
}

逻辑非常简单:检查 html 字符串是否匹配 // 然后渲染 JSX。如果您手头有组件,那就很容易了。

编译组件

我的博客内容是静态生成的,所以我很自然地采用了相同的方法:

  • 扫描内容文件夹中的 *.ssi.tsx 组件(因此有后缀)
  • 创建一个文件来导入它们并将其添加到地图中,以便我可以轻松地通过路径检索它们

这是我的构建脚本的样子:

const rawContent = await readDir("./content");
const content: Record<string article> = {};
const ssi: Array<string> = [];

for (const pathname in rawContent) {
  if (pathname.endsWith(".ssi.tsx")) {
    ssi.push(pathname);
    continue;
  }
}

const scripts = await compileSSI(ssi.map((name) => `./content/${name}`));

const ssiContents = `
import type { FC } from 'hono/jsx';
const SSIComponents = new Map<string component: fc script: string>();
${
  scripts
    ? ssi
        .map(
          (pathname, i) =>
            `SSIComponents.set("${pathname}", { Component: (await import("./${pathname}")).default, script: "${scripts[i]}" })`
        )
        .join("\n")
    : ""
}
export default SSIComponents;
`;

await Deno.writeFile("./content/ssi.ts", new TextEncoder().encode(ssiContents));
</string></string></string>

不要太执着于 Deno 特定功能,它可以轻松地用 Node 或其他任何东西重写。

神奇之处在于编写类似于 JavaScript 代码的文本文件。

这个脚本:

const ssiContents = `
import type { FC } from 'hono/jsx';
const SSIComponents = new Map<string component: fc script: string>();
${
  scripts
    ? ssi
        .map(
          (pathname, i) =>
            `SSIComponents.set("${pathname}", { Component: (await import("./${pathname}")).default, script: "${scripts[i]}" })`
        )
        .join("\n")
    : ""
}
export default SSIComponents;
`;
</string>

返回如下字符串:

import type { FC } from 'hono/jsx';
const SSIComponents = new Map<string component: fc script: string>();
SSIComponents.set("custom-calendar-component/CalendarExample.ssi.tsx", { Component: (await import("./custom-calendar-component/CalendarExample.ssi.tsx")).default, script: "/content/custom-calendar-component/CalendarExample.ssi.js" })
export default SSIComponents;

</string>

然后可以在渲染器中导入和使用:)

写代码的代码!魔法!并且在此过程中没有任何人工智能受到伤害:只是你的老式元编程。

最后,最后一个难题是滋润前端的组件。我使用 esbuild,但我个人打算将其切换到 Vite 或 HMR 附带的任何其他工具。

尽管如此,它看起来是这样的:

HTML comes with a lot of ready to use and flexible elements, but date selector
has a handful of limitations and the need to write your own calendar / date
input emerges sooner rather than later. In this tutorial I'll walk you through
implementing a calendar view and show how you can extend its functionality to fit
your booking widget or dashboard filter.

Here's how the final result might look like:

<!--render:custom-calendar-component/CalendarExample.ssi.tsx-->

您可以注意到一个虚拟入口点,其值为零,但会强制 esbuild 在自己的文件夹中创建文件并具有可预测的路径。

并且 ssi-tsconfig.json 非常通用:

<!--render:custom-calendar-component/CalendarExample.ssi.tsx-->

在实际的前端水合作用中,我选择了简单的方法,并将其添加到我的 .ssi.tsx 文件的底部:

export default class Renderer extends Marked.Renderer {
  constructor(private baseUrl: string, options?: Marked.marked.MarkedOptions) {
    super(options);
  }

  override html(html: string): string {
    const ssiMatch = /<!--render:(.+)-->/.exec(html);
    if (ssiMatch?.length) {
      const filename = ssiMatch[1];
      const ssi = SSIComponents.get(filename);
      if (!ssi) return html;
      const content = render(createElement(ssi.Component, {}));
      return [
        content,
        `<script type="module" src="%24%7Bssi.script%7D"></script>`,
      ].join("");
    }
    return html;
  }
}

我相信读者会找到一种更优雅的方式来做到这一点,但仅此而已!

随意调整代码(下面是存储库的链接),添加您自己的风格并分享您的想法!

Interactive Components in Markdown 瓦莱里娅·VG / valeriavg.dev

以上是Markdown 中的交互组件的详细内容。更多信息请关注PHP中文网其他相关文章!

声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
JavaScript数据类型:浏览器和nodejs之间是否有区别?JavaScript数据类型:浏览器和nodejs之间是否有区别?May 14, 2025 am 12:15 AM

JavaScript核心数据类型在浏览器和Node.js中一致,但处理方式和额外类型有所不同。1)全局对象在浏览器中为window,在Node.js中为global。2)Node.js独有Buffer对象,用于处理二进制数据。3)性能和时间处理在两者间也有差异,需根据环境调整代码。

JavaScript评论:使用//和 / * * / * / * /JavaScript评论:使用//和 / * * / * / * /May 13, 2025 pm 03:49 PM

JavaScriptusestwotypesofcomments:single-line(//)andmulti-line(//).1)Use//forquicknotesorsingle-lineexplanations.2)Use//forlongerexplanationsorcommentingoutblocksofcode.Commentsshouldexplainthe'why',notthe'what',andbeplacedabovetherelevantcodeforclari

Python vs. JavaScript:开发人员的比较分析Python vs. JavaScript:开发人员的比较分析May 09, 2025 am 12:22 AM

Python和JavaScript的主要区别在于类型系统和应用场景。1.Python使用动态类型,适合科学计算和数据分析。2.JavaScript采用弱类型,广泛用于前端和全栈开发。两者在异步编程和性能优化上各有优势,选择时应根据项目需求决定。

Python vs. JavaScript:选择合适的工具Python vs. JavaScript:选择合适的工具May 08, 2025 am 12:10 AM

选择Python还是JavaScript取决于项目类型:1)数据科学和自动化任务选择Python;2)前端和全栈开发选择JavaScript。Python因其在数据处理和自动化方面的强大库而备受青睐,而JavaScript则因其在网页交互和全栈开发中的优势而不可或缺。

Python和JavaScript:了解每个的优势Python和JavaScript:了解每个的优势May 06, 2025 am 12:15 AM

Python和JavaScript各有优势,选择取决于项目需求和个人偏好。1.Python易学,语法简洁,适用于数据科学和后端开发,但执行速度较慢。2.JavaScript在前端开发中无处不在,异步编程能力强,Node.js使其适用于全栈开发,但语法可能复杂且易出错。

JavaScript的核心:它是在C还是C上构建的?JavaScript的核心:它是在C还是C上构建的?May 05, 2025 am 12:07 AM

javascriptisnotbuiltoncorc; saninterpretedlanguagethatrunsonenginesoftenwritteninc.1)javascriptwasdesignedAsalightweight,解释edganguageforwebbrowsers.2)Enginesevolvedfromsimpleterterterpretpreterterterpretertestojitcompilerers,典型地提示。

JavaScript应用程序:从前端到后端JavaScript应用程序:从前端到后端May 04, 2025 am 12:12 AM

JavaScript可用于前端和后端开发。前端通过DOM操作增强用户体验,后端通过Node.js处理服务器任务。1.前端示例:改变网页文本内容。2.后端示例:创建Node.js服务器。

Python vs. JavaScript:您应该学到哪种语言?Python vs. JavaScript:您应该学到哪种语言?May 03, 2025 am 12:10 AM

选择Python还是JavaScript应基于职业发展、学习曲线和生态系统:1)职业发展:Python适合数据科学和后端开发,JavaScript适合前端和全栈开发。2)学习曲线:Python语法简洁,适合初学者;JavaScript语法灵活。3)生态系统:Python有丰富的科学计算库,JavaScript有强大的前端框架。

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热门文章

热工具

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

WebStorm Mac版

WebStorm Mac版

好用的JavaScript开发工具

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

SublimeText3 Linux新版

SublimeText3 Linux新版

SublimeText3 Linux最新版

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具