前几天看技术胖的视频,做了一个笔记的渲染功能,记录一下做法,以后忘记了可以查看 ,可能不是很理解,先记录 。
一般,我们的文章页面 或是 后台的管理 页面,平常可能要 渲染文章 和 编写文章时的浏览;我们可以使用 以下几个插件来完成这个任务!
marked: 码克党语法的渲染;
highlight: 代码高亮;
tocify.tsx: 提取标题成大纲;
npm install marked highlight.js
我的环境是在 react-nuxt 中的,可能会有一些不同,下面的 文章的详情页面,进行笔记语法的渲染 。
details.js
import React from 'react'
import marked from 'marked'
import hljs from 'highlight.js'
import 'highlight.js/styles/monokai-sublime.css'
function Details () {
// 配置 marked
const renderer = new marked.Renderer()
marked.setOptions({
renderer: renderer, // 这个是必须填写的
gfm: true, // 启动类似Github样式的Markdown,
pedantic: false, // 只解析符合Markdown定义的,不修正Markdown的错误
sanitize: false, // 原始输出,忽略HTML标签
tables: true, // 支持Github形式的表格,必须打开gfm选项
breaks: false, // 支持Github换行符,必须打开gfm选项
smartLists: true, // 优化列表输出
smartypants: false,
// 高亮显示规则 ,这里使用highlight.js来完成
highlight: function (code) {
return hljs.highlightAuto(code).value;
}
})
// 文章详情数据
const data = 'xxxxxxx,模拟文章内容数据, markdown 语法格式'
// 里面是数据源
let html = marked(data)
return (
<>
{/* 使用div的属性渲染,才可以有效果 */}
<div dangerouslySetInnerHTML={{__html: html}}></div>
</>
)
}
里面的 data 是数据,文章内容可以在 Typora 笔记中写好格式,然后复制黏贴到里面,作为 文章的内容,这样就会有 markdown 的格式;
这样在页面中,就可以渲染 Markdown 语法了;就是样式有点不好看,我们可以使用 css 修饰一下 。
页面中,使用 F12 检测你的页面结构,将以下的标签进行美化:
/* 代码块 */
code {
margin: 0 5px;
padding: 2px 5px;
background-color: #ffe0e0;
color: #ff502c;
border-radius: 5px;
}
/* 代码块 */
pre > code {
display: block;
padding: 10px;
margin: 10px 0;
background-color: #333;
border-radius: 5px;
overflow-y: auto;
color: #FFF;
font-family: Menlo, monospace;
}
/* p标签的颜色 */
p {
color: #666;
}
ul {
margin-bottom: 16px;
font-size: 1rem;
letter-spacing: 0.1rem;
}
/* li 的项目符号在内侧,显示项目符号 */
ul > li {
list-style: disc inside;
}
ol {
font-size: 1rem;
}
ol > li {
list-style: none;
}
样式你觉得 ok 就可以了 。
一般的文章详情页面,都有大纲,方便浏览者观看文章,所以呢,我们可以使用他来弄 大纲 。
一般会使用 固钉 把大纲给固定到一个地方,不让他随着页面滚动 (项目中 react 的一个框架, antd 这个 ui 框架)。
这个是使用 技术胖 介绍的插件,大家可以去看看 哔哩哔哩传送门;
要使用这个插件有几个条件;
1,你的项目要使用到 antd 这个ui 框架;才能使用他,因为他依赖到里面的 锚点 Anchor
;
2,还有下载 lodash
这个插件;
npm install --save @types/lodash
注意,不是 lodash` ,因为要使用到 ts 来写这个文件(是别人的代码);
tocify.tsx
文件(是一个 ts 文件),编写逻辑:
import React from 'react'
import { Anchor } from 'antd'
import { last } from 'lodash'
const { Link } : any = 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 targetOffset={100}>
{this.renderToc(this.tocItems)}
</Anchor>
);
}
}
上面的代码是我复制黏贴的,因为是 ts 文件,会有几个方面要注意的:
1:引入的组件要先说明,再使用:
import { Anchor } from 'antd'
import { last } from 'lodash'
const { Link } : any = Anchor;
我也不会,所以给 Link 添加了 any 这个类型;在 vscode 中会警告说 组件没有注册,差不多这个意思,不管他好像没有错误(嘻嘻嘻,别骂我);
求求大佬解答?
在文章详情页面导入文件,然后进行配置
web > pages > details.js
// 后来的 马克党
import marked from 'marked'
import hljs from 'highlight.js'
import 'highlight.js/styles/monokai-sublime.css'
// 生成目录,注意不要写错 Tocify / tocify
import Tocify from './api/tocify.tsx'
function Details () {
// 之前配置 marked 笔记渲染的代码
const renderer = new marked.Renderer()
marked.setOptions({
renderer: renderer,
gfm: true,
pedantic: false,
sanitize: false,
tables: true,
breaks: false,
smartLists: true,
smartypants: false,
highlight: function (code) {
return hljs.highlightAuto(code).value;
}
})
// 配置 Tocify 大纲
const tocify = new Tocify()
// 前面有 marked + highlight 配置,是一起作用的
renderer.heading = function(text, level, raw) {
const anchor = tocify.add(text, level)
return `<a id="${anchor}" href="#${anchor}" class="anchor-fix"><h${level}> ${text} </h${level}></a> \n`
}
return (
<>
{/* 固钉-大纲 */}
<Affix>
<div>
<h3>大纲:</h3>
{/* 就是这个 */}
{tocify && tocify.render()}
</div>
</Affix>
</>
)
}
export default Details
一般放在固钉里,固定位置,
如需,控制 内容 的位置,可以在 tsx 文件中调整 Anchor
,就是点击大纲,文章进行定位,如果要调整文章定位的位置,可以使用 targetOffset
(距离顶部位置)进行调整;
return (
<Anchor affix showInkInFixed targetOffset={100}>
{this.renderToc(this.tocItems)}
</Anchor>
);