背景
上一篇文章我们介绍了rn中如何实现文本高亮,但是输入框中实现文本高亮如何做呢?输入框中插入图片等如何实现呢?这篇文章将普及一下这方面的知识,分享给大家。
输入框高亮文本
其实假如你要实现输入框高亮文本,那么可以通过如下方式实现。
<TextInput maxlength={200} onChange={onInputEventDetail} onFocus={() => showBar()} onBlur={() => (Platform.OS == 'ios' ? hideKeyboard() : null)} multiline={true} textAlign={'left'} style={{ textAlignVertical: 'top' }} onKeyPress={onKeyPressfn} onTextInput={onTextInput} className={Style['publish-textarea']} placeholder='haorooms发布帖子测试'>
<Text>
{matchAtData?.length > 0 ? (
<>
{textData
.filter((li) => li.trim())
.map((item, index) => {
if (matchAtData.join('').indexOf(item) != -1) {
return item ? (
<Text className={Style['bbs_text_at']} key={index}>
{item}
</Text>
) : null
} else {
return <Text key={index}>{item}</Text>
}
})}
</>
) : (
textValue
)}
</Text>
</TextInput>
这种方式可以实现文本框里面高亮文本了。
输入框里面插入图片如何实现呢?
假如需要插入图片,上面方式ios不兼容,插入多张图片的时候都不兼容,如何解决呢?只能利用react-native-webview 通过富文本的形式实现。假如通过富文本实现,那么出来的数据结构是如下的:
'<div>你好haorooms博客
<span style="color:#006ff6;" contenteditable="false" data-id="1">@haorooms博客</span>
<span style="color:#006ff6;" contenteditable="false" data-id="2">#文本高亮话题</span>
这里是rn的渲染</div>';
rn里面出现这种富文本,后端存储2种方式,一种直接存储,这样的话,前台展示的时候也要通过富文本渲染出来。第二种我们可以通过转换为json字符串的形式来存储。例如可以转换为如下:
[{
type: 'div',
text: '你好haorooms博客 '
}, {
type: 'span',
text: '@haorooms博客 ',
id: '1'
}, {
type: 'span',
text: '#文本高亮话题',
id: '2'
}, {
type: 'div',
text: '这里是rn的渲染'
}]
将html转换为json字符串,需要一些编译解析。我是这么解析的:
1、html转为josn
const operateHtmlToData = (html) => {
// 改进的正则表达式
const regex = /<(\w+)([^>]*)?>([^<]*)<\/\1>|<(\w+)([^>]*)?>([^<]*)|([^<]+)/g
const matches = html.matchAll(regex)
const result = []
for (const match of matches) {
const [, tagName, tagAttrs, tagText, inlineTagName, inlineTagAttrs, inlineTagText, plainText] = match
if (tagName) {
let _tagText = tagText.trim()
_tagText = _tagText.replace(/<br>/g, '\n')
_tagText = _tagText.replace(/ /g, ' ')
const obj = {
type: tagName,
text: _tagText
}
if (tagAttrs) {
const attrs = tagAttrs.split(' ')
for (const attr of attrs) {
const [key, values] = attr.split('=')
if (key === 'data-id') {
obj.id = values.replace(/("|')/g, '')
}
}
}
if (obj.text || obj.id) {
// 只添加有内容或id的对象
result.push(obj)
}
} else if (inlineTagName) {
let _inlineTagText = inlineTagText.trim()
_inlineTagText = _inlineTagText.replace(/<br>/g, '\n')
_inlineTagText = _inlineTagText.replace(/ /g, ' ')
const obj = {
type: inlineTagName,
text: _inlineTagText
}
if (inlineTagAttrs) {
const attrs = inlineTagAttrs.split(' ')
for (const attr of attrs) {
const [key, values] = attr.split('=')
if (key === 'data-id') {
obj.id = values.replace(/("|')/g, '')
}
}
}
if (obj.text || obj.id) {
// 只添加有内容或id的对象
result.push(obj)
}
} else if (plainText) {
// 对于不在任何HTML标签内的纯文本
let trimmedText = plainText.trim()
trimmedText = trimmedText.replace(/<br>/g, '\n')
trimmedText = trimmedText.replace(/ /g, ' ')
if (trimmedText && plainText != '/div>') {
// 只添加非空文本
result.push({
type: 'text',
text: trimmedText
})
}
}
}
return result
}
2、json转为html
const renderElement = (element) => {
switch (element.type) {
case 'div':
return `<div>${element.text}</div>`
case 'at':
return `<span style='color:#006ff6;' contenteditable="false" data-id=${element.id}>${element.text}</span>`
case 'text':
return element.text
default:
return null
}
}
const renderData = value.map((item) => renderElement(item)).join('')
setTextValue(renderData)
这种方式存储,列表也展示也是可以通过循环数组直接展示出来。但是需要遇到div的时候强制换行,span的时候不换行,需要在rn里面实现这个功能。那么可以利用view包裹一层text来实现这个功能。
今天文章暂时分享到这里。