javascript - Angular2 searchTerm 突出显示

标签 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,这可能是一个提示,递归级别太深了。 我已经尝试过使用第 3 方库,其中没有一个真的是为了从 angular2 中使用而设计的,最重要的是,编写的代码并不难......但它不起作用。

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


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


编辑: 使用 rc4 atm,即将升级,但这应该不是问题(我猜)

最佳答案

感谢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)

感谢您的帮助!


编辑: 有另一个 edgecase,这也使得有必要检查关键字后面的部分。更新了我的示例。

关于javascript - Angular2 searchTerm 突出显示,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39510658/

相关文章:

javascript - 单击按钮时 jQuery ui 对话框不起作用

javascript - 使用 *ngFor 和 ContentChildren 时出现 ExpressionChangedAfterItHasBeenCheckedError

JQuery - 为每个实例化的新 DOM 对象执行代码

javascript - 使用 jQuery 函数关闭多个 DIV 元素

javascript - karma 测试粘贴事件

css - 加载和页面转换时的 Angular2 动画

javascript - 如何在 postman 中使用 javascript 将唯一对象添加到 json 数组

javascript - 我们可以使用 javascript 将图像推送到浏览器缓存吗

javascript - javascript 中的 anchors.length 无法正常工作

Angular Observable HttpInterceptor ForkJoin 不起作用