记录技术成长,奔向未来!

如何实现编辑器插入ai助手

AI 功能通用实现模板(基于 MicroEditor)

核心流程

  1. 保存当前光标/选区
    const savedRange = this.saveSelection();

  2. 弹出多行输入对话框(自定义 DOM,非 window.prompt

    • 包含 <textarea rows="8">、确定按钮、取消按钮。

    • 使用 Promise 等待用户输入。

  3. 恢复选区并聚焦编辑器
    this.restoreSelection(savedRange);
    this.editor.focus();(如需要)

  4. 插入即时反馈提示(临时节点)
    使用 document.execCommand('insertHTML', false, 临时节点HTML)

  5. 发起 AJAX 请求(调用对应的后端 AI 接口,如 /admin/ai/write.php)。

  6. 移除临时节点,并再次恢复选区。

  7. 将返回内容插入编辑器(支持 HTML 格式,可转换换行等)。

  8. 同步到隐藏 textareathis.syncToTextarea())。

关键函数(已在 MicroEditor 类中实现)

  • saveSelection() / restoreSelection(saved):保存/恢复光标位置。

  • syncToTextarea():同步编辑器内容到 textarea。

  • editorDiv / editor:编辑器的可编辑 DOM 元素。

后端接口规范

  • URL/admin/ai/{功能名}.php

  • 方法:POST

  • 请求体{ "prompt": "用户输入的需求" }(可扩展其他参数)

  • 响应{ "content": "生成的文本或 HTML" }(或 error 字段)

可复用的 UI 组件

  • 多行输入对话框(样式与配色助手的模态框一致)

  • 即时反馈提示(“🤖 AI 正在创作,请稍候…”)

  • 错误提示(alert 或模态框)

扩展点

  • 增加“重新生成”按钮(复用当前输入,再次请求)

  • 增加“插入并替换选中内容”选项

  • 支持流式输出(SSE)以实时显示生成过程


代码如下:

//添加ai写作助手

    // 添加 AI 写作助手(多行输入框,带即时提示)
    async aiWriting() {
        // 1. 保存当前光标位置
        const savedRange = this.saveSelection();

        // 2. 创建自定义多行输入对话框
        const dialog = document.createElement('div');
        dialog.style.cssText = `
        position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%);
        background: white; padding: 20px; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.2);
        z-index: 10000; width: 500px; max-width: 90%;
    `;
        dialog.innerHTML = `
        <h3 style="margin-top:0;">AI 写作助手</h3>
        <textarea rows="8" style="width:100%; margin-bottom:10px; padding:8px;" 
            placeholder="请输入写作需求,例如:写一篇关于公司10周年庆典的新闻稿,500字左右。"></textarea>
        <div style="text-align:right;">
            <button id="aiDialogOk" style="padding:5px 15px;">生成</button>
            <button id="aiDialogCancel" style="padding:5px 15px; margin-left:10px;">取消</button>
        </div>
    `;
        document.body.appendChild(dialog);

        const textarea = dialog.querySelector('textarea');
        const okBtn = dialog.querySelector('#aiDialogOk');
        const cancelBtn = dialog.querySelector('#aiDialogCancel');

        // 等待用户输入
        const promptText = await new Promise((resolve) => {
            const close = (value) => {
                dialog.remove();
                resolve(value);
            };
            okBtn.onclick = () => close(textarea.value.trim());
            cancelBtn.onclick = () => close(null);
            // 点击遮罩关闭
            dialog.addEventListener('click', (e) => {
                if (e.target === dialog) close(null);
            });
        });

        if (!promptText) return;  // 用户取消或未输入

        // 3. 恢复保存的选区并聚焦编辑器(关键步骤,确保后续插入位置正确)
        this.restoreSelection(savedRange);
        if (this.editor) this.editor.focus();   // 假设编辑器 DOM 元素为 this.editor,请根据实际调整

        // 4. 在光标位置插入即时提示(临时节点)
        const tempId = 'ai-temp-' + Date.now();
        const tempHtml = `<span id="${tempId}" style="color:#999;">🤖 AI 正在创作,请稍候...</span>`;
        document.execCommand('insertHTML', false, tempHtml);

        // 5. 发起 AI 生成请求
        try {
            const response = await fetch('/admin/ai/write.php', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ prompt: promptText })
            });
            const data = await response.json();

            // 6. 移除临时提示节点
            const tempElem = document.getElementById(tempId);
            if (tempElem) tempElem.remove();

            // 7. 再次恢复选区(临时节点被移除后原位置保留,恢复后即可插入正式内容)
            this.restoreSelection(savedRange);

            if (data.content) {
                // 将换行符转为 HTML 换行,保持段落格式
                const htmlContent = data.content.replace(/\n/g, '<br>');
                document.execCommand('insertHTML', false, htmlContent);
            } else {
                alert(data.error || '生成失败');
            }
        } catch (err) {
            console.error(err);
            // 出错时也要移除临时节点并恢复选区
            const tempElem = document.getElementById(tempId);
            if (tempElem) tempElem.remove();
            this.restoreSelection(savedRange);
            alert('请求失败:' + err.message);
        }

        // 8. 同步内容到隐藏 textarea(如果编辑器需要)
        this.syncToTextarea();
    }

发表评论 (0)

留下你的足迹

验证码 点击图片刷新