【问题标题】:React : Rendering a syntax highlighted code blockReact:渲染语法高亮代码块
【发布时间】:2016-01-03 15:35:44
【问题描述】:

我正在开发一个使用 React 和 JSX 的文章系统。我的文章有时会在其内容中包含代码示例。我已经实现了 highlight.js 来为这些块添加样式。我的主要问题是我的文章使用 HTML 标签,因此我使用了 React 的 dangerouslySetInnerHTML 方法。这可以正常工作,但当然我的代码块中的任何 HTML 代码都会被解释为 HTML。我想知道你们中是否有人对我应该如何实现这一点有任何见解。在安全地将其呈现为文本之前,我是否应该从我的内容中删除所有 HTML 并解析它(使用 markdown)?

感谢您阅读本文。

【问题讨论】:

    标签: javascript reactjs syntax-highlighting


    【解决方案1】:

    我使用 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);
    };

    我正在服务器上进行降价渲染。然后将其发送到组件。

    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>
        );
      }
    }

    【讨论】:

    • 感谢您的回答!我的用例非常轻量级,所以我对使用除 highlightjs 之外的任何库都不感兴趣,我目前也在本地工作,还没有开始在服务器上工作。我将发布我实现的基本解析器以解决此问题,但感谢您的输入!
    【解决方案2】:

    我的解决方案是在我的文章视图中实现一个类似解析器的简单“降价”。这个想法是使用正则表达式解析降价并从这些结果中返回 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]);
        }
    
    }
    });
    

    【讨论】:

      猜你喜欢
      • 2013-01-08
      • 1970-01-01
      • 1970-01-01
      • 2019-06-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多