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 小时前
Vue 2 + JavaScript + vue-count-to 集成案例
前端·javascript·vue.js
并不会2 小时前
常见 CSS 选择器用法
前端·css·学习·html·前端开发·css选择器
悦涵仙子2 小时前
CSS中的变量应用——:root,Sass变量,JavaScript中使用Sass变量
javascript·css·sass
衣乌安、2 小时前
【CSS】居中样式
前端·css·css3
兔老大的胡萝卜2 小时前
ppk谈JavaScript,悟透JavaScript,精通CSS高级Web,JavaScript DOM编程艺术,高性能JavaScript pdf
前端·javascript
低代码布道师2 小时前
CSS的三个重点
前端·css
耶啵奶膘3 小时前
uniapp-是否删除
linux·前端·uni-app
王哈哈^_^5 小时前
【数据集】【YOLO】【目标检测】交通事故识别数据集 8939 张,YOLO道路事故目标检测实战训练教程!
前端·人工智能·深度学习·yolo·目标检测·计算机视觉·pyqt
cs_dn_Jie5 小时前
钉钉 H5 微应用 手机端调试
前端·javascript·vue.js·vue·钉钉
开心工作室_kaic6 小时前
ssm068海鲜自助餐厅系统+vue(论文+源码)_kaic
前端·javascript·vue.js