如何在React Quill或Editor.js中实现类ChatGPT的Typeahead/自动补全?
在React Quill和Editor.js中实现AI驱动的自动补全功能
React Quill 实现方案
React Quill本身无内置这类功能,但可通过自定义逻辑和事件监听实现:
- 输入事件监听:通过
onChange或onTextChange捕获用户输入,当输入长度达到触发阈值(如≥3字符)时,调用OpenAI API获取文本建议。 - 建议弹窗渲染:在编辑器光标下方显示AI返回的建议内容,提示用户可按Tab键插入。
- Tab键绑定:监听键盘事件,按下Tab时将建议内容插入当前光标位置,并隐藏弹窗。
示例代码片段:
import ReactQuill from 'react-quill'; import 'react-quill/dist/quill.snow.css'; import { useState, useRef } from 'react'; const AIEnhancedQuill = () => { const quillRef = useRef(null); const [suggestion, setSuggestion] = useState(''); const [showSuggestion, setShowSuggestion] = useState(false); const handleTextChange = (value, delta, source) => { if (source === 'user') { const editor = quillRef.current?.getEditor(); const content = editor.getText().trim(); if (content.length > 3) { // 调用OpenAI API(建议通过后端代理避免密钥暴露) fetch('/api/openai/completions', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ model: 'gpt-3.5-turbo-instruct', prompt: `继续补充文本:${content}`, max_tokens: 100 }) }) .then(res => res.json()) .then(data => { setSuggestion(data.choices[0].text.trim()); setShowSuggestion(true); }); } else { setShowSuggestion(false); } } }; const handleKeyDown = (e) => { if (e.key === 'Tab' && showSuggestion) { e.preventDefault(); const editor = quillRef.current?.getEditor(); const selection = editor.getSelection(); editor.insertText(selection.index, suggestion); setShowSuggestion(false); } }; return ( <div style={{ position: 'relative' }}> <ReactQuill ref={quillRef} theme="snow" onChange={handleTextChange} onKeyDown={handleKeyDown} /> {showSuggestion && ( <div style={{ position: 'absolute', bottom: '100%', left: '10px', background: '#f5f5f5', padding: '8px 12px', border: '1px solid #ddd', borderRadius: '4px', fontSize: '14px' }}> {suggestion} <span style={{ color: '#666', marginLeft: '8px' }}>按Tab插入</span> </div> )} </div> ); }; export default AIEnhancedQuill;
Editor.js 实现方案
Editor.js需通过监听区块输入事件和自定义弹窗实现功能:
- 区块输入监听:利用Editor.js的
input事件监听用户输入,满足触发条件时调用OpenAI API。 - 建议弹窗管理:在当前编辑区块附近渲染建议弹窗,点击或按Tab键插入内容。
- 全局键盘监听:捕获Tab键事件,将建议内容插入当前编辑区块。
示例代码片段:
import EditorJS from '@editorjs/editorjs'; let currentSuggestion = ''; let suggestionPopup = null; const editor = new EditorJS({ holder: 'editorjs-container', tools: { paragraph: { class: require('@editorjs/paragraph'), inlineToolbar: true } }, onReady: () => { // 监听编辑器输入事件 editor.listeners.on(editor.ui.nodes.wrapper, 'input', () => { const currentBlock = editor.getCurrentBlock(); const content = currentBlock.getText().trim(); if (content.length > 3) { fetch('/api/openai/completions', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ model: 'gpt-3.5-turbo-instruct', prompt: `继续补充文本:${content}`, max_tokens: 100 }) }) .then(res => res.json()) .then(data => { currentSuggestion = data.choices[0].text.trim(); renderSuggestionPopup(currentSuggestion, currentBlock); }); } else { hideSuggestionPopup(); } }); // 监听Tab键插入 document.addEventListener('keydown', (e) => { if (e.key === 'Tab' && currentSuggestion) { e.preventDefault(); const currentBlock = editor.getCurrentBlock(); currentBlock.insertText(currentBlock.getLength(), currentSuggestion); hideSuggestionPopup(); } }); } }); // 渲染建议弹窗 function renderSuggestionPopup(text, block) { hideSuggestionPopup(); suggestionPopup = document.createElement('div'); suggestionPopup.style.position = 'absolute'; suggestionPopup.style.background = '#f5f5f5'; suggestionPopup.style.padding = '8px 12px'; suggestionPopup.style.border = '1px solid #ddd'; suggestionPopup.style.borderRadius = '4px'; suggestionPopup.style.fontSize = '14px'; const blockRect = block.holder.getBoundingClientRect(); suggestionPopup.style.top = `${blockRect.bottom + 8}px`; suggestionPopup.style.left = `${blockRect.left}px`; suggestionPopup.textContent = `${text} 按Tab插入`; document.body.appendChild(suggestionPopup); } // 隐藏建议弹窗 function hideSuggestionPopup() { if (suggestionPopup) { suggestionPopup.remove(); suggestionPopup = null; currentSuggestion = ''; } }
关键优化点
- API请求防抖:添加300ms左右的输入防抖,避免频繁调用OpenAI API。
- 密钥安全:禁止在前端代码中直接暴露OpenAI API密钥,通过后端代理处理请求。
- 光标定位:插入建议后自动将光标移至内容末尾,提升编辑流畅度。
内容的提问来源于stack exchange,提问作者Abdulhakim
相关产品推荐
相关产品推荐

