Динамически переносить текст в теге привязки в Quilljs Ошибка: addRange (): указанный диапазон отсутствует в документе - PullRequest
2 голосов
/ 25 октября 2019

Я ищу в тексте редактора любые хэштеги и помещаю хэштег в тег привязки, чтобы сделать его ссылкой. Итак, это: #whatsup будет следующим: <a href='http://help.com'>#whatsup</a>.

Вот то, что я пока имею, который корректно изменяет текст, но приводит к этой ошибке. addRange(): The given range isn't in document И курсор убирается, что не позволяет мне вводить что-либо еще.

Я получаю ту же ошибку при использовании setContents вместо dangerouslyPasteHTML

Просто введите любое значение хэштега, например:#foo в фрагмент кода и посмотрите на консоль, чтобы воспроизвести ошибку. Любая помощь высоко ценится.

class RichEditor extends React.Component {
    constructor (props) {
        super(props)
        this.state = { 
            editorHtml: '',
            hashTags: [] 
        }
        this.modules = {
            toolbar: [
                [{ header: [1, 2, false] }],
                ['bold', 'italic', 'underline'],
                ['image', 'code-block']
              ]
        }

        this.editor = null;
        this.quillRef = null;
        this.handleChange = this.handleChange.bind(this)
    }

    handleChange (html) {
        var blurtHashtags = this.editor.getText().match(/(?:^|\B)#[a-zA-Z][\w]{1,19}\b/g);

        if (blurtHashtags) {
            var modHtml = html.replace(blurtHashtags[0], "<a href='http://help.com'>" + blurtHashtags[0] + "</a>");
                 this.editor.clipboard.dangerouslyPasteHTML(modHtml);
        } else {
            this.setState(prevState => ({
                editorHtml: html 
            }));
        }
    }
    
    componentDidMount() {
        if (typeof this.quillRef.getEditor !== 'function') return;
        this.editor = this.quillRef.getEditor();
    }
    
    render() {
        return (
            <div>
                <ReactQuill
                    ref={(el) => { this.quillRef = el; }} 
                    onChange={this.handleChange} 
                    modules={this.modules}
                />
            </div>
        );
    }
}

ReactDOM.render( <
  RichEditor / > ,
  document.getElementById("quill")
);
<div id="quill"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<script src="https://unpkg.com/prop-types/prop-types.js"></script>
<script src="https://unpkg.com/react-quill@latest/dist/react-quill.js"></script>
<link href="//cdn.quilljs.com/1.3.6/quill.snow.css" rel="stylesheet">

1 Ответ

2 голосов
/ 28 октября 2019

Довольно интересно, что происходит в фоновом режиме. Решение, которое вы найдете там, использует setTimeout с задержкой 0ms для вызова функции dangerouslyPasteHTML.

Причина, по которой она работает сейчас, как и ожидалось, технически не является хорошей практикой для изменения содержимогов событии-обработчике поля ввода и добавив задержку, цикл обработки событий выполнит модификацию поля ввода - dangerouslyPasteHTML функция - после события обработчика.

Следующий фрагмент кода решает вашу проблему, пожалуйста, примитесмотреть:

class RichEditor extends React.Component {
    constructor (props) {
        super(props)
        this.state = { 
            editorHtml: '',
            hashTags: [] 
        }
        this.modules = {
            toolbar: [
                [{ header: [1, 2, false] }],
                ['bold', 'italic', 'underline'],
                ['image', 'code-block']
              ]
        }

        this.editor = null;
        this.quillRef = null;
        this.handleChange = this.handleChange.bind(this)
    }

    handleChange (html) {
        const linkStart = `<a href="http://help.com" rel="noopener noreferrer" target="_blank">`;
        const linkEnd = `</a>`;

        // remove anchor tag around the hashtag value
        // in order to identify hashtag properly
        let modHtml = html.replace(linkStart, '');
        modHtml = modHtml.replace(linkEnd, '');
        const blurtHashtags = modHtml.match(/(?:^|\B)#[a-zA-Z][\w]{1,19}\b/g);

        if (blurtHashtags) {
            // rebuild link with anchor tag
            const link = `${linkStart}${blurtHashtags[0]}${linkEnd}`;
            modHtml = modHtml.replace(blurtHashtags[0], link);

            let editor = this.editor;
        
            setTimeout(() => {
                editor.clipboard.dangerouslyPasteHTML(modHtml);

                let selection = editor.getSelection();
                selection.index = modHtml.length;
                editor.setSelection(selection);
            }, 0);
        } else {
            this.setState(prevState => ({
                editorHtml: html 
            }));
        }
    }
    
    componentDidMount() {
        if (typeof this.quillRef.getEditor !== 'function') return;
        this.editor = this.quillRef.getEditor();
    }
    
    render() {
        return (
            <div>
                <ReactQuill
                    className="quill-pre"
                    ref={(el) => { this.quillRef = el; }} 
                    onChange={this.handleChange} 
                    modules={this.modules}
                />
            </div>
        );
    }
}

ReactDOM.render( <
  RichEditor / > ,
  document.getElementById("quill")
);
.quill-pre p {
  white-space: pre;
}
<div id="quill"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<script src="https://unpkg.com/prop-types/prop-types.js"></script>
<script src="https://unpkg.com/react-quill@latest/dist/react-quill.js"></script>
<link href="//cdn.quilljs.com/1.3.6/quill.snow.css" rel="stylesheet">

Очевидно, что форматированный текстовый редактор на данный момент не идеален, но подходит для ваших требований, которые удаляли сообщение об ошибке, которое вы имели ранее. Если вы попытаетесь набрать test text value #wassup, то он не выдаст никакого сообщения об ошибке.

Кроме того, я добавил стиль white-space: pre; для тега p в компоненте, который устраняет проблему с белым интервалом после ввода любогохэштег.

Надеюсь, это поможет!

...