uiwjs / react-codemirror

CodeMirror 6 component for React. @codemirror https://uiwjs.github.io/react-codemirror/
https://uiwjs.github.io/react-codemirror/
MIT License
1.65k stars 132 forks source link

v4 no onScroll #350

Closed UvDream closed 2 years ago

UvDream commented 2 years ago

Does the v4 version not get the editor scroll height event?

jaywcjlove commented 2 years ago

@UvDream Example: https://codesandbox.io/embed/react-codemirror-example-codemirror-6-forked-6dymyn?fontsize=14&hidenavigation=1&theme=dark

import React from "react";
import CodeMirror from "@uiw/react-codemirror";
import { javascript } from "@codemirror/lang-javascript";
import { ViewPlugin } from "@codemirror/view";
import { code } from "./code";

export default function App() {
  const scroll = ViewPlugin.fromClass(
    class {
      constructor(view) {
        view.scrollDOM.addEventListener("scroll", () => {
          console.log("sss122");
        });
      }
    }
  );
  const onChange = React.useCallback((value, viewUpdate) => {
    console.log("value:", value);
  }, []);
  return (
    <div>
      <CodeMirror
        value={code}
        height="200px"
        theme="dark"
        extensions={[scroll, javascript({ jsx: true })]}
        onChange={onChange}
      />
    </div>
  );
}
UvDream commented 2 years ago

非常感谢,那么我设置滚动高度也可以通过这个设置吗

jaywcjlove commented 2 years ago
<CodeMirror
  value="console.log('hello world!');"
+  height="200px"
  extensions={[javascript({ jsx: true })]}
  onChange={onChange}
/>

@UvDream

UvDream commented 2 years ago

我的意思是滚动到指定高度,因为我需要做一个同步滚动功能

jaywcjlove commented 2 years ago

@UvDream view.scrollDOM 这是个内置的 dom 节点,你可以正对它进行操控。

UvDream commented 2 years ago

@jaywcjlove 好的,那么我在光标处插入文字是不是也可以操作这个dom来实现

jaywcjlove commented 2 years ago

@UvDream 这个你需要看 codemirror 官方文档,插入文字不使用 dom 实现。

codemirror

UvDream commented 2 years ago

@UvDream 这个你需要看 codemirror 官方文档,插入文字不使用 dom 实现。

codemirror

CodeMirror.instance.replaceSelection("插入文字"),这个CodeMirror就是这个组件?还是组件向外暴露了另外的对象吗

jaywcjlove commented 2 years ago

@UvDream react-codemirror 是基于 codemirror 封装的。

jaywcjlove commented 2 years ago
import CodeMirror from '@uiw/react-codemirror';
import { events } from '@uiw/codemirror-extensions-events';

function App() {
  const [scrollTop, setScrollTop] = useState(0);

  const eventExt = events.scroll({
    scroll: (evn) => {
      setScrollTop(evn.target.scrollTop);
    },
  });

  const eventExt2 = events.content({
    focus: (evn) => {
      console.log('focus');
    },
    blur: (evn) => {
      console.log('blur');
    },
  });

  return <CodeMirror value="console.log('hello world!');" height="200px" extensions={[eventExt, eventExt2]} />;
}
export default App;
UvDream commented 2 years ago

@UvDream react-codemirror 是基于 codemirror 封装的。

还是和这个相关的问题请教下,在1.0的时候获取

image

这个对象是这样的

<CodeMirror
       ...
    ref={this.getInstance}
/>
.....
getInstance=(instance)=>{
    console.log(instance.editor)
}

v4新版本有啥方法可以获取吗,感谢

jaywcjlove commented 2 years ago

@UvDream 一样的获取,但是获取的内容是 CM 6 的对象。 v1~v3 是基于 CM 5 搞的, CM6 变化非常大。

https://github.com/uiwjs/react-codemirror/blob/ed437635928ce51585fad930017fb9c93068802d/core/src/index.tsx#L121

UvDream commented 2 years ago

一样的获取,但是获取的内容是 CM 6 的对象。 v1~v3 是基于 CM 5 搞的, CM6 变化非常大。

https://github.com/uiwjs/react-codemirror/blob/ed437635928ce51585fad930017fb9c93068802d/core/src/index.tsx#L121

@jaywcjlove 不知道为啥获取差异性还挺大

jaywcjlove commented 2 years ago

@UvDream CM6 重构的版本

UvDream commented 2 years ago

@UvDream CM6 重构的版本

好的,我去看看v6版本咋在光标处插入文字

jaywcjlove commented 2 years ago

https://codesandbox.io/embed/react-codemirror-example-codemirror-6-uiwjs-react-codemirror-issues-350-48pwuh?fontsize=14&hidenavigation=1&theme=dark

image
import React from "react";
import CodeMirror from "@uiw/react-codemirror";
import { javascript } from "@codemirror/lang-javascript";

export default function App() {
  const onChange = React.useCallback((value, viewUpdate) => {
    console.log("value:", value);
  }, []);
  return (
    <div>
      <CodeMirror
        value="console.log('hello world!');"
        height="200px"
        theme="dark"
        ref={(instance) => {
          console.log(instance);
        }}
        extensions={[javascript({ jsx: true })]}
        onChange={onChange}
      />
    </div>
  );
}
UvDream commented 2 years ago

https://codesandbox.io/embed/react-codemirror-example-codemirror-6-uiwjs-react-codemirror-issues-350-48pwuh?fontsize=14&hidenavigation=1&theme=dark

image
import React from "react";
import CodeMirror from "@uiw/react-codemirror";
import { javascript } from "@codemirror/lang-javascript";

