Recently, I am trying to use uniapp+vue3 to develop an imitation chatgpt session function.
As shown above: After testing, markdown syntax parsing is supported on the h5/App side/mini program side . After the keyboard is raised, the entire page and the top custom navigation bar will not be raised.
uniapp markdown parsing and syntax highlighting
markdown-it
The and plug-ins are used highlight.js
to implement markdown syntax parsing and code highlighting.
// 引入uniapp markdown插件
import MarkdownIt from '@/plugins/markdown-it.min.js'
import hljs from '@/plugins/highlight/highlight.min.js'
// import '@/plugins/highlight/github-dark.min.css'
import '@/plugins/highlight/atom-one-light.css'
import parseHtml from '@/plugins/html-parser.js'
- Initialize markdown plugin
const markdown = MarkdownIt({
html: true,
highlight: function(str, lang) {
let preCode = ""
try {
preCode = hljs.highlightAuto(str).value
} catch (err) {
preCode = markdown.utils.escapeHtml(str);
}
// 自定义行号
const lines = preCode.split(/\n/).slice(0, -1)
let html = lines.map((item, index) => {
// 去掉空行
if( item == ''){
return ''
}
return '<li><span class="line-num" data-line="' + (index + 1) + '"></span>' + item +'</li>'
}).join('')
html = '<ol style="padding: 0px 30px;">' + html + '</ol>'
// 代码复制
copyCode.push(str)
let htmlCode = `<div class="markdown-wrap">`
// #ifndef MP-WEIXIN
htmlCode += `<div style="color: #aaa;text-align: right;font-size: 12px;padding:8px;">`
htmlCode += `${
lang}<a class="copy-btn" code-data-index="${
copyCode.length - 1}" style="margin-left: 8px;">复制代码</a>`
htmlCode += `</div>`
// #endif
htmlCode += `<pre class="hljs" style="padding:0 8px;margin-bottom:5px;overflow: auto;display: block;border-radius: 5px;"><code>${
html}</code></pre>`;
htmlCode += '</div>'
return htmlCode
}
})
- Parse markdown syntax
const parseNodes = (value) => {
if(!value) return
let htmlString = ''
if (value.split("```").length % 2) {
let msgContent = value
if(msgContent[msgContent.length-1] != '\n'){
msgContent += '\n'
}
htmlString = markdown.render(msgContent)
} else {
htmlString = markdown.render(msgContent.value)
}
// #ifndef APP-NVUE
return htmlString
// #endif
// nvue模式下将htmlString转成htmlArray,其他情况rich-text内部转
// 注:本示例项目还没使用nvue编译
// #ifdef APP-NVUE
return parseHtml(htmlString)
// #endif
}
Call the parseNodes method in the session message.
<rich-text space="nbsp" :nodes="parseNodes(item.content)" @itemclick="handleItemClick"></rich-text>
Components in uniapp rich-text
provide itemclick
methods. Intercept click events (only supports a and img tags) and return the current node information event.detail={node}
// 复制代码
const handleItemClick = (e) => {
console.log(e);
let {
attrs} = e.detail.node
console.log({
attrs});
let {
"code-data-index": codeDataIndex, "class": className} = attrs
if(className == 'copy-btn'){
uni.setClipboardData({
data:copyCode[codeDataIndex],
showToast:false,
success() {
uni.showToast({
title: '复制成功',
icon: 'none'
});
}
})
}
}
At this point, markdown syntax parsing can basically be supported.
uniapp keyboard holds up the page problem
In uniapp, flex is used to layout a chat page. When the input box pops up with the keyboard, the entire page will be pushed up, causing the top navigation bar to disappear.
I was wondering if I could get the keyboard height when the keyboard pops up, and then add padding to the pop-up div layer. After some attempts, this solution worked~~
As shown above: Add a view layer to the outer layer of the editor, and set padding-bottom to the keyboard pop-up height.
const fixPaddingBottom = computed(() => {
let keyH = keyboardHeight.value > 70 ? keyboardHeight.value - 70 : keyboardHeight.value
return (keyH || 10) + 'px'
})
The 70 here can be adjusted according to the actual situation.
Then get the keyboard bounce height in onMounted.
onMounted(() => {
nextTick(() => {
scrollToLast()
})
// #ifndef H5
uni.onKeyboardHeightChange(e => {
keyboardHeight.value = e.height
// 在dom渲染完毕 滚动到最后一条消息
nextTick(() => {
scrollToLast()
})
})
// #endif
})
After some debugging, when the keyboard pops up, only the content area is pushed up, but the custom navigation bar at the top will not be pushed up, which perfectly solves the problem of the entire page being pushed up.
If you have other better solutions, please feel free to discuss them together~~