Markdown解析--之实现博客文章展示

1.Markdown介绍

1.1 Markdown是什么

​ Markdown是一种轻量级标记语言,创始人是约翰·格鲁伯(John Gruber)。它允许人们 “使用易读易写的纯文本格式编写文档,然后转换成有效的XHTML(或者HTML)文档。

1.2 Markdown的基本语法

​ Markdown的语法简洁明了、学习容易,而且功能比纯文本更强,因此有很多人用它写博客。世界上最流行的博客平台WordPress和大型CMS如joomla、drupal都能很好的支持Markdown,Github也是支持markdown的,在个性化语法上也做了不少的改进。Markdown的中文语法介绍:事例

1.3 Markdown 编辑器工具

  • 平台文章编辑器:简书、优快云 等;

  • 本地编辑器:MarkText、Typora、Notable、vnote 等;

  • Web 编辑器:maxiangmdeditor等;

2.MarkDwon解析方法有哪些?

但Markdown不是HTML,目前还不能被浏览器解析,所以我们需要Markdown的解析器,把Markdown翻译成浏览器认识的HTML文档展示出来。

Github 上查找关于如何在 React 实现 markdown 的渲染,查到了这两种库:

​ 第一种:react-markdown

​ https://github.com/rexxars/react-markdown

​ 第二种:marked+highlight.js

​ https://github.com/markedjs/marked

Marked就是一个基于Nodejs的Markdown解析引擎!

3.MarkDwon解析的具体操作

3.1 插件安装

npm install marked --save

npm install highlight.js --save

①marked插件

​ 一款最受欢迎的markdown文件解析插件。

​ 插件地址:https://github.com/chjj/marked

②highlight.js插件

​ 格式化显示各种语言的前端插件,用于解析文档中代码部分。

​ 插件地址:https://highlightjs.readthedocs.io/en/latest/css-classes-reference.html

3.2 引入模块

引入这两个插件及highlight.js样式文件

import marked from 'marked'
import hljs from 'highlight.js'
import 'highlight.js/styles/atom-one-dark.css'

3.3 设置参数

 const renderer = new marked.Renderer();
// marked插件的基础设置
 marked.setOptions({
     renderer: renderer,
     gfm: true, 
     tables: true,
     breaks: false,
     pedantic: false, 
     sanitize: false, 
     smartLists: true,
     smartypants: false,
     xhtml: false,
     highlight: function (code) {
         // 使用highlight 插件解析文档中代码部分,可直接设置高亮显示
         return hljs.highlightAuto(code).value;
     }
 });

参数说明

  • renderer: 这个是必须填写的,你可以通过自定义的Renderer渲染出自定义的格式
  • gfm:启动类似Github样式的Markdown,填写true或者false
  • tables: 支持Github形式的表格,必须打开gfm选项,填写true或者false
  • breaks: 支持Github换行符,必须打开gfm选项,填写true或者false
  • pedantic:只解析符合Markdown定义的,不修正Markdown的错误。填写true或者false
  • sanitize: 原始输出,忽略HTML标签,默认为false。 对输出进行过滤(清理),将忽略任何已经输入的html代码(标签)
  • smartLists:优化列表输出,这个填写ture之后,你的样式会好看很多,所以建议设置成ture
  • highlight: 高亮显示规则 ,这里我们将使用highlight.js来完成

同时搭配highlight.js代码高亮使用

​ 在设置setOptions属性时,可以直接设置高亮显示,代码如下:

highlight: function (code) {
            return hljs.highlightAuto(code).value;
    }

highlight.js是支持多种代码配色风格的,可以在css文件中进行切换,高亮主题可以自己更换自己喜欢的:

import 'highlight.js/styles/atom-one-dark.css'

​ 在这可以看到每种语言的高亮效果和配色风格:highlightjs.org/

​ 在你未设置代码高亮时,代码部分也就是普通文本,展示如下:

​ 设置完成后,你在浏览器检查代码时就可以出现hljs的样式,说明你的效果加成功了,实现了高亮显示代码。

​ 以上操作完毕后就基本能够达到想要的效果了,如果觉得现在的样式不是很好看的话,可以自己继续设置一下样式,如果想让代码块突出显示的话 可以设置 pre code标签的 css,我的设置如下:

/* 实现代码高亮 */
pre{
    display: block;
    background-color:#f3f3f3;
    padding: .5rem !important;
    overflow-y: auto;
    font-weight: 300;
    border-radius: .3rem;
    background-color: #283646 !important;
}
pre >code{
    border:0px !important;
    background-color: #283646 !important;
    color:#FFF;

}
code {
    display: inline-block ;
    background-color:#f3f3f3;
    border:1px solid #fdb9cc;
    border-radius:3px;
    font-size: 12px;
    padding-left: 5px;
    padding-right: 5px;
    color:#4f4f4f;
    margin: 0px 3px;
}

