react hook 版,第一版写的比较简单
效果图:

组件:
index.jsx 文件
import React, { useState, useEffect, useRef } from 'react';
import styles from './index.module.scss';
import PropTypes from 'prop-types';
const MyEditor = props => {
// const getYAMLJS = require('yamljs'); // 需先安装插件,转换 .yaml 文件内容的数据类型
const { value, style, maxRow, onChange } = props;
const [MyValue, setMyValue] = useState("");
const [top, setTop] = useState(0);
const lineNumberBox = useRef();
useEffect(() => {
if (onChange) {
setMyValue(value);
}
}, [value])
const textareaChange = (ev) => { // 修改内容
if (onChange) {
onChange(ev.target.value)
} else {
setMyValue(ev.target.value)
}
}
const textareaScroll = (ev) => { // 获得滚动的距离
setTop(ev.target.scrollTop)
}
const renderList = () => { // 生成行号
const ary = [];
for (let i = 1; i <= maxRow; i++) {
ary.push(<li key={i}>{i}</li>)
}
return ary
}
return (
<div className={styles.myEditor}>
<div style={style} className={styles.myEditorBox}>
<span className={styles.lineNumber}>
<ul ref={lineNumberBox} style={{ top: `-${top}px` }}>
{
renderList()
}
</ul>
</span>
<textarea id="textInner"
className={styles.textInner}
value={MyValue}
onChange={textareaChange}
onScroll={textareaScroll}
style={{
resize: style.height || style.width ? "none" : "auto",
maxHeight: `${maxRow * 24}px`
}}
/>
</div>
</div>
);
};
MyEditor.defaultProps = {
value: "",
style: {
height: "240px"
},
maxRow: 1000,
};
MyEditor.propTypes = {
style: PropTypes.object,
maxRow: PropTypes.number,
// 和 input 一样, value 和 onChange 需同时使用,变成可控组件
value: PropTypes.string,
onChange: PropTypes.func,
};
export default MyEditor;
index.module.scss 样式文件
.myEditor { .myEditorBox{ // 我的编辑器 display: flex; justify-content: space-between; box-sizing: content-box; overflow: hidden; .lineNumber{ box-sizing: content-box; display: inline-block; color: #999; background-color: #333; min- 38px; border-radius: 3px 0 0 3px; text-align: right; overflow: hidden; position: relative; ul{ position: absolute; margin: 2px 0 0 0; padding: 0; 100%; li{ list-style-type: none; // 去掉 li 的默认样式 padding: 0 0.5em 0 0; 100%; line-height: 24px; } } } .textInner{ flex: 1; box-sizing: content-box; padding: 0; line-height: 24px; min-height: 24px; //最小高度 即 每行高度 === 父级 line-height max-height: 2400px; //最大高度 === 10倍 line-height 相当于最多展现10行 // 400px; background-color: #000; color: #ffffff; border-radius: 0 3px 3px 0; outline: none; // 去掉默认样式 } } }
可控组件的使用方式
import React, { useState, useEffect } from 'react';
import MyEditor from "@/components/MyEditor";
function DeveloperPage(props) {
const [value, setvalue] = useState(``)
const onChange = (value) => {
setvalue(value)
}
return (
<div>
<MyEditor
style={{ "500px", height: "300px" }}
value={value}
onChange={onChange}
// maxRow = 1000
/>
</div>
);
}
export default DeveloperPage;