【问题标题】:Angular2 searchTerm highlightingAngular2搜索词突出显示
【发布时间】:2017-01-23 10:52:44
【问题描述】:

以下场景。

我用 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,这可能是一个暗示,递归级别太深了。 我已经尝试过使用 3rd 方库,它们中的任何一个都不是真的可以从 angular2 使用,而且最重要的是,编写的代码并不难……但它不起作用。

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


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


编辑:使用 rc4 atm,很快就会升级,但这应该不是问题(我猜)

【问题讨论】:

  • 在将搜索结果插入 dom 之前,为什么不对搜索结果使用字符串替换功能? (将 'searchvalue' 替换为 'searchvalue')要全部替换,请参阅:stackoverflow.com/questions/1144783/…
  • 首先,感谢您的回答。但问题是,通过简单地调用替换 node#innerHtml 在(例如)a link#href 或 id 中出现的 searchTerm 也会被 span 包围,这会导致突出显示但非常破碎的页面(取决于搜索词)。我也尝试只匹配不在标签中的单词,但由于链接(到其他网站)有无限的可能性,几乎不可能找到正确的正则表达式,尤其是在 js 中缺乏负面外观的情况下......跨度>
  • 然后你可以找到匹配前第一次出现的“”是“>”,匹配后是“
  • @user3791775 我已经根据您的建议制定了一个解决方案。非常感谢!
  • 很高兴听到这个消息!

标签: javascript dom angular highlight


【解决方案1】:

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

感谢您的帮助!


编辑: 有另一个边缘情况,这使得有必要检查关键字之后的部分。更新了我的示例。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-08-04
    • 2012-05-21
    • 2014-02-13
    • 2015-01-28
    • 1970-01-01
    • 2021-06-24
    相关资源
    最近更新 更多