Angular2搜索突出显示

时间:2016-09-15 12:07:55

标签: javascript dom angular highlight

以下情景。

我用material2写了一个angular2应用程序。

在我的SideNav中是一个搜索输入字段。当用户输入时,他被重定向(通过路由)到搜索组件,而搜索到的单词作为路由参数被移交。

搜索组件显示应用程序的所有页面,其中包含搜索的单词(后台索引)。一旦用户点击该条目,他就被重定向到该页面,并且搜索到的单词被附加为查询参数。我现在正试图突出显示页面上搜索词的所有外观,用户被重定向到。目前我正在这样做:

subscription: ISubscription;
searchTerm: string;

constructor(private router: Router, private elementRef: ElementRef) {}

ngOnInit(): void {
  this.subscription = this.router.routerState.queryParams.subscribe(queryParams => {
    let searchTerm = queryParams['searchTerm'];
    if (searchTerm) {
      this.searchTerm = searchTerm;
    } else {
      this.searchTerm = null;
    }
  });
}

ngAfterContentInit(): void {
  if (this.searchTerm && isStaticDoc) {  
    let regExp = new RegExp(`(${this.searchTerm})`, 'i');
    this.highlightWords(this.elementRef.nativeElement, regExp);
  }
}

ngOnDestroy(): void {
  this.subscription.unsubscribe();
}

highlightWords(node, regExp: RegExp) {
  if (!node || ! regExp) {
    return;
  }
  if (node.nodeType === 3) {
  let regs = regExp.exec(node.nodeValue);
    if (regs) {
      let match = document.createElement('span');
      match.appendChild(document.createTextNode(regs[0]));
      match.classList.add('search-hl');

      let after = node.splitText(regs.index);
      after.nodeValue = after.nodeValue.substring(regs[0].length);
      node.parentNode.insertBefore(match, after);
    }
  } else if (node.hasChildNodes()) {
    for (let i = 0; i < node.childNodes.length; i++) {
      this.highlightWords(node.childNodes[i], regExp);
    }
  }
}

现在的问题是,我得到一个错误RangeError: Maximum call stack size exceeded,这可能是一个提示,递归级别是深入的。 我已经尝试过使用第三方库,其中非机器人实际上是从angular2和顶部使用的,编写代码并不困难......但它不起作用。

任何想法如何按照相同或类似的方法在最大调用堆栈大小之下暂存?

tl; dr 尝试在页面上突出显示searchTerm(作为queryParam传递)的所有外观 - &gt;我的方法(见代码)不是 由于最大调用堆栈大小而工作。

修改:使用rc4 atm,很快升级,但这不应该是一个问题(我猜)

1 个答案:

答案 0 :(得分:2)

感谢user3791775我提出了解决方案。

highlightWords(html: string, searchTerm: string): string {

  let regExp = new RegExp(`(${searchTerm})`, 'i');
  let results = regExp.exec(html);

  if (results) {
    let before = html.substr(0, results.index);
    let after = html.substr(results.index + searchTerm.length);

    let indexOpenTag = before.lastIndexOf('<');
    let indexCloseTag = before.lastIndexOf('>');
    let indexOpenTagAfter = after.indexOf('<');
    let indexCloseTagAfter = after.indexOf('>');

    if (indexOpenTag <= indexCloseTag && indexOpenTagAfter <= indexCloseTagAfter) {
      return `${before}<span class="search-hl">${results[0]}</span>${this.highlightWords(after, searchTerm)}`;
    } else {
      return `${before}${results[0]}${this.highlightWords(after, searchTerm)}`;
    }
  } else {
    return html;
  }
}

这可以通过以下方式使用

let ref = document.getElementById('my-highlicht-content');
ref.innerHtml = this.highlightWords(ref.innerHtml, this.searchTerm)

感谢您的帮助!

修改 有另一个边缘,这使得有必要检查关键字后面的部分。更新了我的例子。