使用ReactJS、Twin Macro和Styled Components创建简单的Markdown预览器

使用ReactJS、Twin Macro和Styled Components创建简单的Markdown预览器。 #

大家好!您是否想过使用ReactJS构建自己的Markdown预览器?今天是您的幸运日!我最近使用ReactJS、Twin Macro和styled-components构建了一个Markdown预览器,并且我认为创建一个逐步指南来帮助您构建一个也会很有趣。所以,拿起一杯咖啡(或者茶,如果您喜欢),让我们开始吧!

第一步:设置基本的React应用程序 #

首先,我们需要设置一个基本的React应用程序。如果您还没有安装Node.js和npm,请确保在继续之前安装它们。

打开终端并运行以下命令来创建一个新的React应用程序:

npx create-react-app markdown-previewer

全屏模式退出全屏模式

第二步:安装包 #

接下来,我们需要安装必要的包。转到您的项目文件夹并运行以下命令: 安装所需包的命令如下:

npm install styled-components twin.macro marked dompurify

第三步:导入重要的包 #

现在我们已经安装了我们的包,让我们了解一下代码中的导入语句。

import React, { useState } from 'react';
import styled from 'styled-components';
import tw from 'twin.macro';
import {marked} from 'marked';
import DOMPurify from 'dompurify';

  1. React, { useState }'react' 包中导入。useState hook 用于在我们的函数组件中管理状态。
  2. styled'styled-components' 包中导入。这使我们能够编写实际的 CSS 代码来样式化我们的组件。
  3. tw'twin.macro' 导入。这是一个快速构建自定义设计的实用 CSS 框架。
  4. marked'marked' 导入。 ## 步骤 4:为我们的组件设置样式

既然我们已经准备好导入语句,让我们使用styled-componentstwin.macro为我们的组件设置样式。

const Container = styled.div`
  ${tw`container mx-auto mt-10 mb-20`}
`;

const Header = styled.div`
  ${tw`text-center text-xl font-bold`}
`;

const Row = styled.div`
  ${tw`flex mt-10`}
`;

const Column = styled.div`
  ${tw`flex-1 mx-5 h-[35rem] w-[35rem]`}
`;

const Textarea = styled.textarea`
  ${tw`w-full h-full p-3 border rounded-md transition-all duration-300 ease-in-out`}
  &:focus {
    ${tw`border-blue-500 outline-none shadow-outline`}
  }
`;
const Preview = styled.div`
  ${tw`h-full w-full overflow-y-scroll overflow-x-scroll p-3 border rounded-md bg-gray-100`}`;


输入完毕 在这里,我们使用styled-componentstwin.macro定义了ContainerHeaderRowColumnTextareaPreviewContainer是一个带有一些边距和填充的div元素。Header是一个带有居中文本和粗体字体的div元素。Row是一个带有弹性显示和一些顶部边距的div元素。Column是一个具有弹性-1、边距、高度和宽度定义的div元素。Textarea是一个具有全宽度、全高度、填充、边框、圆角和过渡效果的textarea元素。Preview是一个具有全高度、全宽度、溢出滚动、填充、边框、圆角和灰色背景的div元素。

第五步:处理Markdown输入和预览 #

现在我们已经定义了样式化的组件,让我们来处理Markdown的输入和预览:

const [markdown, setMarkdown] = useState('');
const handleMarkdo wnChange = (e) => {
  setMarkdown(e.target.value);
};

const getSanitizedHTML = () => {
  const rawHTML = marked(markdown);
  return DOMPurify.sanitize(rawHTML);
}

在这段代码中,我们定义了一个markdown状态和一个setMarkdown函数来更新状态。handleMarkdownChange函数用于在用户在Textarea中输入时更新markdown状态。getSanitizedHTML函数用于将markdown文本转换为HTML并使用DOMPurify进行清理,以防止XSS攻击。

第6步:渲染组件 #

最后,让我们渲染我们的组件。下面是组件的返回语句:

