我正在使用React和JSX处理文章系统。我的文章有时会在其内容中包含代码示例。我已经实现了highlight.js来为这些块添加样式。我的主要问题是我的文章使用HTML标签,因此我使用React的危险的SetInnerHTML方法。这没关系,但当然我的代码块中的任何HTML代码都被解释为HTML。我想知道你们中是否有人对如何实现这一点有任何见解。我应该从内容中删除所有HTML并在将其安全地呈现为文本之前解析它(使用markdown)吗?
感谢您阅读本文。
答案 0 :(得分:1)
我使用markdown和highlight,然后使用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);
};
我正在服务器上进行降价渲染。然后将其发送到组件。
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>
);
}
}
答案 1 :(得分:0)
我的解决方案是在文章视图中实现一个简单的“markdown”,就像解析器一样。我们的想法是使用正则表达式解析markdown并从这些结果中返回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]);
}
}
});