用 JSX 中的标签替换部分字符串

Replace part of string with tag in JSX

我正在尝试用 JSX 标签替换部分字符串,如下所示:

render: function() {
    result = this.props.text.replace(":",<div className="spacer"></div>);
    return (
         <div>        
             {result}
         <div>        
    );
}

但是考虑到 this.props.textLorem : ipsum,结果是

<div>
    Lorem [object Object] ipsum.
</div>

有没有办法解决这个问题或用 JSX 标签替换部分字符串的其他方法?

当您将 JSX 元素作为第二个参数传递给 replace() 时,该元素将转换为字符串,因为 replace() 需要将字符串作为第二个参数。您需要做的是将字符串转换为字符串数组和 JSX 元素。所以你的 result 变量应该包含类似 ['Lorem ', <div className="spacer"></div>, ' ipsum'].

的东西

像这样:

function flatMap(array, fn) {
  var result = [];
  for (var i = 0; i < array.length; i++) {
    var mapping = fn(array[i]);
    result = result.concat(mapping);
  }
  return result;
}

var Comp = React.createClass({
  render: function () {
    var result = 'Lorem : ipsum';
    result = flatMap(result.split(':'), function (part) {
      return [part, <div>spacer</div>];
    });
    // Remove the last spacer
    result.pop();
    return (
      <div>        
        {result}
      </div>
    );
  }
});

以下内容也应该有效(假设 ES6),唯一的细微差别是文本实际上包裹在 DIV 元素内,而不是前面,假设您要使用 CSS对于实际间距,这应该不是问题。

const result = this.props.text.split(':').map(t => {
  return <div className='textItem'>{t}</div>;
});

如果您还希望能够在替换中进行替换(例如,在 url 中突出显示搜索词),请查看我创建的这个节点模块 - https://github.com/marcellosachs/react-string-replace-recursively

我有一个更常见的任务 - 用自定义标签包装所有(英文)单词。 我的解决方案:

