一、准备工作
- 前端页面采用tailwind.css html 进行开发
- 还有代码块高亮的js
highlight.js
- 由于后端返回的是流,文本包含有反斜线等,我们需要使用marked.js进行处理
二、实现过程
首先是后端返回的流
code 请求的核心片段如下:
if (window.EventSource) {
const eventsource = new EventSource(`http://192.168.80/80/openai/openai/chat/sse?id=${uuid}&key=${apikey}&prompt=${pro}`)
//建立连接
let test = ''
eventsource.onopen = function (evt) {
console.log("server connect successed");
};
eventsource.onmessage = function (e) {
let aiMessage = JSON.parse(e.data)
console.info("server connect ai", aiMessage);
};
//发送错误,结束
eventsource.onerror = function (evt) {
console.log("服务器内部错误");
//关闭流
eventsource.close();
};
} else {
alert("浏览器不支持!请更换或者升级浏览器版本")
}
code 模拟请求的数据结构如下:
let arr = [
{ content: "简" },
{ content: "单" },
{ content: "的" },
{ content: "for" },
{ content: "循" },
{ content: "环" },
{ content: "的" },
{ content: "示" },
{ content: "例" },
{ content: ":\n\n" },
{ content: "``" },
{ content: "`\n" },
{ content: "for" },
{ content: "(int" },
{ content: " i" },
{ content: "=" },
{ content: "0" },
{ content: ";" },
{ content: " i" },
{ content: "<" },
{ content: "10" },
{ content: ";" },
{ content: " i" },
{ content: "++)" },
{ content: " {\n" },
{ content: " " },
{ content: " System" },
{ content: ".out" },
{ content: ".println" },
{ content: "(i" },
{ content: ");\n" },
{ content: "}\n" },
{ content: "``" },
{ content: "`\n\n" },
{ content: "这" },
{ content: "个" },
{ content: "循" },
{ content: "环" },
{ content: "会" },
{ content: "从" },
{ content: "0" },
{ content: "开始" },
{ content: "," },
{ content: "每" },
{ content: "次" },
{ content: "增" },
{ content: "加" },
{ content: "1" },
{ content: "," },
{ content: "一" },
{ content: "直" },
{ content: "循" },
{ content: "环" },
{ content: "到" },
{ content: "i" },
{ content: "的" },
{ content: "值" },
{ content: "等" },
{ content: "于" },
{ content: "10" },
{ content: "为" },
{ content: "止" },
{ content: "。" },
{ content: "在" },
{ content: "每" },
{ content: "次" },
{ content: "循" },
{ content: "环" },
{ content: "中" },{ content: "," },
{ content: "会" },{ content: "输出" },{ content: "当前" },{ content: "的" },{ content: "i" },{ content: "的" },{ content: "值" },{ content: "。\n\n" },{ content: "如果" }, { content: "需要" },{ content: "环" },{ content: "的" },{ content: "次" },{ content: "数" },{ content: "已" }, { content: "知" },{ content: "," },{ content: "那" },{ content: "么" },{ content: "可以" },{ content: "使用" },{ content: "for" },{ content: "循" },{ content: "环" },{ content: "。" }, { content: "如果" },{ content: "循" },{ content: "环" },{ content: "次" },{ content: "数" },{ content: "未" },{ content: "知" },{ content: ",则" },{ content: "应" }, { content: "该" },{ content: "使用" },{ content: "while" },{ content: "循" }, { content: "环" }, { content: "。" },
];
重点:
— 首先要明白这个hightlight.js高亮的是哪部分?hightlight.js对<pre><code></code></pre>
里面code包裹的代码进行高亮
问题一 :在实现的过程中我们需要对代码片段实现一个黑色背景,并且实现自己的样式,效果如下图2-1所示,问题就是怎么将系统marked.js
渲染的代码片段pre code
中间加入自己的代码片段如下code-1,那么我们在hightlight.js里面预设将我们的这个代码片段加入进去呢?如代码code-2片段所示
我们使用自定义的函数给它识别到code的时候自动加上代码片段。
<div class="bg-black rounded-md mb-4">
<div class="flex items-center relative text-gray-200 bg-gray-800 px-4 py-2 text-xs font-sans justify-between rounded-t-md"><span>Java</span>
<button class="flex ml-auto gap-2"><svg stroke="currentColor" fill="none" stroke-width="2" viewBox="0 0 24 24" stroke-linecap="round" stroke-linejoin="round" class="h-4 w-4" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg"><path d="M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2"></path><rect x="8" y="2" width="8" height="4" rx="1" ry="1"></rect></svg>复制代码</button></div>
<div class="p-4 overflow-y-auto">
<code class="!whitespace-pre hljs language-java">
//这里简单的代码示例
for (var i = 0; i < 10; i++)...
</code>
</div>
</div>
code-1
![[Pasted image 20230606095924.png]]
2-1
<script>
hljs.initHighlightingOnLoad();
// 设置marked
marked.marked.setOptions({
renderer: new marked.Renderer(),
highlight: function (code, language) {
const validLang = !!(language && hljs.getLanguage(language))
console.log(language);
if (validLang) {
const lang = language ?? ''
return highlightBlock(hljs.highlight(code, { language: lang }).value, lang)
}
return highlightBlock(hljs.highlightAuto(code).value, '')
},
pedantic: false,
gfm: true,
tables: true,
breaks: false,
sanitize: false,
smartLists: true,
smartypants: false,
xhtml: false,
});
code-2
//下面的return 后面的代码一定不能换行或者格式化,保持在一行,不然marked.js会将这些空格识别出来,改变里面的样式
function highlightBlock(str, lang) {
return `<div class="bg-black rounded-md mb-4"><div class="flex items-center relative text-gray-200 bg-gray-800 px-4 py-2 text-xs font-sans justify-between rounded-t-md"><span>${lang}</span><button class="flex ml-auto gap-2"><svg stroke="currentColor" fill="none" stroke-width="2" viewBox="0 0 24 24" stroke-linecap="round" stroke-linejoin="round" class="h-4 w-4" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg"><path d="M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2"></path><rect x="8" y="2" width="8" height="4" rx="1" ry="1"></rect></svg>Copy code</button></div><div class="p-4 overflow-y-auto"><code class="!whitespace-pre hljs language-java">${str}</code></div></div>`
}
code-3
问题梳理
— 上面的渲染完成了,接下来遇到的效果是,输入框使用的textarea,里面输入的时候自动撑开,然后使用backspace进行删除,然后不满足的行数就是自动缩小。
问题一:textarea 随着内容高度自动撑开
通过js检测文本的高度,然后动态设置文本框的高度。核心设置row=1,就会出现滚动条,然后获取scrollTop获取文本的高度,动态进行设置高度
html代码片段
<textarea id="prompt-textarea" oninput="getInput()" tabindex="0" data-id="root" rows="1"
onfocus="getFocus()" placeholder="Send a message..."
class="m-0 w-full resize-none border-0 bg-transparent p-0 pr-7 focus:ring-0 focus-visible:ring-0 dark:bg-transparent pl-2 md:pl-0"
style=" overflow-y: hidden; outline: none;"></textarea>
js代码片段
$("#prompt-textarea").css("height", $("#prompt-textarea")[0].scrollHeight + "px");
问题二:textarea内容高度撑开了,文本高度减少了,但是textarea高度不会降低
$("#prompt-textarea").css("height", "auto");