React:呈现语法突出显示的代码块
React : Rendering a syntax highlighted code block
我正在使用 React 和 JSX 开发一个文章系统。我的文章有时在其内容中包含代码示例。我已经实施 highlight.js 来为这些块添加样式。我的主要问题是我的文章使用 HTML 标签,因此我使用 React 的 dangerouslySetInnerHTML 方法。这工作正常,但当然我的代码块中的任何 HTML 代码都会被解释为 HTML。我想知道你们中是否有人对我应该如何实施这一点有任何见解。我是否应该从我的内容中删除所有 HTML 并在安全地将其呈现为文本之前解析它(使用 markdown)?
感谢阅读本文。
我使用带有高亮显示的 markdown,然后使用 innerHtml。这是来自 https://github.com/calitek/ProjectNotes.
'use strict';
var fs = require('fs');
var Remarkable = require('remarkable');
var hljs = require('highlight.js');
let lodash = require('lodash');
var md = new Remarkable({
highlight: function (str, lang) {
if (lang && hljs.getLanguage(lang)) {
try {
return hljs.highlight(lang, str).value;
} catch (err) {}
}
try {
return hljs.highlightAuto(str).value;
} catch (err) {}
return '';
}
});
var rootDataPath = './data';
var getFile = function(clientData, doneCallBack) {
let getNote = function(fileData) {
var filePath = rootDataPath + '/filenotes.json';
var notesReadCallBack = function(err, data){
if (err) doneCallBack({fileData: fileData, noteData: {note: 'error'}});
else {
let noteData;
var jsonData = JSON.parse(data.toString());
let noteRecord = lodash.findWhere(jsonData, {nodeid: clientData.nodeid});
if (noteRecord) {
let noteIndex = lodash.indexOf(jsonData, noteRecord);
noteData = jsonData[noteIndex];
} else {
noteData = {nodeid: clientData.nodeid, note: ""};
}
let returnObject = {
noteData: noteData,
fileData: fileData
}
return doneCallBack(returnObject);
}
};
fs.readFile(filePath, notesReadCallBack);
}
var fileReadCallBack = function(err, data){
if (err) doneCallBack({note: 'error'});
else {
let inData = data.toString();
let inFile = clientData.filePath;
if (inFile.endsWith('.js') || inFile.endsWith('.json') || inFile.endsWith('.css')) {
inData = '``` javascript\n' + inData + '```';
}
let outData = md.render(inData);
getNote(outData);
}
};
fs.readFile(clientData.filePath, fileReadCallBack);
};
我在服务端做markdown渲染。然后将其发送到组件。
import React from 'react';
let FileCtrlSty = {
height: '60%',
marginBottom: '20px',
width: '100%'
};
export default class FileCtrl extends React.Component {
render() {
let htmlDivSty = {height: '100%', width: '100%'}
if (this.props.fileData.startsWith('<pre>')) htmlDivSty.overflow = 'hidden';
else htmlDivSty.overflow = 'auto';
let fileHtml = {__html: this.props.fileData};
return (
<div id='FileCtrlSty' style={FileCtrlSty}>
<div dangerouslySetInnerHTML={fileHtml} style={htmlDivSty}></div>
</div>
);
}
}
我的解决方案是在我的文章视图中实现一个简单的 "markdown" 类解析器。这个想法是使用正则表达式和 return JSX 元素从这些结果中解析降价。我不太擅长正则表达式(这可能会有所改进)但是这里是:
module.exports = React.createClass({
//this regex matchs \n\n, all wrapping ** **, wrapping ''' '''
mainRegex: /(\n\n|\*\*(?:[\s\S]*?)\*\*|'''(?:[\s\S]*?)''')/g,
titleRegex : /(?:\*\*([\s\S]*?)\*\*)/,
codeRegex : /(?:'''([\s\S]*?)''')/,
getInitialState: function() {
return {
content: []
};
},
setContent: function() {
if (this.props.htmlContent && !this.state.content.length) this.setState( {content: this.formatText(this.props.htmlContent) });
},
formatText: function(_text) {
var _this = this;
var _content = [];
_text = _text.split(this.mainRegex);
_text.forEach(function(_frag) {
if (!/\n\n/g.test(_frag) ) {
if (_this.titleRegex.test(_frag)) _content.push( {type: "h2", value: _frag.match(_this.titleRegex)[1] } );
else if (_frag!=="") _content.push({type: "p", value: _frag});
} else if (_this.codeRegex.test(_frag)) {
_content.push( {type: "code", value: _frag.match(_this.codeRegex)[1] } );
}
});
return _content;
},
render: function() {
return <article>
{this.state.content.map(this.renderText)}
</article>;
},
renderText:function(_tag, i) {
switch (_tag.type) {
case "p":
return <p key={i}>{_tag.value}</p>;
break;
case "h2":
return <h2 key={i}>{_tag.value}</h2>;
break;
case "code":
return <pre key={i}><code clasName="js">{_tag.value}</code></pre>;
break;
}
},
componentDidUpdate: function() {
this.setContent();
this.highlightCode();
},
highlightCode: function() {
var _codeBlocks = document.getElementsByTagName('code');
for (var i = 0, j = _codeBlocks.length; i<j; ++i) {
hljs.highlightBlock(_codeBlocks[i]);
}
}
});
我正在使用 React 和 JSX 开发一个文章系统。我的文章有时在其内容中包含代码示例。我已经实施 highlight.js 来为这些块添加样式。我的主要问题是我的文章使用 HTML 标签,因此我使用 React 的 dangerouslySetInnerHTML 方法。这工作正常,但当然我的代码块中的任何 HTML 代码都会被解释为 HTML。我想知道你们中是否有人对我应该如何实施这一点有任何见解。我是否应该从我的内容中删除所有 HTML 并在安全地将其呈现为文本之前解析它(使用 markdown)?
感谢阅读本文。
我使用带有高亮显示的 markdown,然后使用 innerHtml。这是来自 https://github.com/calitek/ProjectNotes.
'use strict';
var fs = require('fs');
var Remarkable = require('remarkable');
var hljs = require('highlight.js');
let lodash = require('lodash');
var md = new Remarkable({
highlight: function (str, lang) {
if (lang && hljs.getLanguage(lang)) {
try {
return hljs.highlight(lang, str).value;
} catch (err) {}
}
try {
return hljs.highlightAuto(str).value;
} catch (err) {}
return '';
}
});
var rootDataPath = './data';
var getFile = function(clientData, doneCallBack) {
let getNote = function(fileData) {
var filePath = rootDataPath + '/filenotes.json';
var notesReadCallBack = function(err, data){
if (err) doneCallBack({fileData: fileData, noteData: {note: 'error'}});
else {
let noteData;
var jsonData = JSON.parse(data.toString());
let noteRecord = lodash.findWhere(jsonData, {nodeid: clientData.nodeid});
if (noteRecord) {
let noteIndex = lodash.indexOf(jsonData, noteRecord);
noteData = jsonData[noteIndex];
} else {
noteData = {nodeid: clientData.nodeid, note: ""};
}
let returnObject = {
noteData: noteData,
fileData: fileData
}
return doneCallBack(returnObject);
}
};
fs.readFile(filePath, notesReadCallBack);
}
var fileReadCallBack = function(err, data){
if (err) doneCallBack({note: 'error'});
else {
let inData = data.toString();
let inFile = clientData.filePath;
if (inFile.endsWith('.js') || inFile.endsWith('.json') || inFile.endsWith('.css')) {
inData = '``` javascript\n' + inData + '```';
}
let outData = md.render(inData);
getNote(outData);
}
};
fs.readFile(clientData.filePath, fileReadCallBack);
};
我在服务端做markdown渲染。然后将其发送到组件。
import React from 'react';
let FileCtrlSty = {
height: '60%',
marginBottom: '20px',
width: '100%'
};
export default class FileCtrl extends React.Component {
render() {
let htmlDivSty = {height: '100%', width: '100%'}
if (this.props.fileData.startsWith('<pre>')) htmlDivSty.overflow = 'hidden';
else htmlDivSty.overflow = 'auto';
let fileHtml = {__html: this.props.fileData};
return (
<div id='FileCtrlSty' style={FileCtrlSty}>
<div dangerouslySetInnerHTML={fileHtml} style={htmlDivSty}></div>
</div>
);
}
}
我的解决方案是在我的文章视图中实现一个简单的 "markdown" 类解析器。这个想法是使用正则表达式和 return JSX 元素从这些结果中解析降价。我不太擅长正则表达式(这可能会有所改进)但是这里是:
module.exports = React.createClass({
//this regex matchs \n\n, all wrapping ** **, wrapping ''' '''
mainRegex: /(\n\n|\*\*(?:[\s\S]*?)\*\*|'''(?:[\s\S]*?)''')/g,
titleRegex : /(?:\*\*([\s\S]*?)\*\*)/,
codeRegex : /(?:'''([\s\S]*?)''')/,
getInitialState: function() {
return {
content: []
};
},
setContent: function() {
if (this.props.htmlContent && !this.state.content.length) this.setState( {content: this.formatText(this.props.htmlContent) });
},
formatText: function(_text) {
var _this = this;
var _content = [];
_text = _text.split(this.mainRegex);
_text.forEach(function(_frag) {
if (!/\n\n/g.test(_frag) ) {
if (_this.titleRegex.test(_frag)) _content.push( {type: "h2", value: _frag.match(_this.titleRegex)[1] } );
else if (_frag!=="") _content.push({type: "p", value: _frag});
} else if (_this.codeRegex.test(_frag)) {
_content.push( {type: "code", value: _frag.match(_this.codeRegex)[1] } );
}
});
return _content;
},
render: function() {
return <article>
{this.state.content.map(this.renderText)}
</article>;
},
renderText:function(_tag, i) {
switch (_tag.type) {
case "p":
return <p key={i}>{_tag.value}</p>;
break;
case "h2":
return <h2 key={i}>{_tag.value}</h2>;
break;
case "code":
return <pre key={i}><code clasName="js">{_tag.value}</code></pre>;
break;
}
},
componentDidUpdate: function() {
this.setContent();
this.highlightCode();
},
highlightCode: function() {
var _codeBlocks = document.getElementsByTagName('code');
for (var i = 0, j = _codeBlocks.length; i<j; ++i) {
hljs.highlightBlock(_codeBlocks[i]);
}
}
});