需求:
建表DDL代码要实现高亮,并且右侧可以有缩略图
代码高亮方案调研:
效果:
使用:
(没有代码行号显示)
import hljs from 'highlight.js/lib/core';
import sql from 'highlight.js/lib/languages/sql';
import 'highlight.js/styles/github.css';
import React from 'react';
hljs.registerLanguage('sql', sql);
import './index.less'
const MyCodeComponent=()=> {
const highlightedCode = hljs.highlight(`create table actorinfo(
id int comment '编号',
name varchar(10) comment '姓名',
age int comment '年龄',
gender varchar(2) comment '性别',
idcard varchar(18) comment '身份证号'
) comment '人员信息表';`, {language: 'sql'}).value
return (
<div className="dg-html">
<div style={{whiteSpace :'pre'}} dangerouslySetInnerHTML={{ __html: highlightedCode }} />
</div>
);
}
export default MyCodeComponent
为了显示行号,可以对数据进行如下处理,就可以显示行号了
// 添加行号为经过highlight.js处理后的code代码块生成对应的行号块。每有一行代码就能在行号块当中添加一个span标签。最后将这个行号块也添加在code代码块当中
function beforNumber(code) {
if (!code.trim()) {
return code;
}
const list = code.split('\n');
const spanList = ['<span aria-hidden="true" line-row>'];
list.forEach(() => {
spanList.push(`<span></span>`);
});
spanList.push('</span>');
list.push(spanList.join(''));
return list.join('\n');
}
/* 在CSS当中,我们在行号块里面添加一个计数器,然后在行号块的span从这个计数器取数,通过before来显示取出来的行号。最后将code和行号块的位置调整一下就能正常显示了。*/
span[line-row] {
position: absolute;
pointer-events: none;
top: 0;
font-size: 100%;
left: 0;
width: 3em;
letter-spacing: -1px;
border-right: 1px solid #999;
user-select: none;
counter-reset: linenumber;
}
span[line-row]>span {
pointer-events: none;
display: block;
counter-increment: linenumber;
}
span[line-row]>span::before {
content: counter(linenumber);
color: #999;
display: block;
padding-right: .8em;
text-align: right
}
最终效果
- react-code-blocks
效果:
使用:
(样式设置的行内样式,没有类名区别,不能控制样式)
import React from 'react';
import { CopyBlock , github} from 'react-code-blocks';
export function CodeComponent() {
return (
<CopyBlock
language="sql"
text={`create table actorinfo(
id int comment '编号',
name varchar(10) comment '姓名',
age int comment '年龄',
gender varchar(2) comment '性别',
idcard varchar(18) comment '身份证号'
) comment '人员信息表';`}
codeBlock
theme={github}
showLineNumbers
/>
);
}
- react-ace
效果图:
缺点:
设置readyOnly后有光标(具体是否可去除没试)
最终方案
综上所述,最后选用highlightjs插件实现代码高亮
代码缩略图实现
DDL组件代码
import React, { useEffect, useRef, useState } from 'react';
import hljs from 'highlight.js/lib/core';
import sql from 'highlight.js/lib/languages/sql';
import 'highlight.js/styles/github.css';
hljs.registerLanguage('sql', sql);
import './index.less'
interface IDdlViewerProps {
code: string
}
function beforNumber(code) {
if (!code.trim()) {
return code;
}
const list = code.split('\n');
const spanList = ['<span aria-hidden="true" line-row>'];
list.forEach(() => {
spanList.push(`<span></span>`);
});
spanList.push('</span>');
list.push(spanList.join(''));
return list.join('\n');
}
const DdlViewer = ({ code }: IDdlViewerProps) => {
const [highlightedCode, setHighlightCode] = useState('')
const abbreviationRef = useRef<any>()
const ddlRef = useRef<any>()
useEffect(() => {
setHighlightCode(beforNumber(hljs.highlight(code, { language: 'sql' }).value))
}, [code])
const clickAbbreviation = (e) => {
const scale = 0.4
const clientY = e.clientY - ddlRef.current.getBoundingClientRect()?.top
const lineHeight = 40
const scrollTop = abbreviationRef.current.scrollTop ? clientY / scale + abbreviationRef.current.scrollTop - lineHeight : clientY / scale - lineHeight
ddlRef.current.scrollTop = scrollTop < 0 ? 0 : scrollTop
}
return (
<div className="ddl-viewer">
<div
ref={ddlRef}
className='viewer ddl-content'
dangerouslySetInnerHTML={{ __html: highlightedCode }}
/>
{/* 缩略图 */}
<div
ref={abbreviationRef}
onClick={clickAbbreviation}
className="viewer abbreviation"
dangerouslySetInnerHTML={{ __html: highlightedCode }}
/>
</div>
);
}
export default DdlViewer
样式设置
.ddl-viewer {
font-size: 13px;
position: relative;
height: 100%;
cursor: pointer;
.viewer {
padding: 10px;
white-space: pre;
padding-left: 3.8em;
position: relative;
height: 100%;
overflow-y: auto;
}
.hljs-keyword {
color: blue;
}
.hljs-type {
color: orange;
}
.hljs-string {
color: green;
}
.hljs-number {
color: red;
}
span[line-row] {
position: absolute;
pointer-events: none;
top: 10px;
font-size: 100%;
left: 0;
width: 3em;
letter-spacing: -1px;
border-right: 1px solid #999;
user-select: none;
counter-reset: linenumber;
}
span[line-row]>span {
pointer-events: none;
display: block;
counter-increment: linenumber;
}
span[line-row]>span::before {
content: counter(linenumber);
color: #999;
display: block;
padding-right: .8em;
text-align: right
}
.abbreviation {
background-color: rgba(0, 0, 0, 0.5);
position: absolute;
top: 0;
right: 10px;
height: 100%;
transform: scale(0.4) translate(70%, -70%);
max-height: 700px;
overflow: auto;
color: #fff;
}
}
组件在页面中使用:
import React, { useEffect, useState } from "react";
import { Button, Drawer } from "antd";
import DdlCode from "./DdlCode"
const code = `
create table actorinfo(
id int comment '编号',
name varchar(10) comment '姓名',
age int comment '年龄',
gender varchar(2) comment '性别',
idcard varchar(18) comment '身份证号'
) comment '人员信息表';
create table actorinfo(
id int comment '编号',
name varchar(10) comment '姓名',
age int comment '年龄',
gender varchar(2) comment '性别',
idcard varchar(18) comment '身份证号'
) comment '人员信息表';
create table actorinfo(
id int comment '编号',
name varchar(10) comment '姓名',
age int comment '年龄',
gender varchar(2) comment '性别',
idcard varchar(18) comment '身份证号'
) comment '人员信息表';
create table actorinfo(
id int comment '编号',
name varchar(10) comment '姓名',
age int comment '年龄',
gender varchar(2) comment '性别',
idcard varchar(18) comment '身份证号'
) comment '人员信息表';
create table actorinfo(
id int comment '编号',
name varchar(10) comment '姓名',
age int comment '年龄',
gender varchar(2) comment '性别',
idcard varchar(18) comment '身份证号'
) comment '人员信息表';
create table actorinfo(
id int comment '编号',
name varchar(10) comment '姓名',
age int comment '年龄',
gender varchar(2) comment '性别',
idcard varchar(18) comment '身份证号'
) comment '人员信息表';
create table actorinfo(
id int comment '编号',
name varchar(10) comment '姓名',
age int comment '年龄',
gender varchar(2) comment '性别',
idcard varchar(18) comment '身份证号'
) comment '人员信息表';
create table actorinfo(
id int comment '编号',
name varchar(10) comment '姓名',
age int comment '年龄',
gender varchar(2) comment '性别',
idcard varchar(18) comment '身份证号'
) comment '人员信息表';
create table actorinfo(
id int comment '编号',
name varchar(10) comment '姓名',
age int comment '年龄',
gender varchar(2) comment '性别',
idcard varchar(18) comment '身份证号'
) comment '人员信息表';
`
const DdlDemo = () => {
const [nowCode, setCode] = useState(code)
const [visible, setVisible] = useState(false)
useEffect(() => {
// 模拟后端请求
setTimeout(() => {
setCode(code)
}, 100)
}, [])
const toShow = () => {
setVisible(true)
}
const onclose = () => {
setVisible(false)
}
return <>
<Button onClick={toShow}>查看</Button>
<Drawer width={632} visible={visible} onClose={onclose}>
<DdlCode code={nowCode}></DdlCode>
</Drawer>
</>
}
export default DdlDemo
最终效果图:
点击缩略图,左侧scrollTop变化