React实现一个双击编辑文字组件

353 阅读1分钟

镜像链接 业务需求需要写一个这个功能,找到了一个vue实现的,然后改了一下放上来

import React, { useState, useRef, useEffect } from 'react';
import styles from './index.less';

const EditTextTest = (props) => {
  // 接收传递过来的参数,可以替换text显示
  const {contentText} = props
  const [isEdit, setIsEdit] = useState(false);
  const [text, setText] = useState('双击编辑文字');
  const textRef = useRef(null);

  useEffect(() => {
    if (isEdit) {
      // 选中文字
      if (window.getSelection) {
        let selection = window.getSelection();
        let range = document.createRange();
        range.selectNodeContents(textRef.current);
        selection.removeAllRanges();
        selection.addRange(range);
      }

      // 粘贴时,去除多余格式
      const handlePaste = (e) => {
        e.preventDefault();
        e.stopPropagation();
        let text;
        let clp = (e.originalEvent || e).clipboardData;
        if (clp === undefined || clp === null) {
          text = window.clipboardData.getData('text') || '';
          if (text !== '') {
            if (window.getSelection) {
              let newNode = document.createElement('span');
              newNode.innerHTML = text;
              window
                .getSelection()
                .getRangeAt(0)
                .insertNode(newNode);
            } else {
              document.selection.createRange().pasteHTML(text);
            }
          }
        } else {
          text = clp.getData('text/plain') || '';
          if (text !== '') {
            document.execCommand('insertText', false, text);
          }
        }
      };

      document.getElementById('textbox').addEventListener('paste', handlePaste);

      return () => {
        // document.getElementById('textbox').removeEventListener('paste', handlePaste);
      };
    }
  }, [isEdit]);

  const editText = () => {
    setIsEdit(true);
    setTimeout(() => {
      setIsEdit(true);
    }, 100);
  };

  const updateText = () => {
    const modifiedText = textRef.current.childNodes[0].innerHTML
      .replace(/<div><br><\/div>/g, '\n')
      .replace(/<div.*?>/g, '\n')
      .replace(/<br.*?>/g, '')
      .replace(/<\/div>|&nbsp;|<\/?span.*?>/g, '');

    setIsEdit(false);

    if (text !== modifiedText) {
      let updatedText = modifiedText;
      if (modifiedText === '') {
        updatedText = '双击备注信息';
      }

      setText(updatedText);
      updateBoxSize();
    }
  };

  const updateBoxSize = () => {
    const height = document.getElementById('textbox').offsetHeight;
    setBoxInfo((prevBoxInfo) => ({ ...prevBoxInfo, height }));
  };

  return (
    // style={{ width: `${boxInfo.width}px`, height: `${boxInfo.height}%` }}
    <section className={styles.elementBox} >
      {isEdit ? (
        <div ref={textRef} className={styles.textBox}>
          <div
            className={styles.textBoxContainer}
            contentEditable
            onBlur={updateText}
            id="textbox"
            // fontSize: '24px',
            style={{ textAlign: 'center' }}
            dangerouslySetInnerHTML={{ __html: text }}
          ></div>
        </div>
      ) : (
        <div className={styles.showText} onDoubleClick={editText} dangerouslySetInnerHTML={{ __html: text }}></div>
      )}
    </section>
  );
};

export default EditTextTest;


.elementBox {
  position: relative;
}

.showText {
  word-break: break-all;
  white-space: pre-line;
}

.textBox {
  width: 100%;
  height: 100%;
  top: 0;
  left: 0;
}

.textboxContainer {
  min-width: 200px;
  min-height: 36px;
  position: absolute;
  border: 1px dashed #000;
  height: auto;
  word-break: break-word;
  outline: none;
  white-space: pre-wrap;
  box-sizing: content-box;
  -webkit-user-select: text !important;
  user-select: text !important;
  -webkit-background-clip: text;
  caret-color: black;
}

效果图:image.png 然后这个一般配合tooltip组件一起使用。。。