export default function App() {
  const onChange = React.useCallback((value, viewUpdate) => {
    console.log("value:", value);
  }, []);
  return (
    <div>
      <CodeMirror
        value="console.log('hello world!');"
        height="200px"
        theme="dark"
        ref={(instance) => {
          console.log(instance);
        }}
        extensions={[javascript({ jsx: true })]}
        onChange={onChange}
      />
    </div>
  );
}

是的,我也是这样的,但是我看api是instance.state.replaceSelection(),

[replaceSelection](https://codemirror.net/docs/ref/#state.EditorState.replaceSelection)([text](https://codemirror.net/docs/ref/#state.EditorState.replaceSelection^text): [string](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String) | [Text](https://codemirror.net/docs/ref/#state.Text)) → [TransactionSpec](https://codemirror.net/docs/ref/#state.TransactionSpec)
Create a [transaction spec](https://codemirror.net/docs/ref/#state.TransactionSpec) that replaces every selection range with the given content.

但是我没插入成功,可以帮忙试试在光标处插入文本吗,感谢

jaywcjlove commented 2 years ago

@UvDream https://codesandbox.io/embed/react-codemirror-example-codemirror-6-markdown-auto-languages-forked-yuymsl?fontsize=14&hidenavigation=1&theme=dark

import CodeMirror from "@uiw/react-codemirror";
import { useRef, useCallback, useState } from "react";
import { javascript } from "@codemirror/lang-javascript";

const code = `console.log('hello world!');
`;

export default function App() {
  const $ref = useRef();
  const [text, setText] = useState(code);
  const handleClick = () => {
    const state = $ref.current.view.viewState.state;
    const range = state.selection.ranges[0];
    console.log(">>>>1>", state.selection.ranges[0]);
    $ref.current.view.dispatch({
      changes: { from: range.from, to: range.to, insert: "test" }
    });
  };
  const onChange = useCallback((value, viewUpdate) => {
    setText(value);
  }, []);
  return (
    <div>
      <button onClick={handleClick}>Click Me!</button>
      <CodeMirror
        ref={$ref}
        value={text}
        height="200px"
        extensions={[javascript({ jsx: true })]}
        onChange={onChange}
      />
    </div>
  );
}
UvDream commented 2 years ago

@UvDream https://codesandbox.io/embed/react-codemirror-example-codemirror-6-markdown-auto-languages-forked-yuymsl?fontsize=14&hidenavigation=1&theme=dark

import CodeMirror from "@uiw/react-codemirror";
import { useRef, useCallback, useState } from "react";
import { javascript } from "@codemirror/lang-javascript";

const code = `console.log('hello world!');
`;

export default function App() {
  const $ref = useRef();
  const [text, setText] = useState(code);
  const handleClick = () => {
    const state = $ref.current.view.viewState.state;
    const range = state.selection.ranges[0];
    console.log(">>>>1>", state.selection.ranges[0]);
    $ref.current.view.dispatch({
      changes: { from: range.from, to: range.to, insert: "test" }
    });
  };
  const onChange = useCallback((value, viewUpdate) => {
    setText(value);
  }, []);
  return (
    <div>
      <button onClick={handleClick}>Click Me!</button>
      <CodeMirror
        ref={$ref}
        value={text}
        height="200px"
        extensions={[javascript({ jsx: true })]}
        onChange={onChange}
      />
    </div>
  );
}

感谢,那文档实在太不易读了

UvDream commented 2 years ago

@jaywcjlove 大佬,我又来问问题了,codemirror6的文档实在太难找了,示例都少,还是那个光标插入的时候如何将光标放入插入文本中间,markdown中加粗光标,以前我是这样写的

editor.replaceSelection(`**${selection}**`);
jaywcjlove commented 2 years ago

正常这种你应该在 官方论坛中提问 https://discuss.codemirror.net , 刚好有人提供了方法,你自己看看去吧。

@UvDream https://github.com/uiwjs/react-codemirror/issues/243#issuecomment-1003873169

使用下面方法移动光标位置:

EditorSelection.cursor(5)
jaywcjlove commented 2 years ago
const { from, to } = ranges[0] || {};
const txt = view.state.sliceDoc(from, to);
view.dispatch(view.state.replaceSelection(`**${txt}**`));
UvDream commented 2 years ago
const { from, to } = ranges[0] || {};
const txt = view.state.sliceDoc(from, to);
view.dispatch(view.state.replaceSelection(`**${txt}**`));

谢谢,我去论坛找到了方法

jaywcjlove commented 2 years ago

@UvDream 是下面方法吗?

view.dispatch(
  view.state.changeByRange((range) => ({
    changes: [
      { from: range.from, insert: "**" },
      { from: range.to, insert: "**" }
    ],
    range: EditorSelection.range(range.from + 2, range.to + 2)
  }))
);
UvDream commented 2 years ago

@UvDream 是下面方法吗?

view.dispatch(
  view.state.changeByRange((range) => ({
    changes: [
      { from: range.from, insert: "**" },
      { from: range.to, insert: "**" }
    ],
    range: EditorSelection.range(range.from + 2, range.to + 2)
  }))
);
export const insert = (editor, text, selection) => {
    const state = editor.current.view.viewState.state;
    const range = state.selection.ranges[0];
    editor.current.view.dispatch({
        changes: {
            from: range.from,
            to: range.to,
            insert: `${text}`
        },
        selection: {anchor: range.from + selection}
    })
}

这个,但是有个bug,我还没找到原因,例如输入# ,第一次输入就是正确一个#,再次触发就输入两个##了,依次累计,触发条件和编辑器不在一个组件里面就会这样,如果和编辑器在一个组件不会,论坛没人鸟我,哈哈哈