【问题标题】:How to replace multiple keywords in a string with a component如何用组件替换字符串中的多个关键字
【发布时间】:2018-07-14 22:08:20
【问题描述】:

首先,我主要是 AngularJS 开发人员,最近切换到 React,我决定将我之前开发的 Angular Web 应用程序转换为 React 应用程序。我对组件ExpressiveText 有一点问题,该组件在字符串中搜索与列表对象上的属性匹配的内容,并在其位置插入组件TriggerModal,单击该组件会触发具有更详细信息的模式。所以传入ExpressiveTest的属性是:texttagstagsProperty

text 是一个字符串(即"My search string"

tags 是一个对象数组(即[{id: 1, name: 'my', data: {...}}, {id: 2, name: 'string', data: {...}}]

tagsProperty 是要作为“标签”搜索的属性名称(即name

我与this issue 一起尝试制定如何解决此问题的想法。我提到我来自 angular 的原因是因为我之前创建的组件只是使用了 text.replace(regex, match => <trigger-modal data={tags[i]} />) 之类的东西,然后使用 angulars $compile 函数在文本中呈现组件。使用反应似乎不可能。这是我在 ExpressiveText 组件中尝试过的:

class ExpressiveTextComponent extends React.Component {
  constructor (props) {
    super(props);
    this.filterText = this.filterText.bind(this);
  }
  filterText () {
    let text = this.props.text;
    this.props.tags.map(tag => {
      const regex = new RegExp(`(${tag[this.props.tagsProperty]})`, 'gi');
      let temp = text.split(regex);
      for(let i = 1; i < temp.length; i+=2){
        temp[i] = <TriggerModal data={tag} label={tag[this.props.tagsProperty]} />;
      }
      text = temp;
    });
    return text;
  }
  render () {
    return (
      <div className={this.props.className}>{this.filterText()}</div>
    );
  }
}

这适用于第一个标签。它的问题是,一旦它到达第二个标签上的maptext 就是一个数组。我尝试添加一个条件来检查text 是否是一个数组,但是问题变成了text 数组变得嵌套并且在下一次迭代中不起作用。我很难考虑如何处理这个问题。我也尝试过使用text.replace(...)dangerouslySetInnerHTML,但这也不起作用,只是渲染[object Object] 来代替组件。非常感谢任何帮助或建议,我不得不说这可能是我切换到 React 后遇到的唯一主要问题,否则它非常简单。

编辑:由于我有一个问题要求具有给定输入和更多说明的预期输出,因此我正在寻找的是一个具有此输入的组件:

&lt;ExpressiveText text="my text" tags={{id: 1, name: 'text'}} tagsProperty="name" /&gt;

会渲染

&lt;div&gt;my &lt;TriggerModal label="text" data={...} /&gt;&lt;/div&gt;

带有功能性TriggerModal 组件。

【问题讨论】:

  • 你到底想做什么?给定一些输入,你能添加一些预期的输出吗?
  • 我不确定如何更好地解释...给定一个字符串 (text),该组件应该搜索多个关键字(来自tags 的对象,使用@987654350 定义的属性@) 并将这些关键字替换为 React 组件。问题是让反应组件呈现。这一切都发生在filterText 方法中。这有帮助吗?
  • 所以,给定这个输入:&lt;ExpressiveText text="my text" tags={{id: 1, name: 'text'}} tagsProperty="name" /&gt;,预期渲染的内容本质上是&lt;div&gt;my &lt;TriggerModal label="text" /&gt;&lt;/div&gt;

标签: javascript arrays angularjs reactjs replace


【解决方案1】:

看来我找到了解决办法。

filterText () {

  let text = this.props.text.split(' '),
    replaceIndexes = [];

  if(this.props.tags.length > 0) {

    this.props.tags.map(tag => {

      const regex = new RegExp('(' + tag[this.props.tagsProperty] + ')', 'gi');

      for(let i = 0; i < text.length; i++){

        if(text[i].match(regex)){

          /** 
           * Pretty simple if its a one-word tag, search for the word and replace.
           * could potentially cause some mis-matched tags but the words 
           * in my usecase are pretty specific, unlikely to be used in 
           * normal dialogue.
           */
          text[i] = <TriggerModal data={tag} label={tag[this.props.tagsLabelProperty || 'name']} />;

        }else{

          // for tags with spaces, split them up.
          let tempTag = tag[this.props.tagsProperty].split(' ');

          // check for length
          if(tempTag.length > 1) {

            // we will be replacing at least 1 item in the array
            let replaceCount = 0,
              startIndex = null;

            // If the first word of tempTag matches the current index, loop through the rest of the tempTag and check to see if the next words in the text array match
            if(tempTag[0].toLowerCase() === text[i].toLowerCase()){

              startIndex = i;
              replaceCount += 1;

              // loop through temp array
              for (let j = 0; j < tempTag.length; j++) {

                if(tempTag[j].toLowerCase() === text[i+j].toLowerCase()){
                  replaceCount += 1;
                }

              }

              // Push data into replaceIndexes array to process later to prevent errors with adjusting the indexes of the text object while looping
              replaceIndexes.push({
                startIndex: startIndex,
                replaceCount: replaceCount,
                element: <TriggerModal data={tag} label={tag[this.props.tagsLabelProperty || 'name']} />
              });

            }

          }
        }
      }

    });

  }

  // Loop through each replace index object 
  replaceIndexes.forEach((rep, index) => {
    text.splice(rep.startIndex - index, rep.replaceCount, [rep.element, ', ']);
  });

  // Since we stripped out spaces, we need to put them back in the places that need them.
  return text.map(item => {
    if(typeof item === "string"){
      return item + ' ';
    }
    return item;
  });

}

编辑:这实际上是非常错误的。我最终放弃了自己的解决方案,转而使用this package

【讨论】:

    【解决方案2】:

    如果我对您要完成的工作的理解是正确的,那么这是实现此目的的一种方法。如果我误解了你的问题,我深表歉意。另外,这是伪代码,稍后我将尝试用真实代码填充它。对不起,如果这很难理解,请告诉我,我会尽力澄清

    filterText () {
        let text = [this.props.text];
    
        for (let item in this.props.tags) {
            //item will be something like {id: 1, name: 'text'}
    
            let searchString = new RegExp(item.name, 'gi');
    
            //loop through text array and see if any item matches search string regex.
            while (text.some(val => val.test(searchString)) {
                //if we are here, at least one item matches the regexp
                //loop thru text array, and split any string by searchString, and insert <TriggerModal> in their place
                for (let i = text.length-1; i >=0; i--) {
                    //if text[i] is string and it matches regexp, then replace with nothing
                    text[i].replace(searchString, "")
                    //insert <trigger modal>       
                    text.splice(i, 0, <TriggerModal ... />)
                } 
            //end of while loop - test again to see if search string still exists in test array
            }
        }
        return text;
      }
    

    【讨论】:

    • 这不起作用,但确实启发了我的解决方案。这样做的问题是它导致了一个无限循环,不断添加新索引,最终导致页面超时。错误地调整它可能是我的错。如果您想了解我最终是如何解决的,请查看我发布的解决方案。
    猜你喜欢
    • 2014-10-07
    • 2014-12-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-01
    相关资源
    最近更新 更多