js 选中文字修改:裁剪,加粗... 获得选中内容_react

使用以下两个api

​MDN Selection API​​​​MDN Range API​

需要 API

const Range = useCallback(() => {
const selObj = window.getSelection();
if (!selObj) return;
return selObj.getRangeAt(0);
}, []);

删除代码

const range = Range();
if (!range) return;
range.deleteContents();// 删除节点

加粗功能代码(修改 加入markdown 语法 ** ** 加粗)

onClick={() => { const range = Range(); if (!range) return; const t = document.createElement("span"); range.surroundContents(t);//标签先加入 然后在改值 t.innerHTML = `**${range.toString()}**`; }}

如果选中的文字不是同一行(不是同一个元素)需要先删除原来的 再添加新的

const range = Range(); if (!range) return; const prev = range.toString(); range.deleteContents(); const t = document.createElement("span"); range.surroundContents(t); t.innerHTML = `**${prev}**`;

完整代码 仅供参考

import { Button } from "antd";
import { useState, useCallback, useRef, useMemo } from "react";
import { FC, ReactElement } from "react";
import styled from "styled-components";
import MarkDown from "../components/MD/MarkDown";

interface IProps {}

const MD: FC<IProps> = (): ReactElement => {
const [content, setContent] = useState("");
const input = useRef<HTMLInputElement | null>(null);
const inputEvent = useMemo(() => {
const event = document.createEvent("HTMLEvents");
event.initEvent("input", true, true);
return event;
}, []);
const Range = useCallback(() => {
const selObj = window.getSelection();
if (!selObj) return;
return selObj.getRangeAt(0);
}, []);

const onInput = useCallback(e => {
setContent(e.target.innerText);
}, []);

const forceInput = useCallback(() => {
input.current?.dispatchEvent(inputEvent);
}, [inputEvent]);

return (
<Container>
<Nav>
<Button
onClick={() => {
const range = Range();
if (!range) return;
range.deleteContents();
forceInput();
}}
>
删除
</Button>
<Button
onClick={() => {
const range = Range();
if (!range) return;
const t = document.createElement("span");
range.surroundContents(t);
t.innerHTML = `**${range.toString()}**`;
forceInput();
range.collapse(false);
}}
>
加粗
</Button>
</Nav>
<EditWrapper>
<div ref={input} onInput={onInput} contentEditable='true'></div>
<MarkDown content={content} />
</EditWrapper>
</Container>
);
};

export default MD;

const Container = styled.div`
display: flex;
flex-direction: column;
width: 100vw;
height: 100vh;
`;

const Nav = styled.nav`
width: 100%;
height: 50px;
background-color: #000;
position: -webkit-sticky;
position: sticky;
top: 0;
z-index: 1;
`;

const EditWrapper = styled.div`
height: calc(100% - 50px);
width: 100%;
display: flex;

& > div {
width: 50%;
max-width: 50%;
padding: 0 5px;
}

& > div:first-child {
border-right: 1px dashed #ccc;
outline: none;
}
`;