return (
  <Container>
    <Header>Markdown预览器</Header>

    <Row>
      <Column>
        <Header>Markdown输入</Header>
        <Textarea value={markdown} onChange={handleMarkdownChange} />
      </Column>

      <Column>
        <Header>预览</He import React, { useState } from 'react';
import styled from 'styled-components';
import tw from 'twin.macro';
import {marked} from 'marked';
import DOMPurify from 'dompurify';

const Container = styled.div`
  ${tw`container mx-auto`}
`;

const Header = styled.h1`
  ${tw`text-4xl font-bold text-center mb-8`}
`;

const Row = styled.div`
  ${tw`flex flex-wrap`}
`;

const Column = styled.div`
  ${tw`w-full md:w-1/2`}
`;

const Textarea = styled.textarea`
  ${tw`w-full h-64 p-4 mb-4`}
`;

const Preview = styled.div`
  ${tw`w-full p-4 bg-gray-200`}
`;

const MarkdownPreviewer = () => {
  const [markdown, setMarkdown] = useState('');

  const handleMarkdownChange = (event) => {
    setMarkdown(event.target.value);
  };

  const getSanitizedHTML = () => {
    const sanitizedHTML = DOMPurify.sanitize(marked(markdown));
    return { __html: sanitizedHTML };
  };

  return (
    <Container>
      <Header>Markdown Previewer</Header>
      <Row>
        <Column>
          <Textarea value={markdown} onChange={handleMarkdownChange} />
        </Column>
        <Column>
          <Preview dangerouslySetInnerHTML={getSanitizedHTML()} />
        </Column>
      </Row>
    </Container>
  );
};

export default MarkdownPreviewer;
``` 转换以下Markdown为中文并删除第一级标题:o mt-10 mb-20`
`;

const Header = styled.div`
  ${tw`text-center text-xl font-bold`}
`;

const Row = styled.div`
  ${tw`flex mt-10`}
`;

const Column = styled.div`
  ${tw`flex-1 mx-5 h-[35rem] w-[35rem]`}
`;

const Textarea = styled.textarea`
  ${tw`w-full h-full p-3 border rounded-md transition-all duration-300 ease-in-out`}
  &:focus {
    ${tw`border-blue-500 outline-none shadow-outline`}
  }
`;

const Preview = styled.div`
  ${tw`h-full w-full overflow-y-scroll overflow-x-scroll p-3 border rounded-md bg-gray-100`}

`;

const MarkdownPreviewer = () => {
  const [markdown, setMarkdown] = useState('');

  const handleMarkdownChange = (e) => {
    setMarkdown(e.target.value);
  };

  const getSanitizedHTML = () => {
    const rawHTML = marked(markdown);
    return DOMPurify.sanitize(rawHTML);
  }

  return (
    <Container>
      <Header>Markdown预览器</Header>

      <Row>
        <Column>
          <Header>Markdown输入</Header>
          <Textarea value={markdown} onChange={handleMarkdownChange} />
        </Column>
        <Column>
          <Header>预览</Header>
          <Preview dangerouslySetInnerHTML={{ __html: getSanitizedHTML() }} />
        </Column>
      </Row>
    </Container>
  );
};

export default MarkdownPreviewer; 以下是将上述Markdown翻译成中文并删除第一级标题的结果:

```jsx
import React, { useState } from "react";
import marked from "marked";
import { Container, Row, Column, Header, Preview } from "./styles";

const MarkdownPreviewer = () => {
  const [markdown, setMarkdown] = useState("");

  const handleChange = (e) => {
    setMarkdown(e.target.value);
  };

  const getSanitizedHTML = () => {
    const sanitizedMarkdown = marked(markdown);
    return { __html: sanitizedMarkdown };
  };

  return (
    <Container>
      <Row>
        <Column>
          <Header>编辑</Header>
          <textarea
            value={markdown}
            onChange={handleChange}
            placeholder="在这里输入Markdown"
          />
        </Column>

        <Column>
          <Header>预览</Header>
          <Preview dangerouslySetInnerHTML={getSanitizedHTML()} />
        </Column>
      </Row>
    </Container>
  );
};

export default MarkdownPreviewer;

这是最终的结果🎉: