react-native的输入框中实现插入高亮文本图片的做法

背景

上一篇文章我们介绍了rn中如何实现文本高亮,但是输入框中实现文本高亮如何做呢?输入框中插入图片等如何实现呢?这篇文章将普及一下这方面的知识,分享给大家。

输入框高亮文本

其实假如你要实现输入框高亮文本,那么可以通过如下方式实现。

ini 复制代码
    <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 通过富文本的形式实现。假如通过富文本实现,那么出来的数据结构是如下的:

ini 复制代码
'<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字符串的形式来存储。例如可以转换为如下:

bash 复制代码
[{
	type: 'div',
	text: '你好haorooms博客 '
}, {
	type: 'span',
	text: '@haorooms博客 ',
	id: '1'
}, {
	type: 'span',
	text: '#文本高亮话题',
	id: '2'
}, {
	type: 'div',
	text: '这里是rn的渲染'
}]

将html转换为json字符串,需要一些编译解析。我是这么解析的:

1、html转为josn

javascript 复制代码
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

javascript 复制代码
  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来实现这个功能。

今天文章暂时分享到这里。

相关推荐
小小小小宇1 小时前
虚拟列表兼容老DOM操作
前端
悦悦子a啊1 小时前
Python之--基本知识
开发语言·前端·python
安全系统学习2 小时前
系统安全之大模型案例分析
前端·安全·web安全·网络安全·xss
涛哥码咖3 小时前
chrome安装AXURE插件后无效
前端·chrome·axure
OEC小胖胖3 小时前
告别 undefined is not a function:TypeScript 前端开发优势与实践指南
前端·javascript·typescript·web
行云&流水3 小时前
Vue3 Lifecycle Hooks
前端·javascript·vue.js
Sally璐璐3 小时前
零基础学HTML和CSS:网页设计入门
前端·css
老虎06273 小时前
JavaWeb(苍穹外卖)--学习笔记04(前端:HTML,CSS,JavaScript)
前端·javascript·css·笔记·学习·html
三水气象台4 小时前
用户中心Vue3网页开发(1.0版)
javascript·css·vue.js·typescript·前端框架·html·anti-design-vue
灿灿121384 小时前
CSS 文字浮雕效果:巧用 text-shadow 实现 3D 立体文字
前端·css