3.4 markdown渲染

import marked from 'marked';

const input = '# This is a header\n\nAnd this is a paragraph';
const html = marked(input);

​ 此时我们将html打印出来并看看他的类型

 console.log(html,typeof(html))
<h1>This is a header</h1>
<p>And this is a paragraph</p>
 string

​ 上边的三步配置完后就可以通过 const html = marked(input) 的方式转换md 内容为html 并进行渲染了,但是需要注意的是在react 中直接对需要渲染的地方使用 dom.innerText=html 的方式进行渲染会渲染出marked 转化出的字符串,这不是我们想要的结果 ,需要强制将字符串转化为html 代码

React中标签字符串强制转html解析的方法

React中我们经常会请求数据并渲染到页面中间显示,我们可以直接使用更新state的方法,并使用tihs.state.(data)的方法进行渲染,但是我们有时候会遇到需要渲染html标签的字符串到页面中如果直接进行渲染我们得到的是html字符串,并不是我们想要的html标签。这个时候我们应该怎么办呢?

1.js原生方法

var html="<p>这是需要渲染的标签字符串</p>"
document.body.innerHTML = html

2.react中强制转为html解析的方法

React 中,我们可以这样做:

<div dangerouslySetInnerHTML={{ __html: html }} />

文章是用 markdown 语法写的,所以要先转成 html 然后插入页面中,这里用了一个 React 不提倡的属性:dangerouslySetInnerHTML

利用marked对文本进行编译,并将编译出来的 HTML传入到dangerouslySetInnerHTML属性中

3.5自定义解析方法

const renderer = new marked.Renderer() 
renderer.table = (header, body) => {
		return '<table class="table table-bordered">'+header+body+'</table>'
}

  • 如:未设置表格解析方法前,表格无表格样式

  • 设置后表格有自定义的样式

参数名称是否必须示例备注
version1.0.0接口版本号
methodvivopay.h5.trade.create接口服务名称
timestamp20180724030750发送请求的时间,格式:yyyyMMddHHmmss
signTypeRSA签名方式,暂定RSA
signALKHIKYQUIHLBNLAHKLHLHJL签名
appId2019002536451112应用编号
bizContent可扩展的业务参数集合,格式为Json对象字符串

4.实现文章导航栏

4.1Tocify组件简介

这是我在网上找的一个文件,可以直接使用

tocify文件

import React from 'react';
import { Anchor } from 'antd';
import { last } from 'lodash';

const { Link } = Anchor;

export interface TocItem {
  anchor: string;
  level: number;
  text: string;
  children?: TocItem[];
}

export type TocItems = TocItem[]; // TOC目录树结构

export default class Tocify {
  tocItems: TocItems = [];

  index: number = 0;

  constructor() {
    this.tocItems = [];
    this.index = 0;
  }

  add(text: string, level: number) {
    const anchor = `toc${level}${++this.index}`;
    const item = { anchor, level, text };
    const items = this.tocItems;

    if (items.length === 0) { // 第一个 item 直接 push
      items.push(item);
    } else {
      let lastItem = last(items) as TocItem; // 最后一个 item

      if (item.level > lastItem.level) { // item 是 lastItem 的 children
        for (let i = lastItem.level + 1; i <= 2; i++) {
          const { children } = lastItem;
          if (!children) { // 如果 children 不存在
            lastItem.children = [item];
            break;
          }
          lastItem = last(children) as TocItem; // 重置 lastItem 为 children 的最后一个 item

          if (item.level <= lastItem.level) { // item level 小于或等于 lastItem level 都视为与 children 同级
            children.push(item);
            break;
          }
        }
      } else { // 置于最顶级
        items.push(item);
      }
    }

    return anchor;
  }

  reset = () => {
    this.tocItems = [];
    this.index = 0;
  };

  renderToc(items: TocItem[]) { // 递归 render
    return items.map(item => (
      <Link key={item.anchor} href={`#${item.anchor}`} title={item.text}>
        {item.children && this.renderToc(item.children)}
      </Link>
    ));
  }

  render() {
    return (
      <Anchor affix showInkInFixed>
         {this.renderToc(this.tocItems)}
      </Anchor>
    );
  }
}

4.2自定义使用方法

通过heading在标题处设置对应的锚点,这里就又涉及到自定义解析方法

 const tocify = new Tocify();
 const renderer = new marked.Renderer();

//  解析<h1>标签时需要将内容包裹在一个拥有特殊布局的<h1>标签中,并且不影响其他head标签的渲染
 renderer.heading = function(text, level, raw) {
 		const anchor = tocify.add(text, level); 
 		return `<h${level} id="${anchor}">${text}</h${level}>\n`;
 };

导航栏部分代码,可直接应用,生成后可实现点击到对应锚点标题处

<div className="details-nav">
    <div className="toc-list">
       {tocify && tocify.render()}
  	</div>
</div>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值