引言
随着人工智能和自然语言处理(NLP)技术的快速发展,基于 AI 的聊天系统变得越来越普遍。无论是简单的问答系统还是复杂的客服聊天机器人,聊天输入框都是用户与系统交互的关键组件。本文将详细介绍如何实现一个功能丰富的 AI 聊天输入框,从基础组件到高级功能,包括用户输入处理、界面设计以及与 AI 模型的集成。
功能介绍
基础功能
- 输入数据并发送聊天消息;
- 支持shift+enter换行;
高级功能
- 表单内容支持:允许嵌套select元素;
实现步骤
实现基础功能
普通的聊天输入框只需要一个简单的input元素即可;
import React, { useState } from 'react';
const ChatInput = ({ onSend }) => {
const [input, setInput] = useState('');
const handleSend = () => {
if (input.trim()) {
onSend(input);
setInput('');
}
};
return (
<div className="chat-input">
<input
type="text"
value={input}
onChange={(e) => setInput(e.target.value)}
onKeyPress={(e) => e.key === 'Enter' && handleSend()}
/>
<button onClick={handleSend}>Send</button>
</div>
);
};
export default ChatInput;
支持换行的聊天输入框只需要一个简单的textarea元素即可;
import React, { useState } from 'react';
const ChatInput = ({ onSend }) => {
const [input, setInput] = useState('');
const handleSend = () => {
if (input.trim()) {
onSend(input);
setInput('');
}
};
const handleKeyPress = (e) => {
if (e.key === 'Enter') {
if (e.shiftKey) {
// 插入换行符
setInput(input + '\n');
} else {
// 发送消息
e.preventDefault(); // 防止输入框获得默认的按键行为
handleSend();
}
}
};
return (
<div className="chat-input">
<textarea
value={input}
onChange={(e) => setInput(e.target.value)}
onKeyPress={handleKeyPress}
rows="3" // 可以根据需要调整行数
/>
<button onClick={handleSend}>Send</button>
</div>
);
};
export default ChatInput;
实现高级功能
表单内容支持:允许嵌套select元素
需要将元素的contenteditable设置为true,最后需要提取元素的字符内容
select元素不能采用受控组件的方式,会有数据同步的问题
export function getSelectValueAndTextContentByDiv(htmlString) {
const parser = new DOMParser();
const htmlDocument = parser.parseFromString(htmlString, 'text/html');
const rootNode = htmlDocument.body;
const iconCharRegex = /[\uE000-\uF8FF]/g;
const lines: string[] = [];
rootNode.childNodes.forEach(child => {
let lineText = '';
if (child.nodeType === Node.ELEMENT_NODE) {
if (child.nodeName === 'SELECT') {
const selectedOption = child.options[child.selectedIndex].text;
lineText += selectedOption;
} else {
lineText += getTextFromNode(child);
}
} else if (child.nodeType === Node.TEXT_NODE) {
lineText += child.textContent.replace(iconCharRegex, '').trim();
}
if (lineText) {
lines.push(lineText);
}
});
function getTextFromNode(node) {
if (node.nodeType === Node.TEXT_NODE) {
return node.textContent.replace(iconCharRegex, '').trim();
} else if (node.nodeType === Node.ELEMENT_NODE && node.nodeName === 'SELECT') {
return node.options[node.selectedIndex].text;
} else {
return Array.from(node.childNodes).map(getTextFromNode).join('');
}
}
const result = lines.join('\n');
return result;
}
同时需要支持输入时换行处理
function insertNewLineAtCaret(el) {
const selection = window.getSelection();
if (!el || !selection.rangeCount) return;
const range = selection.getRangeAt(0);
let container = range.startContainer;
let newLineDiv = document.createElement('div');
newLineDiv.appendChild(document.createElement('br'));
if (container.nodeType === Node.TEXT_NODE && range.startOffset !== 0 && range.startOffset !== container.length) {
const secondPart = container.splitText(range.startOffset);
newLineDiv = document.createElement('div');
newLineDiv.appendChild(secondPart);
}
while (container && container.parentNode !== el) {
container = container.parentNode;
}
if (range.startOffset === 0) {
el.insertBefore(newLineDiv, container);
} else {
el.insertBefore(newLineDiv, container.nextSibling);
}
const newRange = document.createRange();
newRange.selectNodeContents(newLineDiv);
newRange.collapse(true);
selection.removeAllRanges();
selection.addRange(newRange);
}
目前采用的是最简单基础的方式,之后会分析富文本编辑器,比如 Quill 或 Draft.js实现的方式。
标签:指南,node,container,newLineDiv,AI,child,输入框,input,const From: https://blog.csdn.net/vitalityxyl/article/details/140396353