I want to get the cursor position.
我需要获取光标在编辑器中的位置,做一个文本插入的功能,需要怎么做
I need to get the position of the cursor in the editor to implement a text insertion function. What should I do?
在 CodeMirror v6 中,要向光标位置插入字符串,你可以使用 EditorView.dispatch 方法来发送一个 StateEffect,以修改编辑器的状态。具体步骤如下:
-
创建一个
StateEffect,用于表示要插入的字符串。例如,假设你要插入的字符串是insertText:import { StateEffect } from "@codemirror/state"; const insertText = StateEffect.appendText("insertText"); -
使用 ref 获取 codemirror 的 view 对象
-
使用
EditorView.dispatch,将该StateEffect分发给编辑器视图:view.dispatch({ effects: insertText, });
@ilysusu
import React, {forwardRef, useCallback, useContext, useEffect, useImperativeHandle, useRef, useState} from 'react'; import CodeMirror from "@uiw/react-codemirror"; import { StateEffect } from "@codemirror/state"; import { javascript } from "@codemirror/lang-javascript"; import { EditorView } from "@codemirror/view"
const AutoCodeMirror = forwardRef(({exprVal, setExprVal}, ref) => { const currentNode = useContext(NodesContext) const [options, setOptions] = useState([])
const codeMirrorRef = useRef(null);
useImperativeHandle(ref, () => { codeMirrorRef.current })
// 将 codeMirrorRef 暴露给父组件
useImperativeHandle(ref, () => ({
getCodeMirrorInstance: () => codeMirrorRef.current,
}));
useEffect(() => {
function initOptions() {
const currNodeId = parseInt(currentNode.data.nodeId.substring(1), 10);
const newOptions = [];
for (let i = currNodeId; i >= 1; i--) {
const nodeId = N${i.toString().padStart(4, '0')};
newOptions.push({ label: nodeId, type: "variable" });
}
console.log(newOptions, 'newOptions')
setOptions(newOptions)
}
initOptions()
}, [currentNode]);
const onChange = useCallback((val, viewUpdate) => { // console.log("val:", val); setExprVal(val); // 当前光标位置插入数据 const insertText = StateEffect.appendText("insertText"); const view = codeMirrorRef.current.view; console.log(view,' view') view.dispatch({ effects: insertText, }); }, [setExprVal]);
const myCompletions = (context) => { let word = context.matchBefore(/\w*/) if (word.from === word.to && !context.explicit) return null return { from: word.from, // 建议内容 options: options }; };
return ( <> <CodeMirror ref={codeMirrorRef} style={{border: "1px solid #eee"}} value={exprVal} height="250px" extensions={[ javascript({ jsx: true }), javascript().language.data.of({autocomplete: myCompletions}), EditorView.lineWrapping ]} onChange={onChange} />
</>
); })
export default AutoCodeMirror;
这是我的代码,出现报错 update listener: TypeError: StateEffect.appendText is not a function
如果有错误,清使用下面工具工具之一提供重现的示例
- codepen 在线编辑器
- stackblitz 在线编辑器
- codesandbox 在线编辑器
- jsfiddle 在线编辑器
另外我可能给了个错误的示例,我这里有个 编辑器的实现有类似的插入代码
https://github.com/uiwjs/react-markdown-editor/blob/c237b69acdad69c2d1804537ecb797bcdcdc14c9/core/src/commands/bold.tsx#L18-L26
view.dispatch(
view.state.changeByRange((range) => ({
changes: [
{ from: range.from, insert: '**' },
{ from: range.to, insert: '**' },
],
range: EditorSelection.range(range.from + 2, range.to + 2),
})),
);
@ilysusu 你可以参考我封装的 react-markdown-editor 组件代码
https://codesandbox.io/s/react-codemirror-example-codemirror-6-https-github-com-uiwjs-react-codemirror-issues-314-forked-8glmzg?file=/src/App.js 重现的示例 @jaywcjlove
@ilysusu 示例: https://codesandbox.io/embed/https-github-com-uiwjs-react-codemirror-issues-603-wr6ph9?fontsize=14&hidenavigation=1&theme=dark
import React, { useRef, useState } from "react";
import CodeMirror from "@uiw/react-codemirror";
import { StateEffect } from "@codemirror/state";
import { javascript } from "@codemirror/lang-javascript";
import { EditorSelection } from "@codemirror/state";
export default function App() {
const codeMirrorRef = useRef(null);
const [val, setVal] = useState("console.log('hello world!');");
const onChange = React.useCallback((value, viewUpdate) => {
console.log("value:", value);
}, []);
// 从光标位置插入文本
const handleInsertVal = () => {
const view = codeMirrorRef.current.view;
view.dispatch(
view.state.changeByRange((range) => ({
changes: [
{ from: range.from, insert: "**" },
{ from: range.to, insert: "**" }
],
range: EditorSelection.range(range.from + 2, range.to + 2)
}))
);
};
const onRefChange = () => {
codeMirrorRef.current.view.dispatch({
changes: { from: 0, to: 12, insert: "InsertText" }
});
};
return (
<div>
<button onClick={handleInsertVal}> insertValue </button>
<button onClick={onRefChange}>Ref Change Value</button>
<CodeMirror
value={val}
ref={codeMirrorRef}
height="200px"
theme="dark"
extensions={[javascript({ jsx: true })]}
onChange={onChange}
/>
</div>
);
}
In answer to the issue title (for others looking for an answer to "How to get cursor position"
const cursorPosition = editorRef.current?.view?.state?.selection.main.head
NOTE: Use editorRef.current?.view?.state NOT just editorRef.current?.state as the latter seems to always return 0