编辑器react-codemirror2的封装组件简单使用
1、下载安装
npm install react-codemirror2 codemirror --save
2、引入
//引入Codemirror组件
import Cm from './extendCodeMirror.js'; import { UnControlled as CodeMirror } from 'react-codemirror2';
//样式
import 'codemirror/lib/codemirror.css';
import 'codemirror/lib/codemirror.js';
import 'codemirror/theme/dracula.css'; //主题
//代码折叠
import 'codemirror/addon/fold/foldgutter.css';
import 'codemirror/addon/lint/lint.css';
import 'codemirror/addon/fold/foldcode.js';
import 'codemirror/addon/fold/foldgutter.js';
import 'codemirror/addon/fold/brace-fold.js';
import 'codemirror/addon/hint/javascript-hint.js';
import 'codemirror/addon/hint/show-hint.js';
import 'codemirror/addon/lint/lint.js';
import 'codemirror/addon/lint/json-lint.js';
import 'codemirror/addon/lint/javascript-lint.js';
import 'codemirror/addon/display/placeholder.js';
import 'codemirror/mode/javascript/javascript.js';
import 'codemirror/mode/sql/sql.js';
很多属性配置,需要将对应文件引入才生效
//详细信息配置可以查看:https://codemirror.net,我这里用的是json/js/sql ,
//https://www.tun6.com/projects/code_mirror// 这里的也很全面
import React, { useState, useEffect, useRef, useCallback } from 'react';
import { connect } from 'dva';
import { Form, Input, Button } from 'antd';
import styles from './style.less';
import Cm from './extendCodeMirror.js';
import { UnControlled as CodeMirror } from 'react-codemirror2';
// import * as sqlFormatter from 'sql-formatter';
import 'codemirror/lib/codemirror.css';
import 'codemirror/lib/codemirror.js';
import 'codemirror/theme/dracula.css';
import 'codemirror/addon/fold/foldgutter.css';
import 'codemirror/addon/lint/lint.css';
import 'codemirror/addon/fold/foldcode.js';
import 'codemirror/addon/fold/foldgutter.js';
import 'codemirror/addon/fold/brace-fold.js';
import 'codemirror/addon/hint/javascript-hint.js';
import 'codemirror/addon/hint/show-hint.js';
import 'codemirror/addon/lint/lint.js';
import 'codemirror/addon/lint/json-lint.js';
import 'codemirror/addon/lint/javascript-lint.js';
import 'codemirror/addon/display/placeholder.js';
import 'codemirror/mode/javascript/javascript.js';
import 'codemirror/mode/sql/sql.js';
const sqlFormatter = require('sql-formatter');
const Editors = (props) => {
const { dispatch, title, type, editorList, rules, editorListErr } = props;
const [editorVal, sEditorVal] = useState('');
const formRefs = useRef(null);
const [editorBorder, sEditorBorder] = useState('none');
// let editor = null;
useEffect(() => {
if (formRefs.current) {
// console.log(editorList,title+'title')
editorList.map((val) => {
if (val.name == title) {
if (editorVal != val.value) {
sEditorVal(val.value);
}
}
});
}
}, [editorList]);
useEffect(() => {
//点击按钮校验
if (editorListErr && editorListErr != 1) {
takeEditorValue();
}
}, [editorListErr]);
const onEditorDidMount = (editors) => {
// editor.setSize('width', 'height'); // 设置编辑器宽高
// 绑定其他快捷键, 这里以按下ctrl-1 格式化编辑器代码做示例
// editor.addKeyMap({
// F1: autoFormatSelection(),
// });
};
//格式化
const autoFormatSelection = () => {
let editor = formRefs.current.editor;
if (props.type != 'sql') {
// console.log(editor, 1);
const script_length = editor.getValue().length;
const startPos = { line: 0, ch: 0, sticky: null };
const endPos = editor.doc.posFromIndex(script_length);
editor.setSelection(startPos, endPos);
editor.autoFormatRange(startPos, endPos);
editor.commentRange(false, startPos, endPos);
} else {
let splCont = '';
splCont = editor.getValue();
editor.setValue(sqlFormatter.format(splCont));
}
};
//失焦点保存
const takeEditorValue = () => {
let text = formRefs.current ? formRefs.current.editor.getValue() || '' : '';
// console.log(editorList,'editortexttexttexttextList')
rules && !text ? sEditorBorder('1px solid red') : sEditorBorder('none');
props.getEditorList(
{
name: title,
value: text,
},
editorList
);
};
// console.log(props.type);
return (
<div className={styles.editors} style={{ border: editorBorder }} key={props.title + 'editors'}>
<CodeMirror
className={styles.editorsDom}
ref={formRefs}
key={props.title}
editorDidMount={onEditorDidMount}
value={editorVal}
options={{
lineNumbers: true,
mode: { name: props.type == 'sql' ? 'text/x-sql' : 'application/json' },
extraKeys: { Ctrl: autoFormatSelection },
autofocus: false,
styleActiveLine: true,
theme: 'dracula',
lineWrapping: true,
foldGutter: true,
gutters: ['CodeMirror-linenumbers', 'CodeMirror-foldgutter'],
lint: false,
indentUnit: 2,
cursorHeight: 0.85,
placeholder: props.placeholder || '',
}}
onBlur={() => {
takeEditorValue(); //失去焦点保存
}}
/>
{editorBorder != 'none' ? (
<div
className={styles.editorsErrTxext}
key={props.title + 'editorsErrTxext'}
style={{ display: 'flex', justifyContent: 'flex-start', alignItems: 'center', color: '#f5222d' }}
>
{props.placeholder}
</div>
) : (
''
)}
</div>
);
};
export default Editors;
算了,直接贴代码吧,不想写了,只是想打断一下将近两年没来的记录
.editors{ width: 100%; height: 100%; position: relative; .editorsDom{ font-size: 16px; line-height: 26px; // border: 1px solid #e8e8e8; } .editorsErrTxext{ position: absolute; left: 0; bottom: -24px; clear: both; min-height: 24px; margin-top: -2px; color: rgba(0, 0, 0, 0.45); font-size: 15px; line-height: 1.5; transition: color 0.3s cubic-bezier(0.215, 0.61, 0.355, 1) } :global(.CodeMirror) { min-height: 218px !important; height: auto !important; max-height: 747px !important; } :global(.CodeMirror-scroll) { min-height: 218px !important; height: auto !important; max-height: 747px !important; } :global(.CodeMirror-gutter-wrapper) { left: -40px !important; } }
嗯。。。样式。。。

嗯。。。效果
这个是封装的组件,好了,就这吧。

extendCodeMirror.js文件,我优化了一下
// extendCodeMirror.js /* eslint-disable */ import * as CodeMirror from 'codemirror'; CodeMirror.extendMode("css", { commentStart: "/*", commentEnd: "*/", newlineAfterToken: function(type, content) { return /^[;{}]$/.test(content); } }); CodeMirror.extendMode("javascript", { commentStart: "/*", commentEnd: "*/", // FIXME semicolons inside of for newlineAfterToken: function(type, content, textAfter, state) { if (this.jsonMode) { return /^[\[,{]$/.test(content) || /^}/.test(textAfter)|| /^]/.test(textAfter); } else { if (content == ";" && state.lexical && state.lexical.type == ")") return false; return /^[;{}]$/.test(content) && !/^;/.test(textAfter); } } }); CodeMirror.extendMode("xml", { commentStart: "<!--", commentEnd: "-->", newlineAfterToken: function(type, content, textAfter) { return type == "tag" && />$/.test(content) || /^</.test(textAfter); } }); // Comment/uncomment the specified range CodeMirror.defineExtension("commentRange", function (isComment, from, to) { var cm = this, curMode = CodeMirror.innerMode(cm.getMode(), cm.getTokenAt(from).state).mode; cm.operation(function() { if (isComment) { // Comment range cm.replaceRange(curMode.commentEnd, to); cm.replaceRange(curMode.commentStart, from); if (from.line == to.line && from.ch == to.ch) // An empty comment inserted - put cursor inside cm.setCursor(from.line, from.ch + curMode.commentStart.length); } else { // Uncomment range var selText = cm.getRange(from, to); var startIndex = selText.indexOf(curMode.commentStart); var endIndex = selText.lastIndexOf(curMode.commentEnd); if (startIndex > -1 && endIndex > -1 && endIndex > startIndex) { // Take string till comment start selText = selText.substr(0, startIndex) // From comment start till comment end + selText.substring(startIndex + curMode.commentStart.length, endIndex) // From comment end till string end + selText.substr(endIndex + curMode.commentEnd.length); } cm.replaceRange(selText, from, to); } }); }); // Applies automatic mode-aware indentation to the specified range CodeMirror.defineExtension("autoIndentRange", function (from, to) { var cmInstance = this; this.operation(function () { for (var i = from.line; i <= to.line; i++) { cmInstance.indentLine(i, "smart"); } }); }); // Applies automatic formatting to the specified range CodeMirror.defineExtension("autoFormatRange", function (from, to) { var cm = this; var outer = cm.getMode(), text = cm.getRange(from, to).split("\n"); var state = CodeMirror.copyState(outer, cm.getTokenAt(from).state); var tabSize = cm.getOption("tabSize"); var out = "", lines = 0, atSol = from.ch == 0; function newline() { out += "\n"; atSol = true; ++lines; } for (var i = 0; i < text.length; ++i) { var stream = new CodeMirror.StringStream(text[i], tabSize); while (!stream.eol()) { var inner = CodeMirror.innerMode(outer, state); var style = outer.token(stream, state), cur = stream.current(); stream.start = stream.pos; if (!atSol || /\S/.test(cur)) { out += cur; atSol = false; } if (!atSol && inner.mode.newlineAfterToken && inner.mode.newlineAfterToken(style, cur, stream.string.slice(stream.pos) || text[i+1] || "", inner.state)) newline(); } if (!stream.pos && outer.blankLine) outer.blankLine(state); if (!atSol) newline(); } cm.operation(function () { cm.replaceRange(out, from, to); for (var cur = from.line + 1, end = from.line + lines; cur <= end; ++cur) cm.indentLine(cur, "smart"); cm.setSelection(from, cm.getCursor(false)); }); }); // console.log("初始化CodeMirror完成"); export default CodeMirror;
<EditorDom title={item.name} editorListErr={editorListErr} //嗯,忘了干啥了,时间有点长。。。可能也没啥用吧,刚学react时候写的 placeholder={item.placeholder} //为空显示 type="json" key={'JsonEditors'} rules={item.rules} //是否校验不为空 editorList={editorList} //数据,多个编辑器情况下 getEditorList={getEditorList} // 拿到最新内容,修改editorList
/>
就这了吧,有很多可优化的地方,也不改了吧,就这吧。

浙公网安备 33010602011771号