2016-09-15 39 views
1

以下情景。Angular2 searchTerm突出顯示

我用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,這可能是一種提示,遞歸水平的方式來深。 我已經嘗試過使用第三方庫,但它們中的非bot都是從angular2開始使用的,而且書寫的代碼並不那麼困難......但它不起作用。

任何想法如何在遵循相同或類似方法的最大調用堆棧大小下進行播放?


TL;博士刻意突出搜索關鍵詞的所有出現在頁面上(這是經過一個queryParam) - >我的做法(見代碼)不 由於最大調用堆棧大小的工作。


編輯:使用RC4 ATM,很快提升,但是這不應該是一個問題(我猜)

+0

爲什麼不在你的搜索結果中使用字符串替換函數,然後再將它們插入到DOM中? (將'searchvalue'替換爲' searchvalue')要全部替換,請參閱:http://stackoverflow.com/questions/1144783/replacing-all-occurrences-of-a-string-in-首先,javascript – user3791775

+0

,謝謝你的回答。但問題是,通過簡單地調用(例如)'link#href'中的searchTerm事件的'node#innerHtml'中的替換或ID中的''也被'span'包圍,這導致突出顯示但非常破碎的頁面(取決於搜索詞)。 我也嘗試過只匹配沒有站在標籤中的單詞,但是由於在鏈接(對於其他站點)中存在無限的可能性,幾乎不可能找到正確的正則表達式,特別是在js中缺少負面看法... – Mit0x2

+1

然後你可以發現匹配前的'<' or '>'的第一次出現是'>'並且匹配之後是'<'的情況。(所以你知道它不在標籤內) – user3791775

回答

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) 

感謝您的幫助!


編輯: 有另一個edgecase,這使得有必要檢查關鍵字後面的一部分。更新我的例子。