class WrapWords extends React.Component {
  render() {
    const text = this.props.text;
    const isEnglishWord = /\b([-'a-z]+)\b/ig;
    const CustomWordTag = 'word';

    const byWords = text.split(isEnglishWord);

    return (
    <div>
      {
        byWords.map(word => {
          if (word.match(isEnglishWord)) {
            return <CustomWordTag>{word}</CustomWordTag>;
          }
          return word;
        })
      }
    </div>
    );
    
  }
}

// Render it
ReactDOM.render(
  <WrapWords text="Argentina, were playing: England in the quarter-finals (the 1986 World Cup in Mexico). In the 52nd minute the Argentinian captain, Diego Maradona, scored a goal." />,
  document.getElementById("react")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

<div id="react"></div>

经过一些研究,我发现现有的库不符合我的要求。所以,当然,我自己写了:

https://github.com/EfogDev/react-process-string

非常容易使用。您的案例示例:

let result = processString({
    regex: /:/gim,
    fn: () => <div className="spacer"></div>
})(this.props.test);

接受的答案是 5 岁。针对此问题,创建了 #3368 was created and based on the solution provided by a Facebook employee working on React, react-string-replace

使用 react-string-replace,这是解决问题的方法

const reactStringReplace = require('react-string-replace');

const HighlightNumbers = React.createClass({
  render() {
    const content = 'Hey my number is 555:555:5555.';
    return (
      <span>
        {reactStringReplace(content, ':', (match, i) => (
          <div className="spacer"></div>
        ))}
      </span>
    );
  },
});

钩子示例:

import React, { useEffect, useState, useRef } from 'react'

export function Highlight({ value, highlightText }) {
  const [result, resultSet] = useState(wrap())

  const isFirstRun = useRef(true) 

  function wrap() {
    let reg = new RegExp('(' + highlightText + ')', 'gi')
    let parts = value.split(reg)

    for (let i = 1; i < parts.length; i += 2) {
      parts[i] = (
        <span className='highlight' key={i}>
          {parts[i]}
        </span>
      )
    }
    return <div>{parts}</div>
  }

  useEffect(() => {
    //skip first run
    if (isFirstRun.current) {
      isFirstRun.current = false
      return
    }
    resultSet(wrap())
  }, [value, highlightText])

  return result
}

为 jsx 编写了实用函数。

const wrapTags = (text: string, regex: RegExp, className?: string) => {
  const textArray = text.split(regex);
  return textArray.map(str => {
    if (regex.test(str)) {
      return <span className={className}>{str}</span>;
    }
    return str;
  });
};

我已经开始遵循不包括第三方库或正则表达式的简单解决方案,也许它仍然可以帮助某人。

主要是用.replace()把字符串替换成正则的html写成字符串,比如:

text.replace('string-to-replace', '<span class="something"></span>')

然后在元素内使用 dangerouslySetInnerHTML 渲染它。

完整示例:

const textToRepace = 'Insert :' // we will replace : with div spacer
const content = textToRepace.replace(':', '<div class="spacer"></div>') : ''

// then in rendering just use dangerouslySetInnerHTML
render() {
    return(
        <div dangerouslySetInnerHTML={{
            __html: content
        }} />
    )
}

我认为这是最轻的完美解决方案:

render() {
    const searchValue = "an";
    const searchWordRegex = new RegExp(searchValue, "gi");
    const text =
      "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text";
    return (
      <div>
        {text.split(searchWordRegex).length > 1
          ? text.split(searchWordRegex).map((chunk, index) => {
              if (chunk !== "") {
                return index === 0 &&
                  ! new RegExp("^" + searchValue, "gi").test(text) ? (
                  chunk
                ) : (
                  <span key={index}>
                    <span
                      className="highlight"
                      style={{
                        fontWeight: "bold"
                      }}
                    >
                      {searchValue.charAt(0).toUpperCase() +
                        searchValue.slice(1)}
                    </span>
                    {chunk}
                  </span>
                );
              } else {
                return null;
              }
            })
          : text}
      </div>
    );
  }

and here is a working example

除了这个解决方案外,WEB globe 对我没有任何帮助 - https://www.npmjs.com/package/regexify-string

使用 React,字符串并且没有任何额外的依赖项

regexifyString({
    pattern: /\[.*?\]/gim,
    decorator: (match, index) => {
        return (
            <Link
                to={SOME_ROUTE}
                onClick={onClick}
            >
                {match}
            </Link>
        );
    },
    input: 'Some text with [link]',
});

你们正在使用复杂的方法,保持简单:

function replaceJSX(str, find, replace) {
    let parts = str.split(find);
    for(let i = 0, result = []; i < parts.length; i++) {
        result.push(parts[i]);
        result.push(replace);
    }
    return result;
}

用法

replaceJSX(variable, ":", <br />);

像这样:

function replaceByComponent(string, component) {
  const variable = string.substring(
    string.lastIndexOf("{{") + 2, 
    string.lastIndexOf("}}")
  );
  const strParts = string.split(`{{${variable}}}`);
  const strComponent = strParts.map((strPart, index) => {
    if(index === strParts.length - 1) {
      return strPart
    }
    return (   
      <>
        {strPart}
        <span>
          {component}
        </span>
      </>
    )
  })
  return strComponent
}

我只是编写了一个函数助手,用于将一些文本、组件甚至 HTML 替换为我的项目的模板字符串。结果很好很顺利。

const replaceJSX = (str, replacement) => {
    const result = [];
    const keys = Object.keys(replacement);
    const getRegExp = () => {
        const regexp = [];
        keys.forEach((key) => regexp.push(`{${key}}`));
        return new RegExp(regexp.join('|'));
    };
    str.split(getRegExp()).forEach((item, i) => {
        result.push(item, replacement[keys[i]]);
    });
    return result;
};

用法:

const User = ({ href, name }) => {
    return (
        <a href={href} title={name}>
            {name}
        </a>
    );
};

const string = 'Hello {component}, {html}, {string}';

return (
    <div>
        {replaceJSX(string, {
            component: (
                <User
                    href='https://whosebug.com/users/64730/magnus-engdal'
                    name='Magnus Engdal'
                />
            ),
            html: (
                <span style={{ fontWeight: 'bold' }}>
                    This would be your solution
                </span>
            ),
            string: 'Enjoy!',
        })}
    </div>
)

你会得到这样的东西:

<div>Hello <a href="https://whosebug.com/users/64730/magnus-engdal" title="Magnus Engdal">Magnus Engdal</a>, <span style="font-weight: bold;">This would be your solution.</span>, Enjoy!.</div>

就我而言,我使用 React,我想用锚标记替换文本中的 url。

在我的解决方案中,我使用了两个库。

并编写了这段代码。

/* eslint-disable react/no-danger */
import React from 'react';
import { Parser } from 'simple-text-parser';
import urlRegex from 'url-regex';

type TextRendererProps = { text: string };

const parser = new Parser();
const re = urlRegex();

parser.addRule(re, (url) => {
  return `<a href="${url}" target="_blank" rel="noopener noreferrer">${url}</a>`;
});

export const TextRenderer: React.FC<TextRendererProps> = ({ text }) => {
  return (
    <span
      dangerouslySetInnerHTML={{
        __html: parser.render(text),
      }}
    />
  );
};

您只需编写 parser.addRule().

即可轻松添加替换规则